Bug 949475 - Remove JOF_TYPESET from initializer ops. r=bhackett
authorJan de Mooij <jdemooij@mozilla.com>
Sat, 14 Dec 2013 10:57:25 +0100
changeset 176513 1bd9d75fe43b1104b1bf1b50b6738e835624de09
parent 176512 aa1e7e58743c507bf31b3648e6b6c1d0b330a2b8
child 176514 ab057ed707f650241e307525c36877639a5d618d
push id3343
push userffxbld
push dateMon, 17 Mar 2014 21:55:32 +0000
treeherdermozilla-beta@2f7d3415f79f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs949475
milestone29.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 949475 - Remove JOF_TYPESET from initializer ops. r=bhackett
js/src/jit/IonBuilder.cpp
js/src/jit/MCallOptimize.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/VMFunctions.cpp
js/src/jsinfer.h
js/src/jsopcode.tbl
js/src/vm/Interpreter.cpp
js/src/vm/Xdr.h
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -967,18 +967,17 @@ IonBuilder::initScopeChain(MDefinition *
                     return false;
             }
 
             scope = createCallObject(callee, scope);
             if (!scope)
                 return false;
         }
     } else {
-        scope = MConstant::New(alloc(), ObjectValue(script()->global()));
-        current->add(scope);
+        scope = constant(ObjectValue(script()->global()));
     }
 
     current->setScopeChain(scope);
     return true;
 }
 
 bool
 IonBuilder::initArgumentsObject()
