Bug 906284 - Fix Ion SetPropertyIC to pass the right value to SetProperty. r=bhackett,efaust
authorJan de Mooij <jdemooij@mozilla.com>
Tue, 20 Aug 2013 11:09:16 +0200
changeset 156125 f620fcca5ff17cade1d7c1cab286b2701f0450e6
parent 156124 1d65f8868640f615dafed4848b681f7de3ca1676
child 156126 342c800534ab2486f28b110d585da44f2bb26df5
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett, efaust
bugs906284
milestone26.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 906284 - Fix Ion SetPropertyIC to pass the right value to SetProperty. r=bhackett,efaust
js/src/jit-test/tests/ion/bug906284.js
js/src/jit/CodeGenerator.cpp
js/src/jit/IonCaches.cpp
js/src/jit/IonCaches.h
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug906284.js
@@ -0,0 +1,15 @@
+"use strict"
+function f() {
+    h = {}
+}
+var c = 0;
+for (var i=0; i<3; i++) {
+    try {
+	new f();
+	assertEq(0, 1);
+    } catch(e) {
+	c++;
+	assertEq(e.message.contains("undeclared variable"), true);
+    }
+}
+assertEq(c, 3);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -6166,29 +6166,28 @@ CodeGenerator::visitBindNameIC(OutOfLine
     StoreRegisterTo(ic->outputReg()).generate(this);
     restoreLiveIgnore(lir, StoreRegisterTo(ic->outputReg()).clobbered());
 
     masm.jump(ool->rejoin());
     return true;
 }
 
 typedef bool (*SetPropertyFn)(JSContext *, HandleObject,
-                              HandlePropertyName, const HandleValue, bool, int);
+                              HandlePropertyName, const HandleValue, bool, jsbytecode *);
 static const VMFunction SetPropertyInfo =
     FunctionInfo<SetPropertyFn>(SetProperty);
 
 bool
 CodeGenerator::visitCallSetProperty(LCallSetProperty *ins)
 {
     ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LCallSetProperty::Value));
 
     const Register objReg = ToRegister(ins->getOperand(0));
-    JSOp op = JSOp(*ins->mir()->resumePoint()->pc());
-
-    pushArg(Imm32(op));
+
+    pushArg(ImmWord(ins->mir()->resumePoint()->pc()));
     pushArg(Imm32(ins->mir()->strict()));
 
     pushArg(value);
     pushArg(ImmGCPtr(ins->mir()->name()));
     pushArg(objReg);
 
     return callVM(SetPropertyInfo, ins);
 }
@@ -6212,40 +6211,34 @@ CodeGenerator::visitCallDeleteProperty(L
 }
 
 bool
 CodeGenerator::visitSetPropertyCacheV(LSetPropertyCacheV *ins)
 {
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register objReg = ToRegister(ins->getOperand(0));
     ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LSetPropertyCacheV::Value));
