Bug 913978 - Fix over-tight assertions after enabling Baseline getter/setter calls for GETELEM/SETELEM ops. r=efaust
authorKannan Vijayan <kvijayan@mozilla.com>
Tue, 10 Sep 2013 12:26:47 -0400
changeset 159351 7284c374c28d1333edd1b22873ef7d482d9ea6ba
parent 159350 12141799ef109e6d03d47398d647d0f609c51183
child 159352 5f52bbf813be121c857176759d8a5299ba664829
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)
reviewersefaust
bugs913978
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 913978 - Fix over-tight assertions after enabling Baseline getter/setter calls for GETELEM/SETELEM ops. r=efaust
js/src/jit/BaselineBailouts.cpp
js/src/jit/Ion.h
js/src/jit/IonFrames.cpp
js/src/jit/shared/CodeGenerator-shared.cpp
js/src/jsopcode.h
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -374,19 +374,19 @@ IsInlinableFallback(ICFallbackStub *icEn
 {
     return icEntry->isCall_Fallback() || icEntry->isGetProp_Fallback() ||
            icEntry->isSetProp_Fallback();
 }
 
 static inline void*
 GetStubReturnAddress(JSContext *cx, jsbytecode *pc)
 {
-    if (IsGetterPC(pc))
+    if (IsGetPropPC(pc))
         return cx->compartment()->ionCompartment()->baselineGetPropReturnAddr();
-    if (IsSetterPC(pc))
+    if (IsSetPropPC(pc))
         return cx->compartment()->ionCompartment()->baselineSetPropReturnAddr();
     // This should be a call op of some kind, now.
     JS_ASSERT(IsCallPC(pc));
     return cx->compartment()->ionCompartment()->baselineCallReturnAddr();
 }
 
 // For every inline frame, we write out the following data:
 //
@@ -656,26 +656,26 @@ InitFromBailout(JSContext *cx, HandleScr
 
     JSOp op = JSOp(*pc);
     JS_ASSERT_IF(excInfo, op == JSOP_ENTERBLOCK);
 
     // Fixup inlined JSOP_FUNCALL, JSOP_FUNAPPLY, and accessors on the caller side.
     // On the caller side this must represent like the function wasn't inlined.
     uint32_t pushedSlots = 0;
     AutoValueVector savedCallerArgs(cx);
-    bool needToSaveArgs = op == JSOP_FUNAPPLY || IsGetterPC(pc) || IsSetterPC(pc);
+    bool needToSaveArgs = op == JSOP_FUNAPPLY || IsGetPropPC(pc) || IsSetPropPC(pc);
     if (iter.moreFrames() && (op == JSOP_FUNCALL || needToSaveArgs))
     {
         uint32_t inlined_args = 0;
         if (op == JSOP_FUNCALL)
             inlined_args = 2 + GET_ARGC(pc) - 1;
         else if (op == JSOP_FUNAPPLY)
             inlined_args = 2 + blFrame->numActualArgs();
         else
-            inlined_args = 2 + IsSetterPC(pc);
+            inlined_args = 2 + IsSetPropPC(pc);
 
         JS_ASSERT(exprStackSlots >= inlined_args);
         pushedSlots = exprStackSlots - inlined_args;
 
         IonSpew(IonSpew_BaselineBailouts,
                 "      pushing %u expression stack slots before fixup",
                 pushedSlots);
         for (uint32_t i = 0; i < pushedSlots; i++) {
@@ -720,17 +720,17 @@ InitFromBailout(JSContext *cx, HandleScr
             }
             // Save the actual arguments. They are needed on the callee side
             // as the arguments. Else we can't recover them.
             if (!savedCallerArgs.resize(inlined_args))
                 return false;
             for (uint32_t i = 0; i < inlined_args; i++)
                 savedCallerArgs[i] = iter.read();
 
-            if (IsSetterPC(pc)) {
+            if (IsSetPropPC(pc)) {
                 // We would love to just save all the arguments and leave them
                 // in the stub frame pushed below, but we will lose the inital
                 // argument which the function was called with, which we must
                 // return to the caller, even if the setter internally modifies
                 // its arguments. Stash the initial argument on the stack, to be
                 // later retrieved by the SetProp_Fallback stub.
                 Value initialArg = savedCallerArgs[inlined_args - 1];
                 IonSpew(IonSpew_BaselineBailouts, "     pushing setter's initial argument");
@@ -788,17 +788,17 @@ InitFromBailout(JSContext *cx, HandleScr
     uint32_t expectedDepth = js_ReconstructStackDepth(cx, script,
                                                       resumeAfter ? GetNextPc(pc) : pc);
     if (op != JSOP_FUNAPPLY || !iter.moreFrames() || resumeAfter) {
         if (op == JSOP_FUNCALL) {
             // For fun.call(this, ...); the reconstructStackDepth will
             // include the this. When inlining that is not included.
             // So the exprStackSlots will be one less.
             JS_ASSERT(expectedDepth - exprStackSlots <= 1);
-        } else if (iter.moreFrames() && (IsGetterPC(pc) || IsSetterPC(pc))) {
+        } else if (iter.moreFrames() && (IsGetPropPC(pc) || IsSetPropPC(pc))) {
             // Accessors coming out of ion are inlined via a complete
             // lie perpetrated by the compiler internally. Ion just rearranges
             // the stack, and pretends that it looked like a call all along.
             // This means that the depth is actually one *more* than expected
             // by the interpreter, as there is now a JSFunction, |this| and [arg],
             // rather than the expected |this| and [arg]
             // Note that none of that was pushed, but it's still reflected
             // in exprStackSlots.
@@ -1023,17 +1023,17 @@ InitFromBailout(JSContext *cx, HandleScr
     JS_ASSERT(IsIonInlinablePC(pc));
     unsigned actualArgc;
     if (needToSaveArgs) {
         // For FUNAPPLY or an accessor, the arguments are not on the stack anymore,
         // but they are copied in a vector and are written here.
         if (op == JSOP_FUNAPPLY)
             actualArgc = blFrame->numActualArgs();
         else
-            actualArgc = IsSetterPC(pc);
+            actualArgc = IsSetPropPC(pc);
 
         JS_ASSERT(actualArgc + 2 <= exprStackSlots);
         JS_ASSERT(savedCallerArgs.length() == actualArgc + 2);
         for (unsigned i = 0; i < actualArgc + 1; i++) {
             size_t arg = savedCallerArgs.length() - (i + 1);
             if (!builder.writeValue(savedCallerArgs[arg], "ArgVal"))
                 return false;
         }
--- a/js/src/jit/Ion.h
+++ b/js/src/jit/Ion.h
@@ -369,17 +369,17 @@ IsIonEnabled(JSContext *cx)
         cx->typeInferenceEnabled();
 }
 
 inline bool
 IsIonInlinablePC(jsbytecode *pc) {
     // CALL, FUNCALL, FUNAPPLY, EVAL, NEW (Normal Callsites)
     // GETPROP, CALLPROP, and LENGTH. (Inlined Getters)
     // SETPROP, SETNAME, SETGNAME (Inlined Setters)
-    return IsCallPC(pc) || IsGetterPC(pc) || IsSetterPC(pc);
+    return IsCallPC(pc) || IsGetPropPC(pc) || IsSetPropPC(pc);
 }
 
 void ForbidCompilation(JSContext *cx, JSScript *script);
 void ForbidCompilation(JSContext *cx, JSScript *script, ExecutionMode mode);
 uint32_t UsesBeforeIonRecompile(JSScript *script, jsbytecode *pc);
 
 void PurgeCaches(JSScript *script, JS::Zone *zone);
 size_t SizeOfIonData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf);
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -1369,19 +1369,19 @@ InlineFrameIteratorMaybeGC<allowGC>::fin
         JS_ASSERT(IsIonInlinablePC(pc_));
 
         // Recover the number of actual arguments from the script.
         if (JSOp(*pc_) != JSOP_FUNAPPLY)
             numActualArgs_ = GET_ARGC(pc_);
         if (JSOp(*pc_) == JSOP_FUNCALL) {
             JS_ASSERT(GET_ARGC(pc_) > 0);
             numActualArgs_ = GET_ARGC(pc_) - 1;
-        } else if (IsGetterPC(pc_)) {
+        } else if (IsGetPropPC(pc_)) {
             numActualArgs_ = 0;
-        } else if (IsSetterPC(pc_)) {
+        } else if (IsSetPropPC(pc_)) {
             numActualArgs_ = 1;
         }
 
         JS_ASSERT(numActualArgs_ != 0xbadbad);
 
         // Skip over non-argument slots, as well as |this|.
         unsigned skipCount = (si_.slots() - 1) - numActualArgs_ - 1;
         for (unsigned j = 0; j < skipCount; j++)
@@ -1438,17 +1438,17 @@ bool
 InlineFrameIteratorMaybeGC<allowGC>::isConstructing() const
 {
     // Skip the current frame and look at the caller's.
     if (more()) {
         InlineFrameIteratorMaybeGC<allowGC> parent(GetIonContext()->cx, this);
         ++parent;
 
         // Inlined Getters and Setters are never constructing.
-        if (IsGetterPC(parent.pc()) || IsSetterPC(parent.pc()))
+        if (IsGetPropPC(parent.pc()) || IsSetPropPC(parent.pc()))
             return false;
 
         // In the case of a JS frame, look up the pc from the snapshot.
         JS_ASSERT(IsCallPC(parent.pc()));
 
         return (JSOp)*parent.pc() == JSOP_NEW;
     }
 
@@ -1467,30 +1467,31 @@ IonFrameIterator::isConstructing() const
         ++parent;
     } while (!parent.done() && !parent.isScripted());
 
     if (parent.isOptimizedJS()) {
         // In the case of a JS frame, look up the pc from the snapshot.
         InlineFrameIterator inlinedParent(GetIonContext()->cx, &parent);
 
         //Inlined Getters and Setters are never constructing.
-        if (IsGetterPC(inlinedParent.pc()) || IsSetterPC(inlinedParent.pc()))
+        if (IsGetPropPC(inlinedParent.pc()) || IsSetPropPC(inlinedParent.pc()))
             return false;
 
         JS_ASSERT(IsCallPC(inlinedParent.pc()));
 
         return (JSOp)*inlinedParent.pc() == JSOP_NEW;
     }
 
     if (parent.isBaselineJS()) {
         jsbytecode *pc;
         parent.baselineScriptAndPc(NULL, &pc);
 
-        //Inlined Getters and Setters are never constructing.
-        if (IsGetterPC(pc) || IsSetterPC(pc))
+        // Inlined Getters and Setters are never constructing.
+        // Baseline may call getters from [GET|SET]PROP or [GET|SET]ELEM ops.
+        if (IsGetPropPC(pc) || IsSetPropPC(pc) || IsGetElemPC(pc) || IsSetElemPC(pc))
             return false;
 
         JS_ASSERT(IsCallPC(pc));
 
         return JSOp(*pc) == JSOP_NEW;
     }
 
     JS_ASSERT(parent.done());
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -279,17 +279,19 @@ CodeGeneratorShared::encode(LSnapshot *s
 #ifdef DEBUG
         if (GetIonContext()->cx) {
             uint32_t stackDepth = js_ReconstructStackDepth(GetIonContext()->cx, script, bailPC);
             if (JSOp(*bailPC) == JSOP_FUNCALL) {
                 // For fun.call(this, ...); the reconstructStackDepth will
                 // include the this. When inlining that is not included.
                 // So the exprStackSlots will be one less.
                 JS_ASSERT(stackDepth - exprStack <= 1);
-            } else if (JSOp(*bailPC) != JSOP_FUNAPPLY && !IsGetterPC(bailPC) && !IsSetterPC(bailPC)) {
+            } else if (JSOp(*bailPC) != JSOP_FUNAPPLY &&
+                       !IsGetPropPC(bailPC) && !IsSetPropPC(bailPC))
+            {
                 // For fun.apply({}, arguments) the reconstructStackDepth will
                 // have stackdepth 4, but it could be that we inlined the
                 // funapply. In that case exprStackSlots, will have the real
                 // arguments in the slots and not be 4.
 
                 // With accessors, we have different stack depths depending on whether or not we
                 // inlined the accessor, as the inlined stack contains a callee function that should
                 // never have been there and we might just be capturing an uneventful property site,
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -586,30 +586,44 @@ IsGlobalOp(JSOp op)
 
 inline bool
 IsEqualityOp(JSOp op)
 {
     return op == JSOP_EQ || op == JSOP_NE || op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
 }
 
 inline bool
-IsGetterPC(jsbytecode *pc)
+IsGetPropPC(jsbytecode *pc)
 {
     JSOp op = JSOp(*pc);
     return op == JSOP_LENGTH  || op == JSOP_GETPROP || op == JSOP_CALLPROP;
 }
 
 inline bool
-IsSetterPC(jsbytecode *pc)
+IsSetPropPC(jsbytecode *pc)
 {
     JSOp op = JSOp(*pc);
     return op == JSOP_SETPROP || op == JSOP_SETNAME || op == JSOP_SETGNAME;
 }
 
 inline bool
+IsGetElemPC(jsbytecode *pc)
+{
+    JSOp op = JSOp(*pc);
+    return op == JSOP_GETELEM || op == JSOP_CALLELEM;
+}
+
+inline bool
+IsSetElemPC(jsbytecode *pc)
+{
+    JSOp op = JSOp(*pc);
+    return op == JSOP_SETELEM;
+}
+
+inline bool
 IsCallPC(jsbytecode *pc)
 {
     return js_CodeSpec[*pc].format & JOF_INVOKE;
 }
 
 static inline int32_t
 GetBytecodeInteger(jsbytecode *pc)
 {