Bug 1107226 - Share prototype objects for typed object arrays with the same element type, r=nmatsakis.
authorBrian Hackett <bhackett1024@gmail.com>
Fri, 12 Dec 2014 13:36:56 -0700
changeset 219582 46ae5134ab003bc61a20a743c871f03279cdcc4c
parent 219581 14b3d9fca1e778428940cad1c2fe59d15bc73df2
child 219583 7bd6fd85defc58d81f11e9b6cc38c1715b0d37e8
push id27967
push userryanvm@gmail.com
push dateMon, 15 Dec 2014 18:52:54 +0000
treeherdermozilla-central@5d6e0d038f95 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnmatsakis
bugs1107226
milestone37.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 1107226 - Share prototype objects for typed object arrays with the same element type, r=nmatsakis.
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObjectConstants.h
js/src/jit-test/tests/TypedObject/common-array-prototypes.js
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -459,25 +459,21 @@ SimdTypeDescr::alignment(Type t)
  * But what if you want to add a method to all ArrayType instances,
  * not just all A instances?  (Or to all StructType instances.)  The
  * [[Prototype]] of the A.prototype empty object is
  * TypedObject.ArrayType.prototype.prototype (two .prototype levels!).
  * So just set TypedObject.ArrayType.prototype.prototype.methodName =
  * function() { ... } to add a method to all ArrayType instances.
  * (And, again, same with respect to s and S.)
  *
- * This function creates the A.prototype/S.prototype object.  It takes
- * as an argument either the TypedObject.ArrayType or the
- * TypedObject.StructType constructor function, then returns an empty
- * object with the .prototype.prototype object as its [[Prototype]].
+ * This function creates the A.prototype/S.prototype object. It returns an
+ * empty object with the .prototype.prototype object as its [[Prototype]].
  */
 static TypedProto *
