[INFER] Don't treat initializers mutating __proto__ as constant singletons, bug 680217.
authorBrian Hackett <bhackett1024@gmail.com>
Fri, 19 Aug 2011 10:54:51 -0700
changeset 76137 7ef2e842650cfd036ec48bb36f7c37c1f46b58d8
parent 76136 0534f46a70913bb08d114569359daf54b94c9c4b
child 76138 a2bbe9c999b4ac3bd97df974685890172a595e06
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
bugs680217
milestone8.0a1
[INFER] Don't treat initializers mutating __proto__ as constant singletons, bug 680217.
js/src/jit-test/tests/basic/bug680217.js
js/src/jsemit.cpp
js/src/jsinfer.cpp
js/src/jsparse.cpp
js/src/vm/Stack.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug680217.js
@@ -0,0 +1,12 @@
+try {
+for (var BUGNUMBER = 0, sz = Math.pow(2, 21); i < sz; i++)
+  str += '0,';
+} catch (exc1) {}
+var str = '[';
+for (var i = 0, BUGNUMBER; i < sz; i++)
+  str += '0,'; 
+  var obj = {
+    p: { __proto__: null },
+  };
+for (var i = 0, sz = Math.pow(2, 21); i < sz; i++)
+  str += '0,';
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -4881,21 +4881,20 @@ JSParseNode::getConstantValue(JSContext 
                     id = INT_TO_JSID(idvalue.toInt32());
                 else if (!js_InternNonIntElementId(cx, obj, idvalue, &id))
                     return false;
                 if (!obj->defineProperty(cx, id, value, NULL, NULL, JSPROP_ENUMERATE))
                     return false;
             } else {
                 JS_ASSERT(pnid->pn_type == TOK_NAME ||
                           pnid->pn_type == TOK_STRING);
+                JS_ASSERT(pnid->pn_atom != cx->runtime->atomState.protoAtom);
                 jsid id = ATOM_TO_JSID(pnid->pn_atom);
-                if ((pnid->pn_atom == cx->runtime->atomState.protoAtom)
-                    ? !js_SetPropertyHelper(cx, obj, id, 0, &value, strictChecks)
-                    : !DefineNativeProperty(cx, obj, id, value, NULL, NULL,
-                                            JSPROP_ENUMERATE, 0, 0)) {
+                if (!DefineNativeProperty(cx, obj, id, value, NULL, NULL,
+                                          JSPROP_ENUMERATE, 0, 0)) {
                     return false;
                 }
             }
         }
 
         types::FixObjectType(cx, obj);
         vp->setObject(*obj);
         return true;
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -2318,16 +2318,30 @@ TypeCompartment::print(JSContext *cx, bo
 
 static inline bool
 NumberTypes(Type a, Type b)
 {
     return (a.isPrimitive(JSVAL_TYPE_INT32) || a.isPrimitive(JSVAL_TYPE_DOUBLE))
         && (b.isPrimitive(JSVAL_TYPE_INT32) || b.isPrimitive(JSVAL_TYPE_DOUBLE));
 }
 
+/*
+ * As for GetValueType, but requires object types to be non-singletons with
+ * their default prototype. These are the only values that should appear in
+ * arrays and objects whose type can be fixed.
+ */
+static inline Type
+GetValueTypeForTable(JSContext *cx, const Value &v)
+{
+    Type type = GetValueType(cx, v);
+    JS_ASSERT(!type.isSingleObject());
+    JS_ASSERT_IF(type.isTypeObject(), type.typeObject() != &emptyTypeObject);
+    return type;
+}
+
 struct types::ArrayTableKey
 {
     Type type;
     JSObject *proto;
 
     ArrayTableKey()
         : type(Type::UndefinedType()), proto(NULL)
     {}
@@ -2364,20 +2378,20 @@ TypeCompartment::fixArrayType(JSContext 
      * unknown properties.
      */
     JS_ASSERT(obj->isPackedDenseArray());
 
     unsigned len = obj->getDenseArrayInitializedLength();
     if (len == 0)
         return;
 
-    Type type = GetValueType(cx, obj->getDenseArrayElement(0));
+    Type type = GetValueTypeForTable(cx, obj->getDenseArrayElement(0));
 
     for (unsigned i = 1; i < len; i++) {
-        Type ntype = GetValueType(cx, obj->getDenseArrayElement(i));
+        Type ntype = GetValueTypeForTable(cx, obj->getDenseArrayElement(i));
         if (ntype != type) {
             if (NumberTypes(type, ntype))
                 type = Type::DoubleType();
             else
                 return;
         }
     }
 
@@ -2483,17 +2497,17 @@ TypeCompartment::fixObjectType(JSContext
 
     ObjectTypeTable::AddPtr p = objectTypeTable->lookupForAdd(obj);
     const Shape *baseShape = obj->lastProperty();
 
     if (p) {
         /* The lookup ensures the shape matches, now check that the types match. */
         Type *types = p->value.types;
         for (unsigned i = 0; i < obj->slotSpan(); i++) {
-            Type ntype = GetValueType(cx, obj->getSlot(i));
+            Type ntype = GetValueTypeForTable(cx, obj->getSlot(i));
             if (ntype != types[i]) {
                 if (NumberTypes(ntype, types[i])) {
                     if (types[i].isPrimitive(JSVAL_TYPE_INT32)) {
                         types[i] = Type::DoubleType();
                         const Shape *shape = baseShape;
                         while (!JSID_IS_EMPTY(shape->propid)) {
                             if (shape->slot == i) {
                                 Type type = Type::DoubleType();
@@ -2538,17 +2552,17 @@ TypeCompartment::fixObjectType(JSContext
         if (!types) {
             cx->compartment->types.setPendingNukeTypes(cx);
             return;
         }
 
         const Shape *shape = baseShape;
         while (!JSID_IS_EMPTY(shape->propid)) {
             ids[shape->slot] = shape->propid;
-            types[shape->slot] = GetValueType(cx, obj->getSlot(shape->slot));
+            types[shape->slot] = GetValueTypeForTable(cx, obj->getSlot(shape->slot));
             if (!objType->unknownProperties()) {
                 jsid id = MakeTypeId(cx, shape->propid);
                 objType->addPropertyType(cx, id, types[shape->slot]);
             }
             shape = shape->previous();
         }
 
         ObjectTableKey key;
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -8600,18 +8600,26 @@ Parser::primaryExpr(TokenKind tt, JSBool
                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_PROP_ID);
                 return NULL;
             }
 
             op = JSOP_INITPROP;
             tt = tokenStream.getToken();
             if (tt == TOK_COLON) {
                 pnval = assignExpr();
-                if (pnval && !pnval->isConstant())
+
+                /*
+                 * Treat initializers which mutate __proto__ as non-constant,
+                 * so that we can later assume singleton objects delegate to
+                 * the default Object.prototype.
+                 */
+                if ((pnval && !pnval->isConstant()) ||
+                    atom == context->runtime->atomState.protoAtom) {
                     pn->pn_xflags |= PNX_NONCONST;
+                }
             } else {
 #if JS_HAS_DESTRUCTURING_SHORTHAND
                 if (tt != TOK_COMMA && tt != TOK_RC) {
 #endif
                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_COLON_AFTER_ID);
                     return NULL;
 #if JS_HAS_DESTRUCTURING_SHORTHAND
                 }
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -758,17 +758,17 @@ ContextStack::pushDummyFrame(JSContext *
     Value *firstUnused = ensureOnTop(cx, REPORT_ERROR, nvars, CAN_EXTEND, &dfg->pushedSeg_, dest);
     if (!firstUnused)
         return NULL;
 
     StackFrame *fp = reinterpret_cast<StackFrame *>(firstUnused);
     fp->initDummyFrame(cx, scopeChain);
     dfg->regs_.initDummyFrame(*fp);
 
-    cx->compartment = dest;
+    cx->setCompartment(dest);
     dfg->prevRegs_ = seg_->pushRegs(dfg->regs_);
     JS_ASSERT(space().firstUnused() == dfg->regs_.sp);
     dfg->setPushed(*this);
     return true;
 }
 
 void
 ContextStack::popFrame(const FrameGuard &fg)