8006766: Array-like access to characters of a string is slow
authorhannesw
Fri, 25 Jan 2013 17:35:31 +0100
changeset 16195 3f6c0ab2597a
parent 16194 3d0b930f4b47
child 16196 58f6f046bb5e
8006766: Array-like access to characters of a string is slow Reviewed-by: lagergren, attila
nashorn/src/jdk/nashorn/internal/objects/Global.java
nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java
nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java
nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java
nashorn/src/jdk/nashorn/internal/objects/NativeString.java
nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java
nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
nashorn/src/jdk/nashorn/internal/runtime/WithObject.java
nashorn/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
nashorn/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java
nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
--- a/nashorn/src/jdk/nashorn/internal/objects/Global.java	Thu Jan 24 22:38:58 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java	Fri Jan 25 17:35:31 2013 +0100
@@ -55,9 +55,9 @@
 import jdk.nashorn.internal.runtime.ScriptingFunctions;
 import jdk.nashorn.internal.runtime.Source;
 import jdk.nashorn.internal.runtime.linker.InvokeByName;
-import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
 import jdk.nashorn.internal.scripts.JO$;
 import org.dynalang.dynalink.linker.GuardedInvocation;
+import org.dynalang.dynalink.linker.LinkRequest;
 
 /**
  * Representation of global scope.
@@ -427,22 +427,19 @@
         } else if (obj instanceof Boolean) {
             return NativeBoolean.WRAPFILTER;
         }
-        throw new IllegalArgumentException("Unsupported primitive value: " + obj);
+        throw new IllegalArgumentException("Unsupported primitive: " + obj);
     }
 
     @Override
-    public GuardedInvocation numberLookup(final NashornCallSiteDescriptor callSite, final Number self) {
-        return NativeNumber.lookupPrimitive(callSite, self);
-    }
-
-    @Override
-    public GuardedInvocation stringLookup(final NashornCallSiteDescriptor callSite, final CharSequence self) {
-        return NativeString.lookupPrimitive(callSite, self);
-    }
-
-    @Override
-    public GuardedInvocation booleanLookup(final NashornCallSiteDescriptor callSite, final Boolean self) {
-        return NativeBoolean.lookupPrimitive(callSite, self);
+    public GuardedInvocation primitiveLookup(final LinkRequest request, final Object self) {
+        if (self instanceof String || self instanceof ConsString) {
+            return NativeString.lookupPrimitive(request, self);
+        } else if (self instanceof Number) {
+            return NativeNumber.lookupPrimitive(request, self);
+        } else if (self instanceof Boolean) {
+            return NativeBoolean.lookupPrimitive(request, self);
+        }
+        throw new IllegalArgumentException("Unsupported primitive: " + self);
     }
 
     @Override
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java	Thu Jan 24 22:38:58 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java	Fri Jan 25 17:35:31 2013 +0100
@@ -38,9 +38,9 @@
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.linker.MethodHandleFactory;
-import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
 import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
 import org.dynalang.dynalink.linker.GuardedInvocation;
+import org.dynalang.dynalink.linker.LinkRequest;
 
 /**
  * ECMA 15.6 Boolean Objects.
@@ -153,12 +153,12 @@
     /**
      * Lookup the appropriate method for an invoke dynamic call.
      *
-     * @param desc     The invoke dynamic callsite descriptor.
+     * @param request  The link request
      * @param receiver The receiver for the call
      * @return Link to be invoked at call site.
      */
