Package com.google.gwt.dev.js

Source Code of com.google.gwt.dev.js.JsIEBlockSizeVisitor

/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev.js;

import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.js.ast.JsBlock;
import com.google.gwt.dev.js.ast.JsCase;
import com.google.gwt.dev.js.ast.JsContext;
import com.google.gwt.dev.js.ast.JsDefault;
import com.google.gwt.dev.js.ast.JsProgram;
import com.google.gwt.dev.js.ast.JsStatement;
import com.google.gwt.dev.js.ast.JsSwitchMember;
import com.google.gwt.dev.js.ast.JsVisitor;

import java.util.List;
import java.util.ListIterator;

/**
* Some versions of IE7 have a limit on the number of statements that can appear
* within a JsBlock. This visitor will restructure blocks and other block-like
* structures with too many statements in order to reduce the total number of
* statements that appear within any given block to fewer than
* {@value #MAX_BLOCK_SIZE} statements by creating nested blocks: 
*
* <pre>
* {
*   { statements }
*   { statements }
*   remainder of statements
* }
* </pre>
*
* This change is purely structural, it will not affect code flow.
*/
public class JsIEBlockSizeVisitor {

  /**
   * Visits every block-like structure.
   */
  private static class BlockVisitor extends JsVisitor {

    private final JsProgram program;

    public BlockVisitor(JsProgram program) {
      this.program = program;
    }

    @Override
    public void endVisit(JsBlock x, JsContext<JsStatement> ctx) {
      // JsFunctionClusterer handles restructuring top-level statement blocks
      if (!x.isGlobalBlock()) {
        restructure(x.getStatements());
      }
    }

    @Override
    public void endVisit(JsCase x, JsContext<JsSwitchMember> ctx) {
      restructure(x.getStmts());
    }

    @Override
    public void endVisit(JsDefault x, JsContext<JsSwitchMember> ctx) {
      restructure(x.getStmts());
    }

    /**
     * Perform the restructuring on a list of statements. Blocks are created as
     * necessary to prevent any given block from exceeding the maximum size.
     */
    private void restructure(List<JsStatement> statements) {
      SourceInfo sourceInfo = program.createSourceInfoSynthetic(
          JsIEBlockSizeVisitor.class, "Restructured to reduce block size");
      // This outer loop will collapse the newly-created block into super-blocks
      while (statements.size() > MAX_BLOCK_SIZE) {
        ListIterator<JsStatement> i = statements.listIterator();
        List<JsStatement> statementsInNewBlock = null;

        // This loop represents a single fold over the list of statements
        while (statements.size() > MAX_BLOCK_SIZE && i.hasNext()) {
          JsStatement current = i.next();

          if (statementsInNewBlock == null) {
            // Replace the current statement with a new block
            JsBlock newBlock = new JsBlock(sourceInfo);
            statementsInNewBlock = newBlock.getStatements();
            i.set(newBlock);
          } else {
            /*
             * There's an open replacement block, remove the statement from its
             * current block.
             */
            i.remove();
          }

          // Move the statement into the new block
          statementsInNewBlock.add(current);

          /*
           * If we hit the cap on a new block, discard the reference to create a
           * new block for the next statement that we see.
           */
          if (statementsInNewBlock.size() == MAX_BLOCK_SIZE) {
            statementsInNewBlock = null;
          }
        }
      }
      assert statements.size() <= MAX_BLOCK_SIZE;
    }
  }

  // Use this value instead to test the effects of the visitor
  // private static final int MAX_BLOCK_SIZE = 1 << 5;

  private static final int MAX_BLOCK_SIZE = 1 << 15 - 1;

  /**
   * Entry point.
   */
  public static void exec(JsProgram program) {
    (new BlockVisitor(program)).accept(program);
  }
}
TOP

Related Classes of com.google.gwt.dev.js.JsIEBlockSizeVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.