< prev index next >

src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java

Print this page

        

@@ -255,10 +255,13 @@
     private final IntDeque labeledBlockBreakLiveLocals = new IntDeque();
 
     //is this a rest of compilation
     private final int[] continuationEntryPoints;
 
+    // Scope object creators needed for for-of and for-in loops
+    private Deque<FieldObjectCreator<?>> scopeObjectCreators = new ArrayDeque<>();
+
     /**
      * Constructor.
      *
      * @param compiler
      */

@@ -1276,10 +1279,18 @@
 
     boolean useOptimisticTypes() {
         return !lc.inSplitNode() && compiler.useOptimisticTypes();
     }
 
+    // Determine whether a block needs to provide its scope object creator for use by its child nodes.
+    // This is only necessary for synthetic parent blocks of for-in loops with lexical declarations.
+    boolean providesScopeCreator(final Block block) {
+        return block.needsScope() &&  compiler.getScriptEnvironment()._es6
+                && block.isSynthetic() && (block.getLastStatement() instanceof ForNode)
+                && ((ForNode) block.getLastStatement()).needsScopeCreator();
+    }
+
     @Override
     public Node leaveBlock(final Block block) {
         popBlockScope(block);
         method.beforeJoinPoint(block);
 

@@ -1295,10 +1306,13 @@
     }
 
     private void popBlockScope(final Block block) {
         final Label breakLabel = block.getBreakLabel();
 
+        if (providesScopeCreator(block)) {
+            scopeObjectCreators.pop();
+        }
         if(!block.needsScope() || lc.isFunctionBody()) {
             emitBlockBreakLabel(breakLabel);
             return;
         }
 

@@ -1810,10 +1824,18 @@
                 }.emit();
             }
         }.store();
         body.accept(this);
 
+        if (forNode.needsScopeCreator() && providesScopeCreator(lc.getCurrentBlock())) {
+            // for-in loops with lexical declaration need a new scope for each iteration.
+            final FieldObjectCreator<?> creator = scopeObjectCreators.peek();
+            assert creator != null;
+            creator.createForInIterationScope(method);
+            method.storeCompilerConstant(SCOPE);
+        }
+
         if(method.isReachable()) {
             method._goto(continueLabel);
         }
         method.label(breakLabel);
     }

@@ -1921,16 +1943,20 @@
 
             /*
              * Create a new object based on the symbols and values, generate
              * bootstrap code for object
              */
-            new FieldObjectCreator<Symbol>(this, tuples, true, hasArguments) {
+            final FieldObjectCreator<Symbol> creator = new FieldObjectCreator<Symbol>(this, tuples, true, hasArguments) {
                 @Override
                 protected void loadValue(final Symbol value, final Type type) {
                     method.load(value, type);
                 }
-            }.makeObject(method);
+            };
+            creator.makeObject(method);
+            if (providesScopeCreator(block)) {
+                scopeObjectCreators.push(creator);
+            }
             // program function: merge scope into global
             if (isFunctionBody && function.isProgram()) {
                 method.invoke(ScriptRuntime.MERGE_SCOPE);
             }
 

@@ -4478,11 +4504,11 @@
                 @Override
                 public boolean enterIdentNode(final IdentNode node) {
                     final Symbol symbol = node.getSymbol();
                     assert symbol != null;
                     if (symbol.isScope()) {
-                        final int flags = getScopeCallSiteFlags(symbol);
+                        final int flags = getScopeCallSiteFlags(symbol) | (node.isDeclaredHere() ? CALLSITE_DECLARE : 0);
                         if (isFastScope(symbol)) {
                             storeFastScopeVar(symbol, flags);
                         } else {
                             method.dynamicSet(node.getName(), flags, false);
                         }
< prev index next >