-    public static GuardedInvocation lookupPrimitive(final NashornCallSiteDescriptor desc, final Object receiver) {
-        return PrimitiveLookup.lookupPrimitive(desc, Boolean.class, new NativeBoolean((Boolean)receiver), WRAPFILTER);
+    public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
+        return PrimitiveLookup.lookupPrimitive(request, Boolean.class, new NativeBoolean((Boolean)receiver), WRAPFILTER);
     }
 
     /**
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Thu Jan 24 22:38:58 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Fri Jan 25 17:35:31 2013 +0100
@@ -47,6 +47,7 @@
 import jdk.nashorn.internal.runtime.linker.MethodHandleFactory;
 import org.dynalang.dynalink.CallSiteDescriptor;
 import org.dynalang.dynalink.linker.GuardedInvocation;
+import org.dynalang.dynalink.linker.LinkRequest;
 
 /**
  * This class is the implementation of the Nashorn-specific global object named {@code JSAdapter}. It can be
@@ -580,10 +581,10 @@
     }
 
     @Override
-    protected GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final boolean megaMorphic) {
+    protected GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         if (overrides && super.hasOwnProperty(desc.getNameToken(2))) {
             try {
-                final GuardedInvocation inv = super.findCallMethodMethod(desc, megaMorphic);
+                final GuardedInvocation inv = super.findCallMethodMethod(desc, request);
                 if (inv != null) {
                     return inv;
                 }
@@ -596,11 +597,11 @@
     }
 
     @Override
-    protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final boolean megaMorphic, final String operation) {
+    protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operation) {
         final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
         if (overrides && super.hasOwnProperty(name)) {
             try {
-                final GuardedInvocation inv = super.findGetMethod(desc, megaMorphic, operation);
+                final GuardedInvocation inv = super.findGetMethod(desc, request, operation);
                 if (inv != null) {
                     return inv;
                 }
@@ -633,10 +634,10 @@
     }
 
     @Override
-    protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final boolean megaMorphic) {
+    protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         if (overrides && super.hasOwnProperty(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND))) {
             try {
-                final GuardedInvocation inv = super.findSetMethod(desc, megaMorphic);
+                final GuardedInvocation inv = super.findSetMethod(desc, request);
                 if (inv != null) {
                     return inv;
                 }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java	Thu Jan 24 22:38:58 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java	Fri Jan 25 17:35:31 2013 +0100
@@ -34,6 +34,7 @@
 import org.dynalang.dynalink.CallSiteDescriptor;
 import org.dynalang.dynalink.beans.StaticClass;
 import org.dynalang.dynalink.linker.GuardedInvocation;
+import org.dynalang.dynalink.linker.LinkRequest;
 
 /**
  * This is "JavaImporter" constructor. This constructor allows you to use Java types omitting explicit package names.
@@ -107,13 +108,13 @@
     }
 
     @Override
-    public GuardedInvocation noSuchProperty(final CallSiteDescriptor desc) {
-        return createAndSetProperty(desc) ? super.lookup(desc) : super.noSuchProperty(desc);
+    public GuardedInvocation noSuchProperty(final CallSiteDescriptor desc, final LinkRequest request) {
+        return createAndSetProperty(desc) ? super.lookup(desc, request) : super.noSuchProperty(desc, request);
     }
 
     @Override
-    public GuardedInvocation noSuchMethod(final CallSiteDescriptor desc) {
-        return createAndSetProperty(desc) ? super.lookup(desc) : super.noSuchMethod(desc);
+    public GuardedInvocation noSuchMethod(final CallSiteDescriptor desc, final LinkRequest request) {
+        return createAndSetProperty(desc) ? super.lookup(desc, request) : super.noSuchMethod(desc, request);
     }
 
     private boolean createAndSetProperty(final CallSiteDescriptor desc) {
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java	Thu Jan 24 22:38:58 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java	Fri Jan 25 17:35:31 2013 +0100
@@ -46,9 +46,9 @@
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.linker.MethodHandleFactory;
-import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
 import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
 import org.dynalang.dynalink.linker.GuardedInvocation;
+import org.dynalang.dynalink.linker.LinkRequest;
 
 /**
  * ECMA 15.7 Number Objects.
@@ -317,12 +317,12 @@
 
     /**
      * Lookup the appropriate method for an invoke dynamic call.
-     * @param desc The call site descriptor.
+     * @param request  The link request
      * @param receiver receiver of call
      * @return Link to be invoked at call site.
      */
-    public static GuardedInvocation lookupPrimitive(final NashornCallSiteDescriptor desc, final Object receiver) {
-        return PrimitiveLookup.lookupPrimitive(desc, Number.class, new NativeNumber(((Number)receiver).doubleValue()), WRAPFILTER);
+    public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
+        return PrimitiveLookup.lookupPrimitive(request, Number.class, new NativeNumber(((Number)receiver).doubleValue()), WRAPFILTER);
     }
 
     @SuppressWarnings("unused")
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java	Thu Jan 24 22:38:58 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java	Fri Jan 25 17:35:31 2013 +0100
@@ -55,10 +55,11 @@
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
 import jdk.nashorn.internal.runtime.linker.MethodHandleFactory;
-import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
 import jdk.nashorn.internal.runtime.linker.NashornGuards;
 import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
+import org.dynalang.dynalink.CallSiteDescriptor;
 import org.dynalang.dynalink.linker.GuardedInvocation;
