--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java Sat Sep 26 09:22:18 2015 -0700
@@ -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 Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Sat Sep 26 09:22:18 2015 -0700
@@ -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<>();
@@ -1634,7 +1634,7 @@
@Override
void consumeStack() {
- dynamicCall(2 + argsCount, getCallSiteFlags(), origCallee.getName());
+ dynamicCall(2 + argsCount, getCallSiteFlags(), null);
}
}.emit();
return false;
@@ -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 Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FieldObjectCreator.java Sat Sep 26 09:22:18 2015 -0700
@@ -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/FindScopeDepths.java Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FindScopeDepths.java Sat Sep 26 09:22:18 2015 -0700
@@ -275,15 +275,11 @@
final Set<Symbol> symbols = new HashSet<>();
block.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
- public final boolean enterDefault(final Node node) {
- if (!compiler.isOnDemandCompilation()) {
- if (node instanceof IdentNode) {
- final Symbol symbol = ((IdentNode)node).getSymbol();
- if (symbol != null && symbol.isScope()) {
- //if this is an internal symbol, skip it.
- symbols.add(symbol);
- }
- }
+ public boolean enterIdentNode(final IdentNode identNode) {
+ final Symbol symbol = identNode.getSymbol();
+ if (symbol != null && symbol.isScope()) {
+ //if this is an internal symbol, skip it.
+ symbols.add(symbol);
}
return true;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FoldConstants.java Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/FoldConstants.java Sat Sep 26 09:22:18 2015 -0700
@@ -116,7 +116,7 @@
statements.addAll(executed.getStatements()); // Get statements form executed branch
}
if (dropped != null) {
- extractVarNodes(dropped, statements); // Get var-nodes from non-executed branch
+ extractVarNodesFromDeadCode(dropped, statements); // Get var-nodes from non-executed branch
}
if (statements.isEmpty()) {
return new EmptyNode(ifNode);
@@ -185,14 +185,27 @@
protected abstract LiteralNode<?> eval();
}
- private static void extractVarNodes(final Block block, final List<Statement> statements) {
- final LexicalContext lc = new LexicalContext();
- block.accept(lc, new NodeVisitor<LexicalContext>(lc) {
+ /**
+ * When we eliminate dead code, we must preserve var declarations as they are scoped to the whole
+ * function. This method gathers var nodes from code passed to it, removing their initializers.
+ *
+ * @param deadCodeRoot the root node of eliminated dead code
+ * @param statements a list that will be receiving the var nodes from the dead code, with their
+ * initializers removed.
+ */
+ static void extractVarNodesFromDeadCode(final Node deadCodeRoot, final List<Statement> statements) {
+ deadCodeRoot.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public boolean enterVarNode(final VarNode varNode) {
statements.add(varNode.setInit(null));
return false;
}
+
+ @Override
+ public boolean enterFunctionNode(final FunctionNode functionNode) {
+ // Don't descend into nested functions
+ return false;
+ }
});
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java Sat Sep 26 09:22:18 2015 -0700
@@ -121,13 +121,7 @@
terminated = true;
}
} else {
- statement.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
- @Override
- public boolean enterVarNode(final VarNode varNode) {
- newStatements.add(varNode.setInit(null));
- return false;
- }
- });
+ FoldConstants.extractVarNodesFromDeadCode(statement, newStatements);
}
}
return newStatements;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Sat Sep 26 09:22:18 2015 -0700
@@ -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 Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ObjectCreator.java Sat Sep 26 09:22:18 2015 -0700
@@ -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 Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java Sat Sep 26 09:22:18 2015 -0700
@@ -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 Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SpillObjectCreator.java Sat Sep 26 09:22:18 2015 -0700
@@ -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 Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Splitter.java Sat Sep 26 09:22:18 2015 -0700
@@ -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 Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java Sat Sep 26 09:22:18 2015 -0700
@@ -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 Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/Type.java Sat Sep 26 09:22:18 2015 -0700
@@ -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 Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java Sat Sep 26 09:22:18 2015 -0700
@@ -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 Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ObjectNode.java Sat Sep 26 09:22:18 2015 -0700
@@ -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 26 09:22:18 2015 -0700
@@ -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 Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Sat Sep 26 09:22:18 2015 -0700
@@ -64,7 +64,6 @@
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.LongAdder;
@@ -301,7 +300,47 @@
}
}
- private final Map<CodeSource, Reference<Class<?>>> anonymousHostClasses = new ConcurrentHashMap<>();
+ private final Map<CodeSource, HostClassReference> anonymousHostClasses = new HashMap<>();
+ private final ReferenceQueue<Class<?>> anonymousHostClassesRefQueue = new ReferenceQueue<>();
+
+ private static class HostClassReference extends WeakReference<Class<?>> {
+ final CodeSource codeSource;
+
+ HostClassReference(final CodeSource codeSource, final Class<?> clazz, final ReferenceQueue<Class<?>> refQueue) {
+ super(clazz, refQueue);
+ this.codeSource = codeSource;
+ }
+ }
+
+ private synchronized Class<?> getAnonymousHostClass(final CodeSource codeSource) {
+ // Remove cleared entries
+ for(;;) {
+ final HostClassReference clearedRef = (HostClassReference)anonymousHostClassesRefQueue.poll();
+ if (clearedRef == null) {
+ break;
+ }
+ anonymousHostClasses.remove(clearedRef.codeSource, clearedRef);
+ }
+
+ // Try to find an existing host class
+ final Reference<Class<?>> ref = anonymousHostClasses.get(codeSource);
+ if (ref != null) {
+ final Class<?> existingHostClass = ref.get();
+ if (existingHostClass != null) {
+ return existingHostClass;
+ }
+ }
+
+ // Define a new host class if existing is not found
+ final Class<?> newHostClass = createNewLoader().installClass(
+ // NOTE: we're defining these constants in AnonymousContextCodeInstaller so they are not
+ // initialized if we don't use AnonymousContextCodeInstaller. As this method is only ever
+ // invoked from AnonymousContextCodeInstaller, this is okay.
+ AnonymousContextCodeInstaller.ANONYMOUS_HOST_CLASS_NAME,
+ AnonymousContextCodeInstaller.ANONYMOUS_HOST_CLASS_BYTES, codeSource);
+ anonymousHostClasses.put(codeSource, new HostClassReference(codeSource, newHostClass, anonymousHostClassesRefQueue));
+ return newHostClass;
+ }
private static final class AnonymousContextCodeInstaller extends ContextCodeInstaller {
private static final Unsafe UNSAFE = getUnsafe();
@@ -310,9 +349,9 @@
private final Class<?> hostClass;
- private AnonymousContextCodeInstaller(final Context context, final CodeSource codeSource) {
+ private AnonymousContextCodeInstaller(final Context context, final CodeSource codeSource, final Class<?> hostClass) {
super(context, codeSource);
- hostClass = getAnonymousHostClass();
+ this.hostClass = hostClass;
}
@Override
@@ -335,19 +374,6 @@
return new NamedContextCodeInstaller(context, codeSource, context.createNewLoader());
}
- private Class<?> getAnonymousHostClass() {
- final Reference<Class<?>> ref = context.anonymousHostClasses.get(codeSource);
- if (ref != null) {
- final Class<?> existingHostClass = ref.get();
- if (existingHostClass != null) {
- return existingHostClass;
- }
- }
- final Class<?> newHostClass = context.createNewLoader().installClass(ANONYMOUS_HOST_CLASS_NAME, ANONYMOUS_HOST_CLASS_BYTES, codeSource);
- context.anonymousHostClasses.put(codeSource, new WeakReference<>(newHostClass));
- return newHostClass;
- }
-
private static final byte[] getAnonymousHostClassBytes() {
final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
cw.visit(V1_7, Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT, ANONYMOUS_HOST_CLASS_NAME.replace('.', '/'), null, "java/lang/Object", null);
@@ -1034,6 +1060,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
@@ -1404,7 +1440,7 @@
final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader;
installer = new NamedContextCodeInstaller(this, cs, loader);
} else {
- installer = new AnonymousContextCodeInstaller(this, cs);
+ installer = new AnonymousContextCodeInstaller(this, cs, getAnonymousHostClass(cs));
}
if (storedScript == null) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Fri Sep 25 22:59:35 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Sat Sep 26 09:22:18 2015 -0700
@@ -203,6 +203,8 @@
// This is the superclass for our generated adapter.
private final Class<?> superClass;
+ // Interfaces implemented by our generated adapter.
+ private final List<Class<?>> interfaces;
// Class loader used as the parent for the class loader we'll create to load the generated class. It will be a class
// loader that has the visibility of all original types (class to extend and interfaces to implement) and of the
// Nashorn classes.
@@ -254,6 +256,7 @@
assert interfaces != null;
this.superClass = superClass;
+ this.interfaces = interfaces;
this.classOverride = classOverride;
this.commonLoader = commonLoader;
cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) {
@@ -1031,6 +1034,24 @@
endMethod(mv);
}
+ // find the appropriate super type to use for invokespecial on the given interface
+ private Class<?> findInvokespecialOwnerFor(final Class<?> cl) {
+ assert Modifier.isInterface(cl.getModifiers()) : cl + " is not an interface";
+
+ if (cl.isAssignableFrom(superClass)) {
+ return superClass;
+ }
+
+ for (final Class<?> iface : interfaces) {
+ if (cl.isAssignableFrom(iface)) {
+ return iface;
+ }
+ }
+
+ // we better that interface that extends the given interface!
+ throw new AssertionError("can't find the class/interface that extends " + cl);
+ }
+
private void emitSuperCall(final InstructionAdapter mv, final Class<?> owner, final String name, final String methodDesc) {
mv.visitVarInsn(ALOAD, 0);
int nextParam = 1;
@@ -1042,7 +1063,9 @@
// default method - non-abstract, interface method
if (Modifier.isInterface(owner.getModifiers())) {
- mv.invokespecial(Type.getInternalName(owner), name, methodDesc, false);
+ // we should call default method on the immediate "super" type - not on (possibly)
+ // the indirectly inherited interface class!
+ mv.invokespecial(Type.getInternalName(findInvokespecialOwnerFor(owner)), name, methodDesc, false);
} else {
mv.invokespecial(superClassName, name, methodDesc, false);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8134488.js Sat Sep 26 09:22:18 2015 -0700
@@ -0,0 +1,46 @@
+/*
+ * 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-8134488: var statement in if(false) block incorrectly evacuated into enclosing function
+ *
+ * @test
+ * @run
+ */
+
+var x = "string";
+print(x);
+
+(function f1() {
+ (function f2() {
+ // If it finds both 'print' and 'x', it'll print 'string'.
+ print(x);
+ })();
+
+ if (false) {
+ (function f3() {
+ var x;
+ })();
+ }
+
+})();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8134488.js.EXPECTED Sat Sep 26 09:22:18 2015 -0700
@@ -0,0 +1,2 @@
+string
+string
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8134490.js Sat Sep 26 09:22:18 2015 -0700
@@ -0,0 +1,41 @@
+/*
+ * 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-8134490: Dead var statement evacuation incorrectly descends into nested functions
+ *
+ * @test
+ * @run
+ */
+
+var v1;
+
+function f1()
+{
+v1 = 1;
+return true;
+(function () { var v1; })();
+}
+
+f1();
+// If it executes without throwing an exception in code generator, it's working.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8135190.js Sat Sep 26 09:22:18 2015 -0700
@@ -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);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8137134.js Sat Sep 26 09:22:18 2015 -0700
@@ -0,0 +1,55 @@
+/*
+ * 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-8137134: invokespecial on indirect super interface is generated by Java adapter generator
+ *
+ * @test
+ * @run
+ */
+
+var B = Java.type("jdk.nashorn.test.models.B");
+var b1 = new B() {}
+print(b1.a());
+print(b1.b());
+
+var b2 = new B() {
+ b: function() {
+ return "from B.b in script";
+ }
+};
+
+print(b2.a());
+print(b2.b());
+
+var b3 = new B() {
+ a: function() {
+ return "from A.a in script";
+ },
+ b: function() {
+ return "from B.b in script";
+ }
+};
+
+print(b3.a());
+print(b3.b());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8137134.js.EXPECTED Sat Sep 26 09:22:18 2015 -0700
@@ -0,0 +1,6 @@
+from A.a
+from B.b
+from A.a
+from B.b in script
+from A.a in script
+from B.b in script
--- a/nashorn/test/script/currently-failing/gettersetter.js Fri Sep 25 22:59:35 2015 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2014, 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.
- */
-
-/**
- * @test
- * @option -Dnashorn.debug=true
- * @fork
- */
-
-load(__DIR__ + "maputil.js");
-
-function Foo() {
- return {
- get foo() { return 42; },
- set foo(x) {}
- }
-}
-
-var obj1 = Foo();
-var obj2 = Foo();
-
-assertSameMap(obj1, obj2, "Object literals before change");
-
-Object.defineProperty(obj2, "foo", { get: function() { return 'hello' } });
-assertSameMap(obj1, obj2);
-
-Object.defineProperty(obj2, "foo", { set: function(x) { print(x) } });
-assertSameMap(obj1, obj2);
--- a/nashorn/test/script/currently-failing/property_delete.js Fri Sep 25 22:59:35 2015 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2014, 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.
- */
-
-/**
- * @test
- * @option -Dnashorn.debug=true
- * @fork
- */
-
-load(__DIR__ + "maputil.js");
-
-function Foo() {
- this.x = 33;
-}
-
-var obj1 = new Foo();
-var obj2 = new Foo();
-
-assertSameMap(obj1, obj2);
-
-// property deletion at same callsite
-function deleteX(obj) {
- delete obj.x;
-}
-deleteX(obj1);
-deleteX(obj2);
-
-assertSameMap(obj1, obj2);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/maptests/gettersetter.js Sat Sep 26 09:22:18 2015 -0700
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+/**
+ * @test
+ * @option -Dnashorn.debug=true
+ * @fork
+ */
+
+load(__DIR__ + "maputil.js");
+
+function Foo() {
+ return {
+ get foo() { return 42; },
+ set foo(x) {}
+ }
+}
+
+var obj1 = Foo();
+var obj2 = Foo();
+
+assertSameMap(obj1, obj2, "Object literals before change");
+
+Object.defineProperty(obj2, "foo", { get: function() { return 'hello' } });
+assertSameMap(obj1, obj2);
+
+Object.defineProperty(obj2, "foo", { set: function(x) { print(x) } });
+assertSameMap(obj1, obj2);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/maptests/property_delete.js Sat Sep 26 09:22:18 2015 -0700
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+/**
+ * @test
+ * @option -Dnashorn.debug=true
+ * @fork
+ */
+
+load(__DIR__ + "maputil.js");
+
+function Foo() {
+ this.x = 33;
+}
+
+var obj1 = new Foo();
+var obj2 = new Foo();
+
+assertSameMap(obj1, obj2);
+
+// property deletion at same callsite
+function deleteX(obj) {
+ delete obj.x;
+}
+deleteX(obj1);
+deleteX(obj2);
+
+assertEqualWithoutTypeMap(obj1, obj2);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/test/models/A.java Sat Sep 26 09:22:18 2015 -0700
@@ -0,0 +1,32 @@
+/*
+ * 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.test.models;
+
+public interface A {
+ default String a() {
+ return "from A.a";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/test/models/B.java Sat Sep 26 09:22:18 2015 -0700
@@ -0,0 +1,32 @@
+/*
+ * 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.test.models;
+
+public interface B extends A {
+ default String b() {
+ return "from B.b";
+ }
+}