8021350: Share script classes between threads/globals within context

Wed, 12 Mar 2014 11:26:00 +0100

author
hannesw
date
Wed, 12 Mar 2014 11:26:00 +0100
changeset 769
5a1ae83c295f
parent 768
27d6e99ae970
child 770
64a0ac7d08e7

8021350: Share script classes between threads/globals within context
Reviewed-by: lagergren, sundar

make/build.xml file | annotate | diff | comparison | revisions
make/project.properties file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Attr.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CodeGenerator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/SharedScopeCall.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/FunctionNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/Global.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeBoolean.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeJSAdapter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeNumber.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeString.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/parser/Parser.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/AccessorProperty.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Context.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/GlobalObject.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Property.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptFunction.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptFunctionData.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptObject.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/SetMethodCreator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/WithObject.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/NashornGuards.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java file | annotate | diff | comparison | revisions
test/src/jdk/nashorn/api/scripting/ScopeTest.java file | annotate | diff | comparison | revisions
test/src/jdk/nashorn/api/scripting/resources/func.js file | annotate | diff | comparison | revisions
test/src/jdk/nashorn/api/scripting/resources/gettersetter.js file | annotate | diff | comparison | revisions
test/src/jdk/nashorn/api/scripting/resources/witheval.js file | annotate | diff | comparison | revisions
     1.1 --- a/make/build.xml	Wed Mar 12 16:33:28 2014 +0100
     1.2 +++ b/make/build.xml	Wed Mar 12 11:26:00 2014 +0100
     1.3 @@ -250,6 +250,10 @@
     1.4         <fileset dir="${test.src.dir}/jdk/nashorn/internal/runtime/resources"/>
     1.5      </copy>
     1.6  
     1.7 +    <copy todir="${build.test.classes.dir}/jdk/nashorn/api/scripting/resources">
     1.8 +       <fileset dir="${test.src.dir}/jdk/nashorn/api/scripting/resources"/>
     1.9 +    </copy>
    1.10 +
    1.11      <!-- tests that check nashorn internals and internal API -->
    1.12      <jar jarfile="${nashorn.internal.tests.jar}">
    1.13        <fileset dir="${build.test.classes.dir}" excludes="**/api/**"/>
     2.1 --- a/make/project.properties	Wed Mar 12 16:33:28 2014 +0100
     2.2 +++ b/make/project.properties	Wed Mar 12 11:26:00 2014 +0100
     2.3 @@ -202,7 +202,7 @@
     2.4  
     2.5  # test262 test frameworks
     2.6  test262-test-sys-prop.test.js.framework=\
     2.7 -    --class-cache-size=0 \
     2.8 +    --class-cache-size=10 \
     2.9      --no-java \
    2.10      --no-typed-arrays \
    2.11      -timezone=PST \
     3.1 --- a/src/jdk/nashorn/internal/codegen/Attr.java	Wed Mar 12 16:33:28 2014 +0100
     3.2 +++ b/src/jdk/nashorn/internal/codegen/Attr.java	Wed Mar 12 11:26:00 2014 +0100
     3.3 @@ -375,10 +375,11 @@
     3.4       * @return Symbol for given name or null for redefinition.
     3.5       */
     3.6      private Symbol defineSymbol(final Block block, final String name, final int symbolFlags) {
     3.7 -        int    flags  = symbolFlags;
     3.8 -        Symbol symbol = findSymbol(block, name); // Locate symbol.
     3.9 +        int     flags    = symbolFlags;
    3.10 +        Symbol  symbol   = findSymbol(block, name); // Locate symbol.
    3.11 +        boolean isGlobal = (flags & KINDMASK) == IS_GLOBAL;
    3.12  
    3.13 -        if ((flags & KINDMASK) == IS_GLOBAL) {
    3.14 +        if (isGlobal) {
    3.15              flags |= IS_SCOPE;
    3.16          }
    3.17  
    3.18 @@ -414,6 +415,8 @@
    3.19              // Determine where to create it.
    3.20              if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) {
    3.21                  symbolBlock = block; //internal vars are always defined in the block closest to them
    3.22 +            } else if (isGlobal) {
    3.23 +                symbolBlock = lc.getOutermostFunction().getBody();
    3.24              } else {
    3.25                  symbolBlock = lc.getFunctionBody(function);
    3.26              }
     4.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Mar 12 16:33:28 2014 +0100
     4.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Mar 12 11:26:00 2014 +0100
     4.3 @@ -685,7 +685,7 @@
     4.4              private void scopeCall(final IdentNode node, final int flags) {
     4.5                  load(node, Type.OBJECT); // Type.OBJECT as foo() makes no sense if foo == 3
     4.6                  // ScriptFunction will see CALLSITE_SCOPE and will bind scope accordingly.
     4.7 -                method.loadNull(); //the 'this'
     4.8 +                method.loadUndefined(Type.OBJECT); //the 'this' object
     4.9                  method.dynamicCall(callNodeType, 2 + loadArgs(args), flags);
    4.10              }
    4.11  
    4.12 @@ -818,7 +818,7 @@
    4.13              protected boolean enterDefault(final Node node) {
    4.14                  // Load up function.
    4.15                  load(function, Type.OBJECT); //TODO, e.g. booleans can be used as functions
    4.16 -                method.loadNull(); // ScriptFunction will figure out the correct this when it sees CALLSITE_SCOPE
    4.17 +                method.loadUndefined(Type.OBJECT); // ScriptFunction will figure out the correct this when it sees CALLSITE_SCOPE
    4.18                  method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags() | CALLSITE_SCOPE);
    4.19  
    4.20                  return false;
     5.1 --- a/src/jdk/nashorn/internal/codegen/SharedScopeCall.java	Wed Mar 12 16:33:28 2014 +0100
     5.2 +++ b/src/jdk/nashorn/internal/codegen/SharedScopeCall.java	Wed Mar 12 11:26:00 2014 +0100
     5.3 @@ -156,7 +156,7 @@
     5.4          if (isCall) {
     5.5              method.convert(Type.OBJECT);
     5.6              // ScriptFunction will see CALLSITE_SCOPE and will bind scope accordingly.
     5.7 -            method.loadNull();
     5.8 +            method.loadUndefined(Type.OBJECT);
     5.9              int slot = 2;
    5.10              for (final Type type : paramTypes) {
    5.11                  method.load(type, slot++);
     6.1 --- a/src/jdk/nashorn/internal/ir/FunctionNode.java	Wed Mar 12 16:33:28 2014 +0100
     6.2 +++ b/src/jdk/nashorn/internal/ir/FunctionNode.java	Wed Mar 12 11:26:00 2014 +0100
     6.3 @@ -164,11 +164,11 @@
     6.4      public static final int HAS_EVAL                    = 1 << 5;
     6.5  
     6.6      /** Does a nested function contain eval? If it does, then all variables in this function might be get/set by it. */
     6.7 -    public static final int HAS_NESTED_EVAL = 1 << 6;
     6.8 +    public static final int HAS_NESTED_EVAL             = 1 << 6;
     6.9  
    6.10      /** Does this function have any blocks that create a scope? This is used to determine if the function needs to
    6.11       * have a local variable slot for the scope symbol. */
    6.12 -    public static final int HAS_SCOPE_BLOCK = 1 << 7;
    6.13 +    public static final int HAS_SCOPE_BLOCK             = 1 << 7;
    6.14  
    6.15      /**
    6.16       * Flag this function as one that defines the identifier "arguments" as a function parameter or nested function
    6.17 @@ -197,6 +197,9 @@
    6.18      /** Can this function be specialized? */
    6.19      public static final int CAN_SPECIALIZE              = 1 << 14;
    6.20  
    6.21 +    /** Does this function use the "this" keyword? */
    6.22 +    public static final int USES_THIS                   = 1 << 15;
    6.23 +
    6.24      /** Does this function or any nested functions contain an eval? */
    6.25      private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL;
    6.26  
    6.27 @@ -591,6 +594,15 @@
    6.28      }
    6.29  
    6.30      /**
    6.31 +     * Return {@code true} if this function makes use of the {@code this} object.
    6.32 +     *
    6.33 +     * @return true if function uses {@code this} object
    6.34 +     */
    6.35 +    public boolean usesThis() {
    6.36 +        return getFlag(USES_THIS);
    6.37 +    }
    6.38 +
    6.39 +    /**
    6.40       * Get the identifier for this function, this is its symbol.
    6.41       * @return the identifier as an IdentityNode
    6.42       */
     7.1 --- a/src/jdk/nashorn/internal/objects/Global.java	Wed Mar 12 16:33:28 2014 +0100
     7.2 +++ b/src/jdk/nashorn/internal/objects/Global.java	Wed Mar 12 11:26:00 2014 +0100
     7.3 @@ -33,11 +33,8 @@
     7.4  import java.io.PrintWriter;
     7.5  import java.lang.invoke.MethodHandle;
     7.6  import java.lang.invoke.MethodHandles;
     7.7 -import java.lang.ref.ReferenceQueue;
     7.8 -import java.lang.ref.SoftReference;
     7.9  import java.lang.reflect.Field;
    7.10  import java.util.Arrays;
    7.11 -import java.util.LinkedHashMap;
    7.12  import java.util.List;
    7.13  import java.util.Map;
    7.14  import java.util.concurrent.Callable;
    7.15 @@ -59,10 +56,10 @@
    7.16  import jdk.nashorn.internal.runtime.Scope;
    7.17  import jdk.nashorn.internal.runtime.ScriptEnvironment;
    7.18  import jdk.nashorn.internal.runtime.ScriptFunction;
    7.19 +import jdk.nashorn.internal.runtime.ScriptFunctionData;
    7.20  import jdk.nashorn.internal.runtime.ScriptObject;
    7.21  import jdk.nashorn.internal.runtime.ScriptRuntime;
    7.22  import jdk.nashorn.internal.runtime.ScriptingFunctions;
    7.23 -import jdk.nashorn.internal.runtime.Source;
    7.24  import jdk.nashorn.internal.runtime.arrays.ArrayData;
    7.25  import jdk.nashorn.internal.runtime.linker.Bootstrap;
    7.26  import jdk.nashorn.internal.runtime.linker.InvokeByName;
    7.27 @@ -373,9 +370,6 @@
    7.28      // Flag to indicate that a split method issued a return statement
    7.29      private int splitState = -1;
    7.30  
    7.31 -    // class cache
    7.32 -    private ClassCache classCache;
    7.33 -
    7.34      // Used to store the last RegExp result to support deprecated RegExp constructor properties
    7.35      private RegExpResult lastRegExpResult;
    7.36  
    7.37 @@ -426,11 +420,6 @@
    7.38          super(checkAndGetMap(context));
    7.39          this.context = context;
    7.40          this.setIsScope();
    7.41 -
    7.42 -        final int cacheSize = context.getEnv()._class_cache_size;
    7.43 -        if (cacheSize > 0) {
    7.44 -            classCache = new ClassCache(cacheSize);
    7.45 -        }
    7.46      }
    7.47  
    7.48      /**
    7.49 @@ -488,7 +477,7 @@
    7.50  
    7.51      @Override
    7.52      public ScriptFunction newScriptFunction(final String name, final MethodHandle handle, final ScriptObject scope, final boolean strict) {
    7.53 -        return new ScriptFunctionImpl(name, handle, scope, null, strict, false, true);
    7.54 +        return new ScriptFunctionImpl(name, handle, scope, null, strict ? ScriptFunctionData.IS_STRICT_CONSTRUCTOR : ScriptFunctionData.IS_CONSTRUCTOR);
    7.55      }
    7.56  
    7.57      @Override
    7.58 @@ -664,62 +653,6 @@
    7.59      }
    7.60  
    7.61  
    7.62 -    /**
    7.63 -     * Cache for compiled script classes.
    7.64 -     */
    7.65 -    @SuppressWarnings("serial")
    7.66 -    private static class ClassCache extends LinkedHashMap<Source, ClassReference> {
    7.67 -        private final int size;
    7.68 -        private final ReferenceQueue<Class<?>> queue;
    7.69 -
    7.70 -        ClassCache(int size) {
    7.71 -            super(size, 0.75f, true);
    7.72 -            this.size = size;
    7.73 -            this.queue = new ReferenceQueue<>();
    7.74 -        }
    7.75 -
    7.76 -        void cache(final Source source, final Class<?> clazz) {
    7.77 -            put(source, new ClassReference(clazz, queue, source));
    7.78 -        }
    7.79 -
    7.80 -        @Override
    7.81 -        protected boolean removeEldestEntry(final Map.Entry<Source, ClassReference> eldest) {
    7.82 -            return size() > size;
    7.83 -        }
    7.84 -
    7.85 -        @Override
    7.86 -        public ClassReference get(Object key) {
    7.87 -            for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) {
    7.88 -                remove(ref.source);
    7.89 -            }
    7.90 -            return super.get(key);
    7.91 -        }
    7.92 -
    7.93 -    }
    7.94 -
    7.95 -    private static class ClassReference extends SoftReference<Class<?>> {
    7.96 -        private final Source source;
    7.97 -
    7.98 -        ClassReference(final Class<?> clazz, final ReferenceQueue<Class<?>> queue, final Source source) {
    7.99 -            super(clazz, queue);
   7.100 -            this.source = source;
   7.101 -        }
   7.102 -    }
   7.103 -
   7.104 -    // Class cache management
   7.105 -    @Override
   7.106 -    public Class<?> findCachedClass(final Source source) {
   7.107 -        assert classCache != null : "Class cache used without being initialized";
   7.108 -        ClassReference ref = classCache.get(source);
   7.109 -        return ref != null ? ref.get() : null;
   7.110 -    }
   7.111 -
   7.112 -    @Override
   7.113 -    public void cacheClass(final Source source, final Class<?> clazz) {
   7.114 -        assert classCache != null : "Class cache used without being initialized";
   7.115 -        classCache.cache(source, clazz);
   7.116 -    }
   7.117 -
   7.118      private static <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) {
   7.119          final T obj = map.get(key);
   7.120          if (obj != null) {
   7.121 @@ -1838,7 +1771,7 @@
   7.122          anon.deleteOwnProperty(anon.getMap().findProperty("prototype"));
   7.123  
   7.124          // use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3
   7.125 -        this.typeErrorThrower = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER, null, null, false, false, false);
   7.126 +        this.typeErrorThrower = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER, null, null, 0);
   7.127          typeErrorThrower.setPrototype(UNDEFINED);
   7.128          // Non-constructor built-in functions do not have "prototype" property
   7.129          typeErrorThrower.deleteOwnProperty(typeErrorThrower.getMap().findProperty("prototype"));
     8.1 --- a/src/jdk/nashorn/internal/objects/NativeBoolean.java	Wed Mar 12 16:33:28 2014 +0100
     8.2 +++ b/src/jdk/nashorn/internal/objects/NativeBoolean.java	Wed Mar 12 11:26:00 2014 +0100
     8.3 @@ -30,6 +30,7 @@
     8.4  
     8.5  import java.lang.invoke.MethodHandle;
     8.6  import java.lang.invoke.MethodHandles;
     8.7 +import java.lang.invoke.MethodType;
     8.8  import jdk.internal.dynalink.linker.GuardedInvocation;
     8.9  import jdk.internal.dynalink.linker.LinkRequest;
    8.10  import jdk.nashorn.internal.objects.annotations.Attribute;
    8.11 @@ -50,7 +51,10 @@
    8.12  public final class NativeBoolean extends ScriptObject {
    8.13      private final boolean value;
    8.14  
    8.15 -    final static MethodHandle WRAPFILTER = findWrapFilter();
    8.16 +    // Method handle to create an object wrapper for a primitive boolean
    8.17 +    private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeBoolean.class, Object.class));
    8.18 +    // Method handle to retrieve the Boolean prototype object
    8.19 +    private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
    8.20  
    8.21      // initialized by nasgen
    8.22      private static PropertyMap $nasgenmap$;
    8.23 @@ -164,7 +168,7 @@
    8.24       * @return Link to be invoked at call site.
    8.25       */
    8.26      public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
    8.27 -        return PrimitiveLookup.lookupPrimitive(request, Boolean.class, new NativeBoolean((Boolean)receiver), WRAPFILTER);
    8.28 +        return PrimitiveLookup.lookupPrimitive(request, Boolean.class, new NativeBoolean((Boolean)receiver), WRAPFILTER, PROTOFILTER);
    8.29      }
    8.30  
    8.31      /**
    8.32 @@ -178,7 +182,12 @@
    8.33          return new NativeBoolean((Boolean)receiver);
    8.34      }
    8.35  
    8.36 -    private static MethodHandle findWrapFilter() {
    8.37 -        return MH.findStatic(MethodHandles.lookup(), NativeBoolean.class, "wrapFilter", MH.type(NativeBoolean.class, Object.class));
    8.38 +    @SuppressWarnings("unused")
    8.39 +    private static Object protoFilter(final Object object) {
    8.40 +        return Global.instance().getBooleanPrototype();
    8.41 +    }
    8.42 +
    8.43 +    private static MethodHandle findOwnMH(final String name, final MethodType type) {
    8.44 +        return MH.findStatic(MethodHandles.lookup(), NativeBoolean.class, name, type);
    8.45      }
    8.46  }
     9.1 --- a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Wed Mar 12 16:33:28 2014 +0100
     9.2 +++ b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Wed Mar 12 11:26:00 2014 +0100
     9.3 @@ -622,7 +622,7 @@
     9.4          case "getMethod":
     9.5              final FindProperty find = adaptee.findProperty(__call__, true);
     9.6              if (find != null) {
     9.7 -                final Object value = getObjectValue(find);
     9.8 +                final Object value = find.getObjectValue();
     9.9                  if (value instanceof ScriptFunction) {
    9.10                      final ScriptFunctionImpl func = (ScriptFunctionImpl)value;
    9.11                      // TODO: It's a shame we need to produce a function bound to this and name, when we'd only need it bound
    9.12 @@ -691,7 +691,7 @@
    9.13          final MethodType type = desc.getMethodType();
    9.14          if (findData != null) {
    9.15              final String name = desc.getNameTokenCount() > 2 ? desc.getNameToken(2) : null;
    9.16 -            final Object value = getObjectValue(findData);
    9.17 +            final Object value = findData.getObjectValue();
    9.18              if (value instanceof ScriptFunction) {
    9.19                  final ScriptFunction func = (ScriptFunction)value;
    9.20  
    10.1 --- a/src/jdk/nashorn/internal/objects/NativeNumber.java	Wed Mar 12 16:33:28 2014 +0100
    10.2 +++ b/src/jdk/nashorn/internal/objects/NativeNumber.java	Wed Mar 12 11:26:00 2014 +0100
    10.3 @@ -34,6 +34,7 @@
    10.4  
    10.5  import java.lang.invoke.MethodHandle;
    10.6  import java.lang.invoke.MethodHandles;
    10.7 +import java.lang.invoke.MethodType;
    10.8  import java.text.NumberFormat;
    10.9  import java.util.Locale;
   10.10  import jdk.internal.dynalink.linker.GuardedInvocation;
   10.11 @@ -57,7 +58,10 @@
   10.12  @ScriptClass("Number")
   10.13  public final class NativeNumber extends ScriptObject {
   10.14  
   10.15 -    static final MethodHandle WRAPFILTER = findWrapFilter();
   10.16 +    // Method handle to create an object wrapper for a primitive number
   10.17 +    private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeNumber.class, Object.class));
   10.18 +    // Method handle to retrieve the Number prototype object
   10.19 +    private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
   10.20  
   10.21      /** ECMA 15.7.3.2 largest positive finite value */
   10.22      @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
   10.23 @@ -322,7 +326,7 @@
   10.24       * @return Link to be invoked at call site.
   10.25       */
   10.26      public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
   10.27 -        return PrimitiveLookup.lookupPrimitive(request, Number.class, new NativeNumber(((Number)receiver).doubleValue()), WRAPFILTER);
   10.28 +        return PrimitiveLookup.lookupPrimitive(request, Number.class, new NativeNumber(((Number)receiver).doubleValue()), WRAPFILTER, PROTOFILTER);
   10.29      }
   10.30  
   10.31      @SuppressWarnings("unused")
   10.32 @@ -330,6 +334,11 @@
   10.33          return new NativeNumber(((Number)receiver).doubleValue());
   10.34      }
   10.35  
   10.36 +    @SuppressWarnings("unused")
   10.37 +    private static Object protoFilter(final Object object) {
   10.38 +        return Global.instance().getNumberPrototype();
   10.39 +    }
   10.40 +
   10.41      private static double getNumberValue(final Object self) {
   10.42          if (self instanceof Number) {
   10.43              return ((Number)self).doubleValue();
   10.44 @@ -378,7 +387,7 @@
   10.45          return str;
   10.46      }
   10.47  
   10.48 -    private static MethodHandle findWrapFilter() {
   10.49 -        return MH.findStatic(MethodHandles.lookup(), NativeNumber.class, "wrapFilter", MH.type(NativeNumber.class, Object.class));
   10.50 +    private static MethodHandle findOwnMH(final String name, final MethodType type) {
   10.51 +        return MH.findStatic(MethodHandles.lookup(), NativeNumber.class, name, type);
   10.52      }
   10.53  }
    11.1 --- a/src/jdk/nashorn/internal/objects/NativeString.java	Wed Mar 12 16:33:28 2014 +0100
    11.2 +++ b/src/jdk/nashorn/internal/objects/NativeString.java	Wed Mar 12 11:26:00 2014 +0100
    11.3 @@ -32,6 +32,7 @@
    11.4  
    11.5  import java.lang.invoke.MethodHandle;
    11.6  import java.lang.invoke.MethodHandles;
    11.7 +import java.lang.invoke.MethodType;
    11.8  import java.text.Collator;
    11.9  import java.util.ArrayList;
   11.10  import java.util.Arrays;
   11.11 @@ -69,7 +70,10 @@
   11.12  
   11.13      private final CharSequence value;
   11.14  
   11.15 -    static final MethodHandle WRAPFILTER = findWrapFilter();
   11.16 +    // Method handle to create an object wrapper for a primitive string
   11.17 +    private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeString.class, Object.class));
   11.18 +    // Method handle to retrieve the String prototype object
   11.19 +    private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
   11.20  
   11.21      // initialized by nasgen
   11.22      private static PropertyMap $nasgenmap$;
   11.23 @@ -1199,7 +1203,7 @@
   11.24       */
   11.25      public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
   11.26          final MethodHandle guard = NashornGuards.getInstanceOf2Guard(String.class, ConsString.class);
   11.27 -        return PrimitiveLookup.lookupPrimitive(request, guard, new NativeString((CharSequence)receiver), WRAPFILTER);
   11.28 +        return PrimitiveLookup.lookupPrimitive(request, guard, new NativeString((CharSequence)receiver), WRAPFILTER, PROTOFILTER);
   11.29      }
   11.30  
   11.31      @SuppressWarnings("unused")
   11.32 @@ -1207,6 +1211,11 @@
   11.33          return new NativeString((CharSequence)receiver);
   11.34      }
   11.35  
   11.36 +    @SuppressWarnings("unused")
   11.37 +    private static Object protoFilter(final Object object) {
   11.38 +        return Global.instance().getStringPrototype();
   11.39 +    }
   11.40 +
   11.41      private static CharSequence getCharSequence(final Object self) {
   11.42          if (self instanceof String || self instanceof ConsString) {
   11.43              return (CharSequence)self;
   11.44 @@ -1254,7 +1263,7 @@
   11.45          return key >= 0 && key < value.length();
   11.46      }
   11.47  
   11.48 -    private static MethodHandle findWrapFilter() {
   11.49 -        return MH.findStatic(MethodHandles.lookup(), NativeString.class, "wrapFilter", MH.type(NativeString.class, Object.class));
   11.50 +    private static MethodHandle findOwnMH(final String name, final MethodType type) {
   11.51 +        return MH.findStatic(MethodHandles.lookup(), NativeString.class, name, type);
   11.52      }
   11.53  }
    12.1 --- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Wed Mar 12 16:33:28 2014 +0100
    12.2 +++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Wed Mar 12 11:26:00 2014 +0100
    12.3 @@ -75,7 +75,7 @@
    12.4      private static final Object LAZY_PROTOTYPE = new Object();
    12.5  
    12.6      private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final MethodHandle[] specs, final Global global) {
    12.7 -        super(name, invokeHandle, getInitialMap(), null, specs, false, true, true);
    12.8 +        super(name, invokeHandle, getInitialMap(), null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR);
    12.9          init(global);
   12.10      }
   12.11  
   12.12 @@ -92,7 +92,7 @@
   12.13      }
   12.14  
   12.15      private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final MethodHandle[] specs, final Global global) {
   12.16 -        super(name, invokeHandle, map.addAll(getInitialMap()), null, specs, false, true, true);
   12.17 +        super(name, invokeHandle, map.addAll(getInitialMap()), null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR);
   12.18          init(global);
   12.19      }
   12.20  
   12.21 @@ -109,8 +109,8 @@
   12.22          this(name, invokeHandle, map, specs, Global.instance());
   12.23      }
   12.24  
   12.25 -    private ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor, final Global global) {
   12.26 -        super(name, methodHandle, getMap(global, isStrict), scope, specs, isStrict, isBuiltin, isConstructor);
   12.27 +    private ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final int flags, final Global global) {
   12.28 +        super(name, methodHandle, getMap(global, isStrict(flags)), scope, specs, flags);
   12.29          init(global);
   12.30      }
   12.31  
   12.32 @@ -121,12 +121,10 @@
   12.33       * @param methodHandle handle for invocation
   12.34       * @param scope scope object
   12.35       * @param specs specialized versions of this method, if available, null otherwise
   12.36 -     * @param isStrict are we in strict mode
   12.37 -     * @param isBuiltin is this a built-in function
   12.38 -     * @param isConstructor can the function be used as a constructor (most can; some built-ins are restricted).
   12.39 +     * @param flags {@link ScriptFunctionData} flags
   12.40       */
   12.41 -    ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
   12.42 -        this(name, methodHandle, scope, specs, isStrict, isBuiltin, isConstructor, Global.instance());
   12.43 +    ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final int flags) {
   12.44 +        this(name, methodHandle, scope, specs, flags, Global.instance());
   12.45      }
   12.46  
   12.47      private ScriptFunctionImpl(final RecompilableScriptFunctionData data, final ScriptObject scope, final Global global) {
   12.48 @@ -173,6 +171,10 @@
   12.49          return newMap;
   12.50      }
   12.51  
   12.52 +    private static boolean isStrict(final int flags) {
   12.53 +        return (flags & ScriptFunctionData.IS_STRICT) != 0;
   12.54 +    }
   12.55 +
   12.56      // Choose the map based on strict mode!
   12.57      private static PropertyMap getMap(final Global global, final boolean strict) {
   12.58          return strict ? getInitialStrictMap() : getInitialMap();
   12.59 @@ -211,7 +213,7 @@
   12.60       * @return new ScriptFunction
   12.61       */
   12.62      static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs) {
   12.63 -        final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, false, true, false);
   12.64 +        final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, ScriptFunctionData.IS_BUILTIN);
   12.65          func.setPrototype(UNDEFINED);
   12.66          // Non-constructor built-in functions do not have "prototype" property
   12.67          func.deleteOwnProperty(func.getMap().findProperty("prototype"));
    13.1 --- a/src/jdk/nashorn/internal/parser/Parser.java	Wed Mar 12 16:33:28 2014 +0100
    13.2 +++ b/src/jdk/nashorn/internal/parser/Parser.java	Wed Mar 12 11:26:00 2014 +0100
    13.3 @@ -1799,6 +1799,7 @@
    13.4          case THIS:
    13.5              final String name = type.getName();
    13.6              next();
    13.7 +            lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_THIS);
    13.8              return new IdentNode(primaryToken, finish, name);
    13.9          case IDENT:
   13.10              final IdentNode ident = getIdent();
    14.1 --- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Wed Mar 12 16:33:28 2014 +0100
    14.2 +++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Wed Mar 12 11:26:00 2014 +0100
    14.3 @@ -141,10 +141,12 @@
    14.4      private Class<?> currentType;
    14.5  
    14.6      /**
    14.7 -     * Delegate constructor. This is used when adding properties to the Global scope, which
    14.8 -     * is necessary for outermost levels in a script (the ScriptObject is represented by
    14.9 -     * a JO-prefixed ScriptObject class, but the properties need to be in the Global scope
   14.10 -     * and are thus rebound with that as receiver
   14.11 +     * Delegate constructor for bound properties. This is used for properties created by
   14.12 +     * {@link ScriptRuntime#mergeScope} and the Nashorn {@code Object.bindProperties} method.
   14.13 +     * The former is used to add a script's defined globals to the current global scope while
   14.14 +     * still storing them in a JO-prefixed ScriptObject class.
   14.15 +     *
   14.16 +     * <p>All properties created by this constructor have the {@link #IS_BOUND} flag set.</p>
   14.17       *
   14.18       * @param property  accessor property to rebind
   14.19       * @param delegate  delegate object to rebind receiver to
   14.20 @@ -157,6 +159,8 @@
   14.21          this.objectGetter    = bindTo(property.ensureObjectGetter(), delegate);
   14.22          this.objectSetter    = bindTo(property.ensureObjectSetter(), delegate);
   14.23  
   14.24 +        // Properties created this way are bound to a delegate
   14.25 +        this.flags |= IS_BOUND;
   14.26          setCurrentType(property.getCurrentType());
   14.27      }
   14.28  
    15.1 --- a/src/jdk/nashorn/internal/runtime/Context.java	Wed Mar 12 16:33:28 2014 +0100
    15.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java	Wed Mar 12 11:26:00 2014 +0100
    15.3 @@ -36,6 +36,8 @@
    15.4  import java.io.PrintWriter;
    15.5  import java.lang.invoke.MethodHandle;
    15.6  import java.lang.invoke.MethodHandles;
    15.7 +import java.lang.ref.ReferenceQueue;
    15.8 +import java.lang.ref.SoftReference;
    15.9  import java.lang.reflect.Modifier;
   15.10  import java.util.concurrent.atomic.AtomicLong;
   15.11  import java.net.MalformedURLException;
   15.12 @@ -47,6 +49,7 @@
   15.13  import java.security.Permissions;
   15.14  import java.security.PrivilegedAction;
   15.15  import java.security.ProtectionDomain;
   15.16 +import java.util.LinkedHashMap;
   15.17  import java.util.Map;
   15.18  
   15.19  import jdk.internal.org.objectweb.asm.ClassReader;
   15.20 @@ -156,6 +159,9 @@
   15.21  
   15.22      private static final ThreadLocal<ScriptObject> currentGlobal = new ThreadLocal<>();
   15.23  
   15.24 +    // class cache
   15.25 +    private ClassCache classCache;
   15.26 +
   15.27      /**
   15.28       * Get the current global scope
   15.29       * @return the current global scope
   15.30 @@ -349,6 +355,11 @@
   15.31              this.classPathLoader = null;
   15.32          }
   15.33  
   15.34 +        final int cacheSize = env._class_cache_size;
   15.35 +        if (cacheSize > 0) {
   15.36 +            classCache = new ClassCache(cacheSize);
   15.37 +        }
   15.38 +
   15.39          // print version info if asked.
   15.40          if (env._version) {
   15.41              getErr().println("nashorn " + Version.version());
   15.42 @@ -660,7 +671,7 @@
   15.43      public static void checkPackageAccess(final String pkgName) {
   15.44          final SecurityManager sm = System.getSecurityManager();
   15.45          if (sm != null) {
   15.46 -            checkPackageAccess(sm, pkgName.endsWith(".")? pkgName : pkgName + ".");
   15.47 +            checkPackageAccess(sm, pkgName.endsWith(".") ? pkgName : pkgName + ".");
   15.48          }
   15.49      }
   15.50  
   15.51 @@ -926,16 +937,10 @@
   15.52          // start with no errors, no warnings.
   15.53          errMan.reset();
   15.54  
   15.55 -        GlobalObject global = null;
   15.56 -        Class<?> script;
   15.57 -
   15.58 -        if (env._class_cache_size > 0) {
   15.59 -            global = (GlobalObject)Context.getGlobalTrusted();
   15.60 -            script = global.findCachedClass(source);
   15.61 -            if (script != null) {
   15.62 -                Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile.");
   15.63 -                return script;
   15.64 -            }
   15.65 +        Class<?> script = findCachedClass(source);
   15.66 +        if (script != null) {
   15.67 +            Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile.");
   15.68 +            return script;
   15.69          }
   15.70  
   15.71          final FunctionNode functionNode = new Parser(env, source, errMan, strict).parse();
   15.72 @@ -964,10 +969,7 @@
   15.73  
   15.74          final FunctionNode newFunctionNode = compiler.compile(functionNode);
   15.75          script = compiler.install(newFunctionNode);
   15.76 -
   15.77 -        if (global != null) {
   15.78 -            global.cacheClass(source, script);
   15.79 -        }
   15.80 +        cacheClass(source, script);
   15.81  
   15.82          return script;
   15.83      }
   15.84 @@ -989,4 +991,60 @@
   15.85      private long getUniqueScriptId() {
   15.86          return uniqueScriptId.getAndIncrement();
   15.87      }
   15.88 +
   15.89 +    /**
   15.90 +     * Cache for compiled script classes.
   15.91 +     */
   15.92 +    @SuppressWarnings("serial")
   15.93 +    private static class ClassCache extends LinkedHashMap<Source, ClassReference> {
   15.94 +        private final int size;
   15.95 +        private final ReferenceQueue<Class<?>> queue;
   15.96 +
   15.97 +        ClassCache(int size) {
   15.98 +            super(size, 0.75f, true);
   15.99 +            this.size = size;
  15.100 +            this.queue = new ReferenceQueue<>();
  15.101 +        }
  15.102 +
  15.103 +        void cache(final Source source, final Class<?> clazz) {
  15.104 +            put(source, new ClassReference(clazz, queue, source));
  15.105 +        }
  15.106 +
  15.107 +        @Override
  15.108 +        protected boolean removeEldestEntry(final Map.Entry<Source, ClassReference> eldest) {
  15.109 +            return size() > size;
  15.110 +        }
  15.111 +
  15.112 +        @Override
  15.113 +        public ClassReference get(Object key) {
  15.114 +            for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) {
  15.115 +                remove(ref.source);
  15.116 +            }
  15.117 +            return super.get(key);
  15.118 +        }
  15.119 +
  15.120 +    }
  15.121 +
  15.122 +    private static class ClassReference extends SoftReference<Class<?>> {
  15.123 +        private final Source source;
  15.124 +
  15.125 +        ClassReference(final Class<?> clazz, final ReferenceQueue<Class<?>> queue, final Source source) {
  15.126 +            super(clazz, queue);
  15.127 +            this.source = source;
  15.128 +        }
  15.129 +    }
  15.130 +
  15.131 +    // Class cache management
  15.132 +    private Class<?> findCachedClass(final Source source) {
  15.133 +        ClassReference ref = classCache == null ? null : classCache.get(source);
  15.134 +        return ref != null ? ref.get() : null;
  15.135 +    }
  15.136 +
  15.137 +    private void cacheClass(final Source source, final Class<?> clazz) {
  15.138 +        if (classCache != null) {
  15.139 +            classCache.cache(source, clazz);
  15.140 +        }
  15.141 +    }
  15.142 +
  15.143 +
  15.144  }
    16.1 --- a/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java	Wed Mar 12 16:33:28 2014 +0100
    16.2 +++ b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java	Wed Mar 12 11:26:00 2014 +0100
    16.3 @@ -38,31 +38,27 @@
    16.4      /**
    16.5       * Constructor - used for bind
    16.6       *
    16.7 -     * @param name          name
    16.8 -     * @param arity         arity
    16.9 -     * @param functions     precompiled code
   16.10 -     * @param isStrict      strict
   16.11 -     * @param isBuiltin     builtin
   16.12 -     * @param isConstructor constructor
   16.13 +     * @param name      name
   16.14 +     * @param arity     arity
   16.15 +     * @param functions precompiled code
   16.16 +     * @param flags     {@link ScriptFunctionData} flags
   16.17       */
   16.18 -    FinalScriptFunctionData(final String name, int arity, CompiledFunctions functions, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
   16.19 -        super(name, arity, isStrict, isBuiltin, isConstructor);
   16.20 +    FinalScriptFunctionData(final String name, final int arity, final CompiledFunctions functions, final int flags) {
   16.21 +        super(name, arity, flags);
   16.22          code.addAll(functions);
   16.23      }
   16.24  
   16.25      /**
   16.26 -     * Constructor - used from ScriptFunction. This assumes that we have code alraedy for the
   16.27 +     * Constructor - used from ScriptFunction. This assumes that we have code already for the
   16.28       * method (typically a native method) and possibly specializations.
   16.29       *
   16.30 -     * @param name           name
   16.31 -     * @param mh             method handle for generic version of method
   16.32 -     * @param specs          specializations
   16.33 -     * @param isStrict       strict
   16.34 -     * @param isBuiltin      builtin
   16.35 -     * @param isConstructor  constructor
   16.36 +     * @param name  name
   16.37 +     * @param mh    method handle for generic version of method
   16.38 +     * @param specs specializations
   16.39 +     * @param flags {@link ScriptFunctionData} flags
   16.40       */
   16.41 -    FinalScriptFunctionData(final String name, final MethodHandle mh, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
   16.42 -        super(name, arity(mh), isStrict, isBuiltin, isConstructor);
   16.43 +    FinalScriptFunctionData(final String name, final MethodHandle mh, final MethodHandle[] specs, final int flags) {
   16.44 +        super(name, arity(mh), flags);
   16.45  
   16.46          addInvoker(mh);
   16.47          if (specs != null) {
    17.1 --- a/src/jdk/nashorn/internal/runtime/GlobalObject.java	Wed Mar 12 16:33:28 2014 +0100
    17.2 +++ b/src/jdk/nashorn/internal/runtime/GlobalObject.java	Wed Mar 12 11:26:00 2014 +0100
    17.3 @@ -211,22 +211,6 @@
    17.4      public Object getDefaultValue(ScriptObject sobj, Class<?> typeHint);
    17.5  
    17.6      /**
    17.7 -     * Find the compiled Class for the given script source, if available
    17.8 -     *
    17.9 -     * @param source Source object of the script
   17.10 -     * @return compiled Class object or null
   17.11 -     */
   17.12 -    public Class<?> findCachedClass(Source source);
   17.13 -
   17.14 -    /**
   17.15 -     * Put the Source associated Class object in the Source-to-Class cache
   17.16 -     *
   17.17 -     * @param source Source of the script
   17.18 -     * @param clazz compiled Class object for the source
   17.19 -     */
   17.20 -    public void cacheClass(Source source, Class<?> clazz);
   17.21 -
   17.22 -    /**
   17.23       * Get cached InvokeByName object for the given key
   17.24       * @param key key to be associated with InvokeByName object
   17.25       * @param creator if InvokeByName is absent 'creator' is called to make one (lazy init)
    18.1 --- a/src/jdk/nashorn/internal/runtime/Property.java	Wed Mar 12 16:33:28 2014 +0100
    18.2 +++ b/src/jdk/nashorn/internal/runtime/Property.java	Wed Mar 12 11:26:00 2014 +0100
    18.3 @@ -84,9 +84,13 @@
    18.4      /** Can this property be undefined? */
    18.5      public static final int CAN_BE_UNDEFINED = 1 << 8;
    18.6  
    18.7 -    /* Is this a function declaration property ? */
    18.8 +    /** Is this a function declaration property ? */
    18.9      public static final int IS_FUNCTION_DECLARATION = 1 << 9;
   18.10  
   18.11 +    /** Is this property bound to a receiver? This means get/set operations will be delegated to
   18.12 +     *  a statically defined object instead of the object passed as callsite parameter. */
   18.13 +    public static final int IS_BOUND = 1 << 10;
   18.14 +
   18.15      /** Property key. */
   18.16      private final String key;
   18.17  
   18.18 @@ -252,6 +256,16 @@
   18.19      }
   18.20  
   18.21      /**
   18.22 +     * Is this property bound to a receiver? If this method returns {@code true} get and set operations
   18.23 +     * will be delegated to a statically bound object instead of the object passed as parameter.
   18.24 +     *
   18.25 +     * @return true if this is a bound property
   18.26 +     */
   18.27 +    public boolean isBound() {
   18.28 +        return (flags & IS_BOUND) == IS_BOUND;
   18.29 +    }
   18.30 +
   18.31 +    /**
   18.32       * Does this property use any slots in the spill array described in
   18.33       * {@link Property#isSpill}? In that case how many. Currently a property
   18.34       * only uses max one spill slot, but this may change in future representations
    19.1 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Wed Mar 12 16:33:28 2014 +0100
    19.2 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Wed Mar 12 11:26:00 2014 +0100
    19.3 @@ -103,9 +103,7 @@
    19.4      public RecompilableScriptFunctionData(final FunctionNode functionNode, final CodeInstaller<ScriptEnvironment> installer, final String allocatorClassName, final PropertyMap allocatorMap) {
    19.5          super(functionName(functionNode),
    19.6                functionNode.getParameters().size(),
    19.7 -              functionNode.isStrict(),
    19.8 -              false,
    19.9 -              true);
   19.10 +              getFlags(functionNode));
   19.11  
   19.12          this.functionNode       = functionNode;
   19.13          this.source             = functionNode.getSource();
   19.14 @@ -129,10 +127,11 @@
   19.15          final StringBuilder sb = new StringBuilder();
   19.16  
   19.17          if (source != null) {
   19.18 -            sb.append(source.getName())
   19.19 -                .append(':')
   19.20 -                .append(functionNode.getLineNumber())
   19.21 -                .append(' ');
   19.22 +            sb.append(source.getName());
   19.23 +            if (functionNode != null) {
   19.24 +                sb.append(':').append(functionNode.getLineNumber());
   19.25 +            }
   19.26 +            sb.append(' ');
   19.27          }
   19.28  
   19.29          return sb.toString() + super.toString();
   19.30 @@ -159,6 +158,20 @@
   19.31          return Token.toDesc(TokenType.FUNCTION, position, length);
   19.32      }
   19.33  
   19.34 +    private static int getFlags(final FunctionNode functionNode) {
   19.35 +        int flags = IS_CONSTRUCTOR;
   19.36 +        if (functionNode.isStrict()) {
   19.37 +            flags |= IS_STRICT;
   19.38 +        }
   19.39 +        if (functionNode.needsCallee()) {
   19.40 +            flags |= NEEDS_CALLEE;
   19.41 +        }
   19.42 +        if (functionNode.usesThis() || functionNode.hasEval()) {
   19.43 +            flags |= USES_THIS;
   19.44 +        }
   19.45 +        return flags;
   19.46 +    }
   19.47 +
   19.48      @Override
   19.49      ScriptObject allocate(final PropertyMap map) {
   19.50          try {
   19.51 @@ -182,41 +195,42 @@
   19.52          return allocatorMap;
   19.53      }
   19.54  
   19.55 +
   19.56 +    @Override
   19.57 +    protected void ensureCompiled() {
   19.58 +        if (functionNode != null && functionNode.isLazy()) {
   19.59 +            Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'");
   19.60 +            final Compiler compiler = new Compiler(installer);
   19.61 +            functionNode = compiler.compile(functionNode);
   19.62 +            assert !functionNode.isLazy();
   19.63 +            compiler.install(functionNode);
   19.64 +            flags = getFlags(functionNode);
   19.65 +        }
   19.66 +    }
   19.67 +
   19.68      @Override
   19.69      protected synchronized void ensureCodeGenerated() {
   19.70 -         if (!code.isEmpty()) {
   19.71 -             return; // nothing to do, we have code, at least some.
   19.72 -         }
   19.73 +        if (!code.isEmpty()) {
   19.74 +            return; // nothing to do, we have code, at least some.
   19.75 +        }
   19.76  
   19.77 -         if (functionNode.isLazy()) {
   19.78 -             Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'");
   19.79 -             final Compiler compiler = new Compiler(installer);
   19.80 -             functionNode = compiler.compile(functionNode);
   19.81 -             assert !functionNode.isLazy();
   19.82 -             compiler.install(functionNode);
   19.83 +        ensureCompiled();
   19.84  
   19.85 -             /*
   19.86 -              * We don't need to update any flags - varArgs and needsCallee are instrincic
   19.87 -              * in the function world we need to get a destination node from the compile instead
   19.88 -              * and replace it with our function node. TODO
   19.89 -              */
   19.90 -         }
   19.91 +        /*
   19.92 +         * We can't get to this program point unless we have bytecode, either from
   19.93 +         * eager compilation or from running a lazy compile on the lines above
   19.94 +         */
   19.95  
   19.96 -         /*
   19.97 -          * We can't get to this program point unless we have bytecode, either from
   19.98 -          * eager compilation or from running a lazy compile on the lines above
   19.99 -          */
  19.100 +        assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode);
  19.101  
  19.102 -         assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode);
  19.103 +        // code exists - look it up and add it into the automatically sorted invoker list
  19.104 +        addCode(functionNode);
  19.105  
  19.106 -         // code exists - look it up and add it into the automatically sorted invoker list
  19.107 -         addCode(functionNode);
  19.108 -
  19.109 -         if (! functionNode.canSpecialize()) {
  19.110 -             // allow GC to claim IR stuff that is not needed anymore
  19.111 -             functionNode = null;
  19.112 -             installer = null;
  19.113 -         }
  19.114 +        if (! functionNode.canSpecialize()) {
  19.115 +            // allow GC to claim IR stuff that is not needed anymore
  19.116 +            functionNode = null;
  19.117 +            installer = null;
  19.118 +        }
  19.119      }
  19.120  
  19.121      private MethodHandle addCode(final FunctionNode fn) {
    20.1 --- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Wed Mar 12 16:33:28 2014 +0100
    20.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Wed Mar 12 11:26:00 2014 +0100
    20.3 @@ -66,6 +66,8 @@
    20.4  
    20.5      private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", Object.class, Object.class);
    20.6  
    20.7 +    private static final MethodHandle GLOBALFILTER = findOwnMH("globalFilter", Object.class, Object.class);
    20.8 +
    20.9      /** method handle to scope getter for this ScriptFunction */
   20.10      public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
   20.11  
   20.12 @@ -91,9 +93,7 @@
   20.13       * @param map           property map
   20.14       * @param scope         scope
   20.15       * @param specs         specialized version of this function - other method handles
   20.16 -     * @param strict        is this a strict mode function?
   20.17 -     * @param builtin       is this a built in function?
   20.18 -     * @param isConstructor is this a constructor?
   20.19 +     * @param flags         {@link ScriptFunctionData} flags
   20.20       */
   20.21      protected ScriptFunction(
   20.22              final String name,
   20.23 @@ -101,11 +101,9 @@
   20.24              final PropertyMap map,
   20.25              final ScriptObject scope,
   20.26              final MethodHandle[] specs,
   20.27 -            final boolean strict,
   20.28 -            final boolean builtin,
   20.29 -            final boolean isConstructor) {
   20.30 +            final int flags) {
   20.31  
   20.32 -        this(new FinalScriptFunctionData(name, methodHandle, specs, strict, builtin, isConstructor), map, scope);
   20.33 +        this(new FinalScriptFunctionData(name, methodHandle, specs, flags), map, scope);
   20.34      }
   20.35  
   20.36      /**
   20.37 @@ -480,6 +478,13 @@
   20.38          return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(obj);
   20.39      }
   20.40  
   20.41 +
   20.42 +    @SuppressWarnings("unused")
   20.43 +    private static Object globalFilter(final Object object) {
   20.44 +        // replace whatever we get with the current global object
   20.45 +        return Context.getGlobalTrusted();
   20.46 +    }
   20.47 +
   20.48      /**
   20.49       * dyn:call call site signature: (callee, thiz, [args...])
   20.50       * generated method signature:   (callee, thiz, [args...])
   20.51 @@ -495,11 +500,11 @@
   20.52      @Override
   20.53      protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
   20.54          final MethodType type = desc.getMethodType();
   20.55 +        final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc);
   20.56  
   20.57          if (request.isCallSiteUnstable()) {
   20.58 -            // (this, callee, args...) => (this, callee, args[])
   20.59 -            final MethodHandle collector = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class,
   20.60 -                    type.parameterCount() - 2);
   20.61 +            // (callee, this, args...) => (callee, this, args[])
   20.62 +            final MethodHandle collector = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class, type.parameterCount() - 2);
   20.63  
   20.64              // If call site is statically typed to take a ScriptFunction, we don't need a guard, otherwise we need a
   20.65              // generic "is this a ScriptFunction?" guard.
   20.66 @@ -510,17 +515,12 @@
   20.67          MethodHandle boundHandle;
   20.68          MethodHandle guard = null;
   20.69  
   20.70 -        final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc);
   20.71 -
   20.72          if (data.needsCallee()) {
   20.73              final MethodHandle callHandle = getBestInvoker(type, request.getArguments());
   20.74 -            if (scopeCall) {
   20.75 +            if (scopeCall && needsWrappedThis()) {
   20.76                  // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
   20.77 -                // (callee, this, args...) => (callee, args...)
   20.78 -                boundHandle = MH.insertArguments(callHandle, 1, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
   20.79 -                // (callee, args...) => (callee, [this], args...)
   20.80 -                boundHandle = MH.dropArguments(boundHandle, 1, Object.class);
   20.81 -
   20.82 +                // (callee, this, args...) => (callee, [this], args...)
   20.83 +                boundHandle = MH.filterArguments(callHandle, 1, GLOBALFILTER);
   20.84              } else {
   20.85                  // It's already (callee, this, args...), just what we need
   20.86                  boundHandle = callHandle;
   20.87 @@ -531,12 +531,12 @@
   20.88                  // NOTE: the only built-in named "extend" is NativeJava.extend. As a special-case we're binding the
   20.89                  // current lookup as its "this" so it can do security-sensitive creation of adapter classes.
   20.90                  boundHandle = MH.dropArguments(MH.bindTo(callHandle, desc.getLookup()), 0, Object.class, Object.class);
   20.91 -            } else if (scopeCall) {
   20.92 +            } else if (scopeCall && needsWrappedThis()) {
   20.93                  // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
   20.94 -                // (this, args...) => (args...)
   20.95 -                boundHandle = MH.bindTo(callHandle, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
   20.96 -                // (args...) => ([callee], [this], args...)
   20.97 -                boundHandle = MH.dropArguments(boundHandle, 0, Object.class, Object.class);
   20.98 +                // (this, args...) => ([this], args...)
   20.99 +                boundHandle = MH.filterArguments(callHandle, 0, GLOBALFILTER);
  20.100 +                // ([this], args...) => ([callee], [this], args...)
  20.101 +                boundHandle = MH.dropArguments(boundHandle, 0, Object.class);
  20.102              } else {
  20.103                  // (this, args...) => ([callee], this, args...)
  20.104                  boundHandle = MH.dropArguments(callHandle, 0, Object.class);
    21.1 --- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Wed Mar 12 16:33:28 2014 +0100
    21.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Wed Mar 12 11:26:00 2014 +0100
    21.3 @@ -47,33 +47,44 @@
    21.4      /** All versions of this function that have been generated to code */
    21.5      protected final CompiledFunctions code;
    21.6  
    21.7 +    /** Function flags */
    21.8 +    protected int flags;
    21.9 +
   21.10      private int arity;
   21.11  
   21.12 -    private final boolean isStrict;
   21.13 -
   21.14 -    private final boolean isBuiltin;
   21.15 -
   21.16 -    private final boolean isConstructor;
   21.17 -
   21.18      private static final MethodHandle NEWFILTER     = findOwnMH("newFilter", Object.class, Object.class, Object.class);
   21.19      private static final MethodHandle BIND_VAR_ARGS = findOwnMH("bindVarArgs", Object[].class, Object[].class, Object[].class);
   21.20  
   21.21 +    /** Is this a strict mode function? */
   21.22 +    public static final int IS_STRICT      = 1 << 0;
   21.23 +    /** Is this a built-in function? */
   21.24 +    public static final int IS_BUILTIN     = 1 << 1;
   21.25 +    /** Is this a constructor function? */
   21.26 +    public static final int IS_CONSTRUCTOR = 1 << 2;
   21.27 +    /** Does this function expect a callee argument? */
   21.28 +    public static final int NEEDS_CALLEE   = 1 << 3;
   21.29 +    /** Does this function make use of the this-object argument? */
   21.30 +    public static final int USES_THIS      = 1 << 4;
   21.31 +
   21.32 +    /** Flag for strict or built-in functions */
   21.33 +    public static final int IS_STRICT_OR_BUILTIN = IS_STRICT | IS_BUILTIN;
   21.34 +    /** Flag for built-in constructors */
   21.35 +    public static final int IS_BUILTIN_CONSTRUCTOR = IS_BUILTIN | IS_CONSTRUCTOR;
   21.36 +    /** Flag for strict constructors */
   21.37 +    public static final int IS_STRICT_CONSTRUCTOR = IS_STRICT | IS_CONSTRUCTOR;
   21.38 +
   21.39      /**
   21.40       * Constructor
   21.41       *
   21.42       * @param name          script function name
   21.43       * @param arity         arity
   21.44 -     * @param isStrict      is the function strict
   21.45 -     * @param isBuiltin     is the function built in
   21.46 -     * @param isConstructor is the function a constructor
   21.47 +     * @param flags         the function flags
   21.48       */
   21.49 -    ScriptFunctionData(final String name, final int arity, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
   21.50 -        this.name          = name;
   21.51 -        this.arity         = arity;
   21.52 -        this.code          = new CompiledFunctions();
   21.53 -        this.isStrict      = isStrict;
   21.54 -        this.isBuiltin     = isBuiltin;
   21.55 -        this.isConstructor = isConstructor;
   21.56 +    ScriptFunctionData(final String name, final int arity, final int flags) {
   21.57 +        this.name  = name;
   21.58 +        this.arity = arity;
   21.59 +        this.code  = new CompiledFunctions();
   21.60 +        this.flags = flags;
   21.61      }
   21.62  
   21.63      final int getArity() {
   21.64 @@ -105,21 +116,21 @@
   21.65       * @return true if strict, false otherwise
   21.66       */
   21.67      public boolean isStrict() {
   21.68 -        return isStrict;
   21.69 +        return (flags & IS_STRICT) != 0;
   21.70      }
   21.71  
   21.72      boolean isBuiltin() {
   21.73 -        return isBuiltin;
   21.74 +        return (flags & IS_BUILTIN) != 0;
   21.75      }
   21.76  
   21.77      boolean isConstructor() {
   21.78 -        return isConstructor;
   21.79 +        return (flags & IS_CONSTRUCTOR) != 0;
   21.80      }
   21.81  
   21.82      boolean needsCallee() {
   21.83 -        // we don't know if we need a callee or not unless we are generated
   21.84 -        ensureCodeGenerated();
   21.85 -        return code.needsCallee();
   21.86 +        // we don't know if we need a callee or not unless code has been compiled
   21.87 +        ensureCompiled();
   21.88 +        return (flags & NEEDS_CALLEE) != 0;
   21.89      }
   21.90  
   21.91      /**
   21.92 @@ -128,7 +139,7 @@
   21.93       * @return true if this argument must be an object
   21.94       */
   21.95      boolean needsWrappedThis() {
   21.96 -        return !isStrict && !isBuiltin;
   21.97 +        return (flags & USES_THIS) != 0 && (flags & IS_STRICT_OR_BUILTIN) == 0;
   21.98      }
   21.99  
  21.100      String toSource() {
  21.101 @@ -202,6 +213,15 @@
  21.102      }
  21.103  
  21.104      /**
  21.105 +     * If we can have lazy code generation, this is a hook to ensure that the code has been compiled.
  21.106 +     * This does not guarantee the code been installed in this {@code ScriptFunctionData} instance;
  21.107 +     * use {@link #ensureCodeGenerated()} to install the actual method handles.
  21.108 +     */
  21.109 +    protected void ensureCompiled() {
  21.110 +        //empty
  21.111 +    }
  21.112 +
  21.113 +    /**
  21.114       * Return a generic Object/Object invoker for this method. It will ensure code
  21.115       * is generated, get the most generic of all versions of this function and adapt it
  21.116       * to Objects.
  21.117 @@ -259,6 +279,8 @@
  21.118  
  21.119          final Object[] allArgs = args == null ? ScriptRuntime.EMPTY_ARRAY : args;
  21.120          final int length = args == null ? 0 : args.length;
  21.121 +        // Clear the callee and this flags
  21.122 +        final int boundFlags = flags & ~NEEDS_CALLEE & ~USES_THIS;
  21.123  
  21.124          CompiledFunctions boundList = new CompiledFunctions();
  21.125          if (code.size() == 1) {
  21.126 @@ -273,8 +295,7 @@
  21.127              boundList.add(bind(inv, fn, self, allArgs));
  21.128          }
  21.129  
  21.130 -        ScriptFunctionData boundData = new FinalScriptFunctionData(name, arity == -1 ? -1 : Math.max(0, arity - length), boundList, isStrict(), isBuiltin(), isConstructor());
  21.131 -        return boundData;
  21.132 +        return new FinalScriptFunctionData(name, arity == -1 ? -1 : Math.max(0, arity - length), boundList, boundFlags);
  21.133      }
  21.134  
  21.135      /**
    22.1 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Mar 12 16:33:28 2014 +0100
    22.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Wed Mar 12 11:26:00 2014 +0100
    22.3 @@ -66,6 +66,7 @@
    22.4  import jdk.nashorn.internal.lookup.MethodHandleFactory;
    22.5  import jdk.nashorn.internal.objects.AccessorPropertyDescriptor;
    22.6  import jdk.nashorn.internal.objects.DataPropertyDescriptor;
    22.7 +import jdk.nashorn.internal.objects.Global;
    22.8  import jdk.nashorn.internal.runtime.arrays.ArrayData;
    22.9  import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
   22.10  import jdk.nashorn.internal.runtime.linker.Bootstrap;
   22.11 @@ -131,7 +132,8 @@
   22.12  
   22.13      static final MethodHandle GETPROTO           = findOwnMH("getProto", ScriptObject.class);
   22.14      static final MethodHandle SETPROTOCHECK      = findOwnMH("setProtoCheck", void.class, Object.class);
   22.15 -    static final MethodHandle MEGAMORPHIC_GET    = findOwnMH("megamorphicGet", Object.class, String.class, boolean.class);
   22.16 +    static final MethodHandle MEGAMORPHIC_GET    = findOwnMH("megamorphicGet", Object.class, String.class, boolean.class, boolean.class);
   22.17 +    static final MethodHandle GLOBALFILTER       = findOwnMH("globalFilter", Object.class, Object.class);
   22.18  
   22.19      static final MethodHandle SETFIELD           = findOwnMH("setField",         void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, Object.class, Object.class);
   22.20      static final MethodHandle SETSPILL           = findOwnMH("setSpill",         void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
   22.21 @@ -225,6 +227,7 @@
   22.22              final Property oldProp = newMap.findProperty(key);
   22.23              if (oldProp == null) {
   22.24                  if (property instanceof UserAccessorProperty) {
   22.25 +                    // Note: we copy accessor functions to this object which is semantically different from binding.
   22.26                      final UserAccessorProperty prop = this.newUserAccessors(key, property.getFlags(), property.getGetterFunction(source), property.getSetterFunction(source));
   22.27                      newMap = newMap.addPropertyNoHistory(prop);
   22.28                  } else {
   22.29 @@ -975,17 +978,6 @@
   22.30      }
   22.31  
   22.32      /**
   22.33 -      * Get the object value of a property
   22.34 -      *
   22.35 -      * @param find {@link FindProperty} lookup result
   22.36 -      *
   22.37 -      * @return the value of the property
   22.38 -      */
   22.39 -    protected static Object getObjectValue(final FindProperty find) {
   22.40 -        return find.getObjectValue();
   22.41 -    }
   22.42 -
   22.43 -    /**
   22.44       * Return methodHandle of value function for call.
   22.45       *
   22.46       * @param find      data from find property.
   22.47 @@ -995,7 +987,7 @@
   22.48       * @return value of property as a MethodHandle or null.
   22.49       */
   22.50      protected MethodHandle getCallMethodHandle(final FindProperty find, final MethodType type, final String bindName) {
   22.51 -        return getCallMethodHandle(getObjectValue(find), type, bindName);
   22.52 +        return getCallMethodHandle(find.getObjectValue(), type, bindName);
   22.53      }
   22.54  
   22.55      /**
   22.56 @@ -1019,7 +1011,7 @@
   22.57       * @return Value of property.
   22.58       */
   22.59      public final Object getWithProperty(final Property property) {
   22.60 -        return getObjectValue(new FindProperty(this, this, property));
   22.61 +        return new FindProperty(this, this, property).getObjectValue();
   22.62      }
   22.63  
   22.64      /**
   22.65 @@ -1740,7 +1732,7 @@
   22.66      protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
   22.67          final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
   22.68          if (request.isCallSiteUnstable() || hasWithScope()) {
   22.69 -            return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator));
   22.70 +            return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator), isScope() && NashornCallSiteDescriptor.isScope(desc));
   22.71          }
   22.72  
   22.73          final FindProperty find = findProperty(name, true);
   22.74 @@ -1765,9 +1757,8 @@
   22.75          final Property property = find.getProperty();
   22.76          methodHandle = find.getGetter(returnType);
   22.77  
   22.78 -        final boolean noGuard = ObjectClassGenerator.OBJECT_FIELDS_ONLY && NashornCallSiteDescriptor.isFastScope(desc) && !property.canChangeType();
   22.79 -        // getMap() is fine as we have the prototype switchpoint depending on where the property was found
   22.80 -        final MethodHandle guard = noGuard ? null : NashornGuards.getMapGuard(getMap());
   22.81 +        // Get the appropriate guard for this callsite and property.
   22.82 +        final MethodHandle guard = NashornGuards.getGuard(this, property, desc);
   22.83          final ScriptObject owner = find.getOwner();
   22.84  
   22.85          if (methodHandle != null) {
   22.86 @@ -1777,31 +1768,32 @@
   22.87              }
   22.88  
   22.89              if (!property.hasGetterFunction(owner)) {
   22.90 -                // If not a scope bind to actual prototype as changing prototype will change the property map.
   22.91 -                // For scopes we install a filter that replaces the self object with the prototype owning the property.
   22.92 -                methodHandle = isScope() ?
   22.93 -                        addProtoFilter(methodHandle, find.getProtoChainLength()) :
   22.94 -                        bindTo(methodHandle, owner);
   22.95 +                // Add a filter that replaces the self object with the prototype owning the property.
   22.96 +                methodHandle = addProtoFilter(methodHandle, find.getProtoChainLength());
   22.97              }
   22.98 -            return new GuardedInvocation(methodHandle, noGuard ? null : getProtoSwitchPoint(name, owner), guard);
   22.99 +            return new GuardedInvocation(methodHandle, guard == null ? null : getProtoSwitchPoint(name, owner), guard);
  22.100          }
  22.101  
  22.102          assert !NashornCallSiteDescriptor.isFastScope(desc);
  22.103          return new GuardedInvocation(Lookup.emptyGetter(returnType), getProtoSwitchPoint(name, owner), guard);
  22.104      }
  22.105  
  22.106 -    private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod) {
  22.107 -        final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod);
  22.108 +    private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name,
  22.109 +                                                              final boolean isMethod, final boolean isScope) {
  22.110 +        final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod, isScope);
  22.111          final MethodHandle guard = getScriptObjectGuard(desc.getMethodType());
  22.112          return new GuardedInvocation(invoker, guard);
  22.113      }
  22.114  
  22.115      @SuppressWarnings("unused")
  22.116 -    private Object megamorphicGet(final String key, final boolean isMethod) {
  22.117 +    private Object megamorphicGet(final String key, final boolean isMethod, final boolean isScope) {
  22.118          final FindProperty find = findProperty(key, true);
  22.119  
  22.120          if (find != null) {
  22.121 -            return getObjectValue(find);
  22.122 +            return find.getObjectValue();
  22.123 +        }
  22.124 +        if (isScope) {
  22.125 +            throw referenceError("not.defined", key);
  22.126          }
  22.127  
  22.128          return isMethod ? getNoSuchMethod(key) : invokeNoSuchProperty(key);
  22.129 @@ -1996,6 +1988,15 @@
  22.130          }
  22.131      }
  22.132  
  22.133 +    @SuppressWarnings("unused")
  22.134 +    private static Object globalFilter(final Object object) {
  22.135 +        ScriptObject sobj = (ScriptObject) object;
  22.136 +        while (sobj != null && !(sobj instanceof Global)) {
  22.137 +            sobj = sobj.getProto();
  22.138 +        }
  22.139 +        return sobj;
  22.140 +    }
  22.141 +
  22.142      private static GuardedInvocation findMegaMorphicSetMethod(final CallSiteDescriptor desc, final String name) {
  22.143          final MethodType type = desc.getMethodType().insertParameterTypes(1, Object.class);
  22.144          final GuardedInvocation inv = findSetIndexMethod(type, NashornCallSiteDescriptor.isStrict(desc));
  22.145 @@ -2041,7 +2042,7 @@
  22.146              return noSuchProperty(desc, request);
  22.147          }
  22.148  
  22.149 -        final Object value = getObjectValue(find);
  22.150 +        final Object value = find.getObjectValue();
  22.151          if (! (value instanceof ScriptFunction)) {
  22.152              return createEmptyGetter(desc, name);
  22.153          }
  22.154 @@ -2067,7 +2068,7 @@
  22.155          final boolean scopeAccess = isScope() && NashornCallSiteDescriptor.isScope(desc);
  22.156  
  22.157          if (find != null) {
  22.158 -            final Object   value        = getObjectValue(find);
  22.159 +            final Object   value        = find.getObjectValue();
  22.160              ScriptFunction func         = null;
  22.161              MethodHandle   methodHandle = null;
  22.162  
  22.163 @@ -2102,7 +2103,7 @@
  22.164          final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
  22.165  
  22.166          if (find != null) {
  22.167 -            final Object func = getObjectValue(find);
  22.168 +            final Object func = find.getObjectValue();
  22.169  
  22.170              if (func instanceof ScriptFunction) {
  22.171                  return ScriptRuntime.apply((ScriptFunction)func, this, name);
  22.172 @@ -2124,7 +2125,7 @@
  22.173              return invokeNoSuchProperty(name);
  22.174          }
  22.175  
  22.176 -        final Object value = getObjectValue(find);
  22.177 +        final Object value = find.getObjectValue();
  22.178          if (! (value instanceof ScriptFunction)) {
  22.179              return UNDEFINED;
  22.180          }
  22.181 @@ -2664,7 +2665,7 @@
  22.182                      final FindProperty find = object.findProperty(key, false, false, this);
  22.183  
  22.184                      if (find != null) {
  22.185 -                        return getObjectValue(find);
  22.186 +                        return find.getObjectValue();
  22.187                      }
  22.188                  }
  22.189  
  22.190 @@ -2682,7 +2683,7 @@
  22.191              final FindProperty find = findProperty(key, true);
  22.192  
  22.193              if (find != null) {
  22.194 -                return getObjectValue(find);
  22.195 +                return find.getObjectValue();
  22.196              }
  22.197          }
  22.198  
  22.199 @@ -2823,7 +2824,15 @@
  22.200                  throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
  22.201              }
  22.202          } else {
  22.203 -            spill(key, value);
  22.204 +            ScriptObject sobj = this;
  22.205 +            // undefined scope properties are set in the global object.
  22.206 +            if (isScope()) {
  22.207 +                while (sobj != null && !(sobj instanceof Global)) {
  22.208 +                    sobj = sobj.getProto();
  22.209 +                }
  22.210 +                assert sobj != null : "no parent global object in scope";
  22.211 +            }
  22.212 +            sobj.spill(key, value);
  22.213          }
  22.214      }
  22.215  
    23.1 --- a/src/jdk/nashorn/internal/runtime/SetMethodCreator.java	Wed Mar 12 16:33:28 2014 +0100
    23.2 +++ b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java	Wed Mar 12 11:26:00 2014 +0100
    23.3 @@ -31,7 +31,6 @@
    23.4  import java.lang.invoke.MethodHandle;
    23.5  import jdk.internal.dynalink.CallSiteDescriptor;
    23.6  import jdk.internal.dynalink.linker.GuardedInvocation;
    23.7 -import jdk.nashorn.internal.codegen.ObjectClassGenerator;
    23.8  import jdk.nashorn.internal.lookup.Lookup;
    23.9  import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
   23.10  import jdk.nashorn.internal.runtime.linker.NashornGuards;
   23.11 @@ -104,21 +103,9 @@
   23.12           * @return the composed guarded invocation that represents the dynamic setter method for the property.
   23.13           */
   23.14          GuardedInvocation createGuardedInvocation() {
   23.15 -            return new GuardedInvocation(methodHandle, getGuard());
   23.16 +            return new GuardedInvocation(methodHandle, NashornGuards.getGuard(sobj, property, desc));
   23.17          }
   23.18  
   23.19 -        private MethodHandle getGuard() {
   23.20 -            return needsNoGuard() ? null : NashornGuards.getMapGuard(getMap());
   23.21 -        }
   23.22 -
   23.23 -        private boolean needsNoGuard() {
   23.24 -            return NashornCallSiteDescriptor.isFastScope(desc) &&
   23.25 -                    (ObjectClassGenerator.OBJECT_FIELDS_ONLY || isPropertyTypeStable());
   23.26 -        }
   23.27 -
   23.28 -        private boolean isPropertyTypeStable() {
   23.29 -            return property == null || !property.canChangeType();
   23.30 -        }
   23.31      }
   23.32  
   23.33      private SetMethod createSetMethod() {
   23.34 @@ -153,10 +140,7 @@
   23.35  
   23.36          final MethodHandle boundHandle;
   23.37          if (!property.hasSetterFunction(find.getOwner()) && find.isInherited()) {
   23.38 -            // Bind or add prototype filter depending on whether this is a scope object.
   23.39 -            boundHandle = sobj.isScope() ?
   23.40 -                    ScriptObject.addProtoFilter(methodHandle, find.getProtoChainLength()):
   23.41 -                    ScriptObject.bindTo(methodHandle, find.getOwner());
   23.42 +            boundHandle = ScriptObject.addProtoFilter(methodHandle, find.getProtoChainLength());
   23.43          } else {
   23.44              boundHandle = methodHandle;
   23.45          }
   23.46 @@ -165,7 +149,7 @@
   23.47  
   23.48      private SetMethod createGlobalPropertySetter() {
   23.49          final ScriptObject global = Context.getGlobalTrusted();
   23.50 -        return new SetMethod(ScriptObject.bindTo(global.addSpill(getName()), global), null);
   23.51 +        return new SetMethod(MH.filterArguments(global.addSpill(getName()), 0, ScriptObject.GLOBALFILTER), null);
   23.52      }
   23.53  
   23.54      private SetMethod createNewPropertySetter() {
    24.1 --- a/src/jdk/nashorn/internal/runtime/WithObject.java	Wed Mar 12 16:33:28 2014 +0100
    24.2 +++ b/src/jdk/nashorn/internal/runtime/WithObject.java	Wed Mar 12 11:26:00 2014 +0100
    24.3 @@ -88,6 +88,11 @@
    24.4  
    24.5      @Override
    24.6      public GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request) {
    24.7 +        if (request.isCallSiteUnstable()) {
    24.8 +            // Fall back to megamorphic invocation which performs a complete lookup each time without further relinking.
    24.9 +            return super.lookup(desc, request);
   24.10 +        }
   24.11 +
   24.12          // With scopes can never be observed outside of Nashorn code, so all call sites that can address it will of
   24.13          // necessity have a Nashorn descriptor - it is safe to cast.
   24.14          final NashornCallSiteDescriptor ndesc = (NashornCallSiteDescriptor)desc;
   24.15 @@ -265,7 +270,7 @@
   24.16      }
   24.17  
   24.18      private static MethodHandle filter(final MethodHandle mh, final MethodHandle filter) {
   24.19 -        return MH.filterArguments(mh, 0, filter);
   24.20 +        return MH.filterArguments(mh, 0, filter.asType(filter.type().changeReturnType(mh.type().parameterType(0))));
   24.21      }
   24.22  
   24.23      /**
    25.1 --- a/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java	Wed Mar 12 16:33:28 2014 +0100
    25.2 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java	Wed Mar 12 11:26:00 2014 +0100
    25.3 @@ -29,6 +29,11 @@
    25.4  
    25.5  import java.lang.invoke.MethodHandle;
    25.6  import java.lang.invoke.MethodHandles;
    25.7 +import java.lang.ref.WeakReference;
    25.8 +import jdk.internal.dynalink.CallSiteDescriptor;
    25.9 +import jdk.nashorn.internal.codegen.ObjectClassGenerator;
   25.10 +import jdk.nashorn.internal.objects.Global;
   25.11 +import jdk.nashorn.internal.runtime.Property;
   25.12  import jdk.nashorn.internal.runtime.PropertyMap;
   25.13  import jdk.nashorn.internal.runtime.ScriptFunction;
   25.14  import jdk.nashorn.internal.runtime.ScriptObject;
   25.15 @@ -40,6 +45,7 @@
   25.16      private static final MethodHandle IS_SCRIPTOBJECT   = findOwnMH("isScriptObject", boolean.class, Object.class);
   25.17      private static final MethodHandle IS_SCRIPTFUNCTION = findOwnMH("isScriptFunction", boolean.class, Object.class);
   25.18      private static final MethodHandle IS_MAP            = findOwnMH("isMap", boolean.class, Object.class, PropertyMap.class);
   25.19 +    private static final MethodHandle SAME_OBJECT       = findOwnMH("sameObject", boolean.class, Object.class, WeakReference.class);
   25.20      private static final MethodHandle IS_INSTANCEOF_2   = findOwnMH("isInstanceOf2", boolean.class, Object.class, Class.class, Class.class);
   25.21  
   25.22      // don't create me!
   25.23 @@ -75,6 +81,55 @@
   25.24      }
   25.25  
   25.26      /**
   25.27 +     * Determine whether the given callsite needs a guard.
   25.28 +     * @param property the property, or null
   25.29 +     * @param desc the callsite descriptor
   25.30 +     * @return true if a guard should be used for this callsite
   25.31 +     */
   25.32 +    static boolean needsGuard(final Property property, final CallSiteDescriptor desc) {
   25.33 +        return property == null || property.isConfigurable()
   25.34 +                || property.isBound() || !ObjectClassGenerator.OBJECT_FIELDS_ONLY
   25.35 +                || !NashornCallSiteDescriptor.isFastScope(desc) || property.canChangeType();
   25.36 +    }
   25.37 +
   25.38 +    /**
   25.39 +     * Get the guard for a property access. This returns an identity guard for non-configurable global properties
   25.40 +     * and a map guard for everything else.
   25.41 +     *
   25.42 +     * @param sobj the first object in the prototype chain
   25.43 +     * @param property the property
   25.44 +     * @param desc the callsite descriptor
   25.45 +     * @return method handle for guard
   25.46 +     */
   25.47 +    public static MethodHandle getGuard(final ScriptObject sobj, final Property property, final CallSiteDescriptor desc) {
   25.48 +        if (!needsGuard(property, desc)) {
   25.49 +            return null;
   25.50 +        }
   25.51 +        if (NashornCallSiteDescriptor.isScope(desc)) {
   25.52 +            if (property != null && property.isBound()) {
   25.53 +                // This is a declared top level variables in main script or eval, use identity guard.
   25.54 +                return getIdentityGuard(sobj);
   25.55 +            }
   25.56 +            if (!(sobj instanceof Global) && (property == null || property.isConfigurable())) {
   25.57 +                // Undeclared variables in nested evals need stronger guards
   25.58 +                return combineGuards(getIdentityGuard(sobj), getMapGuard(sobj.getMap()));
   25.59 +            }
   25.60 +        }
   25.61 +        return getMapGuard(sobj.getMap());
   25.62 +    }
   25.63 +
   25.64 +
   25.65 +    /**
   25.66 +     * Get a guard that checks referential identity of the current object.
   25.67 +     *
   25.68 +     * @param sobj the self object
   25.69 +     * @return true if same self object instance
   25.70 +     */
   25.71 +    public static MethodHandle getIdentityGuard(final ScriptObject sobj) {
   25.72 +        return MH.insertArguments(SAME_OBJECT, 1, new WeakReference<>(sobj));
   25.73 +    }
   25.74 +
   25.75 +    /**
   25.76       * Get a guard that checks if in item is an instance of either of two classes.
   25.77       *
   25.78       * @param class1 the first class
   25.79 @@ -112,6 +167,11 @@
   25.80      }
   25.81  
   25.82      @SuppressWarnings("unused")
   25.83 +    private static boolean sameObject(final Object self, final WeakReference<ScriptObject> ref) {
   25.84 +        return self == ref.get();
   25.85 +    }
   25.86 +
   25.87 +    @SuppressWarnings("unused")
   25.88      private static boolean isInstanceOf2(final Object self, final Class<?> class1, final Class<?> class2) {
   25.89          return class1.isInstance(self) || class2.isInstance(self);
   25.90      }
    26.1 --- a/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Wed Mar 12 16:33:28 2014 +0100
    26.2 +++ b/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Wed Mar 12 11:26:00 2014 +0100
    26.3 @@ -35,6 +35,7 @@
    26.4  import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
    26.5  import jdk.internal.dynalink.support.Guards;
    26.6  import jdk.nashorn.internal.lookup.Lookup;
    26.7 +import jdk.nashorn.internal.runtime.FindProperty;
    26.8  import jdk.nashorn.internal.runtime.ScriptObject;
    26.9  
   26.10  /**
   26.11 @@ -61,8 +62,9 @@
   26.12       * type {@code receiverClass}.
   26.13       */
   26.14      public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Class<?> receiverClass,
   26.15 -                                                    final ScriptObject wrappedReceiver, final MethodHandle wrapFilter) {
   26.16 -        return lookupPrimitive(request, Guards.getInstanceOfGuard(receiverClass), wrappedReceiver, wrapFilter);
   26.17 +                                                    final ScriptObject wrappedReceiver, final MethodHandle wrapFilter,
   26.18 +                                                    final MethodHandle protoFilter) {
   26.19 +        return lookupPrimitive(request, Guards.getInstanceOfGuard(receiverClass), wrappedReceiver, wrapFilter, protoFilter);
   26.20      }
   26.21  
   26.22      /**
   26.23 @@ -79,7 +81,8 @@
   26.24       * type (that is implied by both {@code guard} and {@code wrappedReceiver}).
   26.25       */
   26.26      public static GuardedInvocation lookupPrimitive(final LinkRequest request, final MethodHandle guard,
   26.27 -                                                    final ScriptObject wrappedReceiver, final MethodHandle wrapFilter) {
   26.28 +                                                    final ScriptObject wrappedReceiver, final MethodHandle wrapFilter,
   26.29 +                                                    final MethodHandle protoFilter) {
   26.30          final CallSiteDescriptor desc = request.getCallSiteDescriptor();
   26.31          final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
   26.32          if ("setProp".equals(operator) || "setElem".equals(operator)) {
   26.33 @@ -93,9 +96,23 @@
   26.34  
   26.35          if(desc.getNameTokenCount() > 2) {
   26.36              final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
   26.37 -            if(wrappedReceiver.findProperty(name, true) == null) {
   26.38 +            final FindProperty find = wrappedReceiver.findProperty(name, true);
   26.39 +            if(find == null) {
   26.40                  // Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it.
   26.41                  return null;
   26.42 +            } else if (find.isInherited() && !find.getProperty().hasGetterFunction(find.getOwner())) {
   26.43 +                // If property is found in the prototype object bind the method handle directly to
   26.44 +                // the proto filter instead of going through wrapper instantiation below.
   26.45 +                final ScriptObject proto = wrappedReceiver.getProto();
   26.46 +                final GuardedInvocation link = proto.lookup(desc, request);
   26.47 +
   26.48 +                if (link != null) {
   26.49 +                    final MethodHandle invocation = link.getInvocation();
   26.50 +                    final MethodHandle adaptedInvocation = MH.asType(invocation, invocation.type().changeParameterType(0, Object.class));
   26.51 +                    final MethodHandle method = MH.filterArguments(adaptedInvocation, 0, protoFilter);
   26.52 +                    final MethodHandle protoGuard = MH.filterArguments(link.getGuard(), 0, protoFilter);
   26.53 +                    return new GuardedInvocation(method, NashornGuards.combineGuards(guard, protoGuard));
   26.54 +                }
   26.55              }
   26.56          }
   26.57          final GuardedInvocation link = wrappedReceiver.lookup(desc, request);
    27.1 --- a/test/src/jdk/nashorn/api/scripting/ScopeTest.java	Wed Mar 12 16:33:28 2014 +0100
    27.2 +++ b/test/src/jdk/nashorn/api/scripting/ScopeTest.java	Wed Mar 12 11:26:00 2014 +0100
    27.3 @@ -245,4 +245,320 @@
    27.4          sb.put("x", "newX");
    27.5          assertTrue(e.eval("x", ctx).equals("newX"));
    27.6      }
    27.7 +
    27.8 +    /**
    27.9 +     * Test multi-threaded access to defined global variables for shared script classes with multiple globals.
   27.10 +     */
   27.11 +    @Test
   27.12 +    public static void multiThreadedVarTest() throws ScriptException, InterruptedException {
   27.13 +        final ScriptEngineManager m = new ScriptEngineManager();
   27.14 +        final ScriptEngine e = m.getEngineByName("nashorn");
   27.15 +        final Bindings b = e.createBindings();
   27.16 +        final ScriptContext origContext = e.getContext();
   27.17 +        final ScriptContext newCtxt = new SimpleScriptContext();
   27.18 +        newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
   27.19 +        final String sharedScript = "foo";
   27.20 +
   27.21 +        assertEquals(e.eval("var foo = 'original context';", origContext), null);
   27.22 +        assertEquals(e.eval("var foo = 'new context';", newCtxt), null);
   27.23 +
   27.24 +        final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
   27.25 +        final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000));
   27.26 +        t1.start();
   27.27 +        t2.start();
   27.28 +        t1.join();
   27.29 +        t2.join();
   27.30 +
   27.31 +        assertEquals(e.eval("var foo = 'newer context';", newCtxt), null);
   27.32 +        final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
   27.33 +        final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
   27.34 +
   27.35 +        t3.start();
   27.36 +        t4.start();
   27.37 +        t3.join();
   27.38 +        t4.join();
   27.39 +
   27.40 +        assertEquals(e.eval(sharedScript), "original context");
   27.41 +        assertEquals(e.eval(sharedScript, newCtxt), "newer context");
   27.42 +    }
   27.43 +
   27.44 +    /**
   27.45 +     * Test multi-threaded access to undefined global variables for shared script classes with multiple globals.
   27.46 +     */
   27.47 +    @Test
   27.48 +    public static void multiThreadedGlobalTest() throws ScriptException, InterruptedException {
   27.49 +        final ScriptEngineManager m = new ScriptEngineManager();
   27.50 +        final ScriptEngine e = m.getEngineByName("nashorn");
   27.51 +        final Bindings b = e.createBindings();
   27.52 +        final ScriptContext origContext = e.getContext();
   27.53 +        final ScriptContext newCtxt = new SimpleScriptContext();
   27.54 +        newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
   27.55 +
   27.56 +        assertEquals(e.eval("foo = 'original context';", origContext), "original context");
   27.57 +        assertEquals(e.eval("foo = 'new context';", newCtxt), "new context");
   27.58 +        final String sharedScript = "foo";
   27.59 +
   27.60 +        final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
   27.61 +        final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000));
   27.62 +        t1.start();
   27.63 +        t2.start();
   27.64 +        t1.join();
   27.65 +        t2.join();
   27.66 +
   27.67 +        Object obj3 = e.eval("delete foo; foo = 'newer context';", newCtxt);
   27.68 +        assertEquals(obj3, "newer context");
   27.69 +        final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
   27.70 +        final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
   27.71 +
   27.72 +        t3.start();
   27.73 +        t4.start();
   27.74 +        t3.join();
   27.75 +        t4.join();
   27.76 +
   27.77 +        Assert.assertEquals(e.eval(sharedScript), "original context");
   27.78 +        Assert.assertEquals(e.eval(sharedScript, newCtxt), "newer context");
   27.79 +    }
   27.80 +
   27.81 +    /**
   27.82 +     * Test multi-threaded access using the postfix ++ operator for shared script classes with multiple globals.
   27.83 +     */
   27.84 +    @Test
   27.85 +    public static void multiThreadedIncTest() throws ScriptException, InterruptedException {
   27.86 +        final ScriptEngineManager m = new ScriptEngineManager();
   27.87 +        final ScriptEngine e = m.getEngineByName("nashorn");
   27.88 +        final Bindings b = e.createBindings();
   27.89 +        final ScriptContext origContext = e.getContext();
   27.90 +        final ScriptContext newCtxt = new SimpleScriptContext();
   27.91 +        newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
   27.92 +
   27.93 +        assertEquals(e.eval("var x = 0;", origContext), null);
   27.94 +        assertEquals(e.eval("var x = 2;", newCtxt), null);
   27.95 +        final String sharedScript = "x++;";
   27.96 +
   27.97 +        final Thread t1 = new Thread(new Runnable() {
   27.98 +            @Override
   27.99 +            public void run() {
  27.100 +                try {
  27.101 +                    for (int i = 0; i < 1000; i++) {
  27.102 +                        assertEquals(e.eval(sharedScript, origContext), (double)i);
  27.103 +                    }
  27.104 +                } catch (ScriptException se) {
  27.105 +                    fail(se.toString());
  27.106 +                }
  27.107 +            }
  27.108 +        });
  27.109 +        final Thread t2 = new Thread(new Runnable() {
  27.110 +            @Override
  27.111 +            public void run() {
  27.112 +                try {
  27.113 +                    for (int i = 2; i < 1000; i++) {
  27.114 +                        assertEquals(e.eval(sharedScript, newCtxt), (double)i);
  27.115 +                    }
  27.116 +                } catch (ScriptException se) {
  27.117 +                    fail(se.toString());
  27.118 +                }
  27.119 +            }
  27.120 +        });
  27.121 +        t1.start();
  27.122 +        t2.start();
  27.123 +        t1.join();
  27.124 +        t2.join();
  27.125 +    }
  27.126 +
  27.127 +    /**
  27.128 +     * Test multi-threaded access to primitive prototype properties for shared script classes with multiple globals.
  27.129 +     */
  27.130 +    @Test
  27.131 +    public static void multiThreadedPrimitiveTest() throws ScriptException, InterruptedException {
  27.132 +        final ScriptEngineManager m = new ScriptEngineManager();
  27.133 +        final ScriptEngine e = m.getEngineByName("nashorn");
  27.134 +        final Bindings b = e.createBindings();
  27.135 +        final ScriptContext origContext = e.getContext();
  27.136 +        final ScriptContext newCtxt = new SimpleScriptContext();
  27.137 +        newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
  27.138 +
  27.139 +        Object obj1 = e.eval("String.prototype.foo = 'original context';", origContext);
  27.140 +        Object obj2 = e.eval("String.prototype.foo = 'new context';", newCtxt);
  27.141 +        assertEquals(obj1, "original context");
  27.142 +        assertEquals(obj2, "new context");
  27.143 +        final String sharedScript = "''.foo";
  27.144 +
  27.145 +        final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
  27.146 +        final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000));
  27.147 +        t1.start();
  27.148 +        t2.start();
  27.149 +        t1.join();
  27.150 +        t2.join();
  27.151 +
  27.152 +        Object obj3 = e.eval("delete String.prototype.foo; Object.prototype.foo = 'newer context';", newCtxt);
  27.153 +        assertEquals(obj3, "newer context");
  27.154 +        final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
  27.155 +        final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
  27.156 +
  27.157 +        t3.start();
  27.158 +        t4.start();
  27.159 +        t3.join();
  27.160 +        t4.join();
  27.161 +
  27.162 +        Assert.assertEquals(e.eval(sharedScript), "original context");
  27.163 +        Assert.assertEquals(e.eval(sharedScript, newCtxt), "newer context");
  27.164 +    }
  27.165 +
  27.166 +    /**
  27.167 +     * Test multi-threaded scope function invocation for shared script classes with multiple globals.
  27.168 +     */
  27.169 +    @Test
  27.170 +    public static void multiThreadedFunctionTest() throws ScriptException, InterruptedException {
  27.171 +        final ScriptEngineManager m = new ScriptEngineManager();
  27.172 +        final ScriptEngine e = m.getEngineByName("nashorn");
  27.173 +        final Bindings b = e.createBindings();
  27.174 +        final ScriptContext origContext = e.getContext();
  27.175 +        final ScriptContext newCtxt = new SimpleScriptContext();
  27.176 +        newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
  27.177 +
  27.178 +        e.eval(new URLReader(ScopeTest.class.getResource("resources/func.js")), origContext);
  27.179 +        assertEquals(origContext.getAttribute("scopeVar"), 1);
  27.180 +        assertEquals(e.eval("scopeTest()"), 1);
  27.181 +
  27.182 +        e.eval(new URLReader(ScopeTest.class.getResource("resources/func.js")), newCtxt);
  27.183 +        assertEquals(newCtxt.getAttribute("scopeVar"), 1);
  27.184 +        assertEquals(e.eval("scopeTest();", newCtxt), 1);
  27.185 +
  27.186 +        assertEquals(e.eval("scopeVar = 3;", newCtxt), 3);
  27.187 +        assertEquals(newCtxt.getAttribute("scopeVar"), 3);
  27.188 +
  27.189 +
  27.190 +        final Thread t1 = new Thread(new ScriptRunner(e, origContext, "scopeTest()", 1, 1000));
  27.191 +        final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, "scopeTest()", 3, 1000));
  27.192 +
  27.193 +        t1.start();
  27.194 +        t2.start();
  27.195 +        t1.join();
  27.196 +        t2.join();
  27.197 +
  27.198 +    }
  27.199 +
  27.200 +    /**
  27.201 +     * Test multi-threaded access to global getters and setters for shared script classes with multiple globals.
  27.202 +     */
  27.203 +    @Test
  27.204 +    public static void getterSetterTest() throws ScriptException, InterruptedException {
  27.205 +        final ScriptEngineManager m = new ScriptEngineManager();
  27.206 +        final ScriptEngine e = m.getEngineByName("nashorn");
  27.207 +        final Bindings b = e.createBindings();
  27.208 +        final ScriptContext origContext = e.getContext();
  27.209 +        final ScriptContext newCtxt = new SimpleScriptContext();
  27.210 +        newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
  27.211 +        final String sharedScript = "accessor1";
  27.212 +
  27.213 +        e.eval(new URLReader(ScopeTest.class.getResource("resources/gettersetter.js")), origContext);
  27.214 +        assertEquals(e.eval("accessor1 = 1;"), 1);
  27.215 +        assertEquals(e.eval(sharedScript), 1);
  27.216 +
  27.217 +        e.eval(new URLReader(ScopeTest.class.getResource("resources/gettersetter.js")), newCtxt);
  27.218 +        assertEquals(e.eval("accessor1 = 2;", newCtxt), 2);
  27.219 +        assertEquals(e.eval(sharedScript, newCtxt), 2);
  27.220 +
  27.221 +
  27.222 +        final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, 1, 1000));
  27.223 +        final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, 2, 1000));
  27.224 +
  27.225 +        t1.start();
  27.226 +        t2.start();
  27.227 +        t1.join();
  27.228 +        t2.join();
  27.229 +
  27.230 +        assertEquals(e.eval(sharedScript), 1);
  27.231 +        assertEquals(e.eval(sharedScript, newCtxt), 2);
  27.232 +        assertEquals(e.eval("v"), 1);
  27.233 +        assertEquals(e.eval("v", newCtxt), 2);
  27.234 +    }
  27.235 +
  27.236 +    /**
  27.237 +     * Test multi-threaded access to global getters and setters for shared script classes with multiple globals.
  27.238 +     */
  27.239 +    @Test
  27.240 +    public static void getterSetter2Test() throws ScriptException, InterruptedException {
  27.241 +        final ScriptEngineManager m = new ScriptEngineManager();
  27.242 +        final ScriptEngine e = m.getEngineByName("nashorn");
  27.243 +        final Bindings b = e.createBindings();
  27.244 +        final ScriptContext origContext = e.getContext();
  27.245 +        final ScriptContext newCtxt = new SimpleScriptContext();
  27.246 +        newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
  27.247 +        final String sharedScript = "accessor2";
  27.248 +
  27.249 +        e.eval(new URLReader(ScopeTest.class.getResource("resources/gettersetter.js")), origContext);
  27.250 +        assertEquals(e.eval("accessor2 = 1;"), 1);
  27.251 +        assertEquals(e.eval(sharedScript), 1);
  27.252 +
  27.253 +        e.eval(new URLReader(ScopeTest.class.getResource("resources/gettersetter.js")), newCtxt);
  27.254 +        assertEquals(e.eval("accessor2 = 2;", newCtxt), 2);
  27.255 +        assertEquals(e.eval(sharedScript, newCtxt), 2);
  27.256 +
  27.257 +
  27.258 +        final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, 1, 1000));
  27.259 +        final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, 2, 1000));
  27.260 +
  27.261 +        t1.start();
  27.262 +        t2.start();
  27.263 +        t1.join();
  27.264 +        t2.join();
  27.265 +
  27.266 +        assertEquals(e.eval(sharedScript), 1);
  27.267 +        assertEquals(e.eval(sharedScript, newCtxt), 2);
  27.268 +        assertEquals(e.eval("x"), 1);
  27.269 +        assertEquals(e.eval("x", newCtxt), 2);
  27.270 +    }
  27.271 +
  27.272 +    /**
  27.273 +     * Test "slow" scopes involving {@code with} and {@code eval} statements for shared script classes with multiple globals.
  27.274 +     */
  27.275 +    @Test
  27.276 +    public static void testSlowScope() throws ScriptException, InterruptedException {
  27.277 +        final ScriptEngineManager m = new ScriptEngineManager();
  27.278 +        final ScriptEngine e = m.getEngineByName("nashorn");
  27.279 +
  27.280 +        for (int i = 0; i < 100; i++) {
  27.281 +            final Bindings b = e.createBindings();
  27.282 +            final ScriptContext ctxt = new SimpleScriptContext();
  27.283 +            ctxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
  27.284 +
  27.285 +            e.eval(new URLReader(ScopeTest.class.getResource("resources/witheval.js")), ctxt);
  27.286 +            assertEquals(e.eval("a", ctxt), 1);
  27.287 +            assertEquals(b.get("a"), 1);
  27.288 +            assertEquals(e.eval("b", ctxt), 3);
  27.289 +            assertEquals(b.get("b"), 3);
  27.290 +            assertEquals(e.eval("c", ctxt), 10);
  27.291 +            assertEquals(b.get("c"), 10);
  27.292 +        }
  27.293 +    }
  27.294 +
  27.295 +    private static class ScriptRunner implements Runnable {
  27.296 +
  27.297 +        final ScriptEngine engine;
  27.298 +        final ScriptContext context;
  27.299 +        final String source;
  27.300 +        final Object expected;
  27.301 +        final int iterations;
  27.302 +
  27.303 +        ScriptRunner(final ScriptEngine engine, final ScriptContext context, final String source, final Object expected, final int iterations) {
  27.304 +            this.engine = engine;
  27.305 +            this.context = context;
  27.306 +            this.source = source;
  27.307 +            this.expected = expected;
  27.308 +            this.iterations = iterations;
  27.309 +        }
  27.310 +
  27.311 +        @Override
  27.312 +        public void run() {
  27.313 +            try {
  27.314 +                for (int i = 0; i < iterations; i++) {
  27.315 +                    assertEquals(engine.eval(source, context), expected);
  27.316 +                }
  27.317 +            } catch (ScriptException se) {
  27.318 +                throw new RuntimeException(se);
  27.319 +            }
  27.320 +        }
  27.321 +    }
  27.322 +
  27.323  }
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/test/src/jdk/nashorn/api/scripting/resources/func.js	Wed Mar 12 11:26:00 2014 +0100
    28.3 @@ -0,0 +1,42 @@
    28.4 +/*
    28.5 + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
    28.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    28.7 + *
    28.8 + * This code is free software; you can redistribute it and/or modify it
    28.9 + * under the terms of the GNU General Public License version 2 only, as
   28.10 + * published by the Free Software Foundation.  Oracle designates this
   28.11 + * particular file as subject to the "Classpath" exception as provided
   28.12 + * by Oracle in the LICENSE file that accompanied this code.
   28.13 + *
   28.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   28.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   28.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   28.17 + * version 2 for more details (a copy is included in the LICENSE file that
   28.18 + * accompanied this code).
   28.19 + *
   28.20 + * You should have received a copy of the GNU General Public License version
   28.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   28.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   28.23 + *
   28.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   28.25 + * or visit www.oracle.com if you need additional information or have any
   28.26 + * questions.
   28.27 + */
   28.28 +
   28.29 +// This script is loaded from jdk.nashorn.api.scripting.ScopeTest to test script class sharing and reuse.
   28.30 +
   28.31 +var scopeVar = 1;
   28.32 +var global = this;
   28.33 +undefGlobal = this;
   28.34 +
   28.35 +function scopeTest() {
   28.36 +    if (this !== global) {
   28.37 +        throw new Error("this !== global");
   28.38 +    }
   28.39 +    if (this !== undefGlobal) {
   28.40 +        throw new Error("this !== undefinedGlobal")
   28.41 +    }
   28.42 +    return scopeVar;
   28.43 +}
   28.44 +
   28.45 +scopeTest();
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/test/src/jdk/nashorn/api/scripting/resources/gettersetter.js	Wed Mar 12 11:26:00 2014 +0100
    29.3 @@ -0,0 +1,38 @@
    29.4 +/*
    29.5 + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
    29.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    29.7 + *
    29.8 + * This code is free software; you can redistribute it and/or modify it
    29.9 + * under the terms of the GNU General Public License version 2 only, as
   29.10 + * published by the Free Software Foundation.  Oracle designates this
   29.11 + * particular file as subject to the "Classpath" exception as provided
   29.12 + * by Oracle in the LICENSE file that accompanied this code.
   29.13 + *
   29.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   29.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   29.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   29.17 + * version 2 for more details (a copy is included in the LICENSE file that
   29.18 + * accompanied this code).
   29.19 + *
   29.20 + * You should have received a copy of the GNU General Public License version
   29.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   29.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   29.23 + *
   29.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   29.25 + * or visit www.oracle.com if you need additional information or have any
   29.26 + * questions.
   29.27 + */
   29.28 +
   29.29 +// This script is loaded from jdk.nashorn.api.scripting.ScopeTest to test script class sharing and reuse.
   29.30 +
   29.31 +var v;
   29.32 +
   29.33 +Object.defineProperty(this, "accessor1", {
   29.34 +    get: function() { return v; },
   29.35 +    set: function(n) { v = n; }
   29.36 +});
   29.37 +
   29.38 +Object.defineProperty(this, "accessor2", {
   29.39 +    get: function() { return x; },
   29.40 +    set: function(n) { x = n; }
   29.41 +});
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/test/src/jdk/nashorn/api/scripting/resources/witheval.js	Wed Mar 12 11:26:00 2014 +0100
    30.3 @@ -0,0 +1,60 @@
    30.4 +/*
    30.5 + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
    30.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    30.7 + *
    30.8 + * This code is free software; you can redistribute it and/or modify it
    30.9 + * under the terms of the GNU General Public License version 2 only, as
   30.10 + * published by the Free Software Foundation.  Oracle designates this
   30.11 + * particular file as subject to the "Classpath" exception as provided
   30.12 + * by Oracle in the LICENSE file that accompanied this code.
   30.13 + *
   30.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   30.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   30.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   30.17 + * version 2 for more details (a copy is included in the LICENSE file that
   30.18 + * accompanied this code).
   30.19 + *
   30.20 + * You should have received a copy of the GNU General Public License version
   30.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   30.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   30.23 + *
   30.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   30.25 + * or visit www.oracle.com if you need additional information or have any
   30.26 + * questions.
   30.27 + */
   30.28 +
   30.29 +// This script is loaded from jdk.nashorn.api.scripting.ScopeTest to test script class sharing and reuse.
   30.30 +
   30.31 +var a;
   30.32 +
   30.33 +function outer(p, e) {
   30.34 +    eval(e);
   30.35 +    with(p) {
   30.36 +        function inner() {
   30.37 +            a = 1;
   30.38 +            c = 10;
   30.39 +            if (a !== 1) {
   30.40 +                throw new Error("a !== 1");
   30.41 +            }
   30.42 +            if (b !== 3) {
   30.43 +                throw new Error("b !== 3");
   30.44 +            }
   30.45 +            if (c !== 10) {
   30.46 +                throw new Error("c !== 10");
   30.47 +            }
   30.48 +        }
   30.49 +        inner();
   30.50 +    }
   30.51 +}
   30.52 +
   30.53 +outer({}, "b = 3;");
   30.54 +
   30.55 +if (a !== 1) {
   30.56 +    throw new Error("a !== 1");
   30.57 +}
   30.58 +if (b !== 3) {
   30.59 +    throw new Error("b !== 3");
   30.60 +}
   30.61 +if (c !== 10) {
   30.62 +    throw new Error("c !== 10");
   30.63 +}

mercurial