+import org.dynalang.dynalink.linker.LinkRequest;
 
 
 /**
@@ -123,6 +124,59 @@
         return value.length();
     }
 
+    // This is to provide array-like access to string characters without creating a NativeString wrapper.
+    @Override
+    protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
+        final Object self = request.getReceiver();
+        final Class<?> returnType = desc.getMethodType().returnType();
+
+        if (returnType == Object.class && (self instanceof String || self instanceof ConsString)) {
+            try {
+                MethodHandle mh = MethodHandles.lookup().findStatic(NativeString.class, "get", desc.getMethodType());
+                return new GuardedInvocation(mh, NashornGuards.getInstanceOf2Guard(String.class, ConsString.class));
+            } catch (final NoSuchMethodException | IllegalAccessException e) {
+                // Shouldn't happen. Fall back to super
+            }
+        }
+        return super.findGetIndexMethod(desc, request);
+    }
+
+    @SuppressWarnings("unused")
+    private static Object get(final Object self, final Object key) {
+        final CharSequence cs = JSType.toCharSequence(self);
+        final int index = getArrayIndexNoThrow(key);
+        if (index >= 0 && index < cs.length()) {
+            return String.valueOf(cs.charAt(index));
+        }
+        return ((ScriptObject) Global.toObject(self)).get(key);
+    }
+
+    @SuppressWarnings("unused")
+    private static Object get(final Object self, final double key) {
+        if (isRepresentableAsInt(key)) {
+            return get(self, (int)key);
+        }
+        return ((ScriptObject) Global.toObject(self)).get(key);
+    }
+
+    @SuppressWarnings("unused")
+    private static Object get(final Object self, final long key) {
+        final CharSequence cs = JSType.toCharSequence(self);
+        if (key >= 0 && key < cs.length()) {
+            return String.valueOf(cs.charAt((int)key));
+        }
+        return ((ScriptObject) Global.toObject(self)).get(key);
+    }
+
+    @SuppressWarnings("unused")
+    private static Object get(final Object self, final int key) {
+        final CharSequence cs = JSType.toCharSequence(self);
+        if (key >= 0 && key < cs.length()) {
+            return String.valueOf(cs.charAt(key));
+        }
+        return ((ScriptObject) Global.toObject(self)).get(key);
+    }
+
     // String characters can be accessed with array-like indexing..
     @Override
     public Object get(final Object key) {
@@ -1066,13 +1120,13 @@
     /**
      * Lookup the appropriate method for an invoke dynamic call.
      *
-     * @param desc the call site descriptor
+     * @param request  the link request
      * @param receiver receiver of call
      * @return Link to be invoked at call site.
      */
-    public static GuardedInvocation lookupPrimitive(final NashornCallSiteDescriptor desc, final Object receiver) {
+    public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
         final MethodHandle guard = NashornGuards.getInstanceOf2Guard(String.class, ConsString.class);
-        return PrimitiveLookup.lookupPrimitive(desc, guard, new NativeString((CharSequence)receiver), WRAPFILTER);
+        return PrimitiveLookup.lookupPrimitive(request, guard, new NativeString((CharSequence)receiver), WRAPFILTER);
     }
 
     @SuppressWarnings("unused")
--- a/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java	Thu Jan 24 22:38:58 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java	Fri Jan 25 17:35:31 2013 +0100
@@ -26,8 +26,8 @@
 package jdk.nashorn.internal.runtime;
 
 import java.lang.invoke.MethodHandle;
-import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
 import org.dynalang.dynalink.linker.GuardedInvocation;
+import org.dynalang.dynalink.linker.LinkRequest;
 
 /**
  * Runtime interface to the global scope of the current context.
@@ -79,34 +79,15 @@
    public MethodHandle getWrapFilter(Object obj);
 
     /**
-     * Wrapper for {@link jdk.nashorn.internal.objects.Global#numberLookup(NashornCallSiteDescriptor, Number)}
+     * Wrapper for {@link jdk.nashorn.internal.objects.Global#primitiveLookup(LinkRequest, Object)}
      *
-     * @param callSite call site descriptor
+     * @param request the link request for the dynamic call site.
      * @param self     self reference
      *
      * @return guarded invocation
      */
-   public GuardedInvocation numberLookup(NashornCallSiteDescriptor callSite, Number self);
+   public GuardedInvocation primitiveLookup(LinkRequest request, Object self);
 