-    jsbytecode *pc = ins->mir()->resumePoint()->pc();
-    bool isSetName = JSOp(*pc) == JSOP_SETNAME || JSOp(*pc) == JSOP_SETGNAME;
-
-    SetPropertyIC cache(liveRegs, objReg, ins->mir()->name(), value,
-                        isSetName, ins->mir()->strict());
+
+    SetPropertyIC cache(liveRegs, objReg, ins->mir()->name(), value, ins->mir()->strict());
     return addCache(ins, allocateCache(cache));
 }
 
 bool
 CodeGenerator::visitSetPropertyCacheT(LSetPropertyCacheT *ins)
 {
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register objReg = ToRegister(ins->getOperand(0));
     ConstantOrRegister value;
-    jsbytecode *pc = ins->mir()->resumePoint()->pc();
-    bool isSetName = JSOp(*pc) == JSOP_SETNAME || JSOp(*pc) == JSOP_SETGNAME;
 
     if (ins->getOperand(1)->isConstant())
         value = ConstantOrRegister(*ins->getOperand(1)->toConstant());
     else
         value = TypedOrValueRegister(ins->valueType(), ToAnyRegister(ins->getOperand(1)));
 
-    SetPropertyIC cache(liveRegs, objReg, ins->mir()->name(), value,
-                        isSetName, ins->mir()->strict());
+    SetPropertyIC cache(liveRegs, objReg, ins->mir()->name(), value, ins->mir()->strict());
     return addCache(ins, allocateCache(cache));
 }
 
 typedef bool (*SetPropertyICFn)(JSContext *, size_t, HandleObject, HandleValue);
 const VMFunction SetPropertyIC::UpdateInfo =
     FunctionInfo<SetPropertyICFn>(SetPropertyIC::update);
 
 bool
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -392,19 +392,19 @@ IonCache::linkAndAttachStub(JSContext *c
 {
     Rooted<IonCode *> code(cx);
     LinkStatus status = linkCode(cx, masm, ion, code.address());
     if (status != LINK_GOOD)
         return status != LINK_ERROR;
 
     attachStub(masm, attacher, code);
 
-    if (pc) {
+    if (pc_) {
         IonSpew(IonSpew_InlineCaches, "Cache %p(%s:%d/%d) generated %s %s stub at %p",
-                this, script->filename(), script->lineno, pc - script->code,
+                this, script_->filename(), script_->lineno, pc_ - script_->code,
                 attachKind, CacheName(kind()), code->raw());
     } else {
         IonSpew(IonSpew_InlineCaches, "Cache %p generated %s %s stub at %p",
                 this, attachKind, CacheName(kind()), code->raw());
     }
     return true;
 }
 
@@ -2282,17 +2282,17 @@ SetPropertyIC::update(JSContext *cx, siz
             }
         }
     }
 
     uint32_t oldSlots = obj->numDynamicSlots();
     RootedShape oldShape(cx, obj->lastProperty());
 
     // Set/Add the property on the object, the inlined cache are setup for the next execution.
-    if (!SetProperty(cx, obj, name, value, cache.strict(), cache.isSetName()))
+    if (!SetProperty(cx, obj, name, value, cache.strict(), cache.pc()))
         return false;
 
     // The property did not exist before, now we can try to inline the property add.
     if (inlinable && !addedSetterStub && obj->lastProperty() != oldShape &&
         IsPropertyAddInlineable(cx, obj, id, oldSlots, &shape))
     {
         RootedShape newShape(cx, obj->lastProperty());
         if (!cache.attachNativeAdding(cx, ion, obj, oldShape, newShape, shape))
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -160,18 +160,18 @@ class IonCache
     bool pure_ : 1;
     bool idempotent_ : 1;
     bool disabled_ : 1;
     size_t stubCount_ : 5;
 
     CodeLocationLabel fallbackLabel_;
 
     // Location of this operation, NULL for idempotent caches.
-    JSScript *script;
-    jsbytecode *pc;
+    JSScript *script_;
+    jsbytecode *pc_;
 
   private:
     static const size_t MAX_STUBS;
     void incrementStubCount() {
         // The IC should stop generating stubs before wrapping stubCount.
         stubCount_++;
         JS_ASSERT(stubCount_);
     }
@@ -179,18 +179,18 @@ class IonCache
   public:
 
     IonCache()
       : pure_(false),
         idempotent_(false),
         disabled_(false),
         stubCount_(0),
         fallbackLabel_(),
-        script(NULL),
-        pc(NULL)
+        script_(NULL),
+        pc_(NULL)
     {
     }
 
     virtual void disable();
     inline bool isDisabled() const {
         return disabled_;
     }
 
@@ -251,30 +251,35 @@ class IonCache
     bool pure() const {
         return pure_;
     }
     bool idempotent() const {
         return idempotent_;
     }
     void setIdempotent() {
         JS_ASSERT(!idempotent_);
-        JS_ASSERT(!script);
-        JS_ASSERT(!pc);
+        JS_ASSERT(!script_);
+        JS_ASSERT(!pc_);
         idempotent_ = true;
     }
 
     void setScriptedLocation(JSScript *script, jsbytecode *pc) {
         JS_ASSERT(!idempotent_);
-        this->script = script;
-        this->pc = pc;
+        script_ = script;
+        pc_ = pc;
     }
 
     void getScriptedLocation(MutableHandleScript pscript, jsbytecode **ppc) const {
-        pscript.set(script);
-        *ppc = pc;
+        pscript.set(script_);
+        *ppc = pc_;
+    }
+
+    jsbytecode *pc() const {
+        JS_ASSERT(pc_);
+        return pc_;
     }
 };
 
 //
 // Repatch caches initially generate a patchable jump to an out of line call
 // to the cache function. Stubs are attached by appending: when attaching a
 // new stub, we patch the any failure conditions in last generated stub to
 // jump to the new stub. Failure conditions in the new stub jump to the cache
