Bug 739494 - rm JSOP_DEFLOCALFUN (r=bhackett)
authorLuke Wagner <luke@mozilla.com>
Mon, 26 Mar 2012 22:08:03 -0700
changeset 93723 493068c3e31215e28f5567b5d3a7d70571ae84bc
parent 93722 a679be907f55c4016cfdc6e0b8a654b4de19d8c9
child 93724 186b88e3ade89e18c5670c0603a5d3b80a98d656
push idunknown
push userunknown
push dateunknown
reviewersbhackett
bugs739494
milestone14.0a1
Bug 739494 - rm JSOP_DEFLOCALFUN (r=bhackett)
js/src/frontend/BytecodeEmitter.cpp
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsinfer.cpp
js/src/jsinterp.cpp
js/src/jsopcode.cpp
js/src/jsopcode.tbl
js/src/methodjit/Compiler.cpp
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -963,32 +963,16 @@ EmitObjectOp(JSContext *cx, ObjectBox *o
 
 static bool
 EmitRegExp(JSContext *cx, uint32_t index, BytecodeEmitter *bce)
 {
     return EmitIndex32(cx, JSOP_REGEXP, index, bce);
 }
 
 static bool
-EmitSlotObjectOp(JSContext *cx, JSOp op, unsigned slot, uint32_t index, BytecodeEmitter *bce)
-{
-    JS_ASSERT(JOF_OPTYPE(op) == JOF_SLOTOBJECT);
-
-    ptrdiff_t off = EmitN(cx, bce, op, SLOTNO_LEN + UINT32_INDEX_LEN);
-    if (off < 0)
-        return false;
-
-    jsbytecode *pc = bce->code(off);
-    SET_SLOTNO(pc, slot);
-    pc += SLOTNO_LEN;
-    SET_UINT32_INDEX(pc, index);
-    return true;
-}
-
-static bool
 EmitArguments(JSContext *cx, BytecodeEmitter *bce)
 {
     if (!bce->mayOverwriteArguments())
         return Emit1(cx, bce, JSOP_ARGUMENTS) >= 0;
     return EmitAtomOp(cx, cx->runtime->atomState.argumentsAtom, JSOP_NAME, bce);
 }
 
 bool
@@ -5049,17 +5033,24 @@ EmitFunc(JSContext *cx, BytecodeEmitter 
         JS_ASSERT(index < JS_BIT(20));
         pn->pn_index = index;
         if (pn->isClosed() &&
             !bce->callsEval() &&
             !bce->closedVars.append(pn->pn_cookie.slot()))
         {
             return false;
         }
-        return EmitSlotObjectOp(cx, JSOP_DEFLOCALFUN, slot, index, bce);
+
+        if (NewSrcNote(cx, bce, SRC_CONTINUE) < 0)
+            return false;
+        if (!EmitIndexOp(cx, JSOP_LAMBDA, index, bce))
+            return false;
+        EMIT_UINT16_IMM_OP(JSOP_SETLOCAL, slot);
+        if (Emit1(cx, bce, JSOP_POP) < 0)
+            return false;
     }
 
     return true;
 }
 
 static bool
 EmitDo(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -535,17 +535,16 @@ ScriptAnalysis::analyzeBytecode(JSContex
             modifiesArguments_ = true;
             isInlineable = false;
             break;
 
           /* Additional opcodes which can be compiled but which can't be inlined. */
           case JSOP_ARGUMENTS:
           case JSOP_THROW:
           case JSOP_EXCEPTION:
-          case JSOP_DEFLOCALFUN:
           case JSOP_LAMBDA:
           case JSOP_DEBUGGER:
           case JSOP_FUNCALL:
           case JSOP_FUNAPPLY:
             isInlineable = false;
             break;
 
           /* Additional opcodes which can be both compiled both normally and inline. */
@@ -824,18 +823,17 @@ ScriptAnalysis::analyzeLifetimes(JSConte
             uint32_t slot = GetBytecodeSlot(script, pc);
             if (!slotEscapes(slot))
                 addVariable(cx, lifetimes[slot], offset, saved, savedCount);
             break;
           }
 
           case JSOP_SETARG:
           case JSOP_SETLOCAL:
-          case JSOP_SETLOCALPOP:
-          case JSOP_DEFLOCALFUN: {
+          case JSOP_SETLOCALPOP: {
             uint32_t slot = GetBytecodeSlot(script, pc);
             if (!slotEscapes(slot))
                 killVariable(cx, lifetimes[slot], offset, saved, savedCount);
             break;
           }
 
           case JSOP_INCARG:
           case JSOP_DECARG:
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -253,17 +253,16 @@ ExtendedDef(jsbytecode *pc)
     switch ((JSOp)*pc) {
       case JSOP_SETARG:
       case JSOP_INCARG:
       case JSOP_DECARG:
       case JSOP_ARGINC:
       case JSOP_ARGDEC:
       case JSOP_SETLOCAL:
       case JSOP_SETLOCALPOP:
-      case JSOP_DEFLOCALFUN:
       case JSOP_INCLOCAL:
       case JSOP_DECLOCAL:
       case JSOP_LOCALINC:
       case JSOP_LOCALDEC:
         return true;
       default:
         return false;
     }
@@ -382,17 +381,16 @@ static inline uint32_t GetBytecodeSlot(J
       case JSOP_ARGINC:
       case JSOP_ARGDEC:
         return ArgSlot(GET_SLOTNO(pc));
 
       case JSOP_GETLOCAL:
       case JSOP_CALLLOCAL:
       case JSOP_SETLOCAL:
       case JSOP_SETLOCALPOP:
-      case JSOP_DEFLOCALFUN:
       case JSOP_INCLOCAL:
       case JSOP_DECLOCAL:
       case JSOP_LOCALINC:
       case JSOP_LOCALDEC:
         return LocalSlot(script, GET_SLOTNO(pc));
 
       case JSOP_THIS:
         return ThisSlot();
@@ -406,17 +404,16 @@ static inline uint32_t GetBytecodeSlot(J
 /* Slot opcodes which update SSA information. */
 static inline bool
 BytecodeUpdatesSlot(JSOp op)
 {
     switch (op) {
       case JSOP_SETARG:
       case JSOP_SETLOCAL:
       case JSOP_SETLOCALPOP:
-      case JSOP_DEFLOCALFUN:
       case JSOP_INCARG:
       case JSOP_DECARG:
       case JSOP_ARGINC:
       case JSOP_ARGDEC:
       case JSOP_INCLOCAL:
       case JSOP_DECLOCAL:
       case JSOP_LOCALINC:
       case JSOP_LOCALDEC:
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -3747,34 +3747,22 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         break;
 
       case JSOP_NEG:
       case JSOP_POS:
         poppedTypes(pc, 0)->addArith(cx, script, pc, &pushed[0]);
         break;
 
       case JSOP_LAMBDA:
-      case JSOP_DEFFUN:
-      case JSOP_DEFLOCALFUN: {
-        unsigned off = op == JSOP_DEFLOCALFUN ? SLOTNO_LEN : 0;
-        JSObject *obj = script->getObject(GET_UINT32_INDEX(pc + off));
+      case JSOP_DEFFUN: {
+        JSObject *obj = script->getObject(GET_UINT32_INDEX(pc));
 
         TypeSet *res = NULL;
-        if (op == JSOP_LAMBDA) {
+        if (op == JSOP_LAMBDA)
             res = &pushed[0];
-        } else if (op == JSOP_DEFLOCALFUN) {
-            uint32_t slot = GetBytecodeSlot(script, pc);
-            if (trackSlot(slot)) {
-                res = &pushed[0];
-            } else {
-                /* Should not see 'let' vars here. */
-                JS_ASSERT(slot < TotalSlots(script));
-                res = TypeScript::SlotTypes(script, slot);
-            }
-        }
 
         if (res) {
             if (script->hasGlobal())
                 res->addType(cx, Type::ObjectType(obj));
             else
                 res->addType(cx, Type::UnknownType());
         } else {
             cx->compartment->types.monitorBytecode(cx, script, offset);
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -1708,16 +1708,17 @@ ADD_EMPTY_CASE(JSOP_UNUSED19)
 ADD_EMPTY_CASE(JSOP_UNUSED20)
 ADD_EMPTY_CASE(JSOP_UNUSED21)
 ADD_EMPTY_CASE(JSOP_UNUSED22)
 ADD_EMPTY_CASE(JSOP_UNUSED23)
 ADD_EMPTY_CASE(JSOP_UNUSED24)
 ADD_EMPTY_CASE(JSOP_UNUSED25)
 ADD_EMPTY_CASE(JSOP_UNUSED26)
 ADD_EMPTY_CASE(JSOP_UNUSED27)
+ADD_EMPTY_CASE(JSOP_UNUSED28)
 ADD_EMPTY_CASE(JSOP_CONDSWITCH)
 ADD_EMPTY_CASE(JSOP_TRY)
 #if JS_HAS_XML_SUPPORT
 ADD_EMPTY_CASE(JSOP_STARTXML)
 ADD_EMPTY_CASE(JSOP_STARTXMLEXPR)
 #endif
 ADD_EMPTY_CASE(JSOP_LOOPHEAD)
 ADD_EMPTY_CASE(JSOP_LOOPENTRY)
@@ -3142,46 +3143,16 @@ BEGIN_CASE(JSOP_DEFFUN)
 
         /* Step 5f. */
         if (!parent->setProperty(cx, name, &rval, script->strictModeCode))
             goto error;
     } while (false);
 }
 END_CASE(JSOP_DEFFUN)
 
-BEGIN_CASE(JSOP_DEFLOCALFUN)
-{
-    /*
-     * Define a local function (i.e., one nested at the top level of another
-     * function), parented by the current scope chain, stored in a local
-     * variable slot that the compiler allocated.  This is an optimization over
-     * JSOP_DEFFUN that avoids requiring a call object for the outer function's
-     * activation.
-     */
-    JSFunction *fun = script->getFunction(GET_UINT32_INDEX(regs.pc + SLOTNO_LEN));
-    JS_ASSERT(fun->isInterpreted());
-
-    JSObject *parent;
-    if (fun->isNullClosure()) {
-        parent = &regs.fp()->scopeChain();
-    } else {
-        parent = GetScopeChain(cx, regs.fp());
-        if (!parent)
-            goto error;
-    }
-    JSObject *obj = CloneFunctionObjectIfNotSingleton(cx, fun, parent);
-    if (!obj)
-        goto error;
-
-    JS_ASSERT_IF(script->hasGlobal(), obj->getProto() == fun->getProto());
-
-    regs.fp()->varSlot(GET_SLOTNO(regs.pc)) = ObjectValue(*obj);
-}
-END_CASE(JSOP_DEFLOCALFUN)
-
 BEGIN_CASE(JSOP_LAMBDA)
 {
     /* Load the specified function object literal. */
     JSFunction *fun = script->getFunction(GET_UINT32_INDEX(regs.pc));
     JSObject *obj = fun;
 
     /* do-while(0) so we can break instead of using a goto. */
     do {
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -4781,18 +4781,32 @@ Decompile(SprintStack *ss, jsbytecode *p
                     las.releaseEarly();
                     if (!rval)
                         return NULL;
                     todo = ss->sprinter.put(rval);
                     cx->free_((void *)rval);
                     break;
                 }
 #endif /* JS_HAS_GENERATOR_EXPRS */
-                /* FALL THROUGH */
-
+                else if (sn && SN_TYPE(sn) == SRC_CONTINUE) {
+                    /*
+                     * Local function definitions have a lambda;setlocal;pop
+                     * triple (annotated with SRC_CONTINUE) in the function
+                     * prologue and a nop (annotated with SRC_FUNCDEF) at the
+                     * actual position where the function definition should
+                     * syntactically appear.
+                     */
+                    LOCAL_ASSERT(pc[JSOP_LAMBDA_LENGTH] == JSOP_SETLOCAL);
+                    LOCAL_ASSERT(pc[JSOP_LAMBDA_LENGTH + JSOP_SETLOCAL_LENGTH] == JSOP_POP);
+                    len = JSOP_LAMBDA_LENGTH + JSOP_SETLOCAL_LENGTH + JSOP_POP_LENGTH;
+                    todo = -2;
+                    break;
+                }
+
+                /* Otherwise, this is a lambda expression. */
                 fun = jp->script->getFunction(GET_UINT32_INDEX(pc));
                 {
                     /*
                      * Always parenthesize expression closures. We can't force
                      * saveop to a low-precedence op to arrange for auto-magic
                      * parenthesization without confusing getter/setter code
                      * that checks for JSOP_LAMBDA.
                      */
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -359,25 +359,19 @@ OPDEF(JSOP_PICK,        133, "pick",    
 
 /*
  * Exception handling no-op, for more economical byte-coding than SRC_TRYFIN
  * srcnote-annotated JSOP_NOPs and to simply stack balance handling.
  */
 OPDEF(JSOP_TRY,         134,"try",        NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_FINALLY,     135,"finally",    NULL,       1,  0,  2,  0,  JOF_BYTE)
 
-OPDEF(JSOP_UNUSED26,    136,"unused20",  NULL,        1,  0,  0,  0,  JOF_BYTE)
-OPDEF(JSOP_UNUSED27,    137,"unused21",  NULL,        1,  0,  0,  0,  JOF_BYTE)
-
-/*
- * Define a local function object as a local variable.
- * The local variable's slot number is the first immediate two-byte operand.
- * The function object's atom index is the second immediate operand.
- */
-OPDEF(JSOP_DEFLOCALFUN, 138,"deflocalfun",NULL,       7,  0,  0,  0,  JOF_SLOTOBJECT|JOF_DECLARING|JOF_TMPSLOT)
+OPDEF(JSOP_UNUSED26,    136,"unused26",  NULL,        1,  0,  0,  0,  JOF_BYTE)
+OPDEF(JSOP_UNUSED27,    137,"unused27",  NULL,        1,  0,  0,  0,  JOF_BYTE)
+OPDEF(JSOP_UNUSED28,    138,"unused28",  NULL,        1,  0,  0,  0,  JOF_BYTE)
 
 /* Extended jumps. */
 OPDEF(JSOP_UNUSED4,       139,"unused4",  NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED5,       140,"unused5",  NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED6,       141,"unused6",  NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED7,       142,"unused7",  NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED8,       143,"unused8",  NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED9,       144,"unused9",  NULL,       1,  0,  0,  0,  JOF_BYTE)
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -3110,41 +3110,16 @@ mjit::Compiler::generateMethod()
             frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg);
           }
           END_CASE(JSOP_LAMBDA)
 
           BEGIN_CASE(JSOP_TRY)
             frame.syncAndForgetEverything();
           END_CASE(JSOP_TRY)
 
-          BEGIN_CASE(JSOP_DEFLOCALFUN)
-          {
-            uint32_t slot = GET_SLOTNO(PC);
-            JSFunction *fun = script->getFunction(GET_UINT32_INDEX(PC + SLOTNO_LEN));
-
-            /*
-             * The liveness analysis will report that the value in |slot| is
-             * defined at the start of this opcode. However, we don't actually
-             * fill it in until the stub returns. This will cause a problem if
-             * we GC inside the stub. So we write a safe value here so that the
-             * GC won't crash.
-             */
-            markUndefinedLocal(PC - script->code, slot);
-
-            prepareStubCall(Uses(0));
-            masm.move(ImmPtr(fun), Registers::ArgReg1);
-            INLINE_STUBCALL(stubs::DefLocalFun, REJOIN_DEFLOCALFUN);
-            frame.takeReg(Registers::ReturnReg);
-            frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg);
-            frame.storeLocal(slot, true);
-            frame.pop();
-            updateVarType();
-          }
-          END_CASE(JSOP_DEFLOCALFUN)
-
           BEGIN_CASE(JSOP_RETRVAL)
             emitReturn(NULL);
             fallthrough = false;
           END_CASE(JSOP_RETRVAL)
 
           BEGIN_CASE(JSOP_GETGNAME)
           BEGIN_CASE(JSOP_CALLGNAME)
           {
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -976,45 +976,16 @@ stubs::InitElem(VMFrame &f, uint32_t las
         if (last && !js_SetLengthProperty(cx, obj, (uint32_t) (JSID_TO_INT(id) + 1)))
             THROW();
     } else {
         if (!obj->defineGeneric(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE))
             THROW();
     }
 }
 
-JSObject * JS_FASTCALL
-stubs::DefLocalFun(VMFrame &f, JSFunction *fun)
-{
-    /*
-     * Define a local function (i.e., one nested at the top level of another
-     * function), parented by the current scope chain, stored in a local
-     * variable slot that the compiler allocated.  This is an optimization over
-     * JSOP_DEFFUN that avoids requiring a call object for the outer function's
-     * activation.
-     */
-    JS_ASSERT(fun->isInterpreted());
-
-    JSObject *parent;
-    if (fun->isNullClosure()) {
-        parent = &f.fp()->scopeChain();
-    } else {
-        parent = GetScopeChain(f.cx, f.fp());
-        if (!parent)
-            THROWV(NULL);
-    }
-    JSObject *obj = CloneFunctionObjectIfNotSingleton(f.cx, fun, parent);
-    if (!obj)
-        THROWV(NULL);
-
-    JS_ASSERT_IF(f.script()->compileAndGo, obj->global() == fun->global());
-
-    return obj;
-}
-
 void JS_FASTCALL
 stubs::RegExp(VMFrame &f, JSObject *regex)
 {
     /*
      * Push a regexp object cloned from the regexp literal object mapped by the
      * bytecode at pc.
      */
     JSObject *proto = f.fp()->scopeChain().global().getOrCreateRegExpPrototype(f.cx);
--- a/js/src/methodjit/StubCalls.h
+++ b/js/src/methodjit/StubCalls.h
@@ -130,18 +130,16 @@ void JS_FASTCALL ImplicitThis(VMFrame &f
 template <JSBool strict> void JS_FASTCALL DelProp(VMFrame &f, PropertyName *name);
 template <JSBool strict> void JS_FASTCALL DelElem(VMFrame &f);
 void JS_FASTCALL DelName(VMFrame &f, PropertyName *name);
 JSBool JS_FASTCALL In(VMFrame &f);
 
 void JS_FASTCALL DefVarOrConst(VMFrame &f, PropertyName *name);
 void JS_FASTCALL SetConst(VMFrame &f, PropertyName *name);
 template<JSBool strict> void JS_FASTCALL DefFun(VMFrame &f, JSFunction *fun);
-JSObject * JS_FASTCALL DefLocalFun(VMFrame &f, JSFunction *fun);
-JSObject * JS_FASTCALL DefLocalFun_FC(VMFrame &f, JSFunction *fun);
 void JS_FASTCALL RegExp(VMFrame &f, JSObject *regex);
 JSObject * JS_FASTCALL Lambda(VMFrame &f, JSFunction *fun);
 JSObject * JS_FASTCALL LambdaJoinableForInit(VMFrame &f, JSFunction *fun);
 JSObject * JS_FASTCALL LambdaJoinableForSet(VMFrame &f, JSFunction *fun);
 JSObject * JS_FASTCALL LambdaJoinableForCall(VMFrame &f, JSFunction *fun);
 JSObject * JS_FASTCALL LambdaJoinableForNull(VMFrame &f, JSFunction *fun);
 JSObject * JS_FASTCALL FlatLambda(VMFrame &f, JSFunction *fun);
 void JS_FASTCALL Arguments(VMFrame &f);