-    /**
-     * Wrapper for {@link jdk.nashorn.internal.objects.Global#stringLookup(NashornCallSiteDescriptor, CharSequence)}
-     *
-     * @param callSite call site descriptor
-     * @param self     self reference
-     *
-     * @return guarded invocation
-     */
-   public GuardedInvocation stringLookup(NashornCallSiteDescriptor callSite, CharSequence self);
-
-    /**
-     * Wrapper for {@link jdk.nashorn.internal.objects.Global#booleanLookup(NashornCallSiteDescriptor, Boolean)}
-     *
-     * @param callSite call site descriptor
-     * @param self     self reference
-     *
-     * @return guarded invocation
-     */
-   public GuardedInvocation booleanLookup(NashornCallSiteDescriptor callSite, Boolean self);
 
     /**
      * Wrapper for {@link jdk.nashorn.internal.objects.Global#newObject()}
--- a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java	Thu Jan 24 22:38:58 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java	Fri Jan 25 17:35:31 2013 +0100
@@ -31,6 +31,7 @@
 import org.dynalang.dynalink.CallSiteDescriptor;
 import org.dynalang.dynalink.beans.StaticClass;
 import org.dynalang.dynalink.linker.GuardedInvocation;
+import org.dynalang.dynalink.linker.LinkRequest;
 
 /**
  * An object that exposes Java packages and classes as its properties. Packages are exposed as objects that have further
@@ -155,10 +156,11 @@
     /**
      * Handle creation of new attribute.
      * @param desc the call site descriptor
+     * @param request the link request
      * @return Link to be invoked at call site.
      */
     @Override
-    public GuardedInvocation noSuchProperty(final CallSiteDescriptor desc) {
+    public GuardedInvocation noSuchProperty(final CallSiteDescriptor desc, final LinkRequest request) {
         final String propertyName = desc.getNameToken(2);
         final String fullName     = name.isEmpty() ? propertyName : name + "." + propertyName;
 
@@ -178,12 +180,12 @@
             set(propertyName, StaticClass.forClass(javaClass), strict);
         }
 
-        return super.lookup(desc);
+        return super.lookup(desc, request);
     }
 
     @Override
-    public GuardedInvocation noSuchMethod(final CallSiteDescriptor desc) {
-        return noSuchProperty(desc);
+    public GuardedInvocation noSuchMethod(final CallSiteDescriptor desc, final LinkRequest request) {
+        return noSuchProperty(desc, request);
     }
 
 }
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Thu Jan 24 22:38:58 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Fri Jan 25 17:35:31 2013 +0100
@@ -45,6 +45,7 @@
 import jdk.nashorn.internal.runtime.options.Options;
 import org.dynalang.dynalink.CallSiteDescriptor;
 import org.dynalang.dynalink.linker.GuardedInvocation;
+import org.dynalang.dynalink.linker.LinkRequest;
 
 /**
  * Runtime representation of a JavaScript function.
@@ -907,15 +908,15 @@
      *   (4) for normal this-calls, drop callee.
      */
     @Override
-    protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final boolean megaMorphic) {
+    protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         final MethodType type = desc.getMethodType();
 
-        if(megaMorphic) {
+        if (request.isCallSiteUnstable()) {
             // (this, callee, args...) => (this, callee, args[])
             final MethodHandle collector = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class,
                     type.parameterCount() - 2);
 
-            return new GuardedInvocation(collector,
+            return new GuardedInvocation(addPrimitiveWrap(collector, desc, request),
                     desc.getMethodType().parameterType(0) == ScriptFunction.class ? null : NashornGuards.getScriptFunctionGuard());
         }
 
@@ -938,6 +939,8 @@
                 assert reorder[1] == 0;
                 final MethodType newType = oldType.changeParameterType(0, oldType.parameterType(1)).changeParameterType(1, oldType.parameterType(0));
                 boundHandle = MethodHandles.permuteArguments(callHandle, newType, reorder);
+                // thiz argument may be a JS primitive needing a wrapper
+                boundHandle = addPrimitiveWrap(boundHandle, desc, request);
             }
         } else {
             final MethodHandle callHandle = getBestSpecializedInvokeHandle(type.dropParameterTypes(0, 1));
@@ -977,6 +980,23 @@
         return pairArguments(methodHandle, type);
     }
 
