src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java

Print this page
rev 758 : 8021350: Share script classes between threads/globals within context
Reviewed-by: lagergren, sundar

@@ -33,10 +33,11 @@
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
 import jdk.internal.dynalink.support.Guards;
 import jdk.nashorn.internal.lookup.Lookup;
+import jdk.nashorn.internal.runtime.FindProperty;
 import jdk.nashorn.internal.runtime.ScriptObject;
 
 /**
  * Implements lookup of methods to link for dynamic operations on JavaScript primitive values (booleans, strings, and
  * numbers). This class is only public so it can be accessed by classes in the {@code jdk.nashorn.internal.objects}

@@ -59,12 +60,13 @@
      * method - it will be combined into the returned invocation as an argument filter on the receiver.
      * @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 LinkRequest request, final Class<?> receiverClass,
-                                                    final ScriptObject wrappedReceiver, final MethodHandle wrapFilter) {
-        return lookupPrimitive(request, Guards.getInstanceOfGuard(receiverClass), wrappedReceiver, wrapFilter);
+                                                    final ScriptObject wrappedReceiver, final MethodHandle wrapFilter,
+                                                    final MethodHandle protoFilter) {
+        return lookupPrimitive(request, Guards.getInstanceOfGuard(receiverClass), wrappedReceiver, wrapFilter, protoFilter);
     }
 
     /**
      * Returns a guarded invocation representing the linkage for a dynamic operation on a primitive Java value.
      * @param request the link request for the dynamic call site.

@@ -77,11 +79,12 @@
      * method - it will be combined into the returned invocation as an argument filter on the receiver.
      * @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 LinkRequest request, final MethodHandle guard,
-                                                    final ScriptObject wrappedReceiver, final MethodHandle wrapFilter) {
+                                                    final ScriptObject wrappedReceiver, final MethodHandle wrapFilter,
+                                                    final MethodHandle protoFilter) {
         final CallSiteDescriptor desc = request.getCallSiteDescriptor();
         final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
         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)));

@@ -91,13 +94,27 @@
             return new GuardedInvocation(method, guard);
         }
 
         if(desc.getNameTokenCount() > 2) {
             final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
-            if(wrappedReceiver.findProperty(name, true) == null) {
+            final FindProperty find = wrappedReceiver.findProperty(name, true);
+            if(find == null) {
                 // Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it.
                 return null;
+            } else if (find.isInherited() && !find.getProperty().hasGetterFunction(find.getOwner())) {
+                // If property is found in the prototype object bind the method handle directly to
+                // the proto filter instead of going through wrapper instantiation below.
+                final ScriptObject proto = wrappedReceiver.getProto();
+                final GuardedInvocation link = proto.lookup(desc, request);
+
+                if (link != null) {
+                    final MethodHandle invocation = link.getInvocation();
+                    final MethodHandle adaptedInvocation = MH.asType(invocation, invocation.type().changeParameterType(0, Object.class));
+                    final MethodHandle method = MH.filterArguments(adaptedInvocation, 0, protoFilter);
+                    final MethodHandle protoGuard = MH.filterArguments(link.getGuard(), 0, protoFilter);
+                    return new GuardedInvocation(method, NashornGuards.combineGuards(guard, protoGuard));
+                }
             }
         }
         final GuardedInvocation link = wrappedReceiver.lookup(desc, request);
         if (link != null) {
             MethodHandle method = link.getInvocation();