Bug 1134970 part 2. Add JS friend API to quickly copy properties from one object to another if the objects are similar enough. r=bhackett,waldo
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 24 Feb 2015 16:04:22 -0500
changeset 230599 1a8fca17a4fab911cf9e0594a9f022295cd24700
parent 230598 0512c8c17930163fc91b9f0afe3e64f7f3028d1f
child 230600 ba350d5576dfff9b65d8053399920fba018b17ca
push id28332
push usercbook@mozilla.com
push dateWed, 25 Feb 2015 11:06:35 +0000
treeherdermozilla-central@6608e0605dfc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett, waldo
bugs1134970
milestone39.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 1134970 part 2. Add JS friend API to quickly copy properties from one object to another if the objects are similar enough. r=bhackett,waldo
js/src/jsfriendapi.h
js/src/jsobj.cpp
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -146,16 +146,34 @@ JS_ObjectToInnerObject(JSContext *cx, JS
 /* Requires obj != nullptr. */
 extern JS_FRIEND_API(JSObject *)
 JS_ObjectToOuterObject(JSContext *cx, JS::HandleObject obj);
 
 extern JS_FRIEND_API(JSObject *)
 JS_CloneObject(JSContext *cx, JS::HandleObject obj, JS::HandleObject proto,
                JS::HandleObject parent);
 
+/*
+ * Copy the own properties of src to dst in a fast way.  src and dst must both
+ * be native and must be in the compartment of cx.  They must have the same
+ * class, the same parent, and the same prototype.  Class reserved slots will
+ * NOT be copied.
+ *
+ * dst must not have any properties on it before this function is called.
+ *
+ * src must have been allocated via JS_NewObjectWithoutMetadata so that we can
+ * be sure it has no metadata that needs copying to dst.  This also means that
+ * dst needs to have the compartment global as its parent.  This function will
+ * preserve the existing metadata on dst, if any.
+ */
+extern JS_FRIEND_API(bool)
+JS_InitializePropertiesFromCompatibleNativeObject(JSContext *cx,
+                                                  JS::HandleObject dst,
+                                                  JS::HandleObject src);
+
 extern JS_FRIEND_API(JSString *)
 JS_BasicObjectToString(JSContext *cx, JS::HandleObject obj);
 
 JS_FRIEND_API(void)
 js_ReportOverRecursed(JSContext *maybecx);
 
 JS_FRIEND_API(bool)
 js_ObjectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1895,16 +1895,68 @@ js::DeepCloneObjectLiteral(JSContext *cx
     if (obj->is<ArrayObject>() && obj->denseElementsAreCopyOnWrite()) {
         if (!ObjectElements::MakeElementsCopyOnWrite(cx, clone))
             return nullptr;
     }
 
     return clone;
 }
 
+static bool
+InitializePropertiesFromCompatibleNativeObject(JSContext *cx,
+                                               HandleNativeObject dst,
+                                               HandleNativeObject src)
+{
+    assertSameCompartment(cx, src, dst);
+    MOZ_ASSERT(src->getClass() == dst->getClass());
+    MOZ_ASSERT(src->getParent() == dst->getParent());
+    MOZ_ASSERT(dst->getParent() == cx->global());
+    MOZ_ASSERT(src->getProto() == dst->getProto());
+    MOZ_ASSERT(dst->lastProperty()->getObjectFlags() == 0);
+    MOZ_ASSERT(!src->getMetadata());
+    MOZ_ASSERT(!src->isSingleton());
+
+    // Save the dst metadata, if any, before we start messing with its shape.
+    RootedObject dstMetadata(cx, dst->getMetadata());
+
+    if (!dst->ensureElements(cx, src->getDenseInitializedLength()))
+        return false;
+
+    uint32_t initialized = src->getDenseInitializedLength();
+    for (uint32_t i = 0; i < initialized; ++i) {
+        dst->setDenseInitializedLength(i + 1);
+        dst->initDenseElement(i, src->getDenseElement(i));
+    }
+
+    MOZ_ASSERT(!src->hasPrivate());
+    RootedShape shape(cx, src->lastProperty());
+    size_t span = shape->slotSpan();
+    if (!dst->setLastProperty(cx, shape))
+        return false;
+    for (size_t i = JSCLASS_RESERVED_SLOTS(src->getClass()); i < span; i++)
+        dst->setSlot(i, src->getSlot(i));
+
+    if (dstMetadata) {
+        if (!js::SetObjectMetadata(cx, dst, dstMetadata))
+            return false;
+    }
+
+    return true;
+}
+
+JS_FRIEND_API(bool)
+JS_InitializePropertiesFromCompatibleNativeObject(JSContext *cx,
+                                                  HandleObject dst,
+                                                  HandleObject src)
+{
+    return InitializePropertiesFromCompatibleNativeObject(cx,
+                                                          dst.as<NativeObject>(),
+                                                          src.as<NativeObject>());
+}
+
 template<XDRMode mode>
 bool
 js::XDRObjectLiteral(XDRState<mode> *xdr, MutableHandleNativeObject obj)
 {
     /* NB: Keep this in sync with DeepCloneObjectLiteral. */
 
     JSContext *cx = xdr->cx();
     MOZ_ASSERT_IF(mode == XDR_ENCODE && obj->isSingleton(),