8013325: function named 'arguments' should set DEFINES_ARGUMENTS flag in its parent, not itself
authorattila
Fri, 26 Apr 2013 09:20:37 +0200
changeset 17249 a2014831ae7a
parent 17248 60ef2a001ec2
child 17250 e102b63819ad
8013325: function named 'arguments' should set DEFINES_ARGUMENTS flag in its parent, not itself Reviewed-by: hannesw, sundar
nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java
nashorn/src/jdk/nashorn/internal/codegen/Attr.java
nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java
nashorn/src/jdk/nashorn/internal/objects/NativeString.java
nashorn/src/jdk/nashorn/internal/parser/Parser.java
nashorn/test/script/basic/JDK-8013325.js
nashorn/test/script/basic/JDK-8013325.js.EXPECTED
--- a/nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java	Fri Apr 26 12:17:11 2013 +0530
+++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java	Fri Apr 26 09:20:37 2013 +0200
@@ -84,10 +84,10 @@
 package jdk.internal.dynalink.beans;
 
 import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import java.util.HashMap;
 import java.util.Map;
-import jdk.nashorn.internal.lookup.Lookup;
 
 class StaticClassIntrospector extends FacetIntrospector {
     StaticClassIntrospector(Class<?> clazz) {
@@ -98,7 +98,7 @@
     Map<String, MethodHandle> getInnerClassGetters() {
         final Map<String, MethodHandle> map = new HashMap<>();
         for(Class<?> innerClass: membersLookup.getInnerClasses()) {
-            map.put(innerClass.getSimpleName(), editMethodHandle(Lookup.MH.constant(StaticClass.class,
+            map.put(innerClass.getSimpleName(), editMethodHandle(MethodHandles.constant(StaticClass.class,
                     StaticClass.forClass(innerClass))));
         }
         return map;
@@ -110,7 +110,7 @@
     }
 
     static MethodHandle dropReceiver(final MethodHandle mh, final Class<?> receiverClass) {
-        MethodHandle newHandle = Lookup.MH.dropArguments(mh, 0, receiverClass);
+        MethodHandle newHandle = MethodHandles.dropArguments(mh, 0, receiverClass);
         // NOTE: this is a workaround for the fact that dropArguments doesn't preserve vararg collector state.
         if(mh.isVarargsCollector() && !newHandle.isVarargsCollector()) {
             final MethodType type = mh.type();
--- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java	Fri Apr 26 12:17:11 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java	Fri Apr 26 09:20:37 2013 +0200
@@ -48,10 +48,8 @@
 import java.util.ArrayList;
 import java.util.Deque;
 import java.util.HashSet;
-import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.AccessNode;
@@ -91,6 +89,7 @@
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.Property;
 import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
 
 /**
@@ -126,8 +125,6 @@
 
     private final Deque<Type> returnTypes;
 
-    private final Map<Symbol, FunctionNode> selfSymbolToFunction = new IdentityHashMap<>();
-
     private static final DebugLogger LOG   = new DebugLogger("attr");
     private static final boolean     DEBUG = LOG.isEnabled();
 
@@ -173,23 +170,26 @@
 
         if (functionNode.isProgram()) {
             initFromPropertyMap(body);
-        }
+        } else if(!functionNode.isDeclared()) {
+            // It's neither declared nor program - it's a function expression then; assign it a self-symbol.
 
-        // Add function name as local symbol
-        if (!functionNode.isDeclared() && !functionNode.isProgram()) {
             if (functionNode.getSymbol() != null) {
                 // a temporary left over from an earlier pass when the function was lazy
                 assert functionNode.getSymbol().isTemp();
                 // remove it
                 functionNode.setSymbol(null);
             }
-            final Symbol selfSymbol;
-            if (functionNode.isAnonymous()) {
-                selfSymbol = ensureSymbol(functionNode, Type.OBJECT, functionNode);
+            final boolean anonymous = functionNode.isAnonymous();
+            final String name = anonymous ? null : functionNode.getIdent().getName();
+            if (anonymous || body.getExistingSymbol(name) != null) {
+                // The function is either anonymous, or another local identifier already trumps its name on entry:
+                // either it has the same name as one of its parameters, or is named "arguments" and also references the
+                // "arguments" identifier in its body.
+                ensureSymbol(functionNode, Type.typeFor(ScriptFunction.class), functionNode);
             } else {
-                selfSymbol = defineSymbol(body, functionNode.getIdent().getName(), IS_VAR | IS_FUNCTION_SELF, functionNode);
+                final Symbol selfSymbol = defineSymbol(body, name, IS_VAR | IS_FUNCTION_SELF, functionNode);
+                assert selfSymbol.isFunctionSelf();
                 newType(selfSymbol, Type.OBJECT);
-                selfSymbolToFunction.put(selfSymbol, functionNode);
             }
         }
 
--- a/nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java	Fri Apr 26 12:17:11 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java	Fri Apr 26 09:20:37 2013 +0200
@@ -27,7 +27,6 @@
 import java.io.File;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
-
 import jdk.nashorn.internal.codegen.Label;
 import jdk.nashorn.internal.runtime.Debug;
 import jdk.nashorn.internal.runtime.Source;
@@ -171,6 +170,7 @@
     public <T extends LexicalContextNode> T pop(final T node) {
         --sp;
         final LexicalContextNode popped = stack[sp];
+        stack[sp] = null;
         if (popped instanceof Flags) {
             return (T)((Flags<?>)popped).setFlag(this, flags[sp]);
         }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java	Fri Apr 26 12:17:11 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java	Fri Apr 26 09:20:37 2013 +0200
@@ -25,11 +25,11 @@
 
 package jdk.nashorn.internal.objects;
 
+import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndexNoThrow;
-import static jdk.nashorn.internal.lookup.Lookup.MH;
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -41,6 +41,7 @@
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.nashorn.internal.lookup.MethodHandleFactory;
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Constructor;
 import jdk.nashorn.internal.objects.annotations.Function;
@@ -55,7 +56,6 @@
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
-import jdk.nashorn.internal.lookup.MethodHandleFactory;
 import jdk.nashorn.internal.runtime.linker.NashornGuards;
 import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
 
@@ -841,7 +841,7 @@
         final long lim = (limit == UNDEFINED) ? JSType.MAX_UINT : JSType.toUint32(limit);
 
         if (separator == UNDEFINED) {
-            return limit == 0 ? new NativeArray() : new NativeArray(new Object[]{str});
+            return lim == 0 ? new NativeArray() : new NativeArray(new Object[]{str});
         }
 
         if (separator instanceof NativeRegExp) {
--- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java	Fri Apr 26 12:17:11 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java	Fri Apr 26 09:20:37 2013 +0200
@@ -2339,7 +2339,7 @@
                 functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED);
             }
             if (ARGUMENTS.symbolName().equals(name.getName())) {
-                functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
+                lc.setFlag(lc.getCurrentFunction(), FunctionNode.DEFINES_ARGUMENTS);
             }
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8013325.js	Fri Apr 26 09:20:37 2013 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010, 2013, 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-8013325: function named 'arguments' should still access arguments object within itself.
+ * Its parent should however see the function and not an arguments object.
+ *
+ * @test
+ * @run
+ */
+
+function x() {
+  // x doesn't see an arguments object as it has a nested function with that name
+  // so it'll invoke the function.
+  arguments("a", "b", "c");
+  
+  function arguments(x, y, z) {
+      // The function 'arguments' OTOH can't see itself; if it uses the 
+      // identifier 'arguments', it'll see its own arguments object.
+      print(arguments)
+      print(x + " " + y + " " + z)
+  }
+}
+x()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8013325.js.EXPECTED	Fri Apr 26 09:20:37 2013 +0200
@@ -0,0 +1,2 @@
+[object Arguments]
+a b c