nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
changeset 32781 d8f34ffbbc7a
parent 32692 8f60bd284bf4
child 32784 f7e0a3e05aa1
equal deleted inserted replaced
32712:f61a63b7d1e5 32781:d8f34ffbbc7a
   103 import jdk.nashorn.internal.ir.LabelNode;
   103 import jdk.nashorn.internal.ir.LabelNode;
   104 import jdk.nashorn.internal.ir.LexicalContext;
   104 import jdk.nashorn.internal.ir.LexicalContext;
   105 import jdk.nashorn.internal.ir.LexicalContextNode;
   105 import jdk.nashorn.internal.ir.LexicalContextNode;
   106 import jdk.nashorn.internal.ir.LiteralNode;
   106 import jdk.nashorn.internal.ir.LiteralNode;
   107 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
   107 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
   108 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
       
   109 import jdk.nashorn.internal.ir.LiteralNode.PrimitiveLiteralNode;
   108 import jdk.nashorn.internal.ir.LiteralNode.PrimitiveLiteralNode;
   110 import jdk.nashorn.internal.ir.LocalVariableConversion;
   109 import jdk.nashorn.internal.ir.LocalVariableConversion;
   111 import jdk.nashorn.internal.ir.LoopNode;
   110 import jdk.nashorn.internal.ir.LoopNode;
   112 import jdk.nashorn.internal.ir.Node;
   111 import jdk.nashorn.internal.ir.Node;
   113 import jdk.nashorn.internal.ir.ObjectNode;
   112 import jdk.nashorn.internal.ir.ObjectNode;
   116 import jdk.nashorn.internal.ir.ReturnNode;
   115 import jdk.nashorn.internal.ir.ReturnNode;
   117 import jdk.nashorn.internal.ir.RuntimeNode;
   116 import jdk.nashorn.internal.ir.RuntimeNode;
   118 import jdk.nashorn.internal.ir.RuntimeNode.Request;
   117 import jdk.nashorn.internal.ir.RuntimeNode.Request;
   119 import jdk.nashorn.internal.ir.SetSplitState;
   118 import jdk.nashorn.internal.ir.SetSplitState;
   120 import jdk.nashorn.internal.ir.SplitReturn;
   119 import jdk.nashorn.internal.ir.SplitReturn;
       
   120 import jdk.nashorn.internal.ir.Splittable;
   121 import jdk.nashorn.internal.ir.Statement;
   121 import jdk.nashorn.internal.ir.Statement;
   122 import jdk.nashorn.internal.ir.SwitchNode;
   122 import jdk.nashorn.internal.ir.SwitchNode;
   123 import jdk.nashorn.internal.ir.Symbol;
   123 import jdk.nashorn.internal.ir.Symbol;
   124 import jdk.nashorn.internal.ir.TernaryNode;
   124 import jdk.nashorn.internal.ir.TernaryNode;
   125 import jdk.nashorn.internal.ir.ThrowNode;
   125 import jdk.nashorn.internal.ir.ThrowNode;
   240     private CompileUnit unit;
   240     private CompileUnit unit;
   241 
   241 
   242     private final DebugLogger log;
   242     private final DebugLogger log;
   243 
   243 
   244     /** From what size should we use spill instead of fields for JavaScript objects? */
   244     /** From what size should we use spill instead of fields for JavaScript objects? */
   245     private static final int OBJECT_SPILL_THRESHOLD = Options.getIntProperty("nashorn.spill.threshold", 256);
   245     static final int OBJECT_SPILL_THRESHOLD = Options.getIntProperty("nashorn.spill.threshold", 256);
   246 
   246 
   247     private final Set<String> emittedMethods = new HashSet<>();
   247     private final Set<String> emittedMethods = new HashSet<>();
   248 
   248 
   249     // Function Id -> ContinuationInfo. Used by compilation of rest-of function only.
   249     // Function Id -> ContinuationInfo. Used by compilation of rest-of function only.
   250     private ContinuationInfo continuationInfo;
   250     private ContinuationInfo continuationInfo;
  2232      * Load a list of nodes as an array of a specific type
  2232      * Load a list of nodes as an array of a specific type
  2233      * The array will contain the visited nodes.
  2233      * The array will contain the visited nodes.
  2234      *
  2234      *
  2235      * @param arrayLiteralNode the array of contents
  2235      * @param arrayLiteralNode the array of contents
  2236      * @param arrayType        the type of the array, e.g. ARRAY_NUMBER or ARRAY_OBJECT
  2236      * @param arrayType        the type of the array, e.g. ARRAY_NUMBER or ARRAY_OBJECT
  2237      *
       
  2238      * @return the method generator that was used
       
  2239      */
  2237      */
  2240     private MethodEmitter loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) {
  2238     private void loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) {
  2241         assert arrayType == Type.INT_ARRAY || arrayType == Type.LONG_ARRAY || arrayType == Type.NUMBER_ARRAY || arrayType == Type.OBJECT_ARRAY;
  2239         assert arrayType == Type.INT_ARRAY || arrayType == Type.LONG_ARRAY || arrayType == Type.NUMBER_ARRAY || arrayType == Type.OBJECT_ARRAY;
  2242 
  2240 
  2243         final Expression[]    nodes    = arrayLiteralNode.getValue();
  2241         final Expression[]     nodes    = arrayLiteralNode.getValue();
  2244         final Object          presets  = arrayLiteralNode.getPresets();
  2242         final Object           presets  = arrayLiteralNode.getPresets();
  2245         final int[]           postsets = arrayLiteralNode.getPostsets();
  2243         final int[]            postsets = arrayLiteralNode.getPostsets();
  2246         final Class<?>        type     = arrayType.getTypeClass();
  2244         final List<Splittable.SplitRange> ranges   = arrayLiteralNode.getSplitRanges();
  2247         final List<ArrayUnit> units    = arrayLiteralNode.getUnits();
       
  2248 
  2245 
  2249         loadConstant(presets);
  2246         loadConstant(presets);
  2250 
  2247 
  2251         final Type elementType = arrayType.getElementType();
  2248         final Type elementType = arrayType.getElementType();
  2252 
  2249 
  2253         if (units != null) {
  2250         if (ranges != null) {
  2254             final MethodEmitter savedMethod     = method;
  2251 
  2255             final FunctionNode  currentFunction = lc.getCurrentFunction();
  2252             loadSplitLiteral(new SplitLiteralCreator() {
  2256 
  2253                 @Override
  2257             for (final ArrayUnit arrayUnit : units) {
  2254                 public void populateRange(final MethodEmitter method, final Type type, final int slot, final int start, final int end) {
  2258                 unit = lc.pushCompileUnit(arrayUnit.getCompileUnit());
  2255                     for (int i = start; i < end; i++) {
  2259 
  2256                         method.load(type, slot);
  2260                 final String className = unit.getUnitClassName();
  2257                         storeElement(nodes, elementType, postsets[i]);
  2261                 assert unit != null;
  2258                     }
  2262                 final String name      = currentFunction.uniqueName(SPLIT_PREFIX.symbolName());
  2259                     method.load(type, slot);
  2263                 final String signature = methodDescriptor(type, ScriptFunction.class, Object.class, ScriptObject.class, type);
  2260                 }
  2264 
  2261             }, ranges, arrayType);
  2265                 pushMethodEmitter(unit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature));
  2262 
  2266 
  2263             return;
  2267                 method.setFunctionNode(currentFunction);
       
  2268                 method.begin();
       
  2269 
       
  2270                 defineCommonSplitMethodParameters();
       
  2271                 defineSplitMethodParameter(CompilerConstants.SPLIT_ARRAY_ARG.slot(), arrayType);
       
  2272 
       
  2273                 // NOTE: when this is no longer needed, SplitIntoFunctions will no longer have to add IS_SPLIT
       
  2274                 // to synthetic functions, and FunctionNode.needsCallee() will no longer need to test for isSplit().
       
  2275                 final int arraySlot = fixScopeSlot(currentFunction, 3);
       
  2276 
       
  2277                 lc.enterSplitNode();
       
  2278 
       
  2279                 for (int i = arrayUnit.getLo(); i < arrayUnit.getHi(); i++) {
       
  2280                     method.load(arrayType, arraySlot);
       
  2281                     storeElement(nodes, elementType, postsets[i]);
       
  2282                 }
       
  2283 
       
  2284                 method.load(arrayType, arraySlot);
       
  2285                 method._return();
       
  2286                 lc.exitSplitNode();
       
  2287                 method.end();
       
  2288                 lc.releaseSlots();
       
  2289                 popMethodEmitter();
       
  2290 
       
  2291                 assert method == savedMethod;
       
  2292                 method.loadCompilerConstant(CALLEE);
       
  2293                 method.swap();
       
  2294                 method.loadCompilerConstant(THIS);
       
  2295                 method.swap();
       
  2296                 method.loadCompilerConstant(SCOPE);
       
  2297                 method.swap();
       
  2298                 method.invokestatic(className, name, signature);
       
  2299 
       
  2300                 unit = lc.popCompileUnit(unit);
       
  2301             }
       
  2302 
       
  2303             return method;
       
  2304         }
  2264         }
  2305 
  2265 
  2306         if(postsets.length > 0) {
  2266         if(postsets.length > 0) {
  2307             final int arraySlot = method.getUsedSlotsWithLiveTemporaries();
  2267             final int arraySlot = method.getUsedSlotsWithLiveTemporaries();
  2308             method.storeTemp(arrayType, arraySlot);
  2268             method.storeTemp(arrayType, arraySlot);
  2310                 method.load(arrayType, arraySlot);
  2270                 method.load(arrayType, arraySlot);
  2311                 storeElement(nodes, elementType, postset);
  2271                 storeElement(nodes, elementType, postset);
  2312             }
  2272             }
  2313             method.load(arrayType, arraySlot);
  2273             method.load(arrayType, arraySlot);
  2314         }
  2274         }
  2315         return method;
       
  2316     }
  2275     }
  2317 
  2276 
  2318     private void storeElement(final Expression[] nodes, final Type elementType, final int index) {
  2277     private void storeElement(final Expression[] nodes, final Type elementType, final int index) {
  2319         method.load(index);
  2278         method.load(index);
  2320 
  2279 
  2535         final List<PropertyNode> elements = objectNode.getElements();
  2494         final List<PropertyNode> elements = objectNode.getElements();
  2536 
  2495 
  2537         final List<MapTuple<Expression>> tuples = new ArrayList<>();
  2496         final List<MapTuple<Expression>> tuples = new ArrayList<>();
  2538         final List<PropertyNode> gettersSetters = new ArrayList<>();
  2497         final List<PropertyNode> gettersSetters = new ArrayList<>();
  2539         final int ccp = getCurrentContinuationEntryPoint();
  2498         final int ccp = getCurrentContinuationEntryPoint();
       
  2499         final List<Splittable.SplitRange> ranges = objectNode.getSplitRanges();
  2540 
  2500 
  2541         Expression protoNode = null;
  2501         Expression protoNode = null;
  2542         boolean restOfProperty = false;
  2502         boolean restOfProperty = false;
  2543 
  2503 
  2544         for (final PropertyNode propertyNode : elements) {
  2504         for (final PropertyNode propertyNode : elements) {
  2581                 @Override
  2541                 @Override
  2582                 protected void loadValue(final Expression node, final Type type) {
  2542                 protected void loadValue(final Expression node, final Type type) {
  2583                     loadExpressionAsType(node, type);
  2543                     loadExpressionAsType(node, type);
  2584                 }};
  2544                 }};
  2585         }
  2545         }
  2586         oc.makeObject(method);
  2546 
       
  2547         if (ranges != null) {
       
  2548             oc.createObject(method);
       
  2549             loadSplitLiteral(oc, ranges, Type.typeFor(oc.getAllocatorClass()));
       
  2550         } else {
       
  2551             oc.makeObject(method);
       
  2552         }
  2587 
  2553 
  2588         //if this is a rest of method and our continuation point was found as one of the values
  2554         //if this is a rest of method and our continuation point was found as one of the values
  2589         //in the properties above, we need to reset the map to oc.getMap() in the continuation
  2555         //in the properties above, we need to reset the map to oc.getMap() in the continuation
  2590         //handler
  2556         //handler
  2591         if (restOfProperty) {
  2557         if (restOfProperty) {
  2895     }
  2861     }
  2896 
  2862 
  2897     private void defineSplitMethodParameter(final int slot, final Type type) {
  2863     private void defineSplitMethodParameter(final int slot, final Type type) {
  2898         method.defineBlockLocalVariable(slot, slot + type.getSlots());
  2864         method.defineBlockLocalVariable(slot, slot + type.getSlots());
  2899         method.onLocalStore(type, slot);
  2865         method.onLocalStore(type, slot);
       
  2866     }
       
  2867 
       
  2868     private void loadSplitLiteral(final SplitLiteralCreator creator, final List<Splittable.SplitRange> ranges, final Type literalType) {
       
  2869         assert ranges != null;
       
  2870 
       
  2871         // final Type literalType = Type.typeFor(literalClass);
       
  2872         final MethodEmitter savedMethod     = method;
       
  2873         final FunctionNode  currentFunction = lc.getCurrentFunction();
       
  2874 
       
  2875         for (final Splittable.SplitRange splitRange : ranges) {
       
  2876             unit = lc.pushCompileUnit(splitRange.getCompileUnit());
       
  2877 
       
  2878             assert unit != null;
       
  2879             final String className = unit.getUnitClassName();
       
  2880             final String name      = currentFunction.uniqueName(SPLIT_PREFIX.symbolName());
       
  2881             final Class<?> clazz   = literalType.getTypeClass();
       
  2882             final String signature = methodDescriptor(clazz, ScriptFunction.class, Object.class, ScriptObject.class, clazz);
       
  2883 
       
  2884             pushMethodEmitter(unit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature));
       
  2885 
       
  2886             method.setFunctionNode(currentFunction);
       
  2887             method.begin();
       
  2888 
       
  2889             defineCommonSplitMethodParameters();
       
  2890             defineSplitMethodParameter(CompilerConstants.SPLIT_ARRAY_ARG.slot(), literalType);
       
  2891 
       
  2892             // NOTE: when this is no longer needed, SplitIntoFunctions will no longer have to add IS_SPLIT
       
  2893             // to synthetic functions, and FunctionNode.needsCallee() will no longer need to test for isSplit().
       
  2894             final int literalSlot = fixScopeSlot(currentFunction, 3);
       
  2895 
       
  2896             lc.enterSplitNode();
       
  2897 
       
  2898             creator.populateRange(method, literalType, literalSlot, splitRange.getLow(), splitRange.getHigh());
       
  2899 
       
  2900             method._return();
       
  2901             lc.exitSplitNode();
       
  2902             method.end();
       
  2903             lc.releaseSlots();
       
  2904             popMethodEmitter();
       
  2905 
       
  2906             assert method == savedMethod;
       
  2907             method.loadCompilerConstant(CALLEE).swap();
       
  2908             method.loadCompilerConstant(THIS).swap();
       
  2909             method.loadCompilerConstant(SCOPE).swap();
       
  2910             method.invokestatic(className, name, signature);
       
  2911 
       
  2912             unit = lc.popCompileUnit(unit);
       
  2913         }
  2900     }
  2914     }
  2901 
  2915 
  2902     private int fixScopeSlot(final FunctionNode functionNode, final int extraSlot) {
  2916     private int fixScopeSlot(final FunctionNode functionNode, final int extraSlot) {
  2903         // TODO hack to move the scope to the expected slot (needed because split methods reuse the same slots as the root method)
  2917         // TODO hack to move the scope to the expected slot (needed because split methods reuse the same slots as the root method)
  2904         final int actualScopeSlot = functionNode.compilerConstant(SCOPE).getSlot(SCOPE_TYPE);
  2918         final int actualScopeSlot = functionNode.compilerConstant(SCOPE).getSlot(SCOPE_TYPE);
  5459             method._catch(catchLabel);
  5473             method._catch(catchLabel);
  5460             popScopes(scopePopCount);
  5474             popScopes(scopePopCount);
  5461             method.uncheckedGoto(targetCatchLabel);
  5475             method.uncheckedGoto(targetCatchLabel);
  5462         }
  5476         }
  5463     }
  5477     }
       
  5478 
       
  5479     /**
       
  5480      * Interface implemented by object creators that support splitting over multiple methods.
       
  5481      */
       
  5482     interface SplitLiteralCreator {
       
  5483         /**
       
  5484          * Generate code to populate a range of the literal object. A reference to the object
       
  5485          * should be left on the stack when the method terminates.
       
  5486          *
       
  5487          * @param method the method emitter
       
  5488          * @param type the type of the literal object
       
  5489          * @param slot the local slot containing the literal object
       
  5490          * @param start the start index (inclusive)
       
  5491          * @param end the end index (exclusive)
       
  5492          */
       
  5493         void populateRange(MethodEmitter method, Type type, int slot, int start, int end);
       
  5494     }
  5464 }
  5495 }