+    private MethodHandle addPrimitiveWrap(final MethodHandle mh, final CallSiteDescriptor desc, final LinkRequest request) {
+        // Check whether thiz is a JS primitive type and needs an object wrapper for non-strict function
+        if (!NashornCallSiteDescriptor.isScope(desc) && isNonStrictFunction()) {
+            Object self = request.getArguments()[1];
+            if (isPrimitiveThis(self)) {
+                MethodHandle wrapFilter = ((GlobalObject) Context.getGlobalTrusted()).getWrapFilter(self);
+                return MH.filterArguments(mh, 1, MH.asType(wrapFilter, wrapFilter.type().changeReturnType(Object.class)));
+            }
+        }
+        return mh;
+    }
+
+    private static boolean isPrimitiveThis(Object obj) {
+        return obj instanceof String || obj instanceof ConsString ||
+               obj instanceof Number || obj instanceof Boolean;
+    }
+
     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
         final Class<?>   own = ScriptFunction.class;
         final MethodType mt  = MH.type(rtype, types);
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Jan 24 22:38:58 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java	Fri Jan 25 17:35:31 2013 +0100
@@ -68,6 +68,7 @@
 import jdk.nashorn.internal.runtime.linker.NashornGuards;
 import org.dynalang.dynalink.CallSiteDescriptor;
 import org.dynalang.dynalink.linker.GuardedInvocation;
+import org.dynalang.dynalink.linker.LinkRequest;
 import org.dynalang.dynalink.support.CallSiteDescriptorFactory;
 
 /**
@@ -1506,22 +1507,11 @@
      * with the appropriate guard(s).
      *
      * @param desc call site descriptor
+     * @param request the link request
      *
      * @return GuardedInvocation for the callsite
      */
-    public final GuardedInvocation lookup(final CallSiteDescriptor desc) {
-        return lookup(desc, false);
-    }
-
-    /**
-     * Lookup the appropriate method for an invoke dynamic call.
-     *
-     * @param desc The descriptor of the call site.
-     * @param megaMorphic if the call site is considered megamorphic
-     *
-     * @return GuardedInvocation to be invoked at call site.
-     */
-    public GuardedInvocation lookup(final CallSiteDescriptor desc, final boolean megaMorphic) {
+    public GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request) {
         final int c = desc.getNameTokenCount();
         // JavaScript is "immune" to all currently defined Dynalink composite operation - getProp is the same as getElem
         // is the same as getMethod as JavaScript objects have a single namespace for all three. Therefore, we don't
@@ -1535,16 +1525,16 @@
         case "getProp":
         case "getElem":
         case "getMethod":
-            return c > 2 ? findGetMethod(desc, megaMorphic, operator) : findGetIndexMethod(desc);
+            return c > 2 ? findGetMethod(desc, request, operator) : findGetIndexMethod(desc, request);
         case "setProp":
         case "setElem":
-            return c > 2 ? findSetMethod(desc, megaMorphic) : findSetIndexMethod(desc);
+            return c > 2 ? findSetMethod(desc, request) : findSetIndexMethod(desc);
         case "call":
-            return findCallMethod(desc, megaMorphic);
+            return findCallMethod(desc, request);
         case "new":
             return findNewMethod(desc);
         case "callMethod":
-            return findCallMethodMethod(desc, megaMorphic);
+            return findCallMethodMethod(desc, request);
         default:
             return null;
         }
@@ -1565,12 +1555,12 @@
      * Find the appropriate CALL method for an invoke dynamic call.
      * This generates "not a function" always
      *
-     * @param desc        the call site descriptor.
-     * @param megaMorphic is this call site megaMorphic, as reported by Dynalink - then just do apply
+     * @param desc    the call site descriptor.
+     * @param request the link request
      *
      * @return GuardedInvocation to be invoed at call site.
      */
-    protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final boolean megaMorphic) {
+    protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         return notAFunction();
     }
 
@@ -1585,17 +1575,17 @@
      * one for "dyn:call". Explicit support for "dyn:callMethod" is provided for the benefit of potential external
      * callers. The implementation itself actually folds a "dyn:getMethod" method handle into a "dyn:call" method handle.
      *
-     * @param desc The call site descriptor.
-     * @param megaMorphic is this call site megaMorphic, as reported by Dynalink - then just do apply
+     * @param desc    the call site descriptor.
+     * @param request the link request
      *
      * @return GuardedInvocation to be invoked at call site.
      */