-CreatePrototypeObjectForComplexTypeInstance(JSContext *cx,
-                                            Handle<TypeDescr*> descr,
-                                            HandleObject ctorPrototype)
+CreatePrototypeObjectForComplexTypeInstance(JSContext *cx, HandleObject ctorPrototype)
 {
     RootedObject ctorPrototypePrototype(cx, GetPrototype(cx, ctorPrototype));
     if (!ctorPrototypePrototype)
         return nullptr;
 
     return NewObjectWithProto<TypedProto>(cx,
                                           &*ctorPrototypePrototype,
                                           nullptr,
@@ -608,20 +604,27 @@ ArrayMetaTypeDescr::create(JSContext *cx
                                   nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT))
     {
         return nullptr;
     }
 
     if (!CreateUserSizeAndAlignmentProperties(cx, obj))
         return nullptr;
 
+    // All arrays with the same element type have the same prototype. This
+    // prototype is created lazily and stored in the element type descriptor.
     Rooted<TypedProto*> prototypeObj(cx);
-    prototypeObj = CreatePrototypeObjectForComplexTypeInstance(cx, obj, arrayTypePrototype);
-    if (!prototypeObj)
-        return nullptr;
+    if (elementType->getReservedSlot(JS_DESCR_SLOT_ARRAYPROTO).isObject()) {
+        prototypeObj = &elementType->getReservedSlot(JS_DESCR_SLOT_ARRAYPROTO).toObject().as<TypedProto>();
+    } else {
+        prototypeObj = CreatePrototypeObjectForComplexTypeInstance(cx, arrayTypePrototype);
+        if (!prototypeObj)
+            return nullptr;
+        elementType->setReservedSlot(JS_DESCR_SLOT_ARRAYPROTO, ObjectValue(*prototypeObj));
+    }
 
     obj->initReservedSlot(JS_DESCR_SLOT_TYPROTO, ObjectValue(*prototypeObj));
 
     if (!LinkConstructorAndPrototype(cx, obj, prototypeObj))
         return nullptr;
 
     if (!CreateTraceList(cx, obj))
         return nullptr;
@@ -965,17 +968,17 @@ StructMetaTypeDescr::create(JSContext *c
     {
         return nullptr;
     }
 
     if (!CreateUserSizeAndAlignmentProperties(cx, descr))
         return nullptr;
 
     Rooted<TypedProto*> prototypeObj(cx);
-    prototypeObj = CreatePrototypeObjectForComplexTypeInstance(cx, descr, structTypePrototype);
+    prototypeObj = CreatePrototypeObjectForComplexTypeInstance(cx, structTypePrototype);
     if (!prototypeObj)
         return nullptr;
 
     descr->initReservedSlot(JS_DESCR_SLOT_TYPROTO, ObjectValue(*prototypeObj));
 
     if (!LinkConstructorAndPrototype(cx, descr, prototypeObj))
         return nullptr;
 
--- a/js/src/builtin/TypedObjectConstants.h
+++ b/js/src/builtin/TypedObjectConstants.h
@@ -24,32 +24,33 @@
 
 // Slots on all type objects
 #define JS_DESCR_SLOT_KIND               0  // Atomized string representation
 #define JS_DESCR_SLOT_STRING_REPR        1  // Atomized string representation
 #define JS_DESCR_SLOT_ALIGNMENT          2  // Alignment in bytes
 #define JS_DESCR_SLOT_SIZE               3  // Size in bytes, else 0
 #define JS_DESCR_SLOT_OPAQUE             4  // Atomized string representation
 #define JS_DESCR_SLOT_TYPROTO            5  // Prototype for instances, if any
-#define JS_DESCR_SLOT_TRACE_LIST         6  // List of references for use in tracing
+#define JS_DESCR_SLOT_ARRAYPROTO         6  // Lazily created prototype for arrays
+#define JS_DESCR_SLOT_TRACE_LIST         7  // List of references for use in tracing
 
 // Slots on scalars, references, and x4s
-#define JS_DESCR_SLOT_TYPE               7  // Type code
+#define JS_DESCR_SLOT_TYPE               8  // Type code
 
 // Slots on array descriptors
-#define JS_DESCR_SLOT_ARRAY_ELEM_TYPE    7
-#define JS_DESCR_SLOT_ARRAY_LENGTH       8
+#define JS_DESCR_SLOT_ARRAY_ELEM_TYPE    8
+#define JS_DESCR_SLOT_ARRAY_LENGTH       9
 
 // Slots on struct type objects
-#define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 7
-#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 8
-#define JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS 9
+#define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 8
+#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 9
+#define JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS 10
 
 // Maximum number of slots for any descriptor
-#define JS_DESCR_SLOTS                   10
+#define JS_DESCR_SLOTS                   11
 
 // These constants are for use exclusively in JS code. In C++ code,
 // prefer TypeRepresentation::Scalar etc, which allows you to
 // write a switch which will receive a warning if you omit a case.
 #define JS_TYPEREPR_SCALAR_KIND         1
 #define JS_TYPEREPR_REFERENCE_KIND      2
 #define JS_TYPEREPR_STRUCT_KIND         3
 #define JS_TYPEREPR_ARRAY_KIND          4
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/TypedObject/common-array-prototypes.js
@@ -0,0 +1,22 @@
+
+if (typeof TypedObject === "undefined")
+    quit();
+
+// Test the relationships between prototypes for array typed objects.
+
+var arrA = new TypedObject.ArrayType(TypedObject.int32, 10);
+var arrB = new TypedObject.ArrayType(TypedObject.int32, 20);
+var arrC = new TypedObject.ArrayType(TypedObject.int8, 10);
+
+assertEq(arrA.prototype == arrB.prototype, true);
+assertEq(arrA.prototype == arrC.prototype, false);
+assertEq(Object.getPrototypeOf(arrA.prototype) == Object.getPrototypeOf(arrC.prototype), true);
+assertEq(Object.getPrototypeOf(arrA.prototype) == TypedObject.ArrayType.prototype.prototype, true);
+
+var instanceA = new arrA();
+var instanceB = new arrB();
+var instanceC = new arrC();
+
+assertEq(Object.getPrototypeOf(instanceA) == arrA.prototype, true);
+assertEq(Object.getPrototypeOf(instanceB) == arrB.prototype, true);
+assertEq(Object.getPrototypeOf(instanceC) == arrC.prototype, true);