8044760: Avoid PropertyMap duplicate for global instances
authorsundar
Fri, 04 Jul 2014 20:15:41 +0530
changeset 25421 a1df2de833a2
parent 25420 18a7c7d3c1ca
child 25422 199a23bee487
8044760: Avoid PropertyMap duplicate for global instances Reviewed-by: attila, hannesw
nashorn/src/jdk/nashorn/internal/objects/Global.java
nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java
nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java
nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
--- a/nashorn/src/jdk/nashorn/internal/objects/Global.java	Fri Jul 04 15:56:53 2014 +0530
+++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java	Fri Jul 04 20:15:41 2014 +0530
@@ -447,12 +447,7 @@
         // null check on context
         context.getClass();
 
-        /*
-         * Duplicate global's map and use it. This way the initial Map filled
-         * by nasgen (referenced from static field in this class) is retained
-         * 'as is' (as that one is process wide singleton.
-         */
-        return $nasgenmap$.duplicate();
+        return $nasgenmap$;
     }
 
     /**
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java	Fri Jul 04 15:56:53 2014 +0530
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java	Fri Jul 04 20:15:41 2014 +0530
@@ -222,7 +222,6 @@
         out.println("ScriptFunction allocations " + ScriptFunction.getAllocations());
         out.println("PropertyMap count " + PropertyMap.getCount());
         out.println("PropertyMap cloned " + PropertyMap.getClonedCount());
-        out.println("PropertyMap duplicated " + PropertyMap.getDuplicatedCount());
         out.println("PropertyMap history hit " + PropertyMap.getHistoryHit());
         out.println("PropertyMap proto invalidations " + PropertyMap.getProtoInvalidations());
         out.println("PropertyMap proto history hit " + PropertyMap.getProtoHistoryHit());
--- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java	Fri Jul 04 15:56:53 2014 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java	Fri Jul 04 20:15:41 2014 +0530
@@ -145,21 +145,6 @@
         this(propertyMap, propertyMap.properties);
     }
 
-    /**
-     * Duplicates this PropertyMap instance. This is used to duplicate 'shared'
-     * maps {@link PropertyMap} used as process wide singletons. Shared maps are
-     * duplicated for every global scope object. That way listeners, proto and property
-     * histories are scoped within a global scope.
-     *
-     * @return Duplicated {@link PropertyMap}.
-     */
-    public PropertyMap duplicate() {
-        if (Context.DEBUG) {
-            duplicatedCount++;
-        }
-        return new PropertyMap(this.properties, this.className, 0, 0, 0, containsArrayKeys());
-    }
-
     private void writeObject(final ObjectOutputStream out) throws IOException {
         out.defaultWriteObject();
         out.writeObject(properties.getProperties());
@@ -968,7 +953,6 @@
     // counters updated only in debug mode
     private static int count;
     private static int clonedCount;
-    private static int duplicatedCount;
     private static int historyHit;
     private static int protoInvalidations;
     private static int protoHistoryHit;
@@ -989,13 +973,6 @@
     }
 
     /**
-     * @return The number of maps that are duplicated.
-     */
-    public static int getDuplicatedCount() {
-        return duplicatedCount;
-    }
-
-    /**
      * @return The number of times history was successfully used.
      */
     public static int getHistoryHit() {
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java	Fri Jul 04 15:56:53 2014 +0530
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java	Fri Jul 04 20:15:41 2014 +0530
@@ -160,7 +160,8 @@
     static final MethodHandle GLOBALFILTER       = findOwnMH_S("globalFilter", Object.class, Object.class);
 
     private static final MethodHandle TRUNCATINGFILTER   = findOwnMH_S("truncatingFilter", Object[].class, int.class, Object[].class);
-    private static final MethodHandle KNOWNFUNCPROPGUARD = findOwnMH_S("knownFunctionPropertyGuard", boolean.class, Object.class, PropertyMap.class, MethodHandle.class, Object.class, ScriptFunction.class);
+    private static final MethodHandle KNOWNFUNCPROPGUARDSELF = findOwnMH_S("knownFunctionPropertyGuardSelf", boolean.class, Object.class, PropertyMap.class, MethodHandle.class, ScriptFunction.class);
+    private static final MethodHandle KNOWNFUNCPROPGUARDPROTO = findOwnMH_S("knownFunctionPropertyGuardProto", boolean.class, Object.class, PropertyMap.class, MethodHandle.class, int.class, ScriptFunction.class);
 
     private static final ArrayList<MethodHandle> PROTO_FILTERS = new ArrayList<>();
 
@@ -2271,13 +2272,20 @@
                 if (scopeAccess && func.isStrict()) {
                     mh = bindTo(mh, UNDEFINED);
                 }
+
                 return new GuardedInvocation(
                         mh,
-                        //TODO this always does a scriptobject check
-                        getKnownFunctionPropertyGuard(
+                        find.isSelf()?
+                            getKnownFunctionPropertyGuardSelf(
                                 getMap(),
                                 find.getGetter(Object.class, INVALID_PROGRAM_POINT),
-                                find.getOwner(),
+                                func)
+                            :
+                            //TODO this always does a scriptobject check
+                            getKnownFunctionPropertyGuardProto(
+                                getMap(),
+                                find.getGetter(Object.class, INVALID_PROGRAM_POINT),
+                                find.getProtoChainLength(),
                                 func),
                         getProtoSwitchPoint(NO_SUCH_PROPERTY_NAME, find.getOwner()),
                         //TODO this doesn't need a ClassCastException as guard always checks script object
@@ -3595,15 +3603,51 @@
         return MH.findStatic(MethodHandles.lookup(), ScriptObject.class, name, MH.type(rtype, types));
     }
 
-    private static MethodHandle getKnownFunctionPropertyGuard(final PropertyMap map, final MethodHandle getter, final Object where, final ScriptFunction func) {
-        return MH.insertArguments(KNOWNFUNCPROPGUARD, 1, map, getter, where, func);
+    private static MethodHandle getKnownFunctionPropertyGuardSelf(final PropertyMap map, final MethodHandle getter, final ScriptFunction func) {
+        return MH.insertArguments(KNOWNFUNCPROPGUARDSELF, 1, map, getter, func);
     }
 
     @SuppressWarnings("unused")
-    private static boolean knownFunctionPropertyGuard(final Object self, final PropertyMap map, final MethodHandle getter, final Object where, final ScriptFunction func) {
+    private static boolean knownFunctionPropertyGuardSelf(final Object self, final PropertyMap map, final MethodHandle getter, final ScriptFunction func) {
         if (self instanceof ScriptObject && ((ScriptObject)self).getMap() == map) {
             try {
-                return getter.invokeExact(where) == func;
+                return getter.invokeExact(self) == func;
+            } catch (final RuntimeException | Error e) {
+                throw e;
+            } catch (final Throwable t) {
+                throw new RuntimeException(t);
+            }
+        }
+
+        return false;
+    }
+
+    private static MethodHandle getKnownFunctionPropertyGuardProto(final PropertyMap map, final MethodHandle getter, final int depth, final ScriptFunction func) {
+        return MH.insertArguments(KNOWNFUNCPROPGUARDPROTO, 1, map, getter, depth, func);
+    }
+
+    @SuppressWarnings("unused")
+    private static ScriptObject getProto(final ScriptObject self, final int depth) {
+        ScriptObject proto = self;
+        for (int d = 0; d < depth; d++) {
+            proto = proto.getProto();
+            if (proto == null) {
+                return null;
+            }
+        }
+
+        return proto;
+    }
+
+    @SuppressWarnings("unused")
+    private static boolean knownFunctionPropertyGuardProto(final Object self, final PropertyMap map, final MethodHandle getter, final int depth, final ScriptFunction func) {
+        if (self instanceof ScriptObject && ((ScriptObject)self).getMap() == map) {
+            final ScriptObject proto = getProto((ScriptObject)self, depth);
+            if (proto == null) {
+                return false;
+            }
+            try {
+                return getter.invokeExact((Object)proto) == func;
             } catch (final RuntimeException | Error e) {
                 throw e;
             } catch (final Throwable t) {