-    protected GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final boolean megaMorphic) {
+    protected GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         // R(P0, P1, ...)
         final MethodType callType = desc.getMethodType();
         // use type Object(P0) for the getter
         final CallSiteDescriptor getterType = desc.changeMethodType(MethodType.methodType(Object.class, callType.parameterType(0)));
-        final GuardedInvocation getter = findGetMethod(getterType, megaMorphic, "getMethod");
+        final GuardedInvocation getter = findGetMethod(getterType, request, "getMethod");
 
         // Object(P0) => Object(P0, P1, ...)
         final MethodHandle argDroppingGetter = MH.dropArguments(getter.getInvocation(), 1, callType.parameterList().subList(1, callType.parameterCount()));
@@ -1608,16 +1598,16 @@
     /**
      * Find the appropriate GET method for an invoke dynamic call.
      *
-     * @param desc         the call site descriptor
-     * @param megaMorphic  is this call site megaMorphic, as reported by Dynalink - then just do apply
-     * @param operator     operator for get: getProp, getMethod, getElem etc
+     * @param desc     the call site descriptor
+     * @param request  the link request
+     * @param operator operator for get: getProp, getMethod, getElem etc
      *
      * @return GuardedInvocation to be invoked at call site.
      */
-    protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final boolean megaMorphic, final String operator) {
+    protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
         final String name = desc.getNameToken(2);
 
-        if (megaMorphic) {
+        if (request.isCallSiteUnstable()) {
             return findMegaMorphicGetMethod(desc, name);
         }
 
@@ -1627,9 +1617,9 @@
 
         if (find == null) {
             if ("getProp".equals(operator)) {
-                return noSuchProperty(desc);
+                return noSuchProperty(desc, request);
             } else if ("getMethod".equals(operator)) {
-                return noSuchMethod(desc);
+                return noSuchMethod(desc, request);
             } else if ("getElem".equals(operator)) {
                 return createEmptyGetter(desc, name);
             }
@@ -1673,11 +1663,12 @@
     /**
      * Find the appropriate GETINDEX method for an invoke dynamic call.
      *
-     * @param desc the call site descriptor
+     * @param desc    the call site descriptor
+     * @param request the link request
      *
      * @return GuardedInvocation to be invoked at call site.
      */
-    private static GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc) {
+    protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         return findGetIndexMethod(desc.getMethodType());
     }
 
@@ -1708,14 +1699,14 @@
     /**
      * Find the appropriate SET method for an invoke dynamic call.
      *
-     * @param desc the call site descriptor
-     * @param megaMorphic  is this call site megaMorphic, as reported by Dynalink - then just do apply
+     * @param desc    the call site descriptor
+     * @param request the link request
      *
      * @return GuardedInvocation to be invoked at call site.
      */
-    protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final boolean megaMorphic) {
+    protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
-        if(megaMorphic) {
+        if(request.isCallSiteUnstable()) {
             return findMegaMorphicSetMethod(desc, name);
         }
 
@@ -1861,9 +1852,10 @@
     /**
      * Fall back if a function property is not found.
      * @param desc The call site descriptor
+     * @param request the link request
      * @return GuardedInvocation to be invoked at call site.
      */
-    public GuardedInvocation noSuchMethod(final CallSiteDescriptor desc) {
+    public GuardedInvocation noSuchMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         final String       name      = desc.getNameToken(2);
         final FindProperty find      = findProperty(NO_SUCH_METHOD_NAME, true);
         final boolean      scopeCall = isScope() && NashornCallSiteDescriptor.isScope(desc);
@@ -1887,9 +1879,10 @@
     /**
      * Fall back if a property is not found.
      * @param desc the call site descriptor.
+     * @param request the link request
      * @return GuardedInvocation to be invoked at call site.
      */
-    public GuardedInvocation noSuchProperty(final CallSiteDescriptor desc) {
+    public GuardedInvocation noSuchProperty(final CallSiteDescriptor desc, final LinkRequest request) {
         final String name = desc.getNameToken(2);
         final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
         final boolean scopeAccess = isScope() && NashornCallSiteDescriptor.isScope(desc);
--- a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java	Thu Jan 24 22:38:58 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java	Fri Jan 25 17:35:31 2013 +0100
@@ -32,6 +32,7 @@
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
 import org.dynalang.dynalink.CallSiteDescriptor;
 import org.dynalang.dynalink.linker.GuardedInvocation;
+import org.dynalang.dynalink.linker.LinkRequest;
 import org.dynalang.dynalink.support.CallSiteDescriptorFactory;
 
 
@@ -86,7 +87,7 @@
 
 
     @Override
-    public GuardedInvocation lookup(final CallSiteDescriptor desc, final boolean megaMorphic) {
+    public GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request) {
         // With scopes can never be observed outside of Nashorn code, so all call sites that can address it will of
         // necessity have a Nashorn descriptor - it is safe to cast.
         final NashornCallSiteDescriptor ndesc = (NashornCallSiteDescriptor)desc;
@@ -111,7 +112,7 @@
             }
 
             if (find != null) {
-                link = self.lookup(desc);
+                link = self.lookup(desc, request);
 
                 if (link != null) {
                     return fixExpressionCallSite(ndesc, link);
@@ -125,7 +126,7 @@
         }
 
         if (find != null) {
-            return fixScopeCallSite(scope.lookup(desc));
+            return fixScopeCallSite(scope.lookup(desc, request));
         }
 
         // the property is not found - now check for
@@ -155,11 +156,11 @@
                 if (find != null) {
                     switch (operator) {
                     case "getMethod":
-                        link = self.noSuchMethod(desc);
+                        link = self.noSuchMethod(desc, request);
                         break;
                     case "getProp":
                     case "getElem":
-                        link = self.noSuchProperty(desc);
+                        link = self.noSuchProperty(desc, request);
                         break;
                     default:
                         break;
@@ -174,7 +175,7 @@
 
         // still not found, may be scope can handle with it's own
         // __noSuchProperty__, __noSuchMethod__ etc.
-        link = scope.lookup(desc);
+        link = scope.lookup(desc, request);
 
         if (link != null) {
             return fixScopeCallSite(link);
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java	Thu Jan 24 22:38:58 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java	Fri Jan 25 17:35:31 2013 +0100
@@ -30,9 +30,6 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 
-import jdk.nashorn.internal.runtime.ConsString;
-import jdk.nashorn.internal.runtime.Context;
-import jdk.nashorn.internal.runtime.GlobalObject;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.Undefined;
@@ -75,23 +72,9 @@
             return null;
         }
 
-        GuardedInvocation inv;
+        final GuardedInvocation inv;
         if (self instanceof ScriptObject) {
-            inv = ((ScriptObject)self).lookup(desc, request.isCallSiteUnstable());
-
-            if (self instanceof ScriptFunction && "call".equals(desc.getNameToken(CallSiteDescriptor.OPERATOR))) {
-
-                // Add toObject wrapper for non-object self argument to non-strict functions
-                assert request.getArguments().length >= 2 : "No self argument in script function callsite";
-                Object thisObject = request.getArguments()[1];
-                // Add wrapper filter for primitive this-object on non-strict functions
-                if (NashornGuardedInvocation.isNonStrict(inv) && isPrimitive(thisObject)) {
-                    MethodHandle wrapFilter = ((GlobalObject) Context.getGlobal()).getWrapFilter(thisObject);
-                    MethodHandle invocation = MH.filterArguments(inv.getInvocation(), 1,
-                            MH.asType(wrapFilter, wrapFilter.type().changeReturnType(Object.class)));
-                    inv = new GuardedInvocation(invocation, inv.getSwitchPoint(), inv.getGuard());
-                }
-            }
+            inv = ((ScriptObject)self).lookup(desc, request);
         } else if (self instanceof Undefined) {
             inv = Undefined.lookup(desc);
         } else {
@@ -153,13 +136,6 @@
                 JavaAdapterFactory.isAutoConvertibleFromFunction(clazz);
     }
 
-    private static boolean isPrimitive(Object obj) {
-        return obj instanceof Boolean ||
-               obj instanceof Number ||
-               obj instanceof String ||
-               obj instanceof ConsString;
-    }
-
     @Override
     public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
         if(ScriptObject.class.isAssignableFrom(sourceType)) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java	Thu Jan 24 22:38:58 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java	Fri Jan 25 17:35:31 2013 +0100
@@ -64,14 +64,7 @@
         final GlobalObject global = (GlobalObject) Context.getGlobal();
         final NashornCallSiteDescriptor desc = (NashornCallSiteDescriptor) request.getCallSiteDescriptor();
 
-        if (self instanceof Number) {
-            return Bootstrap.asType(global.numberLookup(desc, (Number) self), linkerServices, desc);
-        } else if (self instanceof String || self instanceof ConsString) {
-           return Bootstrap.asType(global.stringLookup(desc, (CharSequence) self), linkerServices, desc);
-        } else if (self instanceof Boolean) {
-            return Bootstrap.asType(global.booleanLookup(desc, (Boolean) self), linkerServices, desc);
-        }
-        throw new AssertionError(); // Can't reach here
+        return Bootstrap.asType(global.primitiveLookup(request, self), linkerServices, desc);
     }
 
     /**
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Thu Jan 24 22:38:58 2013 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Fri Jan 25 17:35:31 2013 +0100
@@ -32,6 +32,7 @@
 import jdk.nashorn.internal.runtime.ScriptObject;
 import org.dynalang.dynalink.CallSiteDescriptor;
 import org.dynalang.dynalink.linker.GuardedInvocation;
+import org.dynalang.dynalink.linker.LinkRequest;
 import org.dynalang.dynalink.support.CallSiteDescriptorFactory;
 import org.dynalang.dynalink.support.Guards;
 
@@ -47,7 +48,7 @@
 
     /**
      * Returns a guarded invocation representing the linkage for a dynamic operation on a primitive Java value.
-     * @param desc the descriptor of the call site identifying the dynamic operation.
+     * @param request the link request for the dynamic call site.
      * @param receiverClass the class of the receiver value (e.g., {@link java.lang.Boolean}, {@link java.lang.String} etc.)
      * @param wrappedReceiver a transient JavaScript native wrapper object created as the object proxy for the primitive
      * value; see ECMAScript 5.1, section 8.7.1 for discussion of using {@code [[Get]]} on a property reference with a
@@ -58,14 +59,14 @@
      * @return a guarded invocation representing the operation at the call site when performed on a JavaScript primitive
      * type {@code receiverClass}.
      */
-    public static GuardedInvocation lookupPrimitive(final CallSiteDescriptor desc, final Class<?> receiverClass,
+    public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Class<?> receiverClass,
                                                     final ScriptObject wrappedReceiver, final MethodHandle wrapFilter) {
-        return lookupPrimitive(desc, Guards.getInstanceOfGuard(receiverClass), wrappedReceiver, wrapFilter);
+        return lookupPrimitive(request, Guards.getInstanceOfGuard(receiverClass), wrappedReceiver, wrapFilter);
     }
 
     /**
      * Returns a guarded invocation representing the linkage for a dynamic operation on a primitive Java value.
-     * @param desc the descriptor of the call site identifying the dynamic operation.
+     * @param request the link request for the dynamic call site.
      * @param guard an explicit guard that will be used for the returned guarded invocation.
      * @param wrappedReceiver a transient JavaScript native wrapper object created as the object proxy for the primitive
      * value; see ECMAScript 5.1, section 8.7.1 for discussion of using {@code [[Get]]} on a property reference with a
@@ -76,12 +77,17 @@
      * @return a guarded invocation representing the operation at the call site when performed on a JavaScript primitive
      * type (that is implied by both {@code guard} and {@code wrappedReceiver}).
      */
-    public static GuardedInvocation lookupPrimitive(final CallSiteDescriptor desc, final MethodHandle guard,
+    public static GuardedInvocation lookupPrimitive(final LinkRequest request, final MethodHandle guard,
                                                     final ScriptObject wrappedReceiver, final MethodHandle wrapFilter) {
+        final CallSiteDescriptor desc = request.getCallSiteDescriptor();
         final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
-        if ("setProp".equals(operator) && desc.getNameTokenCount() > 2) {
-            return new GuardedInvocation(MH.asType(Lookup.EMPTY_SETTER, MH.type(void.class, Object.class,
-                    desc.getMethodType().parameterType(1))), guard);
+        if ("setProp".equals(operator) || "setElem".equals(operator)) {
+            MethodType type = desc.getMethodType();
+            MethodHandle method = MH.asType(Lookup.EMPTY_SETTER, MH.type(void.class, Object.class, type.parameterType(1)));
+            if (type.parameterCount() == 3) {
+                method = MH.dropArguments(method, 2, type.parameterType(2));
+            }
+            return new GuardedInvocation(method, guard);
         }
 
         if(desc.getNameTokenCount() > 2) {
@@ -91,7 +97,7 @@
                 return null;
             }
         }
-        final GuardedInvocation link = wrappedReceiver.lookup(desc);
+        final GuardedInvocation link = wrappedReceiver.lookup(desc, request);
         if (link != null) {
             MethodHandle method = link.getInvocation();
             final Class<?> receiverType = method.type().parameterType(0);