--- 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);
+ }
}