@@ -3592,19 +3591,17 @@ IonBuilder::processThrow()
     // Make sure no one tries to use this block now.
     setCurrent(nullptr);
     return processControlEnd();
 }
 
 bool
 IonBuilder::pushConstant(const Value &v)
 {
-    MConstant *ins = MConstant::New(alloc(), v);
-    current->add(ins);
-    current->push(ins);
+    current->push(constant(v));
     return true;
 }
 
 bool
 IonBuilder::jsop_bitnot()
 {
     MDefinition *input = current->pop();
     MBitNot *ins = MBitNot::New(alloc(), input);
@@ -4192,18 +4189,17 @@ IonBuilder::inlineCallsite(ObjectVector 
         // folded to ensure this happens.
         callInfo.fun()->setFoldedUnchecked();
 
         // If the callee is not going to be a lambda (which may vary across
         // different invocations), then the callee definition can be replaced by a
         // constant.
         if (!lambda) {
             // Replace the function with an MConstant.
-            MConstant *constFun = MConstant::New(alloc(), ObjectValue(*target));
-            current->add(constFun);
+            MConstant *constFun = constant(ObjectValue(*target));
             callInfo.setFun(constFun);
         }
 
         return inlineSingleCall(callInfo, target);
     }
 
     // Choose a subset of the targets for polymorphic inlining.
     BoolVector choiceSet(alloc());
@@ -4435,17 +4431,17 @@ IonBuilder::inlineCalls(CallInfo &callIn
             continue;
         }
 
         MBasicBlock *inlineBlock = newBlock(dispatchBlock, pc);
         if (!inlineBlock)
             return false;
 
         // Create a function MConstant to use in the entry ResumePoint.
-        MConstant *funcDef = MConstant::New(alloc(), ObjectValue(*target));
+        MConstant *funcDef = MConstant::New(alloc(), ObjectValue(*target), constraints());
         funcDef->setFoldedUnchecked();
         dispatchBlock->add(funcDef);
 
         // Use the MConstant in the inline resume point and on stack.
         int funIndex = inlineBlock->entryResumePoint()->numOperands() - callInfo.numFormals();
         inlineBlock->entryResumePoint()->replaceOperand(funIndex, funcDef);
         inlineBlock->rewriteSlot(funIndex, funcDef);
 
@@ -4721,17 +4717,17 @@ IonBuilder::createThisScriptedSingleton(
 
         // Trigger recompilation if the templateObject changes.
         types::TypeObjectKey::get(templateType)->watchStateChangeForNewScriptTemplate(constraints());
     }
 
     // Generate an inline path to create a new |this| object with
     // the given singleton prototype.
     MCreateThisWithTemplate *createThis =
-        MCreateThisWithTemplate::New(alloc(), templateObject,
+        MCreateThisWithTemplate::New(alloc(), constraints(), templateObject,
                                      templateObject->type()->initialHeap(constraints()));
     current->add(createThis);
 
     return createThis;
 }
 
 MDefinition *
 IonBuilder::createThis(JSFunction *target, MDefinition *callee)
@@ -5061,20 +5057,18 @@ IonBuilder::jsop_call(uint32_t argc, boo
 MDefinition *
 IonBuilder::makeCallsiteClone(JSFunction *target, MDefinition *fun)
 {
     // Bake in the clone eagerly if we have a known target. We have arrived here
     // because TI told us that the known target is a should-clone-at-callsite
     // function, which means that target already is the clone. Make sure to ensure
     // that the old definition remains in resume points.
     if (target) {
-        MConstant *constant = MConstant::New(alloc(), ObjectValue(*target));
-        current->add(constant);
         fun->setFoldedUnchecked();
-        return constant;
+        return constant(ObjectValue(*target));
     }
 
     // Add a callsite clone IC if we have multiple targets. Note that we
     // should have checked already that at least some targets are marked as
     // should-clone-at-callsite.
     MCallsiteCloneCache *clone = MCallsiteCloneCache::New(alloc(), fun, pc);
     current->add(clone);
     return clone;
@@ -5414,43 +5408,41 @@ IonBuilder::jsop_newarray(uint32_t count
 
     JS_ASSERT(templateObject->is<ArrayObject>());
     if (templateObject->type()->unknownProperties()) {
         // We will get confused in jsop_initelem_array if we can't find the
         // type object being initialized.
         return abort("New array has unknown properties");
     }
 
+    MNewArray *ins = MNewArray::New(alloc(), constraints(), count, templateObject,
+                                    templateObject->type()->initialHeap(constraints()),
+                                    MNewArray::NewArray_Allocating);
+    current->add(ins);
+    current->push(ins);
+
     types::TemporaryTypeSet::DoubleConversion conversion =
-        bytecodeTypes(pc)->convertDoubleElements(constraints());
+        ins->resultTypeSet()->convertDoubleElements(constraints());
     if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
         templateObject->setShouldConvertDoubleElements();
-
-    MNewArray *ins = MNewArray::New(alloc(), count, templateObject,
-                                    templateObject->type()->initialHeap(constraints()),
-                                    MNewArray::NewArray_Allocating);
-
-    current->add(ins);
-    current->push(ins);
-
     return true;
 }
 
 bool
 IonBuilder::jsop_newobject()
 {
     // Don't bake in the TypeObject for non-CNG scripts.
     JS_ASSERT(script()->compileAndGo());
 
     JSObject *templateObject = inspector->getTemplateObject(pc);
     if (!templateObject)
         return abort("No template object for NEWOBJECT");
 
     JS_ASSERT(templateObject->is<JSObject>());
-    MNewObject *ins = MNewObject::New(alloc(), templateObject,
+    MNewObject *ins = MNewObject::New(alloc(), constraints(), templateObject,
                                       templateObject->hasSingletonType()
                                       ? gc::TenuredHeap
                                       : templateObject->type()->initialHeap(constraints()),
                                       /* templateObjectIsClassPrototype = */ false);
 
     current->add(ins);
     current->push(ins);
 
@@ -6318,18 +6310,17 @@ IonBuilder::getStaticName(JSObject *stat
                 return pushConstant(ObjectValue(*singleton));
         }
         if (knownType == JSVAL_TYPE_UNDEFINED)
             return pushConstant(UndefinedValue());
         if (knownType == JSVAL_TYPE_NULL)
             return pushConstant(NullValue());
     }
 
-    MInstruction *obj = MConstant::New(alloc(), ObjectValue(*staticObject));
-    current->add(obj);
+    MInstruction *obj = constant(ObjectValue(*staticObject));
 
     MIRType rvalType = MIRTypeFromValueType(types->getKnownTypeTag());
     if (barrier)
         rvalType = MIRType_Value;
 
     return loadSlot(obj, property.maybeTypes()->definiteSlot(), NumFixedSlots(staticObject),
                     rvalType, barrier, types);
 }
@@ -6417,18 +6408,17 @@ IonBuilder::setStaticName(JSObject *stat
                      value, needsBarrier, slotType);
 }
 
 bool
 IonBuilder::jsop_getname(PropertyName *name)
 {
     MDefinition *object;
     if (js_CodeSpec[*pc].format & JOF_GNAME) {
-        MInstruction *global = MConstant::New(alloc(), ObjectValue(script()->global()));
-        current->add(global);
+        MInstruction *global = constant(ObjectValue(script()->global()));
         object = global;
     } else {
         current->push(current->scopeChain());
         object = current->pop();
     }
 
     MGetNameCache *ins;
     if (JSOp(*GetNextPc(pc)) == JSOP_TYPEOF)
@@ -6466,20 +6456,17 @@ IonBuilder::jsop_intrinsic(PropertyName 
         return pushTypeBarrier(ins, types, true);
     }
 
     // Bake in the intrinsic. Make sure that TI agrees with us on the type.
     Value vp;
     JS_ALWAYS_TRUE(script()->global().maybeGetIntrinsicValue(name, &vp));
     JS_ASSERT(types->hasType(types::GetValueType(vp)));
 
-    MConstant *ins = MConstant::New(alloc(), vp);
-    current->add(ins);
-    current->push(ins);
-
+    pushConstant(vp);
     return true;
 }
 
 bool
 IonBuilder::jsop_bindname(PropertyName *name)
 {
     JS_ASSERT(analysis().usesScopeChain());
 
@@ -7761,28 +7748,29 @@ IonBuilder::jsop_rest()
 
     if (inliningDepth_ == 0) {
         // We don't know anything about the callee.
         MArgumentsLength *numActuals = MArgumentsLength::New(alloc());
         current->add(numActuals);
 
         // Pass in the number of actual arguments, the number of formals (not
         // including the rest parameter slot itself), and the template object.
-        MRest *rest = MRest::New(alloc(), numActuals, info().nargs() - 1, templateObject);
+        MRest *rest = MRest::New(alloc(), constraints(), numActuals, info().nargs() - 1,
+                                 templateObject);
         current->add(rest);
         current->push(rest);
         return true;
     }
 
     // We know the exact number of arguments the callee pushed.
     unsigned numActuals = inlineCallInfo_->argv().length();
     unsigned numFormals = info().nargs() - 1;
     unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0;
 
-    MNewArray *array = MNewArray::New(alloc(), numRest, templateObject,
+    MNewArray *array = MNewArray::New(alloc(), constraints(), numRest, templateObject,
                                       templateObject->type()->initialHeap(constraints()),
                                       MNewArray::NewArray_Allocating);
     current->add(array);
 
     if (numRest == 0) {
         // No more updating to do. (Note that in this one case the length from
         // the template object is already correct.)
         current->push(array);
@@ -7964,19 +7952,17 @@ IonBuilder::testCommonGetterSetter(types
     // ensure there isn't a lower shadowing getter or setter installed in the
     // future.
     freezePropertiesForCommonPrototype(types, name, foundProto);
 
     // Add a shape guard on the prototype we found the property on. The rest of
     // the prototype chain is guarded by TI freezes. Note that a shape guard is
     // good enough here, even in the proxy case, because we have ensured there
     // are no lookup hooks for this property.
-    MInstruction *wrapper = MConstant::New(alloc(), ObjectValue(*foundProto));
-    current->add(wrapper);
-
+    MInstruction *wrapper = constant(ObjectValue(*foundProto));
     return addShapeGuard(wrapper, lastProperty, Bailout_ShapeGuard);
 }
 
 bool
 IonBuilder::annotateGetPropertyCache(MDefinition *obj, MGetPropertyCache *getPropCache,
                                      types::TemporaryTypeSet *objTypes,
                                      types::TemporaryTypeSet *pushedTypes)
 {
@@ -8248,20 +8234,17 @@ IonBuilder::getPropTryConstant(bool *emi
     JS_ASSERT(!testString || !testObject);
     if (testObject)
         current->add(MGuardObject::New(alloc(), obj));
     else if (testString)
         current->add(MGuardString::New(alloc(), obj));
     else
         obj->setFoldedUnchecked();
 
-    MConstant *known = MConstant::New(alloc(), ObjectValue(*singleton));
-
-    current->add(known);
-    current->push(known);
+    pushConstant(ObjectValue(*singleton));
 
     *emitted = true;
     return true;
 }
 
 bool
 IonBuilder::getPropTryTypedObject(bool *emitted, PropertyName *name,
                                   types::TemporaryTypeSet *resultTypes)
@@ -9054,17 +9037,17 @@ IonBuilder::jsop_regexp(RegExpObject *re
         JS_ASSERT((origFlags & staticsFlags) == staticsFlags);
 
         if (!reobj->global() && !reobj->sticky())
             mustClone = false;
     }
 
     JSObject *prototype = reobj->getProto();
 
-    MRegExp *regexp = MRegExp::New(alloc(), reobj, prototype, mustClone);
+    MRegExp *regexp = MRegExp::New(alloc(), constraints(), reobj, prototype, mustClone);
     current->add(regexp);
     current->push(regexp);
 
     regexp->setMovable();
 
     // The MRegExp is set to be movable.
     // That would be incorrect for global/sticky, because lastIndex could be wrong.
     // Therefore setting the lastIndex to 0. That is faster than removing the movable flag.
@@ -9079,33 +9062,30 @@ IonBuilder::jsop_regexp(RegExpObject *re
     }
 
     return true;
 }
 
 bool
 IonBuilder::jsop_object(JSObject *obj)
 {
-    MConstant *ins = MConstant::New(alloc(), ObjectValue(*obj));
-    current->add(ins);
-    current->push(ins);
-
+    pushConstant(ObjectValue(*obj));
     return true;
 }
 
 bool
 IonBuilder::jsop_lambda(JSFunction *fun)
 {
     JS_ASSERT(analysis().usesScopeChain());
     if (fun->isArrow())
         return abort("bound arrow function");
     if (fun->isNative() && IsAsmJSModuleNative(fun->native()))
         return abort("asm.js module function");
 
-    MLambda *ins = MLambda::New(alloc(), current->scopeChain(), fun);
+    MLambda *ins = MLambda::New(alloc(), constraints(), current->scopeChain(), fun);
     current->add(ins);
     current->push(ins);
 
     return resumeAfter(ins);
 }
 
 bool
 IonBuilder::jsop_setarg(uint32_t arg)
@@ -9470,19 +9450,17 @@ IonBuilder::jsop_setaliasedvar(ScopeCoor
                 return false;
         }
         MDefinition *value = current->pop();
         PropertyName *name = ScopeCoordinateName(scopeCoordinateNameCache, script(), pc);
 
         if (call) {
             // Push the object on the stack to match the bound object expected in
             // the global and property set cases.
-            MInstruction *constant = MConstant::New(alloc(), ObjectValue(*call));
-            current->add(constant);
-            current->push(constant);
+            pushConstant(ObjectValue(*call));
             current->push(value);
             return setStaticName(call, name);
         }
 
         // The call object has type information we need to respect but we
         // couldn't find it. Just do a normal property assign.
         MDefinition *obj = walkScopeChain(sc.hops);
         current->push(obj);
@@ -9896,17 +9874,17 @@ IonBuilder::storeScalarTypedObjectValue(
     current->add(store);
 
     return true;
 }
 
 MConstant *
 IonBuilder::constant(const Value &v)
 {
-    MConstant *c = MConstant::New(alloc(), v);
+    MConstant *c = MConstant::New(alloc(), v, constraints());
     current->add(c);
     return c;
 }
 
 MConstant *
 IonBuilder::constantInt(int32_t i)
 {
     return constant(Int32Value(i));
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -241,17 +241,17 @@ IonBuilder::inlineArray(CallInfo &callIn
 
     callInfo.unwrapArgs();
 
     types::TemporaryTypeSet::DoubleConversion conversion =
         getInlineReturnTypeSet()->convertDoubleElements(constraints());
     if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
         templateObject->setShouldConvertDoubleElements();
 
-    MNewArray *ins = MNewArray::New(alloc(), initLength, templateObject,
+    MNewArray *ins = MNewArray::New(alloc(), constraints(), initLength, templateObject,
                                     templateObject->type()->initialHeap(constraints()),
                                     allocating);
     current->add(ins);
     current->push(ins);
 
     if (callInfo.argc() >= 2) {
         // Get the elements vector.
         MElements *elements = MElements::New(alloc(), ins);
@@ -490,18 +490,18 @@ IonBuilder::inlineArrayConcat(CallInfo &
     // Inline the call.
     JSObject *templateObj = inspector->getTemplateObjectForNative(pc, js::array_concat);
     if (!templateObj || templateObj->type() != baseThisType)
         return InliningStatus_NotInlined;
     JS_ASSERT(templateObj->is<ArrayObject>());
 
     callInfo.unwrapArgs();
 
-    MArrayConcat *ins = MArrayConcat::New(alloc(), callInfo.thisArg(), callInfo.getArg(0), templateObj,
-                                          templateObj->type()->initialHeap(constraints()));
+    MArrayConcat *ins = MArrayConcat::New(alloc(), constraints(), callInfo.thisArg(), callInfo.getArg(0),
+                                          templateObj, templateObj->type()->initialHeap(constraints()));
     current->add(ins);
     current->push(ins);
 
     if (!resumeAfter(ins))
         return InliningStatus_Error;
     return InliningStatus_Inlined;
 }
 
@@ -964,17 +964,18 @@ IonBuilder::inlineStringSplit(CallInfo &
 
     if (!key.maybeTypes()->hasType(types::Type::StringType())) {
         key.freeze(constraints());
         return InliningStatus_NotInlined;
     }
 
     callInfo.unwrapArgs();
 
-    MStringSplit *ins = MStringSplit::New(alloc(), callInfo.thisArg(), callInfo.getArg(0), templateObject);
+    MStringSplit *ins = MStringSplit::New(alloc(), constraints(), callInfo.thisArg(),
+                                          callInfo.getArg(0), templateObject);
     current->add(ins);
     current->push(ins);
 
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineStrCharCodeAt(CallInfo &callInfo)
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -408,44 +408,51 @@ MDefinition::replaceAllUsesWith(MDefinit
 
 bool
 MDefinition::emptyResultTypeSet() const
 {
     return resultTypeSet() && resultTypeSet()->empty();
 }
 
 MConstant *
-MConstant::New(TempAllocator &alloc, const Value &v)
+MConstant::New(TempAllocator &alloc, const Value &v, types::CompilerConstraintList *constraints)
 {
-    return new(alloc) MConstant(v);
+    return new(alloc) MConstant(v, constraints);
 }
 
 MConstant *
 MConstant::NewAsmJS(TempAllocator &alloc, const Value &v, MIRType type)
 {
-    MConstant *constant = new(alloc) MConstant(v);
+    MConstant *constant = new(alloc) MConstant(v, nullptr);
     constant->setResultType(type);
     return constant;
 }
 
 types::TemporaryTypeSet *
-jit::MakeSingletonTypeSet(JSObject *obj)
+jit::MakeSingletonTypeSet(types::CompilerConstraintList *constraints, JSObject *obj)
 {
-    LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
-    return alloc->new_<types::TemporaryTypeSet>(types::Type::ObjectType(obj));
+    // Invalidate when this object's TypeObject gets unknown properties. This
+    // happens for instance when we mutate an object's __proto__, in this case
+    // we want to invalidate and mark this TypeSet as containing AnyObject
+    // (because mutating __proto__ will change an object's TypeObject).
+    JS_ASSERT(constraints);
+    types::TypeObjectKey *objType = types::TypeObjectKey::get(obj);
+    objType->hasFlags(constraints, types::OBJECT_FLAG_UNKNOWN_PROPERTIES);
+
+    return GetIonContext()->temp->lifoAlloc()->new_<types::TemporaryTypeSet>(types::Type::ObjectType(obj));
 }
 
-MConstant::MConstant(const js::Value &vp)
+MConstant::MConstant(const js::Value &vp, types::CompilerConstraintList *constraints)
   : value_(vp)
 {
     setResultType(MIRTypeFromValue(vp));
     if (vp.isObject()) {
         // Create a singleton type set for the object. This isn't necessary for
         // other types as the result type encodes all needed information.
-        setResultTypeSet(MakeSingletonTypeSet(&vp.toObject()));
+        setResultTypeSet(MakeSingletonTypeSet(constraints, &vp.toObject()));
     }
 
     setMovable();
 }
 
 HashNumber
 MConstant::valueHash() const
 {
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -946,21 +946,22 @@ class MNop : public MNullaryInstruction
 };
 
 // A constant js::Value.
 class MConstant : public MNullaryInstruction
 {
     Value value_;
 
   protected:
-    MConstant(const Value &v);
+    MConstant(const Value &v, types::CompilerConstraintList *constraints);
 
   public:
     INSTRUCTION_HEADER(Constant)
-    static MConstant *New(TempAllocator &alloc, const Value &v);
+    static MConstant *New(TempAllocator &alloc, const Value &v,
+                          types::CompilerConstraintList *constraints = nullptr);
     static MConstant *NewAsmJS(TempAllocator &alloc, const Value &v, MIRType type);
 
     const js::Value &value() const {
         return value_;
     }
     const js::Value *vp() const {
         return &value_;
     }
@@ -1360,17 +1361,17 @@ class MThrow
     }
     bool possiblyCalls() const {
         return true;
     }
 };
 
 // Fabricate a type set containing only the type of the specified object.
 types::TemporaryTypeSet *
-MakeSingletonTypeSet(JSObject *obj);
+MakeSingletonTypeSet(types::CompilerConstraintList *constraints, JSObject *obj);
 
 void
 MergeTypes(MIRType *ptype, types::TemporaryTypeSet **ptypeSet,
            MIRType newType, types::TemporaryTypeSet *newTypeSet);
 
 class MNewArray : public MNullaryInstruction
 {
   public:
@@ -1383,34 +1384,36 @@ class MNewArray : public MNullaryInstruc
     // Number of space to allocate for the array.
     uint32_t count_;
     // Template for the created object.
     CompilerRootObject templateObject_;
     gc::InitialHeap initialHeap_;
     // Allocate space at initialization or not
     AllocatingBehaviour allocating_;
 
-    MNewArray(uint32_t count, JSObject *templateObject, gc::InitialHeap initialHeap,
-              AllocatingBehaviour allocating)
+    MNewArray(types::CompilerConstraintList *constraints, uint32_t count, JSObject *templateObject,
+              gc::InitialHeap initialHeap, AllocatingBehaviour allocating)
       : count_(count),
         templateObject_(templateObject),
         initialHeap_(initialHeap),
         allocating_(allocating)
     {
         setResultType(MIRType_Object);
-        setResultTypeSet(MakeSingletonTypeSet(templateObject));
+        if (!templateObject->hasSingletonType())
+            setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
     }
 
   public:
     INSTRUCTION_HEADER(NewArray)
 
-    static MNewArray *New(TempAllocator &alloc, uint32_t count, JSObject *templateObject,
+    static MNewArray *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
+                          uint32_t count, JSObject *templateObject,
                           gc::InitialHeap initialHeap, AllocatingBehaviour allocating)
     {
-        return new(alloc) MNewArray(count, templateObject, initialHeap, allocating);
+        return new(alloc) MNewArray(constraints, count, templateObject, initialHeap, allocating);
     }
 
     uint32_t count() const {
         return count_;
     }
 
     JSObject *templateObject() const {
         return templateObject_;
@@ -1440,34 +1443,37 @@ class MNewArray : public MNullaryInstruc
 };
 
 class MNewObject : public MNullaryInstruction
 {
     CompilerRootObject templateObject_;
     gc::InitialHeap initialHeap_;
     bool templateObjectIsClassPrototype_;
 
-    MNewObject(JSObject *templateObject, gc::InitialHeap initialHeap,
-               bool templateObjectIsClassPrototype)
+    MNewObject(types::CompilerConstraintList *constraints, JSObject *templateObject,
+               gc::InitialHeap initialHeap, bool templateObjectIsClassPrototype)
       : templateObject_(templateObject),
         initialHeap_(initialHeap),
         templateObjectIsClassPrototype_(templateObjectIsClassPrototype)
     {
         JS_ASSERT_IF(templateObjectIsClassPrototype, !shouldUseVM());
         setResultType(MIRType_Object);
-        setResultTypeSet(MakeSingletonTypeSet(templateObject));
+        if (!templateObject->hasSingletonType())
+            setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
     }
 
   public:
     INSTRUCTION_HEADER(NewObject)
 
-    static MNewObject *New(TempAllocator &alloc, JSObject *templateObject, gc::InitialHeap initialHeap,
+    static MNewObject *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
+                           JSObject *templateObject, gc::InitialHeap initialHeap,
                            bool templateObjectIsClassPrototype)
     {
-        return new(alloc) MNewObject(templateObject, initialHeap, templateObjectIsClassPrototype);
+        return new(alloc) MNewObject(constraints, templateObject, initialHeap,
+                                     templateObjectIsClassPrototype);
     }
 
     // Returns true if the code generator should call through to the
     // VM rather than the fast path.
     bool shouldUseVM() const;
 
     bool templateObjectIsClassPrototype() const {
         return templateObjectIsClassPrototype_;
@@ -2519,30 +2525,31 @@ class MAssertRange
 // Given a templateobject, construct |this| for JSOP_NEW
 class MCreateThisWithTemplate
   : public MNullaryInstruction
 {
     // Template for |this|, provided by TI
     CompilerRootObject templateObject_;
     gc::InitialHeap initialHeap_;
 
-    MCreateThisWithTemplate(JSObject *templateObject, gc::InitialHeap initialHeap)
+    MCreateThisWithTemplate(types::CompilerConstraintList *constraints, JSObject *templateObject,
+                            gc::InitialHeap initialHeap)
       : templateObject_(templateObject),
         initialHeap_(initialHeap)
     {
         setResultType(MIRType_Object);
-        setResultTypeSet(MakeSingletonTypeSet(templateObject));
+        setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
     }
 
   public:
     INSTRUCTION_HEADER(CreateThisWithTemplate);
-    static MCreateThisWithTemplate *New(TempAllocator &alloc, JSObject *templateObject,
-                                        gc::InitialHeap initialHeap)
-    {
-        return new(alloc) MCreateThisWithTemplate(templateObject, initialHeap);
+    static MCreateThisWithTemplate *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
+                                        JSObject *templateObject, gc::InitialHeap initialHeap)
+    {
+        return new(alloc) MCreateThisWithTemplate(constraints, templateObject, initialHeap);
     }
 
     JSObject *templateObject() const {
         return templateObject_;
     }
 
     gc::InitialHeap initialHeap() const {
         return initialHeap_;
@@ -4350,31 +4357,33 @@ class MFromCharCode
 };
 
 class MStringSplit
   : public MBinaryInstruction,
     public MixPolicy<StringPolicy<0>, StringPolicy<1> >
 {
     types::TypeObject *typeObject_;
 
-    MStringSplit(MDefinition *string, MDefinition *sep, JSObject *templateObject)
+    MStringSplit(types::CompilerConstraintList *constraints, MDefinition *string, MDefinition *sep,
+                 JSObject *templateObject)
       : MBinaryInstruction(string, sep),
         typeObject_(templateObject->type())
     {
         setResultType(MIRType_Object);
-        setResultTypeSet(MakeSingletonTypeSet(templateObject));
+        setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
     }
 
   public:
     INSTRUCTION_HEADER(StringSplit)
 
-    static MStringSplit *New(TempAllocator &alloc, MDefinition *string, MDefinition *sep,
+    static MStringSplit *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
+                             MDefinition *string, MDefinition *sep,
                              JSObject *templateObject)
     {
-        return new(alloc) MStringSplit(string, sep, templateObject);
+        return new(alloc) MStringSplit(constraints, string, sep, templateObject);
     }
     types::TypeObject *typeObject() const {
         return typeObject_;
     }
     MDefinition *string() const {
         return getOperand(0);
     }
     MDefinition *separator() const {
@@ -4840,34 +4849,35 @@ class MDefFun : public MUnaryInstruction
 };
 
 class MRegExp : public MNullaryInstruction
 {
     CompilerRoot<RegExpObject *> source_;
     CompilerRootObject prototype_;
     bool mustClone_;
 
-    MRegExp(RegExpObject *source, JSObject *prototype, bool mustClone)
+    MRegExp(types::CompilerConstraintList *constraints, RegExpObject *source, JSObject *prototype, bool mustClone)
       : source_(source),
         prototype_(prototype),
         mustClone_(mustClone)
     {
         setResultType(MIRType_Object);
 
         JS_ASSERT(source->getProto() == prototype);
-        setResultTypeSet(MakeSingletonTypeSet(source));
+        setResultTypeSet(MakeSingletonTypeSet(constraints, source));
     }
 
   public:
     INSTRUCTION_HEADER(RegExp)
 
-    static MRegExp *New(TempAllocator &alloc, RegExpObject *source, JSObject *prototype,
+    static MRegExp *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
+                        RegExpObject *source, JSObject *prototype,
                         bool mustClone)
     {
-        return new(alloc) MRegExp(source, prototype, mustClone);
+        return new(alloc) MRegExp(constraints, source, prototype, mustClone);
     }
 
     bool mustClone() const {
         return mustClone_;
     }
     RegExpObject *source() const {
         return source_;
     }
@@ -4946,29 +4956,31 @@ struct LambdaFunctionInfo
 };
 
 class MLambda
   : public MUnaryInstruction,
     public SingleObjectPolicy
 {
     LambdaFunctionInfo info_;
 
-    MLambda(MDefinition *scopeChain, JSFunction *fun)
+    MLambda(types::CompilerConstraintList *constraints, MDefinition *scopeChain, JSFunction *fun)
       : MUnaryInstruction(scopeChain), info_(fun)
     {
         setResultType(MIRType_Object);
         if (!fun->hasSingletonType() && !types::UseNewTypeForClone(fun))
-            setResultTypeSet(MakeSingletonTypeSet(fun));
+            setResultTypeSet(MakeSingletonTypeSet(constraints, fun));
     }
 
   public:
     INSTRUCTION_HEADER(Lambda)
 
-    static MLambda *New(TempAllocator &alloc, MDefinition *scopeChain, JSFunction *fun) {
-        return new(alloc) MLambda(scopeChain, fun);
+    static MLambda *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
+                        MDefinition *scopeChain, JSFunction *fun)
+    {
+        return new(alloc) MLambda(constraints, scopeChain, fun);
     }
     MDefinition *scopeChain() const {
         return getOperand(0);
     }
     const LambdaFunctionInfo &info() const {
         return info_;
     }
     TypePolicy *typePolicy() {
@@ -5934,32 +5946,34 @@ class MArrayPush
 // Array.prototype.concat on two dense arrays.
 class MArrayConcat
   : public MBinaryInstruction,
     public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >
 {
     CompilerRootObject templateObj_;
     gc::InitialHeap initialHeap_;
 
-    MArrayConcat(MDefinition *lhs, MDefinition *rhs, JSObject *templateObj, gc::InitialHeap initialHeap)
+    MArrayConcat(types::CompilerConstraintList *constraints, MDefinition *lhs, MDefinition *rhs,
+                 JSObject *templateObj, gc::InitialHeap initialHeap)
       : MBinaryInstruction(lhs, rhs),
         templateObj_(templateObj),
         initialHeap_(initialHeap)
     {
         setResultType(MIRType_Object);
-        setResultTypeSet(MakeSingletonTypeSet(templateObj));
+        setResultTypeSet(MakeSingletonTypeSet(constraints, templateObj));
     }
 
   public:
     INSTRUCTION_HEADER(ArrayConcat)
 
-    static MArrayConcat *New(TempAllocator &alloc, MDefinition *lhs, MDefinition *rhs,
+    static MArrayConcat *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
+                             MDefinition *lhs, MDefinition *rhs,
                              JSObject *templateObj, gc::InitialHeap initialHeap)
     {
-        return new(alloc) MArrayConcat(lhs, rhs, templateObj, initialHeap);
+        return new(alloc) MArrayConcat(constraints, lhs, rhs, templateObj, initialHeap);
     }
 
     JSObject *templateObj() const {
         return templateObj_;
     }
 
     gc::InitialHeap initialHeap() const {
         return initialHeap_;
@@ -8481,31 +8495,33 @@ class MRestCommon
     }
 };
 
 class MRest
   : public MUnaryInstruction,
     public MRestCommon,
     public IntPolicy<0>
 {
-    MRest(MDefinition *numActuals, unsigned numFormals, JSObject *templateObject)
+    MRest(types::CompilerConstraintList *constraints, MDefinition *numActuals, unsigned numFormals,
+          JSObject *templateObject)
       : MUnaryInstruction(numActuals),
         MRestCommon(numFormals, templateObject)
     {
         setResultType(MIRType_Object);
-        setResultTypeSet(MakeSingletonTypeSet(templateObject));
+        setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
     }
 
   public:
     INSTRUCTION_HEADER(Rest);
 
-    static MRest *New(TempAllocator &alloc, MDefinition *numActuals, unsigned numFormals,
+    static MRest *New(TempAllocator &alloc, types::CompilerConstraintList *constraints,
+                      MDefinition *numActuals, unsigned numFormals,
                       JSObject *templateObject)
     {
-        return new(alloc) MRest(numActuals, numFormals, templateObject);
+        return new(alloc) MRest(constraints, numActuals, numFormals, templateObject);
     }
 
     MDefinition *numActuals() const {
         return getOperand(0);
     }
 
     TypePolicy *typePolicy() {
         return this;
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -282,38 +282,34 @@ NewInitArray(JSContext *cx, uint32_t cou
     RootedTypeObject type(cx, typeArg);
     NewObjectKind newKind = !type ? SingletonObject : GenericObject;
     if (type && type->shouldPreTenure())
         newKind = TenuredObject;
     RootedObject obj(cx, NewDenseAllocatedArray(cx, count, nullptr, newKind));
     if (!obj)
         return nullptr;
 
-    if (!type)
-        types::TypeScript::Monitor(cx, ObjectValue(*obj));
-    else
+    if (type)
         obj->setType(type);
 
     return obj;
 }
 
 JSObject*
 NewInitObject(JSContext *cx, HandleObject templateObject)
 {
     NewObjectKind newKind = templateObject->hasSingletonType() ? SingletonObject : GenericObject;
     if (!templateObject->hasLazyType() && templateObject->type()->shouldPreTenure())
         newKind = TenuredObject;
     RootedObject obj(cx, CopyInitializerObject(cx, templateObject, newKind));
 
     if (!obj)
         return nullptr;
 
-    if (templateObject->hasSingletonType())
-        types::TypeScript::Monitor(cx, ObjectValue(*obj));
-    else
+    if (!templateObject->hasSingletonType())
         obj->setType(templateObject->type());
 
     return obj;
 }
 
 JSObject *
 NewInitObjectWithClassPrototype(JSContext *cx, HandleObject templateObject)
 {
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -419,29 +419,28 @@ enum {
     OBJECT_FLAG_RUNONCE_INVALIDATED   = 0x00200000,
 
     /*
      * Whether objects with this type should be allocated directly in the
      * tenured heap.
      */
     OBJECT_FLAG_PRE_TENURE            = 0x00400000,
 
-    /* Flags which indicate dynamic properties of represented objects. */
-    OBJECT_FLAG_DYNAMIC_MASK          = 0x007f0000,
-
     /*
      * Whether all properties of this object are considered unknown.
-     * If set, all flags in DYNAMIC_MASK will also be set.
+     * If set, all other flags in DYNAMIC_MASK will also be set.
      */
     OBJECT_FLAG_UNKNOWN_PROPERTIES    = 0x00800000,
 
+    /* Flags which indicate dynamic properties of represented objects. */
+    OBJECT_FLAG_DYNAMIC_MASK          = 0x00ff0000,
+
     /* Mask for objects created with unknown properties. */
     OBJECT_FLAG_UNKNOWN_MASK =
         OBJECT_FLAG_DYNAMIC_MASK
-      | OBJECT_FLAG_UNKNOWN_PROPERTIES
       | OBJECT_FLAG_SETS_MARKED_UNKNOWN
 };
 typedef uint32_t TypeObjectFlags;
 
 class StackTypeSet;
 class HeapTypeSet;
 class TemporaryTypeSet;
 
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -189,19 +189,19 @@ OPDEF(JSOP_UINT16,    88, "uint16",     
 /*
  * Object and array literal support.  NEWINIT takes the kind of initializer
  * (JSProto_Array or JSProto_Object).  NEWARRAY is an array initializer
  * taking the final length, which can be filled in at the start and initialized
  * directly.  NEWOBJECT is an object initializer taking an object with the final
  * shape, which can be set at the start and slots then filled in directly.
  * NEWINIT has an extra byte so it can be exchanged with NEWOBJECT during emit.
  */
-OPDEF(JSOP_NEWINIT,   89, "newinit",    NULL,         5,  0,  1, JOF_UINT8|JOF_TYPESET)
-OPDEF(JSOP_NEWARRAY,  90, "newarray",   NULL,         4,  0,  1, JOF_UINT24|JOF_TYPESET)
-OPDEF(JSOP_NEWOBJECT, 91, "newobject",  NULL,         5,  0,  1, JOF_OBJECT|JOF_TYPESET)
+OPDEF(JSOP_NEWINIT,   89, "newinit",    NULL,         5,  0,  1, JOF_UINT8)
+OPDEF(JSOP_NEWARRAY,  90, "newarray",   NULL,         4,  0,  1, JOF_UINT24)
+OPDEF(JSOP_NEWOBJECT, 91, "newobject",  NULL,         5,  0,  1, JOF_OBJECT)
 OPDEF(JSOP_ENDINIT,   92, "endinit",    NULL,         1,  0,  0, JOF_BYTE)
 OPDEF(JSOP_INITPROP,  93, "initprop",   NULL,         5,  2,  1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
 
 /* Initialize a numeric property in an object literal, like {1: x}. */
 OPDEF(JSOP_INITELEM,  94, "initelem",   NULL,         1,  3,  1, JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING)
 
 /* Used in array literals with spread. */
 OPDEF(JSOP_INITELEM_INC,95, "initelem_inc", NULL,     1,  3,  2, JOF_BYTE|JOF_ELEM|JOF_SET)
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -3087,47 +3087,44 @@ CASE(JSOP_NEWINIT)
         gc::AllocKind allocKind = GuessObjectGCKind(0);
         newKind = UseNewTypeForInitializer(script, REGS.pc, &JSObject::class_);
         obj = NewBuiltinClassInstance(cx, &JSObject::class_, allocKind, newKind);
     }
     if (!obj || !SetInitializerObjectType(cx, script, REGS.pc, obj, newKind))
         goto error;
 
     PUSH_OBJECT(*obj);
-    TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]);
 }
 END_CASE(JSOP_NEWINIT)
 
 CASE(JSOP_NEWARRAY)
 {
     unsigned count = GET_UINT24(REGS.pc);
     RootedObject &obj = rootObject0;
     NewObjectKind newKind = UseNewTypeForInitializer(script, REGS.pc, &ArrayObject::class_);
     obj = NewDenseAllocatedArray(cx, count, nullptr, newKind);
     if (!obj || !SetInitializerObjectType(cx, script, REGS.pc, obj, newKind))
         goto error;
 
     PUSH_OBJECT(*obj);
-    TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]);
 }
 END_CASE(JSOP_NEWARRAY)
 
 CASE(JSOP_NEWOBJECT)
 {
     RootedObject &baseobj = rootObject0;
     baseobj = script->getObject(REGS.pc);
 
     RootedObject &obj = rootObject1;
     NewObjectKind newKind = UseNewTypeForInitializer(script, REGS.pc, baseobj->getClass());
     obj = CopyInitializerObject(cx, baseobj, newKind);
     if (!obj || !SetInitializerObjectType(cx, script, REGS.pc, obj, newKind))
         goto error;
 
     PUSH_OBJECT(*obj);
-    TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]);
 }
 END_CASE(JSOP_NEWOBJECT)
 
 CASE(JSOP_ENDINIT)
 {
     /* FIXME remove JSOP_ENDINIT bug 588522 */
     JS_ASSERT(REGS.stackDepth() >= 1);
     JS_ASSERT(REGS.sp[-1].isObject() || REGS.sp[-1].isUndefined());
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -17,17 +17,17 @@ namespace js {
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number is XDR'd near the front of xdr bytecode and
  * aborts deserialization if there is a mismatch between the current
  * and saved versions. If deserialization fails, the data should be
  * invalidated if possible.
  */
-static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 156);
+static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 157);
 
 class XDRBuffer {
   public:
     XDRBuffer(JSContext *cx)
       : context(cx), base(nullptr), cursor(nullptr), limit(nullptr) { }
 
     JSContext *cx() const {
         return context;