@@ -600,45 +605,40 @@ class SetPropertyIC : public RepatchIonC
   protected:
     // Registers live after the cache, excluding output registers. The initial
     // value of these registers must be preserved by the cache.
     RegisterSet liveRegs_;
 
     Register object_;
     PropertyName *name_;
     ConstantOrRegister value_;
-    bool isSetName_;
     bool strict_;
 
   public:
     SetPropertyIC(RegisterSet liveRegs, Register object, PropertyName *name,
-                  ConstantOrRegister value, bool isSetName, bool strict)
+                  ConstantOrRegister value, bool strict)
       : liveRegs_(liveRegs),
         object_(object),
         name_(name),
         value_(value),
-        isSetName_(isSetName),
         strict_(strict)
     {
     }
 
     CACHE_HEADER(SetProperty)
 
     Register object() const {
         return object_;
     }
     PropertyName *name() const {
         return name_;
     }
     ConstantOrRegister value() const {
         return value_;
     }
-    bool isSetName() const {
-        return isSetName_;
-    }
     bool strict() const {
         return strict_;
     }
 
     bool attachNativeExisting(JSContext *cx, IonScript *ion, HandleObject obj, HandleShape shape);
     bool attachSetterCall(JSContext *cx, IonScript *ion, HandleObject obj,
                           HandleObject holder, HandleShape shape, void *returnAddr);
     bool attachNativeAdding(JSContext *cx, IonScript *ion, JSObject *obj, HandleShape oldshape,
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -392,32 +392,34 @@ StringFromCharCode(JSContext *cx, int32_
     if (StaticStrings::hasUnit(c))
         return cx->runtime()->staticStrings.getUnit(c);
 
     return js_NewStringCopyN<CanGC>(cx, &c, 1);
 }
 
 bool
 SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
-            bool strict, int jsop)
+            bool strict, jsbytecode *pc)
 {
     RootedValue v(cx, value);
     RootedId id(cx, NameToId(name));
 
-    if (jsop == JSOP_SETALIASEDVAR) {
+    JSOp op = JSOp(*pc);
+
+    if (op == JSOP_SETALIASEDVAR) {
         // Aliased var assigns ignore readonly attributes on the property, as
         // required for initializing 'const' closure variables.
         Shape *shape = obj->nativeLookup(cx, name);
         JS_ASSERT(shape && shape->hasSlot());
         JSObject::nativeSetSlotWithType(cx, obj, shape, value);
         return true;
     }
 
     if (JS_LIKELY(!obj->getOps()->setProperty)) {
-        unsigned defineHow = (jsop == JSOP_SETNAME || jsop == JSOP_SETGNAME) ? DNP_UNQUALIFIED : 0;
+        unsigned defineHow = (op == JSOP_SETNAME || op == JSOP_SETGNAME) ? DNP_UNQUALIFIED : 0;
         return baseops::SetPropertyHelper(cx, obj, obj, id, defineHow, &v, strict);
     }
 
     return JSObject::setGeneric(cx, obj, obj, id, &v, strict);
 }
 
 bool
 InterruptCheck(JSContext *cx)
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -609,17 +609,17 @@ bool ArrayPopDense(JSContext *cx, Handle
 bool ArrayPushDense(JSContext *cx, HandleObject obj, HandleValue v, uint32_t *length);
 bool ArrayShiftDense(JSContext *cx, HandleObject obj, MutableHandleValue rval);
 JSObject *ArrayConcatDense(JSContext *cx, HandleObject obj1, HandleObject obj2, HandleObject res);
 
 bool CharCodeAt(JSContext *cx, HandleString str, int32_t index, uint32_t *code);
 JSFlatString *StringFromCharCode(JSContext *cx, int32_t code);
 
 bool SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
-                 bool strict, int jsop);
+                 bool strict, jsbytecode *pc);
 
 bool InterruptCheck(JSContext *cx);
 
 HeapSlot *NewSlots(JSRuntime *rt, unsigned nslots);
 JSObject *NewCallObject(JSContext *cx, HandleScript script,
                         HandleShape shape, HandleTypeObject type, HeapSlot *slots);
 JSObject *NewStringObject(JSContext *cx, HandleString str);