8135190: Method code too large in Babel browser.js script
Reviewed-by: attila, sundar
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java Wed Jul 05 20:50:41 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java Sat Sep 19 16:04:28 2015 +0200
@@ -70,11 +70,10 @@
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LexicalContextNode;
import jdk.nashorn.internal.ir.LiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.RuntimeNode.Request;
+import jdk.nashorn.internal.ir.Splittable;
import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol;
@@ -984,7 +983,7 @@
boolean previousWasBlock = false;
for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) {
final LexicalContextNode node = it.next();
- if (node instanceof FunctionNode || isSplitArray(node)) {
+ if (node instanceof FunctionNode || isSplitLiteral(node)) {
// We reached the function boundary or a splitting boundary without seeing a definition for the symbol.
// It needs to be in scope.
return true;
@@ -1010,12 +1009,8 @@
throw new AssertionError();
}
- private static boolean isSplitArray(final LexicalContextNode expr) {
- if(!(expr instanceof ArrayLiteralNode)) {
- return false;
- }
- final List<ArrayUnit> units = ((ArrayLiteralNode)expr).getUnits();
- return !(units == null || units.isEmpty());
+ private static boolean isSplitLiteral(final LexicalContextNode expr) {
+ return expr instanceof Splittable && ((Splittable) expr).getSplitRanges() != null;
}
private void throwUnprotectedSwitchError(final VarNode varNode) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Jul 05 20:50:41 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Sat Sep 19 16:04:28 2015 +0200
@@ -105,7 +105,6 @@
import jdk.nashorn.internal.ir.LexicalContextNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.LiteralNode.PrimitiveLiteralNode;
import jdk.nashorn.internal.ir.LocalVariableConversion;
import jdk.nashorn.internal.ir.LoopNode;
@@ -118,6 +117,7 @@
import jdk.nashorn.internal.ir.RuntimeNode.Request;
import jdk.nashorn.internal.ir.SetSplitState;
import jdk.nashorn.internal.ir.SplitReturn;
+import jdk.nashorn.internal.ir.Splittable;
import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol;
@@ -242,7 +242,7 @@
private final DebugLogger log;
/** From what size should we use spill instead of fields for JavaScript objects? */
- private static final int OBJECT_SPILL_THRESHOLD = Options.getIntProperty("nashorn.spill.threshold", 256);
+ static final int OBJECT_SPILL_THRESHOLD = Options.getIntProperty("nashorn.spill.threshold", 256);
private final Set<String> emittedMethods = new HashSet<>();
@@ -2234,73 +2234,33 @@
*
* @param arrayLiteralNode the array of contents
* @param arrayType the type of the array, e.g. ARRAY_NUMBER or ARRAY_OBJECT
- *
- * @return the method generator that was used
*/
- private MethodEmitter loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) {
+ private void loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) {
assert arrayType == Type.INT_ARRAY || arrayType == Type.LONG_ARRAY || arrayType == Type.NUMBER_ARRAY || arrayType == Type.OBJECT_ARRAY;
- final Expression[] nodes = arrayLiteralNode.getValue();
- final Object presets = arrayLiteralNode.getPresets();
- final int[] postsets = arrayLiteralNode.getPostsets();
- final Class<?> type = arrayType.getTypeClass();
- final List<ArrayUnit> units = arrayLiteralNode.getUnits();
+ final Expression[] nodes = arrayLiteralNode.getValue();
+ final Object presets = arrayLiteralNode.getPresets();
+ final int[] postsets = arrayLiteralNode.getPostsets();
+ final List<Splittable.SplitRange> ranges = arrayLiteralNode.getSplitRanges();
loadConstant(presets);
final Type elementType = arrayType.getElementType();
- if (units != null) {
- final MethodEmitter savedMethod = method;
- final FunctionNode currentFunction = lc.getCurrentFunction();
-
- for (final ArrayUnit arrayUnit : units) {
- unit = lc.pushCompileUnit(arrayUnit.getCompileUnit());
-
- final String className = unit.getUnitClassName();
- assert unit != null;
- final String name = currentFunction.uniqueName(SPLIT_PREFIX.symbolName());
- final String signature = methodDescriptor(type, ScriptFunction.class, Object.class, ScriptObject.class, type);
-
- pushMethodEmitter(unit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature));
-
- method.setFunctionNode(currentFunction);
- method.begin();
-
- defineCommonSplitMethodParameters();
- defineSplitMethodParameter(CompilerConstants.SPLIT_ARRAY_ARG.slot(), arrayType);
-
- // NOTE: when this is no longer needed, SplitIntoFunctions will no longer have to add IS_SPLIT
- // to synthetic functions, and FunctionNode.needsCallee() will no longer need to test for isSplit().
- final int arraySlot = fixScopeSlot(currentFunction, 3);
-
- lc.enterSplitNode();
-
- for (int i = arrayUnit.getLo(); i < arrayUnit.getHi(); i++) {
- method.load(arrayType, arraySlot);
- storeElement(nodes, elementType, postsets[i]);
+ if (ranges != null) {
+
+ loadSplitLiteral(new SplitLiteralCreator() {
+ @Override
+ public void populateRange(final MethodEmitter method, final Type type, final int slot, final int start, final int end) {
+ for (int i = start; i < end; i++) {
+ method.load(type, slot);
+ storeElement(nodes, elementType, postsets[i]);
+ }
+ method.load(type, slot);
}
-
- method.load(arrayType, arraySlot);
- method._return();
- lc.exitSplitNode();
- method.end();
- lc.releaseSlots();
- popMethodEmitter();
-
- assert method == savedMethod;
- method.loadCompilerConstant(CALLEE);
- method.swap();
- method.loadCompilerConstant(THIS);
- method.swap();
- method.loadCompilerConstant(SCOPE);
- method.swap();
- method.invokestatic(className, name, signature);
-
- unit = lc.popCompileUnit(unit);
- }
-
- return method;
+ }, ranges, arrayType);
+
+ return;
}
if(postsets.length > 0) {
@@ -2312,7 +2272,6 @@
}
method.load(arrayType, arraySlot);
}
- return method;
}
private void storeElement(final Expression[] nodes, final Type elementType, final int index) {
@@ -2537,6 +2496,7 @@
final List<MapTuple<Expression>> tuples = new ArrayList<>();
final List<PropertyNode> gettersSetters = new ArrayList<>();
final int ccp = getCurrentContinuationEntryPoint();
+ final List<Splittable.SplitRange> ranges = objectNode.getSplitRanges();
Expression protoNode = null;
boolean restOfProperty = false;
@@ -2583,7 +2543,13 @@
loadExpressionAsType(node, type);
}};
}
- oc.makeObject(method);
+
+ if (ranges != null) {
+ oc.createObject(method);
+ loadSplitLiteral(oc, ranges, Type.typeFor(oc.getAllocatorClass()));
+ } else {
+ oc.makeObject(method);
+ }
//if this is a rest of method and our continuation point was found as one of the values
//in the properties above, we need to reset the map to oc.getMap() in the continuation
@@ -2899,6 +2865,54 @@
method.onLocalStore(type, slot);
}
+ private void loadSplitLiteral(final SplitLiteralCreator creator, final List<Splittable.SplitRange> ranges, final Type literalType) {
+ assert ranges != null;
+
+ // final Type literalType = Type.typeFor(literalClass);
+ final MethodEmitter savedMethod = method;
+ final FunctionNode currentFunction = lc.getCurrentFunction();
+
+ for (final Splittable.SplitRange splitRange : ranges) {
+ unit = lc.pushCompileUnit(splitRange.getCompileUnit());
+
+ assert unit != null;
+ final String className = unit.getUnitClassName();
+ final String name = currentFunction.uniqueName(SPLIT_PREFIX.symbolName());
+ final Class<?> clazz = literalType.getTypeClass();
+ final String signature = methodDescriptor(clazz, ScriptFunction.class, Object.class, ScriptObject.class, clazz);
+
+ pushMethodEmitter(unit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature));
+
+ method.setFunctionNode(currentFunction);
+ method.begin();
+
+ defineCommonSplitMethodParameters();
+ defineSplitMethodParameter(CompilerConstants.SPLIT_ARRAY_ARG.slot(), literalType);
+
+ // NOTE: when this is no longer needed, SplitIntoFunctions will no longer have to add IS_SPLIT
+ // to synthetic functions, and FunctionNode.needsCallee() will no longer need to test for isSplit().
+ final int literalSlot = fixScopeSlot(currentFunction, 3);
+
+ lc.enterSplitNode();
+
+ creator.populateRange(method, literalType, literalSlot, splitRange.getLow(), splitRange.getHigh());
+
+ method._return();
+ lc.exitSplitNode();
+ method.end();
+ lc.releaseSlots();
+ popMethodEmitter();
+
+ assert method == savedMethod;
+ method.loadCompilerConstant(CALLEE).swap();
+ method.loadCompilerConstant(THIS).swap();
+ method.loadCompilerConstant(SCOPE).swap();
+ method.invokestatic(className, name, signature);
+
+ unit = lc.popCompileUnit(unit);
+ }
+ }
+
private int fixScopeSlot(final FunctionNode functionNode, final int extraSlot) {
// TODO hack to move the scope to the expected slot (needed because split methods reuse the same slots as the root method)
final int actualScopeSlot = functionNode.compilerConstant(SCOPE).getSlot(SCOPE_TYPE);
@@ -5461,4 +5475,21 @@
method.uncheckedGoto(targetCatchLabel);
}
}
+
+ /**
+ * Interface implemented by object creators that support splitting over multiple methods.
+ */
+ interface SplitLiteralCreator {
+ /**
+ * Generate code to populate a range of the literal object. A reference to the object
+ * should be left on the stack when the method terminates.
+ *
+ * @param method the method emitter
+ * @param type the type of the literal object
+ * @param slot the local slot containing the literal object
+ * @param start the start index (inclusive)
+ * @param end the end index (exclusive)
+ */
+ void populateRange(MethodEmitter method, Type type, int slot, int start, int end);
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java Wed Jul 05 20:50:41 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java Sat Sep 19 16:04:28 2015 +0200
@@ -34,7 +34,6 @@
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
-import java.util.Iterator;
import java.util.List;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.Symbol;
@@ -91,27 +90,20 @@
findClass();
}
- /**
- * Construct an object.
- *
- * @param method the method emitter
- */
@Override
- protected void makeObject(final MethodEmitter method) {
+ public void createObject(final MethodEmitter method) {
makeMap();
final String className = getClassName();
- try {
- // NOTE: we must load the actual structure class here, because the API operates with Nashorn Type objects,
- // and Type objects need a loaded class, for better or worse. We also have to be specific and use the type
- // of the actual structure class, we can't generalize it to e.g. Type.typeFor(ScriptObject.class) as the
- // exact type information is needed for generating continuations in rest-of methods. If we didn't do this,
- // object initializers like { x: arr[i] } would fail during deoptimizing compilation on arr[i], as the
- // values restored from the RewriteException would be cast to "ScriptObject" instead of to e.g. "JO4", and
- // subsequently the "PUTFIELD J04.L0" instruction in the continuation code would fail bytecode verification.
- method._new(Context.forStructureClass(className.replace('/', '.'))).dup();
- } catch (final ClassNotFoundException e) {
- throw new AssertionError(e);
- }
+ // NOTE: we must load the actual structure class here, because the API operates with Nashorn Type objects,
+ // and Type objects need a loaded class, for better or worse. We also have to be specific and use the type
+ // of the actual structure class, we can't generalize it to e.g. Type.typeFor(ScriptObject.class) as the
+ // exact type information is needed for generating continuations in rest-of methods. If we didn't do this,
+ // object initializers like { x: arr[i] } would fail during deoptimizing compilation on arr[i], as the
+ // values restored from the RewriteException would be cast to "ScriptObject" instead of to e.g. "JO4", and
+ // subsequently the "PUTFIELD J04.L0" instruction in the continuation code would fail bytecode verification.
+ assert fieldObjectClass != null;
+ method._new(fieldObjectClass).dup();
+
loadMap(method); //load the map
if (isScope()) {
@@ -126,14 +118,14 @@
} else {
method.invoke(constructorNoLookup(className, PropertyMap.class));
}
+ }
- helpOptimisticRecognizeDuplicateIdentity(method);
-
+ @Override
+ public void populateRange(final MethodEmitter method, final Type objectType, final int objectSlot, final int start, final int end) {
+ method.load(objectType, objectSlot);
// Set values.
- final Iterator<MapTuple<T>> iter = tuples.iterator();
-
- while (iter.hasNext()) {
- final MapTuple<T> tuple = iter.next();
+ for (int i = start; i < end; i++) {
+ final MapTuple<T> tuple = tuples.get(i);
//we only load when we have both symbols and values (which can be == the symbol)
//if we didn't load, we need an array property
if (tuple.symbol != null && tuple.value != null) {
@@ -212,6 +204,11 @@
}
}
+ @Override
+ protected Class<? extends ScriptObject> getAllocatorClass() {
+ return fieldObjectClass;
+ }
+
/**
* Get the class name for the object class,
* e.g. {@code com.nashorn.oracle.scripts.JO2P0}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Wed Jul 05 20:50:41 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Sat Sep 19 16:04:28 2015 +0200
@@ -257,8 +257,7 @@
*/
private Type popType(final Type expected) {
final Type type = popType();
- assert type.isObject() && expected.isObject() ||
- type.isEquivalentTo(expected) : type + " is not compatible with " + expected;
+ assert type.isEquivalentTo(expected) : type + " is not compatible with " + expected;
return type;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ObjectCreator.java Wed Jul 05 20:50:41 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ObjectCreator.java Sat Sep 19 16:04:28 2015 +0200
@@ -36,7 +36,7 @@
* Base class for object creation code generation.
* @param <T> value type
*/
-public abstract class ObjectCreator<T> {
+public abstract class ObjectCreator<T> implements CodeGenerator.SplitLiteralCreator {
/** List of keys & symbols to initiate in this ObjectCreator */
final List<MapTuple<T>> tuples;
@@ -69,7 +69,23 @@
* Generate code for making the object.
* @param method Script method.
*/
- protected abstract void makeObject(final MethodEmitter method);
+ public void makeObject(final MethodEmitter method) {
+ createObject(method);
+ // We need to store the object in a temporary slot as populateRange expects to load the
+ // object from a slot (as it is also invoked within split methods). Note that this also
+ // helps optimistic continuations to handle the stack in case an optimistic assumption
+ // fails during initialization (see JDK-8079269).
+ final int objectSlot = method.getUsedSlotsWithLiveTemporaries();
+ final Type objectType = method.peekType();
+ method.storeTemp(objectType, objectSlot);
+ populateRange(method, objectType, objectSlot, 0, tuples.size());
+ }
+
+ /**
+ * Generate code for creating and initializing the object.
+ * @param method the method emitter
+ */
+ protected abstract void createObject(final MethodEmitter method);
/**
* Construct the property map appropriate for the object.
@@ -125,6 +141,12 @@
}
/**
+ * Get the class of objects created by this ObjectCreator
+ * @return class of created object
+ */
+ abstract protected Class<? extends ScriptObject> getAllocatorClass();
+
+ /**
* Technique for loading an initial value. Defined by anonymous subclasses in code gen.
*
* @param value Value to load.
@@ -145,29 +167,4 @@
MethodEmitter loadTuple(final MethodEmitter method, final MapTuple<T> tuple) {
return loadTuple(method, tuple, true);
}
-
- /**
- * If using optimistic typing, let the code generator realize that the newly created object on the stack
- * when DUP-ed will be the same value. Basically: {NEW, DUP, INVOKESPECIAL init, DUP} will leave a stack
- * load specification {unknown, unknown} on stack (that is "there's two values on the stack, but neither
- * comes from a known local load"). If there's an optimistic operation in the literal initializer,
- * OptimisticOperation.storeStack will allocate two temporary locals for it and store them as
- * {ASTORE 4, ASTORE 3}. If we instead do {NEW, DUP, INVOKESPECIAL init, ASTORE 3, ALOAD 3, DUP} we end up
- * with stack load specification {ALOAD 3, ALOAD 3} (as DUP can track that the value it duplicated came
- * from a local load), so if/when a continuation needs to be recreated from it, it'll be
- * able to emit ALOAD 3, ALOAD 3 to recreate the stack. If we didn't do this, deoptimization within an
- * object literal initialization could in rare cases cause an incompatible change in the shape of the
- * local variable table for the temporaries, e.g. in the following snippet where a variable is reassigned
- * to a wider type in an object initializer:
- * <code>var m = 1; var obj = {p0: m, p1: m = "foo", p2: m}</code>
- * @param method the current method emitter.
- */
- void helpOptimisticRecognizeDuplicateIdentity(final MethodEmitter method) {
- if (codegen.useOptimisticTypes()) {
- final Type objectType = method.peekType();
- final int tempSlot = method.defineTemporaryLocalVariable(objectType.getSlots());
- method.storeHidden(objectType, tempSlot);
- method.load(objectType, tempSlot);
- }
- }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java Wed Jul 05 20:50:41 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java Sat Sep 19 16:04:28 2015 +0200
@@ -27,13 +27,15 @@
import java.util.ArrayList;
import java.util.List;
+
import jdk.nashorn.internal.ir.CompileUnitHolder;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.ObjectNode;
+import jdk.nashorn.internal.ir.Splittable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
/**
@@ -70,15 +72,28 @@
public Node leaveLiteralNode(final LiteralNode<?> node) {
if (node instanceof ArrayLiteralNode) {
final ArrayLiteralNode aln = (ArrayLiteralNode)node;
- if (aln.getUnits() == null) {
+ if (aln.getSplitRanges() == null) {
return node;
}
- final List<ArrayUnit> newArrayUnits = new ArrayList<>();
- for (final ArrayUnit au : aln.getUnits()) {
- newArrayUnits.add(new ArrayUnit(getExistingReplacement(au), au.getLo(), au.getHi()));
+ final List<Splittable.SplitRange> newArrayUnits = new ArrayList<>();
+ for (final Splittable.SplitRange au : aln.getSplitRanges()) {
+ newArrayUnits.add(new Splittable.SplitRange(getExistingReplacement(au), au.getLow(), au.getHigh()));
}
- return aln.setUnits(lc, newArrayUnits);
+ return aln.setSplitRanges(lc, newArrayUnits);
}
return node;
}
+
+ @Override
+ public Node leaveObjectNode(final ObjectNode objectNode) {
+ final List<Splittable.SplitRange> ranges = objectNode.getSplitRanges();
+ if (ranges != null) {
+ final List<Splittable.SplitRange> newRanges = new ArrayList<>();
+ for (final Splittable.SplitRange range : ranges) {
+ newRanges.add(new Splittable.SplitRange(getExistingReplacement(range), range.getLow(), range.getHigh()));
+ }
+ return objectNode.setSplitRanges(lc, newRanges);
+ }
+ return super.leaveObjectNode(objectNode);
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SpillObjectCreator.java Wed Jul 05 20:50:41 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SpillObjectCreator.java Sat Sep 19 16:04:28 2015 +0200
@@ -61,7 +61,7 @@
}
@Override
- protected void makeObject(final MethodEmitter method) {
+ public void createObject(final MethodEmitter method) {
assert !isScope() : "spill scope objects are not currently supported";
final int length = tuples.size();
@@ -69,9 +69,7 @@
final int spillLength = ScriptObject.spillAllocationLength(length);
final long[] jpresetValues = dualFields ? new long[spillLength] : null;
final Object[] opresetValues = new Object[spillLength];
- final Set<Integer> postsetValues = new LinkedHashSet<>();
- final int callSiteFlags = codegen.getCallSiteFlags();
- final Class<?> objectClass = dualFields ? JD.class : JO.class;
+ final Class<?> objectClass = getAllocatorClass();
ArrayData arrayData = ArrayData.allocate(ScriptRuntime.EMPTY_ARRAY);
// Compute constant property values
@@ -85,9 +83,7 @@
if (value != null) {
final Object constantValue = LiteralNode.objectAsConstant(value);
- if (constantValue == LiteralNode.POSTSET_MARKER) {
- postsetValues.add(pos);
- } else {
+ if (constantValue != LiteralNode.POSTSET_MARKER) {
final Property property = propertyMap.findProperty(key);
if (property != null) {
// normal property key
@@ -146,25 +142,34 @@
// instantiate the script object with spill objects
method.invoke(constructorNoLookup(objectClass, PropertyMap.class, long[].class, Object[].class));
- helpOptimisticRecognizeDuplicateIdentity(method);
-
// Set prefix array data if any
if (arrayData.length() > 0) {
method.dup();
codegen.loadConstant(arrayData);
method.invoke(virtualCallNoLookup(ScriptObject.class, "setArray", void.class, ArrayData.class));
}
+ }
+
+ @Override
+ public void populateRange(final MethodEmitter method, final Type objectType, final int objectSlot, final int start, final int end) {
+ final int callSiteFlags = codegen.getCallSiteFlags();
+ method.load(objectType, objectSlot);
// set postfix values
- for (final int i : postsetValues) {
+ for (int i = start; i < end; i++) {
final MapTuple<Expression> tuple = tuples.get(i);
+
+ if (LiteralNode.isConstant(tuple.value)) {
+ continue;
+ }
+
final Property property = propertyMap.findProperty(tuple.key);
+
if (property == null) {
final int index = ArrayIndex.getArrayIndex(tuple.key);
assert ArrayIndex.isValidArrayIndex(index);
method.dup();
method.load(ArrayIndex.toLongIndex(index));
- //method.println("putting " + tuple + " into arraydata");
loadTuple(method, tuple);
method.dynamicSetIndex(callSiteFlags);
} else {
@@ -178,8 +183,7 @@
@Override
protected PropertyMap makeMap() {
assert propertyMap == null : "property map already initialized";
- final boolean dualFields = codegen.useDualFields();
- final Class<? extends ScriptObject> clazz = dualFields ? JD.class : JO.class;
+ final Class<? extends ScriptObject> clazz = getAllocatorClass();
propertyMap = new MapCreator<>(clazz, tuples).makeSpillMap(false, codegen.useDualFields());
return propertyMap;
}
@@ -188,4 +192,9 @@
protected void loadValue(final Expression expr, final Type type) {
codegen.loadExpressionAsType(expr, type);
}
+
+ @Override
+ protected Class<? extends ScriptObject> getAllocatorClass() {
+ return codegen.useDualFields() ? JD.class : JO.class;
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Splitter.java Wed Jul 05 20:50:41 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Splitter.java Sat Sep 19 16:04:28 2015 +0200
@@ -36,9 +36,11 @@
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.ObjectNode;
+import jdk.nashorn.internal.ir.PropertyNode;
import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.Splittable;
import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Context;
@@ -295,7 +297,7 @@
final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal;
final Node[] value = arrayLiteralNode.getValue();
final int[] postsets = arrayLiteralNode.getPostsets();
- final List<ArrayUnit> units = new ArrayList<>();
+ final List<Splittable.SplitRange> ranges = new ArrayList<>();
long totalWeight = 0;
int lo = 0;
@@ -309,7 +311,7 @@
if (totalWeight >= SPLIT_THRESHOLD) {
final CompileUnit unit = compiler.findUnit(totalWeight - weight);
- units.add(new ArrayUnit(unit, lo, i));
+ ranges.add(new Splittable.SplitRange(unit, lo, i));
lo = i;
totalWeight = weight;
}
@@ -317,16 +319,59 @@
if (lo != postsets.length) {
final CompileUnit unit = compiler.findUnit(totalWeight);
- units.add(new ArrayUnit(unit, lo, postsets.length));
+ ranges.add(new Splittable.SplitRange(unit, lo, postsets.length));
}
- return arrayLiteralNode.setUnits(lc, units);
+ return arrayLiteralNode.setSplitRanges(lc, ranges);
}
return literal;
}
@Override
+ public Node leaveObjectNode(final ObjectNode objectNode) {
+ long weight = WeighNodes.weigh(objectNode);
+
+ if (weight < SPLIT_THRESHOLD) {
+ return objectNode;
+ }
+
+ final FunctionNode functionNode = lc.getCurrentFunction();
+ lc.setFlag(functionNode, FunctionNode.IS_SPLIT);
+
+ final List<Splittable.SplitRange> ranges = new ArrayList<>();
+ final List<PropertyNode> properties = objectNode.getElements();
+ final boolean isSpillObject = properties.size() > CodeGenerator.OBJECT_SPILL_THRESHOLD;
+ long totalWeight = 0;
+ int lo = 0;
+
+ for (int i = 0; i < properties.size(); i++) {
+
+ final PropertyNode property = properties.get(i);
+ final boolean isConstant = LiteralNode.isConstant(property.getValue());
+
+ if (!isConstant || !isSpillObject) {
+ weight = isConstant ? 0 : WeighNodes.weigh(property.getValue());
+ totalWeight += WeighNodes.AASTORE_WEIGHT + weight;
+
+ if (totalWeight >= SPLIT_THRESHOLD) {
+ final CompileUnit unit = compiler.findUnit(totalWeight - weight);
+ ranges.add(new Splittable.SplitRange(unit, lo, i));
+ lo = i;
+ totalWeight = weight;
+ }
+ }
+ }
+
+ if (lo != properties.size()) {
+ final CompileUnit unit = compiler.findUnit(totalWeight);
+ ranges.add(new Splittable.SplitRange(unit, lo, properties.size()));
+ }
+
+ return objectNode.setSplitRanges(lc, ranges);
+ }
+
+ @Override
public boolean enterFunctionNode(final FunctionNode node) {
//only go into the function node for this splitter. any subfunctions are rejected
return node == outermost;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java Wed Jul 05 20:50:41 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java Sat Sep 19 16:04:28 2015 +0200
@@ -44,12 +44,13 @@
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.PropertyNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.Splittable;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.ThrowNode;
import jdk.nashorn.internal.ir.TryNode;
@@ -88,6 +89,8 @@
static final long THROW_WEIGHT = 2;
static final long VAR_WEIGHT = 40;
static final long WITH_WEIGHT = 8;
+ static final long OBJECT_WEIGHT = 16;
+ static final long SETPROP_WEIGHT = 5;
/** Accumulated weight. */
private long weight;
@@ -213,7 +216,7 @@
final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
final Node[] value = arrayLiteralNode.getValue();
final int[] postsets = arrayLiteralNode.getPostsets();
- final List<ArrayUnit> units = arrayLiteralNode.getUnits();
+ final List<Splittable.SplitRange> units = arrayLiteralNode.getSplitRanges();
if (units == null) {
for (final int postset : postsets) {
@@ -233,6 +236,27 @@
}
@Override
+ public boolean enterObjectNode(final ObjectNode objectNode) {
+ weight += OBJECT_WEIGHT;
+ final List<PropertyNode> properties = objectNode.getElements();
+ final boolean isSpillObject = properties.size() > CodeGenerator.OBJECT_SPILL_THRESHOLD;
+
+ for (final PropertyNode property : properties) {
+ if (!LiteralNode.isConstant(property.getValue())) {
+ weight += SETPROP_WEIGHT;
+ property.getValue().accept(this);
+ } else if (!isSpillObject) {
+ // constants in spill object are set via preset spill array,
+ // but fields objects need to set constants.
+ weight += SETPROP_WEIGHT;
+ }
+
+ }
+
+ return false;
+ }
+
+ @Override
public Node leavePropertyNode(final PropertyNode propertyNode) {
weight += LITERAL_WEIGHT;
return propertyNode;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java Wed Jul 05 20:50:41 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java Sat Sep 19 16:04:28 2015 +0200
@@ -65,6 +65,7 @@
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
+import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.Undefined;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
@@ -256,6 +257,9 @@
case jdk.internal.org.objectweb.asm.Type.DOUBLE:
return NUMBER;
case jdk.internal.org.objectweb.asm.Type.OBJECT:
+ if (Context.isStructureClass(itype.getClassName())) {
+ return SCRIPT_OBJECT;
+ }
try {
return Type.typeFor(Class.forName(itype.getClassName()));
} catch(final ClassNotFoundException e) {
@@ -949,7 +953,7 @@
/**
* This is the singleton for integer arrays
*/
- public static final ArrayType INT_ARRAY = new ArrayType(int[].class) {
+ public static final ArrayType INT_ARRAY = putInCache(new ArrayType(int[].class) {
private static final long serialVersionUID = 1L;
@Override
@@ -973,12 +977,12 @@
public Type getElementType() {
return INT;
}
- };
+ });
/**
* This is the singleton for long arrays
*/
- public static final ArrayType LONG_ARRAY = new ArrayType(long[].class) {
+ public static final ArrayType LONG_ARRAY = putInCache(new ArrayType(long[].class) {
private static final long serialVersionUID = 1L;
@Override
@@ -1002,12 +1006,12 @@
public Type getElementType() {
return LONG;
}
- };
+ });
/**
* This is the singleton for numeric arrays
*/
- public static final ArrayType NUMBER_ARRAY = new ArrayType(double[].class) {
+ public static final ArrayType NUMBER_ARRAY = putInCache(new ArrayType(double[].class) {
private static final long serialVersionUID = 1L;
@Override
@@ -1031,13 +1035,7 @@
public Type getElementType() {
return NUMBER;
}
- };
-
- /** Singleton for method handle arrays used for properties etc. */
- public static final ArrayType METHODHANDLE_ARRAY = putInCache(new ArrayType(MethodHandle[].class));
-
- /** This is the singleton for string arrays */
- public static final ArrayType STRING_ARRAY = putInCache(new ArrayType(String[].class));
+ });
/** This is the singleton for object arrays */
public static final ArrayType OBJECT_ARRAY = putInCache(new ArrayType(Object[].class));
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java Wed Jul 05 20:50:41 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java Sat Sep 19 16:04:28 2015 +0200
@@ -25,11 +25,9 @@
package jdk.nashorn.internal.ir;
-import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.codegen.types.ArrayType;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -583,6 +581,15 @@
return POSTSET_MARKER;
}
+ /**
+ * Test whether {@code object} represents a constant value.
+ * @param object a node or value object
+ * @return true if object is a constant value
+ */
+ public static boolean isConstant(final Object object) {
+ return objectAsConstant(object) != POSTSET_MARKER;
+ }
+
private static final class NullLiteralNode extends PrimitiveLiteralNode<Object> {
private static final long serialVersionUID = 1L;
@@ -614,7 +621,7 @@
* Array literal node class.
*/
@Immutable
- public static final class ArrayLiteralNode extends LiteralNode<Expression[]> implements LexicalContextNode {
+ public static final class ArrayLiteralNode extends LiteralNode<Expression[]> implements LexicalContextNode, Splittable {
private static final long serialVersionUID = 1L;
/** Array element type. */
@@ -626,8 +633,8 @@
/** Indices of array elements requiring computed post sets. */
private final int[] postsets;
- /** Sub units with indexes ranges, in which to split up code generation, for large literals */
- private final List<ArrayUnit> units;
+ /** Ranges for splitting up large literals in code generation */
+ private final List<Splittable.SplitRange> splitRanges;
@Override
public boolean isArray() {
@@ -635,64 +642,13 @@
}
- /**
- * An ArrayUnit is a range in an ArrayLiteral. ArrayLiterals can
- * be split if they are too large, for bytecode generation reasons
- */
- public static final class ArrayUnit implements CompileUnitHolder, Serializable {
- private static final long serialVersionUID = 1L;
-
- /** Compile unit associated with the postsets range. */
- private final CompileUnit compileUnit;
-
- /** postsets range associated with the unit (hi not inclusive). */
- private final int lo, hi;
-
- /**
- * Constructor
- * @param compileUnit compile unit
- * @param lo lowest array index in unit
- * @param hi highest array index in unit + 1
- */
- public ArrayUnit(final CompileUnit compileUnit, final int lo, final int hi) {
- this.compileUnit = compileUnit;
- this.lo = lo;
- this.hi = hi;
- }
-
- /**
- * Get the high index position of the ArrayUnit (non inclusive)
- * @return high index position
- */
- public int getHi() {
- return hi;
- }
-
- /**
- * Get the low index position of the ArrayUnit (inclusive)
- * @return low index position
- */
- public int getLo() {
- return lo;
- }
-
- /**
- * The array compile unit
- * @return array compile unit
- */
- @Override
- public CompileUnit getCompileUnit() {
- return compileUnit;
- }
- }
-
private static final class ArrayLiteralInitializer {
static ArrayLiteralNode initialize(final ArrayLiteralNode node) {
final Type elementType = computeElementType(node.value);
final int[] postsets = computePostsets(node.value);
final Object presets = computePresets(node.value, elementType, postsets);
- return new ArrayLiteralNode(node, node.value, elementType, postsets, presets, node.units);
+ return new ArrayLiteralNode(node, node.value, elementType, postsets, presets, node.splitRanges);
}
private static Type computeElementType(final Expression[] value) {
@@ -725,7 +681,7 @@
for (int i = 0; i < value.length; i++) {
final Expression element = value[i];
- if (element == null || objectAsConstant(element) == POSTSET_MARKER) {
+ if (element == null || !isConstant(element)) {
computed[nComputed++] = i;
}
}
@@ -842,19 +798,19 @@
this.elementType = Type.UNKNOWN;
this.presets = null;
this.postsets = null;
- this.units = null;
+ this.splitRanges = null;
}
/**
* Copy constructor
* @param node source array literal node
*/
- private ArrayLiteralNode(final ArrayLiteralNode node, final Expression[] value, final Type elementType, final int[] postsets, final Object presets, final List<ArrayUnit> units) {
+ private ArrayLiteralNode(final ArrayLiteralNode node, final Expression[] value, final Type elementType, final int[] postsets, final Object presets, final List<Splittable.SplitRange> splitRanges) {
super(node, value);
this.elementType = elementType;
this.postsets = postsets;
this.presets = presets;
- this.units = units;
+ this.splitRanges = splitRanges;
}
/**
@@ -946,26 +902,27 @@
}
/**
- * Get the array units that make up this ArrayLiteral
- * @see ArrayUnit
- * @return list of array units
+ * Get the split ranges for this ArrayLiteral, or null if this array does not have to be split.
+ * @see Splittable.SplitRange
+ * @return list of split ranges
*/
- public List<ArrayUnit> getUnits() {
- return units == null ? null : Collections.unmodifiableList(units);
+ @Override
+ public List<Splittable.SplitRange> getSplitRanges() {
+ return splitRanges == null ? null : Collections.unmodifiableList(splitRanges);
}
/**
- * Set the ArrayUnits that make up this ArrayLiteral
+ * Set the SplitRanges that make up this ArrayLiteral
* @param lc lexical context
- * @see ArrayUnit
- * @param units list of array units
- * @return new or changed arrayliteralnode
+ * @see Splittable.SplitRange
+ * @param splitRanges list of split ranges
+ * @return new or changed node
*/
- public ArrayLiteralNode setUnits(final LexicalContext lc, final List<ArrayUnit> units) {
- if (this.units == units) {
+ public ArrayLiteralNode setSplitRanges(final LexicalContext lc, final List<Splittable.SplitRange> splitRanges) {
+ if (this.splitRanges == splitRanges) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, units));
+ return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, splitRanges));
}
@Override
@@ -987,7 +944,7 @@
if (this.value == value) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, units));
+ return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, splitRanges));
}
private ArrayLiteralNode setValue(final LexicalContext lc, final List<Expression> value) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ObjectNode.java Wed Jul 05 20:50:41 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ObjectNode.java Sat Sep 19 16:04:28 2015 +0200
@@ -27,6 +27,7 @@
import java.util.Collections;
import java.util.List;
+import java.util.RandomAccess;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -35,12 +36,15 @@
* IR representation of an object literal.
*/
@Immutable
-public final class ObjectNode extends Expression {
+public final class ObjectNode extends Expression implements LexicalContextNode, Splittable {
private static final long serialVersionUID = 1L;
/** Literal elements. */
private final List<PropertyNode> elements;
+ /** Ranges for splitting large literals over multiple compile units in codegen. */
+ private final List<Splittable.SplitRange> splitRanges;
+
/**
* Constructor
*
@@ -51,19 +55,27 @@
public ObjectNode(final long token, final int finish, final List<PropertyNode> elements) {
super(token, finish);
this.elements = elements;
+ this.splitRanges = null;
+ assert elements instanceof RandomAccess : "Splitting requires random access lists";
}
- private ObjectNode(final ObjectNode objectNode, final List<PropertyNode> elements) {
+ private ObjectNode(final ObjectNode objectNode, final List<PropertyNode> elements,
+ final List<Splittable.SplitRange> splitRanges ) {
super(objectNode);
this.elements = elements;
+ this.splitRanges = splitRanges;
}
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+ return Acceptor.accept(this, visitor);
+ }
+
+ @Override
+ public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterObjectNode(this)) {
- return visitor.leaveObjectNode(setElements(Node.accept(visitor, elements)));
+ return visitor.leaveObjectNode(setElements(lc, Node.accept(visitor, elements)));
}
-
return this;
}
@@ -102,10 +114,35 @@
return Collections.unmodifiableList(elements);
}
- private ObjectNode setElements(final List<PropertyNode> elements) {
+ private ObjectNode setElements(final LexicalContext lc, final List<PropertyNode> elements) {
if (this.elements == elements) {
return this;
}
- return new ObjectNode(this, elements);
+ return Node.replaceInLexicalContext(lc, this, new ObjectNode(this, elements, this.splitRanges));
}
+
+ /**
+ * Set the split ranges for this ObjectNode
+ * @see Splittable.SplitRange
+ * @param lc the lexical context
+ * @param splitRanges list of split ranges
+ * @return new or changed object node
+ */
+ public ObjectNode setSplitRanges(final LexicalContext lc, final List<Splittable.SplitRange> splitRanges) {
+ if (this.splitRanges == splitRanges) {
+ return this;
+ }
+ return Node.replaceInLexicalContext(lc, this, new ObjectNode(this, elements, splitRanges));
+ }
+
+ /**
+ * Get the split ranges for this ObjectNode, or null if the object is not split.
+ * @see Splittable.SplitRange
+ * @return list of split ranges
+ */
+ @Override
+ public List<Splittable.SplitRange> getSplitRanges() {
+ return splitRanges == null ? null : Collections.unmodifiableList(splitRanges);
+ }
+
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Splittable.java Sat Sep 19 16:04:28 2015 +0200
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.ir;
+
+import java.io.Serializable;
+import java.util.List;
+import jdk.nashorn.internal.codegen.CompileUnit;
+
+/**
+ * An interface for splittable expressions.
+ */
+public interface Splittable {
+
+ /**
+ * Get a list of split ranges for this splittable expression, or null
+ * if the expression should not be split.
+ *
+ * @return a list of split ranges
+ */
+ List<SplitRange> getSplitRanges();
+
+ /**
+ * A SplitRange is a range in a splittable expression. It defines the
+ * boundaries of the split range and provides a compile unit for code generation.
+ */
+ final class SplitRange implements CompileUnitHolder, Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /** Compile unit associated with the postsets range. */
+ private final CompileUnit compileUnit;
+
+ /** postsets range associated with the unit (hi not inclusive). */
+ private final int low, high;
+
+ /**
+ * Constructor
+ * @param compileUnit compile unit
+ * @param low lowest array index in unit
+ * @param high highest array index in unit + 1
+ */
+ public SplitRange(final CompileUnit compileUnit, final int low, final int high) {
+ this.compileUnit = compileUnit;
+ this.low = low;
+ this.high = high;
+ }
+
+ /**
+ * Get the high index position of the ArrayUnit (exclusive)
+ * @return high index position
+ */
+ public int getHigh() {
+ return high;
+ }
+
+ /**
+ * Get the low index position of the ArrayUnit (inclusive)
+ * @return low index position
+ */
+ public int getLow() {
+ return low;
+ }
+
+ /**
+ * The array compile unit
+ * @return array compile unit
+ */
+ @Override
+ public CompileUnit getCompileUnit() {
+ return compileUnit;
+ }
+ }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Wed Jul 05 20:50:41 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Sat Sep 19 16:04:28 2015 +0200
@@ -1034,6 +1034,16 @@
}
/**
+ * Is {@code className} the name of a structure class?
+ *
+ * @param className a class name
+ * @return true if className is a structure class name
+ */
+ public static boolean isStructureClass(final String className) {
+ return StructureLoader.isStructureClass(className);
+ }
+
+ /**
* Checks that the given Class can be accessed from no permissions context.
*
* @param clazz Class object
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8135190.js Sat Sep 19 16:04:28 2015 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8135190: Method code too large in Babel browser.js script
+ *
+ * @test
+ * @run
+ */
+
+// Make sure huge object literals are parsed correctly and don't throw
+// (using buildObject -> JSON.stringify -> eval -> testObject)
+
+function buildObject(n, d) {
+ if (n < 2) {
+ return {name: "property", type: "identifier"};
+ }
+ var obj = {};
+ for (var i = 0; i < n; i++) {
+ obj["expr" + i] = buildObject(Math.floor(n / d), d);
+ }
+ return obj;
+}
+
+function testObject(obj, n, d) {
+ var keys = Object.keys(obj);
+ if (n < 2) {
+ Assert.assertTrue(keys.length === 2);
+ Assert.assertTrue(keys[0] === "name");
+ Assert.assertTrue(keys[1] === "type");
+ } else {
+ Assert.assertTrue(keys.length === n);
+ for (var i = 0; i < n; i++) {
+ Assert.assertTrue(keys[i] === "expr" + i);
+ }
+ }
+ if (n >= 2) {
+ for (var k in keys) {
+ testObject(obj[keys[k]], Math.floor(n / d), d)
+ }
+ }
+}
+
+var fieldObject = (eval("(" + JSON.stringify(buildObject(25, 2)) + ")"));
+testObject(fieldObject, 25, 2);
+var spillObject = (eval("(" + JSON.stringify(buildObject(1000, 100)) + ")"));
+testObject(spillObject, 1000, 100);