8135190: Method code too large in Babel browser.js script

Sat, 19 Sep 2015 16:04:28 +0200

author
hannesw
date
Sat, 19 Sep 2015 16:04:28 +0200
changeset 1542
89477d713a96
parent 1541
e4a553f79ebd
child 1543
8173e810dc17

8135190: Method code too large in Babel browser.js script
Reviewed-by: attila, sundar

src/jdk/nashorn/internal/codegen/AssignSymbols.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CodeGenerator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/FieldObjectCreator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/MethodEmitter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/ObjectCreator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/SpillObjectCreator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Splitter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/WeighNodes.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/types/Type.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/LiteralNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/ObjectNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/Splittable.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Context.java file | annotate | diff | comparison | revisions
test/script/basic/JDK-8135190.js file | annotate | diff | comparison | revisions
     1.1 --- a/src/jdk/nashorn/internal/codegen/AssignSymbols.java	Thu Sep 17 18:23:53 2015 +0530
     1.2 +++ b/src/jdk/nashorn/internal/codegen/AssignSymbols.java	Sat Sep 19 16:04:28 2015 +0200
     1.3 @@ -70,11 +70,10 @@
     1.4  import jdk.nashorn.internal.ir.LexicalContext;
     1.5  import jdk.nashorn.internal.ir.LexicalContextNode;
     1.6  import jdk.nashorn.internal.ir.LiteralNode;
     1.7 -import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
     1.8 -import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
     1.9  import jdk.nashorn.internal.ir.Node;
    1.10  import jdk.nashorn.internal.ir.RuntimeNode;
    1.11  import jdk.nashorn.internal.ir.RuntimeNode.Request;
    1.12 +import jdk.nashorn.internal.ir.Splittable;
    1.13  import jdk.nashorn.internal.ir.Statement;
    1.14  import jdk.nashorn.internal.ir.SwitchNode;
    1.15  import jdk.nashorn.internal.ir.Symbol;
    1.16 @@ -984,7 +983,7 @@
    1.17          boolean previousWasBlock = false;
    1.18          for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) {
    1.19              final LexicalContextNode node = it.next();
    1.20 -            if (node instanceof FunctionNode || isSplitArray(node)) {
    1.21 +            if (node instanceof FunctionNode || isSplitLiteral(node)) {
    1.22                  // We reached the function boundary or a splitting boundary without seeing a definition for the symbol.
    1.23                  // It needs to be in scope.
    1.24                  return true;
    1.25 @@ -1010,12 +1009,8 @@
    1.26          throw new AssertionError();
    1.27      }
    1.28  
    1.29 -    private static boolean isSplitArray(final LexicalContextNode expr) {
    1.30 -        if(!(expr instanceof ArrayLiteralNode)) {
    1.31 -            return false;
    1.32 -        }
    1.33 -        final List<ArrayUnit> units = ((ArrayLiteralNode)expr).getUnits();
    1.34 -        return !(units == null || units.isEmpty());
    1.35 +    private static boolean isSplitLiteral(final LexicalContextNode expr) {
    1.36 +        return expr instanceof Splittable && ((Splittable) expr).getSplitRanges() != null;
    1.37      }
    1.38  
    1.39      private void throwUnprotectedSwitchError(final VarNode varNode) {
     2.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Sep 17 18:23:53 2015 +0530
     2.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Sat Sep 19 16:04:28 2015 +0200
     2.3 @@ -105,7 +105,6 @@
     2.4  import jdk.nashorn.internal.ir.LexicalContextNode;
     2.5  import jdk.nashorn.internal.ir.LiteralNode;
     2.6  import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
     2.7 -import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
     2.8  import jdk.nashorn.internal.ir.LiteralNode.PrimitiveLiteralNode;
     2.9  import jdk.nashorn.internal.ir.LocalVariableConversion;
    2.10  import jdk.nashorn.internal.ir.LoopNode;
    2.11 @@ -118,6 +117,7 @@
    2.12  import jdk.nashorn.internal.ir.RuntimeNode.Request;
    2.13  import jdk.nashorn.internal.ir.SetSplitState;
    2.14  import jdk.nashorn.internal.ir.SplitReturn;
    2.15 +import jdk.nashorn.internal.ir.Splittable;
    2.16  import jdk.nashorn.internal.ir.Statement;
    2.17  import jdk.nashorn.internal.ir.SwitchNode;
    2.18  import jdk.nashorn.internal.ir.Symbol;
    2.19 @@ -242,7 +242,7 @@
    2.20      private final DebugLogger log;
    2.21  
    2.22      /** From what size should we use spill instead of fields for JavaScript objects? */
    2.23 -    private static final int OBJECT_SPILL_THRESHOLD = Options.getIntProperty("nashorn.spill.threshold", 256);
    2.24 +    static final int OBJECT_SPILL_THRESHOLD = Options.getIntProperty("nashorn.spill.threshold", 256);
    2.25  
    2.26      private final Set<String> emittedMethods = new HashSet<>();
    2.27  
    2.28 @@ -2234,73 +2234,33 @@
    2.29       *
    2.30       * @param arrayLiteralNode the array of contents
    2.31       * @param arrayType        the type of the array, e.g. ARRAY_NUMBER or ARRAY_OBJECT
    2.32 -     *
    2.33 -     * @return the method generator that was used
    2.34       */
    2.35 -    private MethodEmitter loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) {
    2.36 +    private void loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) {
    2.37          assert arrayType == Type.INT_ARRAY || arrayType == Type.LONG_ARRAY || arrayType == Type.NUMBER_ARRAY || arrayType == Type.OBJECT_ARRAY;
    2.38  
    2.39 -        final Expression[]    nodes    = arrayLiteralNode.getValue();
    2.40 -        final Object          presets  = arrayLiteralNode.getPresets();
    2.41 -        final int[]           postsets = arrayLiteralNode.getPostsets();
    2.42 -        final Class<?>        type     = arrayType.getTypeClass();
    2.43 -        final List<ArrayUnit> units    = arrayLiteralNode.getUnits();
    2.44 +        final Expression[]     nodes    = arrayLiteralNode.getValue();
    2.45 +        final Object           presets  = arrayLiteralNode.getPresets();
    2.46 +        final int[]            postsets = arrayLiteralNode.getPostsets();
    2.47 +        final List<Splittable.SplitRange> ranges   = arrayLiteralNode.getSplitRanges();
    2.48  
    2.49          loadConstant(presets);
    2.50  
    2.51          final Type elementType = arrayType.getElementType();
    2.52  
    2.53 -        if (units != null) {
    2.54 -            final MethodEmitter savedMethod     = method;
    2.55 -            final FunctionNode  currentFunction = lc.getCurrentFunction();
    2.56 -
    2.57 -            for (final ArrayUnit arrayUnit : units) {
    2.58 -                unit = lc.pushCompileUnit(arrayUnit.getCompileUnit());
    2.59 -
    2.60 -                final String className = unit.getUnitClassName();
    2.61 -                assert unit != null;
    2.62 -                final String name      = currentFunction.uniqueName(SPLIT_PREFIX.symbolName());
    2.63 -                final String signature = methodDescriptor(type, ScriptFunction.class, Object.class, ScriptObject.class, type);
    2.64 -
    2.65 -                pushMethodEmitter(unit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature));
    2.66 -
    2.67 -                method.setFunctionNode(currentFunction);
    2.68 -                method.begin();
    2.69 -
    2.70 -                defineCommonSplitMethodParameters();
    2.71 -                defineSplitMethodParameter(CompilerConstants.SPLIT_ARRAY_ARG.slot(), arrayType);
    2.72 -
    2.73 -                // NOTE: when this is no longer needed, SplitIntoFunctions will no longer have to add IS_SPLIT
    2.74 -                // to synthetic functions, and FunctionNode.needsCallee() will no longer need to test for isSplit().
    2.75 -                final int arraySlot = fixScopeSlot(currentFunction, 3);
    2.76 -
    2.77 -                lc.enterSplitNode();
    2.78 -
    2.79 -                for (int i = arrayUnit.getLo(); i < arrayUnit.getHi(); i++) {
    2.80 -                    method.load(arrayType, arraySlot);
    2.81 -                    storeElement(nodes, elementType, postsets[i]);
    2.82 +        if (ranges != null) {
    2.83 +
    2.84 +            loadSplitLiteral(new SplitLiteralCreator() {
    2.85 +                @Override
    2.86 +                public void populateRange(final MethodEmitter method, final Type type, final int slot, final int start, final int end) {
    2.87 +                    for (int i = start; i < end; i++) {
    2.88 +                        method.load(type, slot);
    2.89 +                        storeElement(nodes, elementType, postsets[i]);
    2.90 +                    }
    2.91 +                    method.load(type, slot);
    2.92                  }
    2.93 -
    2.94 -                method.load(arrayType, arraySlot);
    2.95 -                method._return();
    2.96 -                lc.exitSplitNode();
    2.97 -                method.end();
    2.98 -                lc.releaseSlots();
    2.99 -                popMethodEmitter();
   2.100 -
   2.101 -                assert method == savedMethod;
   2.102 -                method.loadCompilerConstant(CALLEE);
   2.103 -                method.swap();
   2.104 -                method.loadCompilerConstant(THIS);
   2.105 -                method.swap();
   2.106 -                method.loadCompilerConstant(SCOPE);
   2.107 -                method.swap();
   2.108 -                method.invokestatic(className, name, signature);
   2.109 -
   2.110 -                unit = lc.popCompileUnit(unit);
   2.111 -            }
   2.112 -
   2.113 -            return method;
   2.114 +            }, ranges, arrayType);
   2.115 +
   2.116 +            return;
   2.117          }
   2.118  
   2.119          if(postsets.length > 0) {
   2.120 @@ -2312,7 +2272,6 @@
   2.121              }
   2.122              method.load(arrayType, arraySlot);
   2.123          }
   2.124 -        return method;
   2.125      }
   2.126  
   2.127      private void storeElement(final Expression[] nodes, final Type elementType, final int index) {
   2.128 @@ -2537,6 +2496,7 @@
   2.129          final List<MapTuple<Expression>> tuples = new ArrayList<>();
   2.130          final List<PropertyNode> gettersSetters = new ArrayList<>();
   2.131          final int ccp = getCurrentContinuationEntryPoint();
   2.132 +        final List<Splittable.SplitRange> ranges = objectNode.getSplitRanges();
   2.133  
   2.134          Expression protoNode = null;
   2.135          boolean restOfProperty = false;
   2.136 @@ -2583,7 +2543,13 @@
   2.137                      loadExpressionAsType(node, type);
   2.138                  }};
   2.139          }
   2.140 -        oc.makeObject(method);
   2.141 +
   2.142 +        if (ranges != null) {
   2.143 +            oc.createObject(method);
   2.144 +            loadSplitLiteral(oc, ranges, Type.typeFor(oc.getAllocatorClass()));
   2.145 +        } else {
   2.146 +            oc.makeObject(method);
   2.147 +        }
   2.148  
   2.149          //if this is a rest of method and our continuation point was found as one of the values
   2.150          //in the properties above, we need to reset the map to oc.getMap() in the continuation
   2.151 @@ -2899,6 +2865,54 @@
   2.152          method.onLocalStore(type, slot);
   2.153      }
   2.154  
   2.155 +    private void loadSplitLiteral(final SplitLiteralCreator creator, final List<Splittable.SplitRange> ranges, final Type literalType) {
   2.156 +        assert ranges != null;
   2.157 +
   2.158 +        // final Type literalType = Type.typeFor(literalClass);
   2.159 +        final MethodEmitter savedMethod     = method;
   2.160 +        final FunctionNode  currentFunction = lc.getCurrentFunction();
   2.161 +
   2.162 +        for (final Splittable.SplitRange splitRange : ranges) {
   2.163 +            unit = lc.pushCompileUnit(splitRange.getCompileUnit());
   2.164 +
   2.165 +            assert unit != null;
   2.166 +            final String className = unit.getUnitClassName();
   2.167 +            final String name      = currentFunction.uniqueName(SPLIT_PREFIX.symbolName());
   2.168 +            final Class<?> clazz   = literalType.getTypeClass();
   2.169 +            final String signature = methodDescriptor(clazz, ScriptFunction.class, Object.class, ScriptObject.class, clazz);
   2.170 +
   2.171 +            pushMethodEmitter(unit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature));
   2.172 +
   2.173 +            method.setFunctionNode(currentFunction);
   2.174 +            method.begin();
   2.175 +
   2.176 +            defineCommonSplitMethodParameters();
   2.177 +            defineSplitMethodParameter(CompilerConstants.SPLIT_ARRAY_ARG.slot(), literalType);
   2.178 +
   2.179 +            // NOTE: when this is no longer needed, SplitIntoFunctions will no longer have to add IS_SPLIT
   2.180 +            // to synthetic functions, and FunctionNode.needsCallee() will no longer need to test for isSplit().
   2.181 +            final int literalSlot = fixScopeSlot(currentFunction, 3);
   2.182 +
   2.183 +            lc.enterSplitNode();
   2.184 +
   2.185 +            creator.populateRange(method, literalType, literalSlot, splitRange.getLow(), splitRange.getHigh());
   2.186 +
   2.187 +            method._return();
   2.188 +            lc.exitSplitNode();
   2.189 +            method.end();
   2.190 +            lc.releaseSlots();
   2.191 +            popMethodEmitter();
   2.192 +
   2.193 +            assert method == savedMethod;
   2.194 +            method.loadCompilerConstant(CALLEE).swap();
   2.195 +            method.loadCompilerConstant(THIS).swap();
   2.196 +            method.loadCompilerConstant(SCOPE).swap();
   2.197 +            method.invokestatic(className, name, signature);
   2.198 +
   2.199 +            unit = lc.popCompileUnit(unit);
   2.200 +        }
   2.201 +    }
   2.202 +
   2.203      private int fixScopeSlot(final FunctionNode functionNode, final int extraSlot) {
   2.204          // TODO hack to move the scope to the expected slot (needed because split methods reuse the same slots as the root method)
   2.205          final int actualScopeSlot = functionNode.compilerConstant(SCOPE).getSlot(SCOPE_TYPE);
   2.206 @@ -5461,4 +5475,21 @@
   2.207              method.uncheckedGoto(targetCatchLabel);
   2.208          }
   2.209      }
   2.210 +
   2.211 +    /**
   2.212 +     * Interface implemented by object creators that support splitting over multiple methods.
   2.213 +     */
   2.214 +    interface SplitLiteralCreator {
   2.215 +        /**
   2.216 +         * Generate code to populate a range of the literal object. A reference to the object
   2.217 +         * should be left on the stack when the method terminates.
   2.218 +         *
   2.219 +         * @param method the method emitter
   2.220 +         * @param type the type of the literal object
   2.221 +         * @param slot the local slot containing the literal object
   2.222 +         * @param start the start index (inclusive)
   2.223 +         * @param end the end index (exclusive)
   2.224 +         */
   2.225 +        void populateRange(MethodEmitter method, Type type, int slot, int start, int end);
   2.226 +    }
   2.227  }
     3.1 --- a/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java	Thu Sep 17 18:23:53 2015 +0530
     3.2 +++ b/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java	Sat Sep 19 16:04:28 2015 +0200
     3.3 @@ -34,7 +34,6 @@
     3.4  import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
     3.5  import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
     3.6  
     3.7 -import java.util.Iterator;
     3.8  import java.util.List;
     3.9  import jdk.nashorn.internal.codegen.types.Type;
    3.10  import jdk.nashorn.internal.ir.Symbol;
    3.11 @@ -91,27 +90,20 @@
    3.12          findClass();
    3.13      }
    3.14  
    3.15 -    /**
    3.16 -     * Construct an object.
    3.17 -     *
    3.18 -     * @param method the method emitter
    3.19 -     */
    3.20      @Override
    3.21 -    protected void makeObject(final MethodEmitter method) {
    3.22 +    public void createObject(final MethodEmitter method) {
    3.23          makeMap();
    3.24          final String className = getClassName();
    3.25 -        try {
    3.26 -            // NOTE: we must load the actual structure class here, because the API operates with Nashorn Type objects,
    3.27 -            // and Type objects need a loaded class, for better or worse. We also have to be specific and use the type
    3.28 -            // of the actual structure class, we can't generalize it to e.g. Type.typeFor(ScriptObject.class) as the
    3.29 -            // exact type information is needed for generating continuations in rest-of methods. If we didn't do this,
    3.30 -            // object initializers like { x: arr[i] } would fail during deoptimizing compilation on arr[i], as the
    3.31 -            // values restored from the RewriteException would be cast to "ScriptObject" instead of to e.g. "JO4", and
    3.32 -            // subsequently the "PUTFIELD J04.L0" instruction in the continuation code would fail bytecode verification.
    3.33 -            method._new(Context.forStructureClass(className.replace('/', '.'))).dup();
    3.34 -        } catch (final ClassNotFoundException e) {
    3.35 -            throw new AssertionError(e);
    3.36 -        }
    3.37 +        // NOTE: we must load the actual structure class here, because the API operates with Nashorn Type objects,
    3.38 +        // and Type objects need a loaded class, for better or worse. We also have to be specific and use the type
    3.39 +        // of the actual structure class, we can't generalize it to e.g. Type.typeFor(ScriptObject.class) as the
    3.40 +        // exact type information is needed for generating continuations in rest-of methods. If we didn't do this,
    3.41 +        // object initializers like { x: arr[i] } would fail during deoptimizing compilation on arr[i], as the
    3.42 +        // values restored from the RewriteException would be cast to "ScriptObject" instead of to e.g. "JO4", and
    3.43 +        // subsequently the "PUTFIELD J04.L0" instruction in the continuation code would fail bytecode verification.
    3.44 +        assert fieldObjectClass != null;
    3.45 +        method._new(fieldObjectClass).dup();
    3.46 +
    3.47          loadMap(method); //load the map
    3.48  
    3.49          if (isScope()) {
    3.50 @@ -126,14 +118,14 @@
    3.51          } else {
    3.52              method.invoke(constructorNoLookup(className, PropertyMap.class));
    3.53          }
    3.54 +    }
    3.55  
    3.56 -        helpOptimisticRecognizeDuplicateIdentity(method);
    3.57 -
    3.58 +    @Override
    3.59 +    public void populateRange(final MethodEmitter method, final Type objectType, final int objectSlot, final int start, final int end) {
    3.60 +        method.load(objectType, objectSlot);
    3.61          // Set values.
    3.62 -        final Iterator<MapTuple<T>> iter = tuples.iterator();
    3.63 -
    3.64 -        while (iter.hasNext()) {
    3.65 -            final MapTuple<T> tuple = iter.next();
    3.66 +        for (int i = start; i < end; i++) {
    3.67 +            final MapTuple<T> tuple = tuples.get(i);
    3.68              //we only load when we have both symbols and values (which can be == the symbol)
    3.69              //if we didn't load, we need an array property
    3.70              if (tuple.symbol != null && tuple.value != null) {
    3.71 @@ -212,6 +204,11 @@
    3.72          }
    3.73      }
    3.74  
    3.75 +    @Override
    3.76 +    protected Class<? extends ScriptObject> getAllocatorClass() {
    3.77 +        return fieldObjectClass;
    3.78 +    }
    3.79 +
    3.80      /**
    3.81       * Get the class name for the object class,
    3.82       * e.g. {@code com.nashorn.oracle.scripts.JO2P0}
     4.1 --- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Thu Sep 17 18:23:53 2015 +0530
     4.2 +++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Sat Sep 19 16:04:28 2015 +0200
     4.3 @@ -258,8 +258,7 @@
     4.4       */
     4.5      private Type popType(final Type expected) {
     4.6          final Type type = popType();
     4.7 -        assert type.isObject() && expected.isObject() ||
     4.8 -            type.isEquivalentTo(expected) : type + " is not compatible with " + expected;
     4.9 +        assert type.isEquivalentTo(expected) : type + " is not compatible with " + expected;
    4.10          return type;
    4.11      }
    4.12  
     5.1 --- a/src/jdk/nashorn/internal/codegen/ObjectCreator.java	Thu Sep 17 18:23:53 2015 +0530
     5.2 +++ b/src/jdk/nashorn/internal/codegen/ObjectCreator.java	Sat Sep 19 16:04:28 2015 +0200
     5.3 @@ -36,7 +36,7 @@
     5.4   * Base class for object creation code generation.
     5.5   * @param <T> value type
     5.6   */
     5.7 -public abstract class ObjectCreator<T> {
     5.8 +public abstract class ObjectCreator<T> implements CodeGenerator.SplitLiteralCreator {
     5.9  
    5.10      /** List of keys & symbols to initiate in this ObjectCreator */
    5.11      final List<MapTuple<T>> tuples;
    5.12 @@ -69,7 +69,23 @@
    5.13       * Generate code for making the object.
    5.14       * @param method Script method.
    5.15       */
    5.16 -    protected abstract void makeObject(final MethodEmitter method);
    5.17 +    public void makeObject(final MethodEmitter method) {
    5.18 +        createObject(method);
    5.19 +        // We need to store the object in a temporary slot as populateRange expects to load the
    5.20 +        // object from a slot (as it is also invoked within split methods). Note that this also
    5.21 +        // helps optimistic continuations to handle the stack in case an optimistic assumption
    5.22 +        // fails during initialization (see JDK-8079269).
    5.23 +        final int objectSlot = method.getUsedSlotsWithLiveTemporaries();
    5.24 +        final Type objectType = method.peekType();
    5.25 +        method.storeTemp(objectType, objectSlot);
    5.26 +        populateRange(method, objectType, objectSlot, 0, tuples.size());
    5.27 +    }
    5.28 +
    5.29 +    /**
    5.30 +     * Generate code for creating and initializing the object.
    5.31 +     * @param method the method emitter
    5.32 +     */
    5.33 +    protected abstract void createObject(final MethodEmitter method);
    5.34  
    5.35      /**
    5.36       * Construct the property map appropriate for the object.
    5.37 @@ -125,6 +141,12 @@
    5.38      }
    5.39  
    5.40      /**
    5.41 +     * Get the class of objects created by this ObjectCreator
    5.42 +     * @return class of created object
    5.43 +     */
    5.44 +    abstract protected Class<? extends ScriptObject> getAllocatorClass();
    5.45 +
    5.46 +    /**
    5.47       * Technique for loading an initial value. Defined by anonymous subclasses in code gen.
    5.48       *
    5.49       * @param value Value to load.
    5.50 @@ -145,29 +167,4 @@
    5.51      MethodEmitter loadTuple(final MethodEmitter method, final MapTuple<T> tuple) {
    5.52          return loadTuple(method, tuple, true);
    5.53      }
    5.54 -
    5.55 -    /**
    5.56 -     * If using optimistic typing, let the code generator realize that the newly created object on the stack
    5.57 -     * when DUP-ed will be the same value. Basically: {NEW, DUP, INVOKESPECIAL init, DUP} will leave a stack
    5.58 -     * load specification {unknown, unknown} on stack (that is "there's two values on the stack, but neither
    5.59 -     * comes from a known local load"). If there's an optimistic operation in the literal initializer,
    5.60 -     * OptimisticOperation.storeStack will allocate two temporary locals for it and store them as
    5.61 -     * {ASTORE 4, ASTORE 3}. If we instead do {NEW, DUP, INVOKESPECIAL init, ASTORE 3, ALOAD 3, DUP} we end up
    5.62 -     * with stack load specification {ALOAD 3, ALOAD 3} (as DUP can track that the value it duplicated came
    5.63 -     * from a local load), so if/when a continuation needs to be recreated from it, it'll be
    5.64 -     * able to emit ALOAD 3, ALOAD 3 to recreate the stack. If we didn't do this, deoptimization within an
    5.65 -     * object literal initialization could in rare cases cause an incompatible change in the shape of the
    5.66 -     * local variable table for the temporaries, e.g. in the following snippet where a variable is reassigned
    5.67 -     * to a wider type in an object initializer:
    5.68 -     * <code>var m = 1; var obj = {p0: m, p1: m = "foo", p2: m}</code>
    5.69 -     * @param method the current method emitter.
    5.70 -     */
    5.71 -    void helpOptimisticRecognizeDuplicateIdentity(final MethodEmitter method) {
    5.72 -        if (codegen.useOptimisticTypes()) {
    5.73 -            final Type objectType = method.peekType();
    5.74 -            final int tempSlot = method.defineTemporaryLocalVariable(objectType.getSlots());
    5.75 -            method.storeHidden(objectType, tempSlot);
    5.76 -            method.load(objectType, tempSlot);
    5.77 -        }
    5.78 -    }
    5.79  }
     6.1 --- a/src/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java	Thu Sep 17 18:23:53 2015 +0530
     6.2 +++ b/src/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java	Sat Sep 19 16:04:28 2015 +0200
     6.3 @@ -27,13 +27,15 @@
     6.4  
     6.5  import java.util.ArrayList;
     6.6  import java.util.List;
     6.7 +
     6.8  import jdk.nashorn.internal.ir.CompileUnitHolder;
     6.9  import jdk.nashorn.internal.ir.FunctionNode;
    6.10  import jdk.nashorn.internal.ir.LexicalContext;
    6.11  import jdk.nashorn.internal.ir.LiteralNode;
    6.12  import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
    6.13 -import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
    6.14  import jdk.nashorn.internal.ir.Node;
    6.15 +import jdk.nashorn.internal.ir.ObjectNode;
    6.16 +import jdk.nashorn.internal.ir.Splittable;
    6.17  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    6.18  
    6.19  /**
    6.20 @@ -70,15 +72,28 @@
    6.21      public Node leaveLiteralNode(final LiteralNode<?> node) {
    6.22          if (node instanceof ArrayLiteralNode) {
    6.23              final ArrayLiteralNode aln = (ArrayLiteralNode)node;
    6.24 -            if (aln.getUnits() == null) {
    6.25 +            if (aln.getSplitRanges() == null) {
    6.26                  return node;
    6.27              }
    6.28 -            final List<ArrayUnit> newArrayUnits = new ArrayList<>();
    6.29 -            for (final ArrayUnit au : aln.getUnits()) {
    6.30 -                newArrayUnits.add(new ArrayUnit(getExistingReplacement(au), au.getLo(), au.getHi()));
    6.31 +            final List<Splittable.SplitRange> newArrayUnits = new ArrayList<>();
    6.32 +            for (final Splittable.SplitRange au : aln.getSplitRanges()) {
    6.33 +                newArrayUnits.add(new Splittable.SplitRange(getExistingReplacement(au), au.getLow(), au.getHigh()));
    6.34              }
    6.35 -            return aln.setUnits(lc, newArrayUnits);
    6.36 +            return aln.setSplitRanges(lc, newArrayUnits);
    6.37          }
    6.38          return node;
    6.39      }
    6.40 +
    6.41 +    @Override
    6.42 +    public Node leaveObjectNode(final ObjectNode objectNode) {
    6.43 +        final List<Splittable.SplitRange> ranges = objectNode.getSplitRanges();
    6.44 +        if (ranges != null) {
    6.45 +            final List<Splittable.SplitRange> newRanges = new ArrayList<>();
    6.46 +            for (final Splittable.SplitRange range : ranges) {
    6.47 +                newRanges.add(new Splittable.SplitRange(getExistingReplacement(range), range.getLow(), range.getHigh()));
    6.48 +            }
    6.49 +            return objectNode.setSplitRanges(lc, newRanges);
    6.50 +        }
    6.51 +        return super.leaveObjectNode(objectNode);
    6.52 +    }
    6.53  }
     7.1 --- a/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java	Thu Sep 17 18:23:53 2015 +0530
     7.2 +++ b/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java	Sat Sep 19 16:04:28 2015 +0200
     7.3 @@ -61,7 +61,7 @@
     7.4      }
     7.5  
     7.6      @Override
     7.7 -    protected void makeObject(final MethodEmitter method) {
     7.8 +    public void createObject(final MethodEmitter method) {
     7.9          assert !isScope() : "spill scope objects are not currently supported";
    7.10  
    7.11          final int          length        = tuples.size();
    7.12 @@ -69,9 +69,7 @@
    7.13          final int          spillLength   = ScriptObject.spillAllocationLength(length);
    7.14          final long[]       jpresetValues = dualFields ? new long[spillLength] : null;
    7.15          final Object[]     opresetValues = new Object[spillLength];
    7.16 -        final Set<Integer> postsetValues = new LinkedHashSet<>();
    7.17 -        final int          callSiteFlags = codegen.getCallSiteFlags();
    7.18 -        final Class<?>     objectClass   = dualFields ? JD.class : JO.class;
    7.19 +        final Class<?>     objectClass   = getAllocatorClass();
    7.20          ArrayData          arrayData     = ArrayData.allocate(ScriptRuntime.EMPTY_ARRAY);
    7.21  
    7.22          // Compute constant property values
    7.23 @@ -85,9 +83,7 @@
    7.24  
    7.25              if (value != null) {
    7.26                  final Object constantValue = LiteralNode.objectAsConstant(value);
    7.27 -                if (constantValue == LiteralNode.POSTSET_MARKER) {
    7.28 -                    postsetValues.add(pos);
    7.29 -                } else {
    7.30 +                if (constantValue != LiteralNode.POSTSET_MARKER) {
    7.31                      final Property property = propertyMap.findProperty(key);
    7.32                      if (property != null) {
    7.33                          // normal property key
    7.34 @@ -146,25 +142,34 @@
    7.35          // instantiate the script object with spill objects
    7.36          method.invoke(constructorNoLookup(objectClass, PropertyMap.class, long[].class, Object[].class));
    7.37  
    7.38 -        helpOptimisticRecognizeDuplicateIdentity(method);
    7.39 -
    7.40          // Set prefix array data if any
    7.41          if (arrayData.length() > 0) {
    7.42              method.dup();
    7.43              codegen.loadConstant(arrayData);
    7.44              method.invoke(virtualCallNoLookup(ScriptObject.class, "setArray", void.class, ArrayData.class));
    7.45          }
    7.46 +    }
    7.47 +
    7.48 +    @Override
    7.49 +    public void populateRange(final MethodEmitter method, final Type objectType, final int objectSlot, final int start, final int end) {
    7.50 +        final int  callSiteFlags = codegen.getCallSiteFlags();
    7.51 +        method.load(objectType, objectSlot);
    7.52  
    7.53          // set postfix values
    7.54 -        for (final int i : postsetValues) {
    7.55 +        for (int i = start; i < end; i++) {
    7.56              final MapTuple<Expression> tuple = tuples.get(i);
    7.57 +
    7.58 +            if (LiteralNode.isConstant(tuple.value)) {
    7.59 +                continue;
    7.60 +            }
    7.61 +
    7.62              final Property property = propertyMap.findProperty(tuple.key);
    7.63 +
    7.64              if (property == null) {
    7.65                  final int index = ArrayIndex.getArrayIndex(tuple.key);
    7.66                  assert ArrayIndex.isValidArrayIndex(index);
    7.67                  method.dup();
    7.68                  method.load(ArrayIndex.toLongIndex(index));
    7.69 -                //method.println("putting " + tuple + " into arraydata");
    7.70                  loadTuple(method, tuple);
    7.71                  method.dynamicSetIndex(callSiteFlags);
    7.72              } else {
    7.73 @@ -178,8 +183,7 @@
    7.74      @Override
    7.75      protected PropertyMap makeMap() {
    7.76          assert propertyMap == null : "property map already initialized";
    7.77 -        final boolean dualFields = codegen.useDualFields();
    7.78 -        final Class<? extends ScriptObject> clazz = dualFields ? JD.class : JO.class;
    7.79 +        final Class<? extends ScriptObject> clazz = getAllocatorClass();
    7.80          propertyMap = new MapCreator<>(clazz, tuples).makeSpillMap(false, codegen.useDualFields());
    7.81          return propertyMap;
    7.82      }
    7.83 @@ -188,4 +192,9 @@
    7.84      protected void loadValue(final Expression expr, final Type type) {
    7.85          codegen.loadExpressionAsType(expr, type);
    7.86      }
    7.87 +
    7.88 +    @Override
    7.89 +    protected Class<? extends ScriptObject> getAllocatorClass() {
    7.90 +        return codegen.useDualFields() ? JD.class : JO.class;
    7.91 +    }
    7.92  }
     8.1 --- a/src/jdk/nashorn/internal/codegen/Splitter.java	Thu Sep 17 18:23:53 2015 +0530
     8.2 +++ b/src/jdk/nashorn/internal/codegen/Splitter.java	Sat Sep 19 16:04:28 2015 +0200
     8.3 @@ -36,9 +36,11 @@
     8.4  import jdk.nashorn.internal.ir.LexicalContext;
     8.5  import jdk.nashorn.internal.ir.LiteralNode;
     8.6  import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
     8.7 -import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
     8.8  import jdk.nashorn.internal.ir.Node;
     8.9 +import jdk.nashorn.internal.ir.ObjectNode;
    8.10 +import jdk.nashorn.internal.ir.PropertyNode;
    8.11  import jdk.nashorn.internal.ir.SplitNode;
    8.12 +import jdk.nashorn.internal.ir.Splittable;
    8.13  import jdk.nashorn.internal.ir.Statement;
    8.14  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    8.15  import jdk.nashorn.internal.runtime.Context;
    8.16 @@ -295,7 +297,7 @@
    8.17              final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal;
    8.18              final Node[]           value            = arrayLiteralNode.getValue();
    8.19              final int[]            postsets         = arrayLiteralNode.getPostsets();
    8.20 -            final List<ArrayUnit>  units            = new ArrayList<>();
    8.21 +            final List<Splittable.SplitRange> ranges = new ArrayList<>();
    8.22  
    8.23              long totalWeight = 0;
    8.24              int  lo          = 0;
    8.25 @@ -309,7 +311,7 @@
    8.26  
    8.27                  if (totalWeight >= SPLIT_THRESHOLD) {
    8.28                      final CompileUnit unit = compiler.findUnit(totalWeight - weight);
    8.29 -                    units.add(new ArrayUnit(unit, lo, i));
    8.30 +                    ranges.add(new Splittable.SplitRange(unit, lo, i));
    8.31                      lo = i;
    8.32                      totalWeight = weight;
    8.33                  }
    8.34 @@ -317,16 +319,59 @@
    8.35  
    8.36              if (lo != postsets.length) {
    8.37                  final CompileUnit unit = compiler.findUnit(totalWeight);
    8.38 -                units.add(new ArrayUnit(unit, lo, postsets.length));
    8.39 +                ranges.add(new Splittable.SplitRange(unit, lo, postsets.length));
    8.40              }
    8.41  
    8.42 -            return arrayLiteralNode.setUnits(lc, units);
    8.43 +            return arrayLiteralNode.setSplitRanges(lc, ranges);
    8.44          }
    8.45  
    8.46          return literal;
    8.47      }
    8.48  
    8.49      @Override
    8.50 +    public Node leaveObjectNode(final ObjectNode objectNode) {
    8.51 +        long weight = WeighNodes.weigh(objectNode);
    8.52 +
    8.53 +        if (weight < SPLIT_THRESHOLD) {
    8.54 +            return objectNode;
    8.55 +        }
    8.56 +
    8.57 +        final FunctionNode functionNode = lc.getCurrentFunction();
    8.58 +        lc.setFlag(functionNode, FunctionNode.IS_SPLIT);
    8.59 +
    8.60 +        final List<Splittable.SplitRange> ranges        = new ArrayList<>();
    8.61 +        final List<PropertyNode>          properties    = objectNode.getElements();
    8.62 +        final boolean                     isSpillObject = properties.size() > CodeGenerator.OBJECT_SPILL_THRESHOLD;
    8.63 +        long totalWeight = 0;
    8.64 +        int  lo          = 0;
    8.65 +
    8.66 +        for (int i = 0; i < properties.size(); i++) {
    8.67 +
    8.68 +            final PropertyNode property = properties.get(i);
    8.69 +            final boolean isConstant = LiteralNode.isConstant(property.getValue());
    8.70 +
    8.71 +            if (!isConstant || !isSpillObject) {
    8.72 +                weight = isConstant ? 0 : WeighNodes.weigh(property.getValue());
    8.73 +                totalWeight += WeighNodes.AASTORE_WEIGHT + weight;
    8.74 +
    8.75 +                if (totalWeight >= SPLIT_THRESHOLD) {
    8.76 +                    final CompileUnit unit = compiler.findUnit(totalWeight - weight);
    8.77 +                    ranges.add(new Splittable.SplitRange(unit, lo, i));
    8.78 +                    lo = i;
    8.79 +                    totalWeight = weight;
    8.80 +                }
    8.81 +            }
    8.82 +        }
    8.83 +
    8.84 +        if (lo != properties.size()) {
    8.85 +            final CompileUnit unit = compiler.findUnit(totalWeight);
    8.86 +            ranges.add(new Splittable.SplitRange(unit, lo, properties.size()));
    8.87 +        }
    8.88 +
    8.89 +        return objectNode.setSplitRanges(lc, ranges);
    8.90 +    }
    8.91 +
    8.92 +    @Override
    8.93      public boolean enterFunctionNode(final FunctionNode node) {
    8.94          //only go into the function node for this splitter. any subfunctions are rejected
    8.95          return node == outermost;
     9.1 --- a/src/jdk/nashorn/internal/codegen/WeighNodes.java	Thu Sep 17 18:23:53 2015 +0530
     9.2 +++ b/src/jdk/nashorn/internal/codegen/WeighNodes.java	Sat Sep 19 16:04:28 2015 +0200
     9.3 @@ -44,12 +44,13 @@
     9.4  import jdk.nashorn.internal.ir.LexicalContext;
     9.5  import jdk.nashorn.internal.ir.LiteralNode;
     9.6  import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
     9.7 -import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
     9.8  import jdk.nashorn.internal.ir.Node;
     9.9 +import jdk.nashorn.internal.ir.ObjectNode;
    9.10  import jdk.nashorn.internal.ir.PropertyNode;
    9.11  import jdk.nashorn.internal.ir.ReturnNode;
    9.12  import jdk.nashorn.internal.ir.RuntimeNode;
    9.13  import jdk.nashorn.internal.ir.SplitNode;
    9.14 +import jdk.nashorn.internal.ir.Splittable;
    9.15  import jdk.nashorn.internal.ir.SwitchNode;
    9.16  import jdk.nashorn.internal.ir.ThrowNode;
    9.17  import jdk.nashorn.internal.ir.TryNode;
    9.18 @@ -88,6 +89,8 @@
    9.19      static final long THROW_WEIGHT     =  2;
    9.20      static final long VAR_WEIGHT       = 40;
    9.21      static final long WITH_WEIGHT      =  8;
    9.22 +    static final long OBJECT_WEIGHT    = 16;
    9.23 +    static final long SETPROP_WEIGHT   =  5;
    9.24  
    9.25      /** Accumulated weight. */
    9.26      private long weight;
    9.27 @@ -213,7 +216,7 @@
    9.28              final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
    9.29              final Node[]           value            = arrayLiteralNode.getValue();
    9.30              final int[]            postsets         = arrayLiteralNode.getPostsets();
    9.31 -            final List<ArrayUnit>  units            = arrayLiteralNode.getUnits();
    9.32 +            final List<Splittable.SplitRange>  units            = arrayLiteralNode.getSplitRanges();
    9.33  
    9.34              if (units == null) {
    9.35                  for (final int postset : postsets) {
    9.36 @@ -233,6 +236,27 @@
    9.37      }
    9.38  
    9.39      @Override
    9.40 +    public boolean enterObjectNode(final ObjectNode objectNode) {
    9.41 +        weight += OBJECT_WEIGHT;
    9.42 +        final List<PropertyNode> properties = objectNode.getElements();
    9.43 +        final boolean isSpillObject = properties.size() > CodeGenerator.OBJECT_SPILL_THRESHOLD;
    9.44 +
    9.45 +        for (final PropertyNode property : properties) {
    9.46 +            if (!LiteralNode.isConstant(property.getValue())) {
    9.47 +                weight += SETPROP_WEIGHT;
    9.48 +                property.getValue().accept(this);
    9.49 +            } else if (!isSpillObject) {
    9.50 +                // constants in spill object are set via preset spill array,
    9.51 +                // but fields objects need to set constants.
    9.52 +                weight += SETPROP_WEIGHT;
    9.53 +            }
    9.54 +
    9.55 +        }
    9.56 +
    9.57 +        return false;
    9.58 +    }
    9.59 +
    9.60 +    @Override
    9.61      public Node leavePropertyNode(final PropertyNode propertyNode) {
    9.62          weight += LITERAL_WEIGHT;
    9.63          return propertyNode;
    10.1 --- a/src/jdk/nashorn/internal/codegen/types/Type.java	Thu Sep 17 18:23:53 2015 +0530
    10.2 +++ b/src/jdk/nashorn/internal/codegen/types/Type.java	Sat Sep 19 16:04:28 2015 +0200
    10.3 @@ -65,6 +65,7 @@
    10.4  import jdk.internal.org.objectweb.asm.Handle;
    10.5  import jdk.internal.org.objectweb.asm.MethodVisitor;
    10.6  import jdk.nashorn.internal.codegen.CompilerConstants.Call;
    10.7 +import jdk.nashorn.internal.runtime.Context;
    10.8  import jdk.nashorn.internal.runtime.ScriptObject;
    10.9  import jdk.nashorn.internal.runtime.Undefined;
   10.10  import jdk.nashorn.internal.runtime.linker.Bootstrap;
   10.11 @@ -256,6 +257,9 @@
   10.12          case jdk.internal.org.objectweb.asm.Type.DOUBLE:
   10.13              return NUMBER;
   10.14          case jdk.internal.org.objectweb.asm.Type.OBJECT:
   10.15 +            if (Context.isStructureClass(itype.getClassName())) {
   10.16 +                return SCRIPT_OBJECT;
   10.17 +            }
   10.18              try {
   10.19                  return Type.typeFor(Class.forName(itype.getClassName()));
   10.20              } catch(final ClassNotFoundException e) {
   10.21 @@ -949,7 +953,7 @@
   10.22      /**
   10.23       * This is the singleton for integer arrays
   10.24       */
   10.25 -    public static final ArrayType INT_ARRAY = new ArrayType(int[].class) {
   10.26 +    public static final ArrayType INT_ARRAY = putInCache(new ArrayType(int[].class) {
   10.27          private static final long serialVersionUID = 1L;
   10.28  
   10.29          @Override
   10.30 @@ -973,12 +977,12 @@
   10.31          public Type getElementType() {
   10.32              return INT;
   10.33          }
   10.34 -    };
   10.35 +    });
   10.36  
   10.37      /**
   10.38       * This is the singleton for long arrays
   10.39       */
   10.40 -    public static final ArrayType LONG_ARRAY = new ArrayType(long[].class) {
   10.41 +    public static final ArrayType LONG_ARRAY = putInCache(new ArrayType(long[].class) {
   10.42          private static final long serialVersionUID = 1L;
   10.43  
   10.44          @Override
   10.45 @@ -1002,12 +1006,12 @@
   10.46          public Type getElementType() {
   10.47              return LONG;
   10.48          }
   10.49 -    };
   10.50 +    });
   10.51  
   10.52      /**
   10.53       * This is the singleton for numeric arrays
   10.54       */
   10.55 -    public static final ArrayType NUMBER_ARRAY = new ArrayType(double[].class) {
   10.56 +    public static final ArrayType NUMBER_ARRAY = putInCache(new ArrayType(double[].class) {
   10.57          private static final long serialVersionUID = 1L;
   10.58  
   10.59          @Override
   10.60 @@ -1031,13 +1035,7 @@
   10.61          public Type getElementType() {
   10.62              return NUMBER;
   10.63          }
   10.64 -    };
   10.65 -
   10.66 -    /** Singleton for method handle arrays used for properties etc. */
   10.67 -    public static final ArrayType METHODHANDLE_ARRAY = putInCache(new ArrayType(MethodHandle[].class));
   10.68 -
   10.69 -    /** This is the singleton for string arrays */
   10.70 -    public static final ArrayType STRING_ARRAY = putInCache(new ArrayType(String[].class));
   10.71 +    });
   10.72  
   10.73      /** This is the singleton for object arrays */
   10.74      public static final ArrayType OBJECT_ARRAY = putInCache(new ArrayType(Object[].class));
    11.1 --- a/src/jdk/nashorn/internal/ir/LiteralNode.java	Thu Sep 17 18:23:53 2015 +0530
    11.2 +++ b/src/jdk/nashorn/internal/ir/LiteralNode.java	Sat Sep 19 16:04:28 2015 +0200
    11.3 @@ -25,11 +25,9 @@
    11.4  
    11.5  package jdk.nashorn.internal.ir;
    11.6  
    11.7 -import java.io.Serializable;
    11.8  import java.util.Arrays;
    11.9  import java.util.Collections;
   11.10  import java.util.List;
   11.11 -import jdk.nashorn.internal.codegen.CompileUnit;
   11.12  import jdk.nashorn.internal.codegen.types.ArrayType;
   11.13  import jdk.nashorn.internal.codegen.types.Type;
   11.14  import jdk.nashorn.internal.ir.annotations.Immutable;
   11.15 @@ -561,6 +559,15 @@
   11.16          return POSTSET_MARKER;
   11.17      }
   11.18  
   11.19 +    /**
   11.20 +     * Test whether {@code object} represents a constant value.
   11.21 +     * @param object a node or value object
   11.22 +     * @return true if object is a constant value
   11.23 +     */
   11.24 +    public static boolean isConstant(final Object object) {
   11.25 +        return objectAsConstant(object) != POSTSET_MARKER;
   11.26 +    }
   11.27 +
   11.28      private static final class NullLiteralNode extends PrimitiveLiteralNode<Object> {
   11.29          private static final long serialVersionUID = 1L;
   11.30  
   11.31 @@ -592,7 +599,7 @@
   11.32       * Array literal node class.
   11.33       */
   11.34      @Immutable
   11.35 -    public static final class ArrayLiteralNode extends LiteralNode<Expression[]> implements LexicalContextNode {
   11.36 +    public static final class ArrayLiteralNode extends LiteralNode<Expression[]> implements LexicalContextNode, Splittable {
   11.37          private static final long serialVersionUID = 1L;
   11.38  
   11.39          /** Array element type. */
   11.40 @@ -604,59 +611,8 @@
   11.41          /** Indices of array elements requiring computed post sets. */
   11.42          private final int[] postsets;
   11.43  
   11.44 -        /** Sub units with indexes ranges, in which to split up code generation, for large literals */
   11.45 -        private final List<ArrayUnit> units;
   11.46 -
   11.47 -        /**
   11.48 -         * An ArrayUnit is a range in an ArrayLiteral. ArrayLiterals can
   11.49 -         * be split if they are too large, for bytecode generation reasons
   11.50 -         */
   11.51 -        public static final class ArrayUnit implements CompileUnitHolder, Serializable {
   11.52 -            private static final long serialVersionUID = 1L;
   11.53 -
   11.54 -            /** Compile unit associated with the postsets range. */
   11.55 -            private final CompileUnit compileUnit;
   11.56 -
   11.57 -            /** postsets range associated with the unit (hi not inclusive). */
   11.58 -            private final int lo, hi;
   11.59 -
   11.60 -            /**
   11.61 -             * Constructor
   11.62 -             * @param compileUnit compile unit
   11.63 -             * @param lo lowest array index in unit
   11.64 -             * @param hi highest array index in unit + 1
   11.65 -             */
   11.66 -            public ArrayUnit(final CompileUnit compileUnit, final int lo, final int hi) {
   11.67 -                this.compileUnit = compileUnit;
   11.68 -                this.lo   = lo;
   11.69 -                this.hi   = hi;
   11.70 -            }
   11.71 -
   11.72 -            /**
   11.73 -             * Get the high index position of the ArrayUnit (non inclusive)
   11.74 -             * @return high index position
   11.75 -             */
   11.76 -            public int getHi() {
   11.77 -                return hi;
   11.78 -            }
   11.79 -
   11.80 -            /**
   11.81 -             * Get the low index position of the ArrayUnit (inclusive)
   11.82 -             * @return low index position
   11.83 -             */
   11.84 -            public int getLo() {
   11.85 -                return lo;
   11.86 -            }
   11.87 -
   11.88 -            /**
   11.89 -             * The array compile unit
   11.90 -             * @return array compile unit
   11.91 -             */
   11.92 -            @Override
   11.93 -            public CompileUnit getCompileUnit() {
   11.94 -                return compileUnit;
   11.95 -            }
   11.96 -        }
   11.97 +        /** Ranges for splitting up large literals in code generation */
   11.98 +        private final List<Splittable.SplitRange> splitRanges;
   11.99  
  11.100          private static final class ArrayLiteralInitializer {
  11.101  
  11.102 @@ -664,7 +620,7 @@
  11.103                  final Type elementType = computeElementType(node.value);
  11.104                  final int[] postsets = computePostsets(node.value);
  11.105                  final Object presets = computePresets(node.value, elementType, postsets);
  11.106 -                return new ArrayLiteralNode(node, node.value, elementType, postsets, presets, node.units);
  11.107 +                return new ArrayLiteralNode(node, node.value, elementType, postsets, presets, node.splitRanges);
  11.108              }
  11.109  
  11.110              private static Type computeElementType(final Expression[] value) {
  11.111 @@ -697,7 +653,7 @@
  11.112  
  11.113                  for (int i = 0; i < value.length; i++) {
  11.114                      final Expression element = value[i];
  11.115 -                    if (element == null || objectAsConstant(element) == POSTSET_MARKER) {
  11.116 +                    if (element == null || !isConstant(element)) {
  11.117                          computed[nComputed++] = i;
  11.118                      }
  11.119                  }
  11.120 @@ -814,19 +770,19 @@
  11.121              this.elementType = Type.UNKNOWN;
  11.122              this.presets     = null;
  11.123              this.postsets    = null;
  11.124 -            this.units       = null;
  11.125 +            this.splitRanges = null;
  11.126          }
  11.127  
  11.128          /**
  11.129           * Copy constructor
  11.130           * @param node source array literal node
  11.131           */
  11.132 -        private ArrayLiteralNode(final ArrayLiteralNode node, final Expression[] value, final Type elementType, final int[] postsets, final Object presets, final List<ArrayUnit> units) {
  11.133 +        private ArrayLiteralNode(final ArrayLiteralNode node, final Expression[] value, final Type elementType, final int[] postsets, final Object presets, final List<Splittable.SplitRange> splitRanges) {
  11.134              super(node, value);
  11.135              this.elementType = elementType;
  11.136              this.postsets    = postsets;
  11.137              this.presets     = presets;
  11.138 -            this.units       = units;
  11.139 +            this.splitRanges = splitRanges;
  11.140          }
  11.141  
  11.142          /**
  11.143 @@ -917,26 +873,27 @@
  11.144          }
  11.145  
  11.146          /**
  11.147 -         * Get the array units that make up this ArrayLiteral
  11.148 -         * @see ArrayUnit
  11.149 -         * @return list of array units
  11.150 +         * Get the split ranges for this ArrayLiteral, or null if this array does not have to be split.
  11.151 +         * @see Splittable.SplitRange
  11.152 +         * @return list of split ranges
  11.153           */
  11.154 -        public List<ArrayUnit> getUnits() {
  11.155 -            return units == null ? null : Collections.unmodifiableList(units);
  11.156 +        @Override
  11.157 +        public List<Splittable.SplitRange> getSplitRanges() {
  11.158 +            return splitRanges == null ? null : Collections.unmodifiableList(splitRanges);
  11.159          }
  11.160  
  11.161          /**
  11.162 -         * Set the ArrayUnits that make up this ArrayLiteral
  11.163 +         * Set the SplitRanges that make up this ArrayLiteral
  11.164           * @param lc lexical context
  11.165 -         * @see ArrayUnit
  11.166 -         * @param units list of array units
  11.167 -         * @return new or changed arrayliteralnode
  11.168 +         * @see Splittable.SplitRange
  11.169 +         * @param splitRanges list of split ranges
  11.170 +         * @return new or changed node
  11.171           */
  11.172 -        public ArrayLiteralNode setUnits(final LexicalContext lc, final List<ArrayUnit> units) {
  11.173 -            if (this.units == units) {
  11.174 +        public ArrayLiteralNode setSplitRanges(final LexicalContext lc, final List<Splittable.SplitRange> splitRanges) {
  11.175 +            if (this.splitRanges == splitRanges) {
  11.176                  return this;
  11.177              }
  11.178 -            return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, units));
  11.179 +            return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, splitRanges));
  11.180          }
  11.181  
  11.182          @Override
  11.183 @@ -958,7 +915,7 @@
  11.184              if (this.value == value) {
  11.185                  return this;
  11.186              }
  11.187 -            return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, units));
  11.188 +            return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, splitRanges));
  11.189          }
  11.190  
  11.191          private ArrayLiteralNode setValue(final LexicalContext lc, final List<Expression> value) {
    12.1 --- a/src/jdk/nashorn/internal/ir/ObjectNode.java	Thu Sep 17 18:23:53 2015 +0530
    12.2 +++ b/src/jdk/nashorn/internal/ir/ObjectNode.java	Sat Sep 19 16:04:28 2015 +0200
    12.3 @@ -27,6 +27,7 @@
    12.4  
    12.5  import java.util.Collections;
    12.6  import java.util.List;
    12.7 +import java.util.RandomAccess;
    12.8  import jdk.nashorn.internal.codegen.types.Type;
    12.9  import jdk.nashorn.internal.ir.annotations.Immutable;
   12.10  import jdk.nashorn.internal.ir.visitor.NodeVisitor;
   12.11 @@ -35,12 +36,15 @@
   12.12   * IR representation of an object literal.
   12.13   */
   12.14  @Immutable
   12.15 -public final class ObjectNode extends Expression {
   12.16 +public final class ObjectNode extends Expression implements LexicalContextNode, Splittable {
   12.17      private static final long serialVersionUID = 1L;
   12.18  
   12.19      /** Literal elements. */
   12.20      private final List<PropertyNode> elements;
   12.21  
   12.22 +    /** Ranges for splitting large literals over multiple compile units in codegen. */
   12.23 +    private final List<Splittable.SplitRange> splitRanges;
   12.24 +
   12.25      /**
   12.26       * Constructor
   12.27       *
   12.28 @@ -51,19 +55,27 @@
   12.29      public ObjectNode(final long token, final int finish, final List<PropertyNode> elements) {
   12.30          super(token, finish);
   12.31          this.elements = elements;
   12.32 +        this.splitRanges = null;
   12.33 +        assert elements instanceof RandomAccess : "Splitting requires random access lists";
   12.34      }
   12.35  
   12.36 -    private ObjectNode(final ObjectNode objectNode, final List<PropertyNode> elements) {
   12.37 +    private ObjectNode(final ObjectNode objectNode, final List<PropertyNode> elements,
   12.38 +                       final List<Splittable.SplitRange> splitRanges ) {
   12.39          super(objectNode);
   12.40          this.elements = elements;
   12.41 +        this.splitRanges = splitRanges;
   12.42      }
   12.43  
   12.44      @Override
   12.45      public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
   12.46 +        return Acceptor.accept(this, visitor);
   12.47 +    }
   12.48 +
   12.49 +    @Override
   12.50 +    public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
   12.51          if (visitor.enterObjectNode(this)) {
   12.52 -            return visitor.leaveObjectNode(setElements(Node.accept(visitor, elements)));
   12.53 +            return visitor.leaveObjectNode(setElements(lc, Node.accept(visitor, elements)));
   12.54          }
   12.55 -
   12.56          return this;
   12.57      }
   12.58  
   12.59 @@ -102,10 +114,35 @@
   12.60          return Collections.unmodifiableList(elements);
   12.61      }
   12.62  
   12.63 -    private ObjectNode setElements(final List<PropertyNode> elements) {
   12.64 +    private ObjectNode setElements(final LexicalContext lc, final List<PropertyNode> elements) {
   12.65          if (this.elements == elements) {
   12.66              return this;
   12.67          }
   12.68 -        return new ObjectNode(this, elements);
   12.69 +        return Node.replaceInLexicalContext(lc, this, new ObjectNode(this, elements, this.splitRanges));
   12.70      }
   12.71 +
   12.72 +    /**
   12.73 +     * Set the split ranges for this ObjectNode
   12.74 +     * @see Splittable.SplitRange
   12.75 +     * @param lc the lexical context
   12.76 +     * @param splitRanges list of split ranges
   12.77 +     * @return new or changed object node
   12.78 +     */
   12.79 +    public ObjectNode setSplitRanges(final LexicalContext lc, final List<Splittable.SplitRange> splitRanges) {
   12.80 +        if (this.splitRanges == splitRanges) {
   12.81 +            return this;
   12.82 +        }
   12.83 +        return Node.replaceInLexicalContext(lc, this, new ObjectNode(this, elements, splitRanges));
   12.84 +    }
   12.85 +
   12.86 +    /**
   12.87 +     * Get the split ranges for this ObjectNode, or null if the object is not split.
   12.88 +     * @see Splittable.SplitRange
   12.89 +     * @return list of split ranges
   12.90 +     */
   12.91 +    @Override
   12.92 +    public List<Splittable.SplitRange> getSplitRanges() {
   12.93 +        return splitRanges == null ? null : Collections.unmodifiableList(splitRanges);
   12.94 +    }
   12.95 +
   12.96  }
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/jdk/nashorn/internal/ir/Splittable.java	Sat Sep 19 16:04:28 2015 +0200
    13.3 @@ -0,0 +1,95 @@
    13.4 +/*
    13.5 + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
    13.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    13.7 + *
    13.8 + * This code is free software; you can redistribute it and/or modify it
    13.9 + * under the terms of the GNU General Public License version 2 only, as
   13.10 + * published by the Free Software Foundation.  Oracle designates this
   13.11 + * particular file as subject to the "Classpath" exception as provided
   13.12 + * by Oracle in the LICENSE file that accompanied this code.
   13.13 + *
   13.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   13.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   13.17 + * version 2 for more details (a copy is included in the LICENSE file that
   13.18 + * accompanied this code).
   13.19 + *
   13.20 + * You should have received a copy of the GNU General Public License version
   13.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   13.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   13.23 + *
   13.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   13.25 + * or visit www.oracle.com if you need additional information or have any
   13.26 + * questions.
   13.27 + */
   13.28 +
   13.29 +package jdk.nashorn.internal.ir;
   13.30 +
   13.31 +import java.io.Serializable;
   13.32 +import java.util.List;
   13.33 +import jdk.nashorn.internal.codegen.CompileUnit;
   13.34 +
   13.35 +/**
   13.36 + * An interface for splittable expressions.
   13.37 + */
   13.38 +public interface Splittable {
   13.39 +
   13.40 +    /**
   13.41 +     * Get a list of split ranges for this splittable expression, or null
   13.42 +     * if the expression should not be split.
   13.43 +     *
   13.44 +     * @return a list of split ranges
   13.45 +     */
   13.46 +    List<SplitRange> getSplitRanges();
   13.47 +
   13.48 +    /**
   13.49 +     * A SplitRange is a range in a splittable expression. It defines the
   13.50 +     * boundaries of the split range and provides a compile unit for code generation.
   13.51 +     */
   13.52 +    final class SplitRange implements CompileUnitHolder, Serializable {
   13.53 +        private static final long serialVersionUID = 1L;
   13.54 +
   13.55 +        /** Compile unit associated with the postsets range. */
   13.56 +        private final CompileUnit compileUnit;
   13.57 +
   13.58 +        /** postsets range associated with the unit (hi not inclusive). */
   13.59 +        private final int low, high;
   13.60 +
   13.61 +        /**
   13.62 +         * Constructor
   13.63 +         * @param compileUnit compile unit
   13.64 +         * @param low lowest array index in unit
   13.65 +         * @param high highest array index in unit + 1
   13.66 +         */
   13.67 +        public SplitRange(final CompileUnit compileUnit, final int low, final int high) {
   13.68 +            this.compileUnit = compileUnit;
   13.69 +            this.low   = low;
   13.70 +            this.high   = high;
   13.71 +        }
   13.72 +
   13.73 +        /**
   13.74 +         * Get the high index position of the ArrayUnit (exclusive)
   13.75 +         * @return high index position
   13.76 +         */
   13.77 +        public int getHigh() {
   13.78 +            return high;
   13.79 +        }
   13.80 +
   13.81 +        /**
   13.82 +         * Get the low index position of the ArrayUnit (inclusive)
   13.83 +         * @return low index position
   13.84 +         */
   13.85 +        public int getLow() {
   13.86 +            return low;
   13.87 +        }
   13.88 +
   13.89 +        /**
   13.90 +         * The array compile unit
   13.91 +         * @return array compile unit
   13.92 +         */
   13.93 +        @Override
   13.94 +        public CompileUnit getCompileUnit() {
   13.95 +            return compileUnit;
   13.96 +        }
   13.97 +    }
   13.98 +}
    14.1 --- a/src/jdk/nashorn/internal/runtime/Context.java	Thu Sep 17 18:23:53 2015 +0530
    14.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java	Sat Sep 19 16:04:28 2015 +0200
    14.3 @@ -987,6 +987,16 @@
    14.4      }
    14.5  
    14.6      /**
    14.7 +     * Is {@code className} the name of a structure class?
    14.8 +     *
    14.9 +     * @param className a class name
   14.10 +     * @return true if className is a structure class name
   14.11 +     */
   14.12 +    public static boolean isStructureClass(final String className) {
   14.13 +        return StructureLoader.isStructureClass(className);
   14.14 +    }
   14.15 +
   14.16 +    /**
   14.17       * Checks that the given Class can be accessed from no permissions context.
   14.18       *
   14.19       * @param clazz Class object
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/test/script/basic/JDK-8135190.js	Sat Sep 19 16:04:28 2015 +0200
    15.3 @@ -0,0 +1,67 @@
    15.4 +/*
    15.5 + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
    15.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    15.7 + * 
    15.8 + * This code is free software; you can redistribute it and/or modify it
    15.9 + * under the terms of the GNU General Public License version 2 only, as
   15.10 + * published by the Free Software Foundation.
   15.11 + * 
   15.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   15.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   15.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   15.15 + * version 2 for more details (a copy is included in the LICENSE file that
   15.16 + * accompanied this code).
   15.17 + * 
   15.18 + * You should have received a copy of the GNU General Public License version
   15.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   15.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   15.21 + * 
   15.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   15.23 + * or visit www.oracle.com if you need additional information or have any
   15.24 + * questions.
   15.25 + */
   15.26 +
   15.27 +/**
   15.28 + * JDK-8135190: Method code too large in Babel browser.js script
   15.29 + *
   15.30 + * @test
   15.31 + * @run
   15.32 + */
   15.33 +
   15.34 +// Make sure huge object literals are parsed correctly and don't throw
   15.35 +// (using buildObject -> JSON.stringify -> eval -> testObject)
   15.36 +
   15.37 +function buildObject(n, d) {
   15.38 +    if (n < 2) {
   15.39 +        return {name: "property", type: "identifier"};
   15.40 +    }
   15.41 +    var obj = {};
   15.42 +    for (var i = 0; i < n; i++) {
   15.43 +        obj["expr" + i] = buildObject(Math.floor(n / d), d);
   15.44 +    }
   15.45 +    return obj;
   15.46 +}
   15.47 +
   15.48 +function testObject(obj, n, d) {
   15.49 +    var keys = Object.keys(obj);
   15.50 +    if (n < 2) {
   15.51 +        Assert.assertTrue(keys.length === 2);
   15.52 +        Assert.assertTrue(keys[0] === "name");
   15.53 +        Assert.assertTrue(keys[1] === "type");
   15.54 +    } else {
   15.55 +        Assert.assertTrue(keys.length === n);
   15.56 +        for (var i = 0; i < n; i++) {
   15.57 +            Assert.assertTrue(keys[i] === "expr" + i);
   15.58 +        }
   15.59 +    }
   15.60 +    if (n >= 2) {
   15.61 +        for (var k in keys) {
   15.62 +            testObject(obj[keys[k]], Math.floor(n / d), d)
   15.63 +        }
   15.64 +    }
   15.65 +}
   15.66 +
   15.67 +var fieldObject = (eval("(" + JSON.stringify(buildObject(25, 2)) + ")"));
   15.68 +testObject(fieldObject, 25, 2);
   15.69 +var spillObject = (eval("(" + JSON.stringify(buildObject(1000, 100)) + ")"));
   15.70 +testObject(spillObject, 1000, 100);

mercurial