[INFER] Don't share shapes between objects with different types, bug 620599.
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 16 Mar 2011 10:02:19 -0700
changeset 74780 af28561f44702b70f35783d336f2b7a37782ea8b
parent 74779 9de854ef345f0646d5acc0aa0a9dc25161c3dbc4
child 74781 0dc23b10fcf623558826fe50e37a3a029781acd9
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs620599
milestone2.0b13pre
[INFER] Don't share shapes between objects with different types, bug 620599.
js/src/jsapi.cpp
js/src/jsemit.cpp
js/src/jsfun.cpp
js/src/jsinterp.cpp
js/src/jsmath.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsproxy.cpp
js/src/jsreflect.cpp
js/src/jsregexpinlines.h
js/src/jsstr.cpp
js/src/methodjit/StubCalls.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3068,19 +3068,18 @@ JS_NewGlobalObject(JSContext *cx, JSClas
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     CHECK_REQUEST(cx);
     JS_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
     JSObject *obj = NewNonFunction<WithProto::Given>(cx, Valueify(clasp), NULL, NULL);
     if (!obj)
         return NULL;
 
     TypeObject *type = cx->newTypeObject("Global", NULL);
-    if (!type)
+    if (!type || !obj->setTypeAndUniqueShape(cx, type))
         return NULL;
-    obj->setType(type);
 
     obj->syncSpecialEquality();
 
     /* Construct a regexp statics object for this global object. */
     JSObject *res = regexp_statics_construct(cx, obj);
     if (!res ||
         !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_REGEXP_STATICS, ObjectValue(*res)) ||
         !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_FLAGS, Int32Value(0))) {
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -6929,16 +6929,27 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          * JSOP_NEWOBJECT with the final shape instead.
          */
         JSObject *obj = NULL;
         if (!cg->hasSharps() && cg->compileAndGo()) {
             gc::FinalizeKind kind = GuessObjectGCKind(pn->pn_count, false);
             obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
             if (!obj)
                 return JS_FALSE;
+
+            /*
+             * Generate a unique empty shape for obj, to distinguish it from
+             * initializers with the same fields created at other points.
+             * Each initialization site has a unique type, but as the script
+             * hasn't been created yet we don't know what that type is.
+             */
+            Shape *newshape = EmptyShape::create(cx, &js_ObjectClass);
+            if (!newshape)
+                return JS_FALSE;
+            obj->setMap(newshape);
         }
 
         uintN methodInits = 0, slowMethodInits = 0;
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
             /* Emit an index for t[2] for later consumption by JSOP_INITELEM. */
             pn3 = pn2->pn_left;
             if (pn3->pn_type == TOK_NUMBER) {
                 if (!EmitNumberOp(cx, pn3->pn_dval, cg))
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1766,19 +1766,18 @@ ResolveInterpretedFunctionPrototype(JSCo
     if (!js_GetClassPrototype(cx, parent, JSProto_Object, &objProto))
         return NULL;
     JSObject *proto = NewNativeClassInstance(cx, &js_ObjectClass, objProto, parent);
     if (!proto)
         return NULL;
 
     /* Make a new type for the prototype object. */
     TypeObject *protoType = cx->newTypeObject(obj->getType()->name(), "prototype", objProto);
-    if (!protoType)
-        return false;
-    proto->setType(protoType);
+    if (!protoType || !proto->setTypeAndUniqueShape(cx, protoType))
+        return NULL;
 
     /*
      * ECMA (15.3.5.2) says that a user-defined function's .prototype property
      * is non-configurable, non-enumerable, and (initially) writable. Hence
      * JSPROP_PERMANENT below. By contrast, the built-in constructors, such as
      * Object (15.2.3.1) and Function (15.3.3.1), have non-writable
      * .prototype properties. Those are eagerly defined, with attributes
      * JSPROP_PERMANENT | JSPROP_READONLY, in js_InitClass.
@@ -2802,20 +2801,19 @@ js_NewFunction(JSContext *cx, JSObject *
         JS_ASSERT(funobj->isFunction());
         funobj->setParent(parent);
     } else {
         funobj = NewFunction(cx, parent);
         if (!funobj)
             return NULL;
         if (handler) {
             TypeFunction *type = cx->newTypeFunction(fullName, funobj->getProto());
-            if (!type)
+            if (!type || !funobj->setTypeAndUniqueShape(cx, type))
                 return NULL;
             type->handler = handler;
-            funobj->setType(type);
         }
     }
     JS_ASSERT(!funobj->getPrivate());
     fun = (JSFunction *) funobj;
 
     /* Initialize all function members. */
     fun->nargs = uint16(nargs);
     fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_KINDMASK | JSFUN_TRCINFO);
@@ -2867,29 +2865,27 @@ js_CloneFunctionObject(JSContext *cx, JS
 
     JSObject *clone;
     if (cx->compartment == fun->compartment()) {
         /*
          * The cloned function object does not need the extra JSFunction members
          * beyond JSObject as it points to fun via the private slot.
          */
         clone = NewNativeClassInstance(cx, &js_FunctionClass, proto, parent);
-        if (!clone)
+        if (!clone || !clone->setTypeAndEmptyShape(cx, type))
             return NULL;
         clone->setPrivate(fun);
-        clone->setType(type);
     } else {
         /*
          * Across compartments we have to deep copy JSFunction and clone the
          * script (for interpreted functions).
          */
         clone = NewFunction(cx, parent);
-        if (!clone)
+        if (!clone || !clone->setTypeAndEmptyShape(cx, type))
             return NULL;
-        clone->setType(type);
 
         JSFunction *cfun = (JSFunction *) clone;
         cfun->nargs = fun->nargs;
         cfun->flags = fun->flags;
         cfun->u = fun->getFunctionPrivate()->u;
         cfun->atom = fun->atom;
         clone->setPrivate(cfun);
         if (cfun->isInterpreted()) {
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -6023,17 +6023,22 @@ BEGIN_CASE(JSOP_NEWINIT)
     }
 
     if (!obj)
         goto error;
 
     TypeObject *type = script->getTypeInitObject(cx, regs.pc, i == JSProto_Array);
     if (!type)
         goto error;
-    obj->setType(type);
+    if (i == JSProto_Array) {
+        obj->setType(type);
+    } else {
+        if (!obj->setTypeAndEmptyShape(cx, type))
+            goto error;
+    }
 
     PUSH_OBJECT(*obj);
     CHECK_INTERRUPT_HANDLER();
 }
 END_CASE(JSOP_NEWINIT)
 
 BEGIN_CASE(JSOP_NEWARRAY)
 {
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -896,19 +896,18 @@ js_IsMathFunction(JSNative native)
 JSObject *
 js_InitMathClass(JSContext *cx, JSObject *obj)
 {
     JSObject *Math = NewNonFunction<WithProto::Class>(cx, &js_MathClass, NULL, obj);
     if (!Math)
         return NULL;
 
     types::TypeObject *type = cx->newTypeObject(js_Math_str, Math->getProto());
-    if (!type)
+    if (!type || !Math->setTypeAndUniqueShape(cx, type))
         return NULL;
-    Math->setType(type);
 
     if (!JS_DefineProperty(cx, obj, js_Math_str, OBJECT_TO_JSVAL(Math),
                            JS_PropertyStub, JS_StrictPropertyStub, 0)) {
         return NULL;
     }
 
     if (!JS_DefineFunctionsWithPrefix(cx, Math, math_static_methods, js_Math_str))
         return NULL;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2895,19 +2895,18 @@ js_Object(JSContext *cx, uintN argc, Val
     if (!obj) {
         /* Make an object whether this was called with 'new' or not. */
         JS_ASSERT(!argc || vp[2].isNull() || vp[2].isUndefined());
         gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass);
         obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
         if (!obj)
             return JS_FALSE;
         TypeObject *type = cx->getTypeCallerInitObject(false);
-        if (!type)
+        if (!type || !obj->setTypeAndEmptyShape(cx, type))
             return JS_FALSE;
-        obj->setType(type);
     }
     vp->setObject(*obj);
     return JS_TRUE;
 }
 
 JSObject*
 js_CreateThis(JSContext *cx, JSObject *callee)
 {
@@ -2961,19 +2960,18 @@ js_CreateThisForFunction(JSContext *cx, 
             return NULL;
     } else {
         proto = NULL;
     }
     JSObject *obj = js_CreateThisForFunctionWithProto(cx, callee, proto);
     if (obj && newType) {
         JS_ASSERT(cx->typeInferenceEnabled());
         types::TypeObject *type = cx->newTypeObject("SpecializedThis", obj->getProto());
-        if (!type)
+        if (!type || !obj->setTypeAndUniqueShape(cx, type))
             return NULL;
-        obj->setType(type);
         if (!callee->getFunctionPrivate()->script()->typeSetThis(cx, (types::jstype) type))
             return NULL;
     }
     return obj;
 }
 
 #ifdef JS_TRACER
 
@@ -3554,18 +3552,24 @@ JSObject::clone(JSContext *cx, JSObject 
             return NULL;
         }
     }
     JSObject *clone = NewObject<WithProto::Given>(cx, getClass(),
                                                   proto, parent,
                                                   gc::FinalizeKind(finalizeKind()));
     if (!clone)
         return NULL;
-    if (getProto() == proto)
-        clone->setType(getType());
+    if (getProto() == proto) {
+        if (isNative()) {
+            if (!clone->setTypeAndEmptyShape(cx, getType()))
+                return NULL;
+        } else {
+            clone->setType(getType());
+        }
+    }
     if (isNative()) {
         if (clone->isFunction() && (compartment() != clone->compartment())) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_CANT_CLONE_OBJECT);
             return NULL;
         }
 
         if (getClass()->flags & JSCLASS_HAS_PRIVATE)
@@ -3947,19 +3951,18 @@ DefineConstructorAndPrototype(JSContext 
      * and (2).
      */
     JSObject *proto = NewObject<WithProto::Class>(cx, clasp, protoProto, obj);
     if (!proto)
         return NULL;
 
     TypeObject *protoType = cx->newTypeObject(clasp->name, "prototype", proto->getProto(),
                                               clasp == &js_FunctionClass);
-    if (!protoType)
+    if (!protoType || !proto->setTypeAndUniqueShape(cx, protoType))
         return NULL;
-    proto->setType(protoType);
 
     if (clasp == &js_ArrayClass && !proto->makeDenseArraySlow(cx))
         return NULL;
 
     TypeObject *type = proto->getNewType(cx);
     if (!type)
         return NULL;
 
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -712,16 +712,18 @@ struct JSObject : js::gc::Cell {
 
     /* Extend this object to have shape as its last-added property. */
     inline void extend(JSContext *cx, const js::Shape *shape, bool isDefinitelyAtom = false);
 
     js::types::TypeObject* getType() const { return type; }
 
     inline bool clearType(JSContext *cx);
     inline void setType(js::types::TypeObject *newType);
+    inline bool setTypeAndUniqueShape(JSContext *cx, js::types::TypeObject *newType);
+    inline bool setTypeAndEmptyShape(JSContext *cx, js::types::TypeObject *newType);
     inline void setTypeAndShape(js::types::TypeObject *newType, const js::Shape *newShape);
 
     inline js::types::TypeObject *getNewType(JSContext *cx);
     void makeNewType(JSContext *cx);
 
     JSObject * getProto() const {
         return type->proto;
     }
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -755,16 +755,45 @@ JSObject::setType(js::types::TypeObject 
 #ifdef DEBUG
     JS_ASSERT(newType);
     for (JSObject *obj = newType->proto; obj; obj = obj->getProto())
         JS_ASSERT(obj != this);
 #endif
     type = newType;
 }
 
+inline bool
+JSObject::setTypeAndUniqueShape(JSContext *cx, js::types::TypeObject *newType)
+{
+    setType(newType);
+
+    if (!isNative())
+        return true;
+    JS_ASSERT(nativeEmpty());
+
+    js::Shape *shape = js::EmptyShape::create(cx, getClass());
+    if (!shape)
+        return false;
+    setMap(shape);
+    return true;
+}
+
+inline bool
+JSObject::setTypeAndEmptyShape(JSContext *cx, js::types::TypeObject *newType)
+{
+    JS_ASSERT(nativeEmpty() && type->canProvideEmptyShape(getClass()));
+    setType(newType);
+
+    js::Shape *shape = type->getEmptyShape(cx, getClass(), finalizeKind());
+    if (!shape)
+        return false;
+    setMap(shape);
+    return true;
+}
+
 inline void
 JSObject::setTypeAndShape(js::types::TypeObject *newType, const js::Shape *newShape)
 {
     JS_ASSERT(newShape->slot == lastProperty()->slot);
     setType(newType);
     setLastProperty(newShape);
 }
 
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -1289,19 +1289,18 @@ static JSFunctionSpec json_static_method
 JSObject *
 js_InitJSONClass(JSContext *cx, JSObject *obj)
 {
     JSObject *JSON = NewNonFunction<WithProto::Class>(cx, &js_JSONClass, NULL, obj);
     if (!JSON)
         return NULL;
 
     TypeObject *type = cx->newTypeObject(js_JSON_str, JSON->getProto());
-    if (!type)
+    if (!type || !JSON->setTypeAndUniqueShape(cx, type))
         return NULL;
-    JSON->setType(type);
 
     if (!JS_DefineProperty(cx, obj, js_JSON_str, OBJECT_TO_JSVAL(JSON),
                            JS_PropertyStub, JS_StrictPropertyStub, 0))
         return NULL;
 
     if (!JS_DefineFunctionsWithPrefix(cx, JSON, json_static_methods, js_JSON_str))
         return NULL;
 
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -1454,19 +1454,18 @@ Class js_ProxyClass = {
 JS_FRIEND_API(JSObject *)
 js_InitProxyClass(JSContext *cx, JSObject *obj)
 {
     JSObject *module = NewNonFunction<WithProto::Class>(cx, &js_ProxyClass, NULL, obj);
     if (!module)
         return NULL;
 
     TypeObject *type = cx->newTypeObject(js_ProxyClass.name, module->getProto());
-    if (!type)
+    if (!type || !module->setTypeAndUniqueShape(cx, type))
         return NULL;
-    module->setType(type);
 
     if (!JS_DefineProperty(cx, obj, "Proxy", OBJECT_TO_JSVAL(module),
                            JS_PropertyStub, JS_StrictPropertyStub, 0)) {
         return NULL;
     }
     if (!JS_DefineFunctionsWithPrefix(cx, module, static_methods, "Proxy"))
         return NULL;
     return module;
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -3303,19 +3303,18 @@ static JSFunctionSpec static_methods[] =
 JSObject *
 js_InitReflectClass(JSContext *cx, JSObject *obj)
 {
     JSObject *Reflect = NewNonFunction<WithProto::Class>(cx, &js_ReflectClass, NULL, obj);
     if (!Reflect)
         return NULL;
 
     types::TypeObject *type = cx->newTypeObject(js_ReflectClass.name, Reflect->getProto());
-    if (!type)
+    if (!type || !Reflect->setTypeAndUniqueShape(cx, type))
         return NULL;
-    Reflect->setType(type);
 
     if (!JS_DefineProperty(cx, obj, js_Reflect_str, OBJECT_TO_JSVAL(Reflect),
                            JS_PropertyStub, JS_StrictPropertyStub, 0)) {
         return NULL;
     }
 
     if (!JS_DefineFunctionsWithPrefix(cx, Reflect, static_methods, "Reflect"))
         return NULL;
--- a/js/src/jsregexpinlines.h
+++ b/js/src/jsregexpinlines.h
@@ -266,48 +266,27 @@ RegExp::checkMatchPairs(JSString *input,
         if (start == -1)
             continue;
         JS_ASSERT(start >= 0);
         JS_ASSERT(size_t(limit) <= inputLength);
     }
 #endif
 }
 
-inline types::TypeObject *
-GetRegExpMatchType(JSContext *cx)
-{
-    types::TypeObject *type = cx->getTypeCallerInitObject(true);
-    if (!type)
-        return NULL;
-
-    if (!cx->addTypeProperty(type, NULL, types::TYPE_STRING) ||
-        !cx->addTypeProperty(type, "index", types::TYPE_INT32) ||
-        !cx->addTypeProperty(type, "input", types::TYPE_STRING) ||
-        !cx->markTypeArrayNotPacked(type, true)) {
-        return NULL;
-    }
-
-    return type;
-}
-
 inline JSObject *
 RegExp::createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount)
 {
     /*
      * Create the result array for a match. Array contents:
      *  0:              matched string
      *  1..pairCount-1: paren matches
      */
     JSObject *array = NewSlowEmptyArray(cx);
     if (!array)
         return NULL;
-    types::TypeObject *type = GetRegExpMatchType(cx);
-    if (!type)
-        return NULL;
-    array->setType(type);
 
     RegExpMatchBuilder builder(cx, array);
     for (size_t i = 0; i < matchItemCount; i += 2) {
         int start = buf[i];
         int end = buf[i + 1];
 
         JSString *captured;
         if (start >= 0) {
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1819,21 +1819,16 @@ BuildFlatMatchArray(JSContext *cx, JSStr
         return true;
     }
 
     /* For this non-global match, produce a RegExp.exec-style array. */
     JSObject *obj = NewSlowEmptyArray(cx);
     if (!obj)
         return false;
 
-    TypeObject *type = GetRegExpMatchType(cx);
-    if (!type)
-        return false;
-    obj->setType(type);
-
     vp->setObject(*obj);
 
     return obj->defineProperty(cx, INT_TO_JSID(0), StringValue(fm.pattern())) &&
            obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.indexAtom),
                                Int32Value(fm.match())) &&
            obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.inputAtom),
                                StringValue(textstr));
 }
@@ -1849,21 +1844,16 @@ MatchCallback(JSContext *cx, RegExpStati
 {
     JS_ASSERT(count <= JSID_INT_MAX);  /* by max string length */
 
     JSObject *&arrayobj = *static_cast<MatchArgType>(p);
     if (!arrayobj) {
         arrayobj = NewDenseEmptyArray(cx);
         if (!arrayobj)
             return false;
-
-        TypeObject *type = GetRegExpMatchType(cx);
-        if (!type)
-            return false;
-        arrayobj->setType(type);
     }
 
     Value v;
     if (!res->createLastMatch(cx, &v))
         return false;
 
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
     return !!arrayobj->setProperty(cx, INT_TO_JSID(count), &v, false);
@@ -3162,39 +3152,16 @@ js_String_getelem(JSContext* cx, JSStrin
     return JSString::getUnitString(cx, str, size_t(i));
 }
 #endif
 
 JS_DEFINE_TRCINFO_1(str_concat,
     (3, (extern, STRING_RETRY, js_ConcatStrings, CONTEXT, THIS_STRING, STRING,
          1, nanojit::ACCSET_NONE)))
 
-static void type_StringMatch(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
-{
-    TypeCallsite *site = Valueify(jssite);
-
-    if (!site->returnTypes)
-        return;
-
-    if (!site->compileAndGo()) {
-        site->returnTypes->addType(cx, TYPE_UNKNOWN);
-        return;
-    }
-
-    if (site->isNew)
-        site->returnTypes->addType(cx, TYPE_UNKNOWN);
-
-    TypeObject *type = site->getInitObject(cx, true);
-    if (!type)
-        return;
-
-    site->returnTypes->addType(cx, TYPE_NULL);
-    site->returnTypes->addType(cx, (jstype) type);
-}
-
 static void type_StringSplit(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
 {
     TypeCallsite *site = Valueify(jssite);
 
     if (!site->returnTypes)
         return;
 
     if (!site->compileAndGo()) {
@@ -3231,17 +3198,17 @@ static JSFunctionSpec string_methods[] =
     JS_FN_TYPE("trim",              str_trim,              0,JSFUN_GENERIC_NATIVE, JS_TypeHandlerString),
     JS_FN_TYPE("trimLeft",          str_trimLeft,          0,JSFUN_GENERIC_NATIVE, JS_TypeHandlerString),
     JS_FN_TYPE("trimRight",         str_trimRight,         0,JSFUN_GENERIC_NATIVE, JS_TypeHandlerString),
     JS_FN_TYPE("toLocaleLowerCase", str_toLocaleLowerCase, 0,JSFUN_GENERIC_NATIVE, JS_TypeHandlerString),
     JS_FN_TYPE("toLocaleUpperCase", str_toLocaleUpperCase, 0,JSFUN_GENERIC_NATIVE, JS_TypeHandlerString),
     JS_FN_TYPE("localeCompare",     str_localeCompare,     1,JSFUN_GENERIC_NATIVE, JS_TypeHandlerInt),
 
     /* Perl-ish methods (search is actually Python-esque). */
-    JS_FN_TYPE("match",             str_match,             1,JSFUN_GENERIC_NATIVE, type_StringMatch),
+    JS_FN_TYPE("match",             str_match,             1,JSFUN_GENERIC_NATIVE, JS_TypeHandlerDynamic),
     JS_FN_TYPE("search",            str_search,            1,JSFUN_GENERIC_NATIVE, JS_TypeHandlerInt),
     JS_FN_TYPE("replace",           str_replace,           2,JSFUN_GENERIC_NATIVE, JS_TypeHandlerString),
     JS_FN_TYPE("split",             str_split,             2,JSFUN_GENERIC_NATIVE, type_StringSplit),
 #if JS_HAS_PERL_SUBSTR
     JS_FN_TYPE("substr",            str_substr,            2,JSFUN_GENERIC_NATIVE, JS_TypeHandlerString),
 #endif
 
     /* Python-esque sequence methods. */
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -1393,18 +1393,18 @@ stubs::NewInitObject(VMFrame &f, JSObjec
     JSContext *cx = f.cx;
     TypeObject *type = (TypeObject *) f.scratch;
 
     if (!baseobj) {
         gc::FinalizeKind kind = GuessObjectGCKind(0, false);
         JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
         if (!obj)
             THROWV(NULL);
-        if (type)
-            obj->setType(type);
+        if (!type || !obj->setTypeAndEmptyShape(cx, type))
+            THROWV(NULL);
         return obj;
     }
 
     JS_ASSERT(type);
     JSObject *obj = CopyInitializerObject(cx, baseobj, type);
 
     if (!obj)
         THROWV(NULL);