Sat, 19 Sep 2015 16:04:28 +0200
8135190: Method code too large in Babel browser.js script
Reviewed-by: attila, sundar
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);