Bug 1484349 - Optimize HasOwnProperty/GetProperty lookup for cloning. r=jandem
authorTom Schuster <evilpies@gmail.com>
Fri, 17 Aug 2018 21:19:30 +0200
changeset 432434 d2195ec4e254ab9c1f3bfaedfcd93dddf3197a19
parent 432433 c66cc808862f6c77361be44b38e78e86b4aa7c69
child 432435 8047901cef0e5c166c1ba26c327f5f5581851f20
push id106736
push userevilpies@gmail.com
push dateMon, 20 Aug 2018 18:27:56 +0000
treeherdermozilla-inbound@075bfbeee249 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1484349
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1484349 - Optimize HasOwnProperty/GetProperty lookup for cloning. r=jandem
js/src/vm/JSObject.cpp
js/src/vm/JSObject.h
js/src/vm/StructuredClone.cpp
js/src/vm/TypedArrayObject.cpp
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -2518,27 +2518,29 @@ js::GetPropertyPure(JSContext* cx, JSObj
         vp->setUndefined();
         return true;
     }
 
     return pobj->isNative() && NativeGetPureInline(&pobj->as<NativeObject>(), id, prop, vp);
 }
 
 bool
-js::GetOwnPropertyPure(JSContext* cx, JSObject* obj, jsid id, Value* vp)
+js::GetOwnPropertyPure(JSContext* cx, JSObject* obj, jsid id, Value* vp, bool* found)
 {
     PropertyResult prop;
     if (!LookupOwnPropertyPure(cx, obj, id, &prop))
         return false;
 
     if (!prop) {
+        *found = false;
         vp->setUndefined();
         return true;
     }
 
+    *found = true;
     return obj->isNative() && NativeGetPureInline(&obj->as<NativeObject>(), id, prop, vp);
 }
 
 static inline bool
 NativeGetGetterPureInline(PropertyResult prop, JSFunction** fp)
 {
     if (!prop.isDenseOrTypedArrayElement() && prop.shape()->hasGetterObject()) {
         Shape* shape = prop.shape();
--- a/js/src/vm/JSObject.h
+++ b/js/src/vm/JSObject.h
@@ -1146,17 +1146,17 @@ LookupPropertyPure(JSContext* cx, JSObje
 bool
 LookupOwnPropertyPure(JSContext* cx, JSObject* obj, jsid id, PropertyResult* propp,
                       bool* isTypedArrayOutOfRange = nullptr);
 
 bool
 GetPropertyPure(JSContext* cx, JSObject* obj, jsid id, Value* vp);
 
 bool
-GetOwnPropertyPure(JSContext* cx, JSObject* obj, jsid id, Value* vp);
+GetOwnPropertyPure(JSContext* cx, JSObject* obj, jsid id, Value* vp, bool* found);
 
 bool
 GetGetterPure(JSContext* cx, JSObject* obj, jsid id, JSFunction** fp);
 
 bool
 GetOwnGetterPure(JSContext* cx, JSObject* obj, jsid id, JSFunction** fp);
 
 bool
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -1381,16 +1381,17 @@ JSStructuredCloneWriter::traverseObject(
     // Get enumerable property ids and put them in reverse order so that they
     // will come off the stack in forward order.
     AutoIdVector properties(context());
     if (!GetPropertyKeys(context(), obj, JSITER_OWNONLY, &properties))
         return false;
 
     for (size_t i = properties.length(); i > 0; --i) {
         MOZ_ASSERT(JSID_IS_STRING(properties[i - 1]) || JSID_IS_INT(properties[i - 1]));
+        // JSStructuredCloneWriter::write relies on this.
         RootedValue val(context(), IdToValue(properties[i - 1]));
         if (!entries.append(val))
             return false;
     }
 
     // Push obj and count to the stack.
     if (!objs.append(ObjectValue(*obj)) || !counts.append(properties.length()))
         return false;
@@ -1902,24 +1903,33 @@ JSStructuredCloneWriter::write(HandleVal
                 checkStack();
 
                 if (!startWrite(key) || !startWrite(val))
                     return false;
             } else if (cls == ESClass::Set || SavedFrame::isSavedFrameOrWrapperAndNotProto(*obj)) {
                 if (!startWrite(key))
                     return false;
             } else {
-                if (!ValueToId<CanGC>(context(), key, &id))
-                  return false;
-                MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id));
+                // This relies on the way JSStructuredCloneWriter::traverseObject
+                // converts JSIDs to Value.
+                if (key.isString())
+                    id = AtomToId(&key.toString()->asAtom());
+                else
+                    id = INT_TO_JSID(key.toInt32());
 
                 // If obj still has an own property named id, write it out.
-                // The cost of re-checking could be avoided by using
-                // NativeIterators.
                 bool found;
+                if (GetOwnPropertyPure(context(), obj, id, val.address(), &found)) {
+                    if (found) {
+                        if (!startWrite(key) || !startWrite(val))
+                            return false;
+                    }
+                    continue;
+                }
+
                 if (!HasOwnProperty(context(), obj, id, &found))
                     return false;
 
                 if (found) {
                     if (!startWrite(key) ||
                         !GetProperty(context(), obj, obj, id, &val) ||
                         !startWrite(val))
                     {
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -1100,17 +1100,18 @@ GetBufferSpeciesConstructor(JSContext* c
         // we don't have to reify the buffer object and can simply return the
         // default arrray buffer constructor.
 
         JSObject* proto = GlobalObject::getOrCreateArrayBufferPrototype(cx, cx->global());
         if (!proto)
             return nullptr;
 
         Value ctor;
-        if (GetOwnPropertyPure(cx, proto, NameToId(cx->names().constructor), &ctor) &&
+        bool found;
+        if (GetOwnPropertyPure(cx, proto, NameToId(cx->names().constructor), &ctor, &found) &&
             ctor.isObject() && &ctor.toObject() == defaultCtor)
         {
             jsid speciesId = SYMBOL_TO_JSID(cx->wellKnownSymbols().species);
             JSFunction* getter;
             if (GetOwnGetterPure(cx, defaultCtor, speciesId, &getter) && getter &&
                 IsArrayBufferSpecies(cx, getter))
             {
                 return defaultCtor;