/[jscoverage]/trunk/js/jsemit.cpp
ViewVC logotype

Diff of /trunk/js/jsemit.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 332 by siliconforks, Thu Oct 23 19:03:33 2008 UTC revision 399 by siliconforks, Tue Dec 9 03:37:47 2008 UTC
# Line 1892  Line 1892 
1892    
1893              ATOM_LIST_SEARCH(ale, &cg->upvarList, atom);              ATOM_LIST_SEARCH(ale, &cg->upvarList, atom);
1894              if (!ale) {              if (!ale) {
1895                  uint32 cookie, length, *vector;                  uint32 length, *vector;
1896    
1897                  ale = js_IndexAtom(cx, atom, &cg->upvarList);                  ale = js_IndexAtom(cx, atom, &cg->upvarList);
1898                  if (!ale)                  if (!ale)
# Line 1919  Line 1919 
1919                      return JS_TRUE;                      return JS_TRUE;
1920                  }                  }
1921    
1922                  cookie = MAKE_UPVAR_COOKIE(1, index);                  JS_ASSERT(cg->staticDepth > caller->fun->u.i.script->staticDepth);
1923                  cg->upvarMap.vector[ALE_INDEX(ale)] = cookie;                  uintN skip = cg->staticDepth - caller->fun->u.i.script->staticDepth;
1924                    cg->upvarMap.vector[ALE_INDEX(ale)] = MAKE_UPVAR_COOKIE(skip, index);
1925              }              }
1926    
1927              pn->pn_op = JSOP_GETUPVAR;              pn->pn_op = JSOP_GETUPVAR;
# Line 2078  Line 2079 
2079          break;          break;
2080    
2081        case PN_LIST:        case PN_LIST:
2082          if (pn->pn_type == TOK_NEW ||          if (pn->pn_op == JSOP_NOP ||
2083              pn->pn_type == TOK_LP ||              pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND ||
2084              pn->pn_type == TOK_LB ||              pn->pn_op == JSOP_STRICTEQ || pn->pn_op == JSOP_STRICTNE) {
2085              pn->pn_type == TOK_RB ||              /*
2086              pn->pn_type == TOK_RC) {               * Non-operators along with ||, &&, ===, and !== never invoke
2087                 * toString or valueOf.
2088                 */
2089                for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)
2090                    ok &= CheckSideEffects(cx, cg, pn2, answer);
2091            } else {
2092              /*              /*
2093               * All invocation operations (construct: TOK_NEW, call: TOK_LP)               * All invocation operations (construct: TOK_NEW, call: TOK_LP)
2094               * are presumed to be useful, because they may have side effects               * are presumed to be useful, because they may have side effects
# Line 2094  Line 2100 
2100               * (the JSOP_ARGUMENTS special case below, in the PN_BINARY case,               * (the JSOP_ARGUMENTS special case below, in the PN_BINARY case,
2101               * does not apply here: arguments[i][j] might invoke a getter).               * does not apply here: arguments[i][j] might invoke a getter).
2102               *               *
2103               * Array and object initializers (TOK_RB and TOK_RC lists) must be               * Likewise, array and object initialisers may call prototype
2104               * considered useful, because they are sugar for constructor calls               * setters (the __defineSetter__ built-in, and writable __proto__
2105               * (to Array and Object, respectively).               * on Array.prototype create this hazard). Initialiser list nodes
2106                 * have JSOP_NEWINIT in their pn_op.
2107               */               */
2108              *answer = JS_TRUE;              *answer = JS_TRUE;
         } else {  
             for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)  
                 ok &= CheckSideEffects(cx, cg, pn2, answer);  
2109          }          }
2110          break;          break;
2111    
# Line 2138  Line 2142 
2142                  }                  }
2143              }              }
2144          } else {          } else {
2145              /*              if (pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND ||
2146               * We can't easily prove that neither operand ever denotes an                  pn->pn_op == JSOP_STRICTEQ || pn->pn_op == JSOP_STRICTNE) {
2147               * object with a toString or valueOf method.                  /*
2148               */                   * ||, &&, ===, and !== do not convert their operands via
2149              *answer = JS_TRUE;                   * toString or valueOf method calls.
2150                     */
2151                    ok = CheckSideEffects(cx, cg, pn->pn_left, answer) &&
2152                         CheckSideEffects(cx, cg, pn->pn_right, answer);
2153                } else {
2154                    /*
2155                     * We can't easily prove that neither operand ever denotes an
2156                     * object with a toString or valueOf method.
2157                     */
2158                    *answer = JS_TRUE;
2159                }
2160          }          }
2161          break;          break;
2162    
# Line 2173  Line 2187 
2187              }              }
2188              break;              break;
2189    
2190              case TOK_UNARYOP:
2191                if (pn->pn_op == JSOP_NOT) {
2192                    /* ! does not convert its operand via toString or valueOf. */
2193                    ok = CheckSideEffects(cx, cg, pn->pn_kid, answer);
2194                    break;
2195                }
2196                /* FALL THROUGH */
2197    
2198            default:            default:
2199              /*              /*
2200               * All of TOK_INC, TOK_DEC, TOK_THROW, TOK_YIELD, and TOK_DEFSHARP               * All of TOK_INC, TOK_DEC, TOK_THROW, TOK_YIELD, and TOK_DEFSHARP
# Line 2344  Line 2366 
2366                    do_indexconst: {                    do_indexconst: {
2367                          JSAtomListElement *ale;                          JSAtomListElement *ale;
2368                          jsatomid atomIndex;                          jsatomid atomIndex;
2369                            
2370                          ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);                          ale = js_IndexAtom(cx, pn->pn_atom, &cg->atomList);
2371                          if (!ale)                          if (!ale)
2372                              return JS_FALSE;                              return JS_FALSE;
2373                          atomIndex = ALE_INDEX(ale);                          atomIndex = ALE_INDEX(ale);
2374                          return EmitSlotIndexOp(cx, op, pn2->pn_slot, atomIndex, cg);                          return EmitSlotIndexOp(cx, op, pn2->pn_slot, atomIndex, cg);
2375                      }                      }
2376                        
2377                    default:;                    default:;
2378                  }                  }
2379              }              }
# Line 3631  Line 3653 
3653              }              }
3654    
3655              /*              /*
3656               * A destructuring initialiser assignment preceded by var is               * A destructuring initialiser assignment preceded by var will
3657               * always evaluated promptly, even if it is to the left of 'in'               * never occur to the left of 'in' in a for-in loop.  As with 'for
3658               * in a for-in loop.  As with 'for (var x = i in o)...', this               * (var x = i in o)...', this will cause the entire 'var [a, b] =
3659               * will cause the entire 'var [a, b] = i' to be hoisted out of               * i' to be hoisted out of the loop.
              * the head of the loop.  
3660               */               */
3661              JS_ASSERT(pn2->pn_type == TOK_ASSIGN);              JS_ASSERT(pn2->pn_type == TOK_ASSIGN);
3662              if (pn->pn_count == 1 && !forInLet) {              JS_ASSERT(!forInVar);
3663                if (pn->pn_count == 1) {
3664                  /*                  /*
3665                   * If this is the only destructuring assignment in the list,                   * If this is the only destructuring assignment in the list,
3666                   * try to optimize to a group assignment.  If we're in a let                   * try to optimize to a group assignment.  If we're in a let
# Line 3648  Line 3670 
3670                  JS_ASSERT(noteIndex < 0 && !pn2->pn_next);                  JS_ASSERT(noteIndex < 0 && !pn2->pn_next);
3671                  op = JSOP_POP;                  op = JSOP_POP;
3672                  if (!MaybeEmitGroupAssignment(cx, cg,                  if (!MaybeEmitGroupAssignment(cx, cg,
3673                                                inLetHead ? JSOP_POP :                                                inLetHead ? JSOP_POP : PN_OP(pn),
                                               PN_OP(pn),  
3674                                                pn2, &op)) {                                                pn2, &op)) {
3675                      return JS_FALSE;                      return JS_FALSE;
3676                  }                  }
# Line 3663  Line 3684 
3684              if (!EmitDestructuringDecls(cx, cg, PN_OP(pn), pn3))              if (!EmitDestructuringDecls(cx, cg, PN_OP(pn), pn3))
3685                  return JS_FALSE;                  return JS_FALSE;
3686    
 #if JS_HAS_BLOCK_SCOPE  
             /*  
              * If this is a 'for (let [x, y] = i in o) ...' let declaration,  
              * throw away i if it is a useless expression.  
              */  
             if (forInLet) {  
                 JSBool useful = JS_FALSE;  
   
                 JS_ASSERT(pn->pn_count == 1);  
                 if (!CheckSideEffects(cx, cg, pn2->pn_right, &useful))  
                     return JS_FALSE;  
                 if (!useful)  
                     return JS_TRUE;  
             }  
 #endif  
   
3687              if (!js_EmitTree(cx, cg, pn2->pn_right))              if (!js_EmitTree(cx, cg, pn2->pn_right))
3688                  return JS_FALSE;                  return JS_FALSE;
3689    
 #if JS_HAS_BLOCK_SCOPE  
             /*  
              * The expression i in 'for (let [x, y] = i in o) ...', which is  
              * pn2->pn_right above, appears to have side effects.  We've just  
              * emitted code to evaluate i, but we must not destructure i yet.  
              * Let the TOK_FOR: code in js_EmitTree do the destructuring to  
              * emit the right combination of source notes and bytecode for the  
              * decompiler.  
              *  
              * This has the effect of hoisting the evaluation of i out of the  
              * for-in loop, without hoisting the let variables, which must of  
              * course be scoped by the loop.  Set PNX_POPVAR to cause JSOP_POP  
              * to be emitted, just before returning from this function.  
              */  
             if (forInVar) {  
                 pn->pn_extra |= PNX_POPVAR;  
                 if (forInLet)  
                     break;  
             }  
 #endif  
   
3690              /*              /*
3691               * Veto pn->pn_op if inLetHead to avoid emitting a SRC_DESTRUCT               * Veto pn->pn_op if inLetHead to avoid emitting a SRC_DESTRUCT
3692               * that's redundant with respect to the SRC_DECL/SRC_DECL_LET that               * that's redundant with respect to the SRC_DECL/SRC_DECL_LET that
# Line 3737  Line 3721 
3721    
3722              pn3 = pn2->pn_expr;              pn3 = pn2->pn_expr;
3723              if (pn3) {              if (pn3) {
3724  #if JS_HAS_BLOCK_SCOPE                  JS_ASSERT(!forInVar);
                 /*  
                  * If this is a 'for (let x = i in o) ...' let declaration,  
                  * throw away i if it is a useless expression.  
                  */  
                 if (forInLet) {  
                     JSBool useful = JS_FALSE;  
   
                     JS_ASSERT(pn->pn_count == 1);  
                     if (!CheckSideEffects(cx, cg, pn3, &useful))  
                         return JS_FALSE;  
                     if (!useful)  
                         return JS_TRUE;  
                 }  
 #endif  
   
3725                  if (op == JSOP_SETNAME) {                  if (op == JSOP_SETNAME) {
3726                      JS_ASSERT(!let);                      JS_ASSERT(!let);
3727                      EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex);                      EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex);
# Line 3772  Line 3741 
3741                      tc->topStmt = stmt->down;                      tc->topStmt = stmt->down;
3742                      tc->topScopeStmt = scopeStmt->downScope;                      tc->topScopeStmt = scopeStmt->downScope;
3743                  }                  }
3744  #ifdef __GNUC__  # ifdef __GNUC__
3745                  else {                  else stmt = scopeStmt = NULL;   /* quell GCC overwarning */
3746                      stmt = scopeStmt = NULL;    /* quell GCC overwarning */  # endif
                 }  
 #endif  
3747  #endif  #endif
3748    
3749                  oldflags = cg->treeContext.flags;                  oldflags = cg->treeContext.flags;
# Line 3795  Line 3762 
3762          }          }
3763    
3764          /*          /*
3765           * 'for (var x in o) ...' and 'for (var x = i in o) ...' call the           * The parser rewrites 'for (var x = i in o)' to hoist 'var x = i' --
3766           * TOK_VAR case, but only the initialized case (a strange one that           * likewise 'for (let x = i in o)' becomes 'i; for (let x in o)' using
3767           * falls out of ECMA-262's grammar) wants to run past this point.           * a TOK_SEQ node to make the two statements appear as one. Therefore
3768           * Both cases must conditionally emit a JSOP_DEFVAR, above.  Note           * if this declaration is part of a for-in loop head, we do not need to
3769           * that the parser error-checks to ensure that pn->pn_count is 1.           * emit op or any source note. Our caller, the TOK_FOR/TOK_IN case in
3770           *           * js_EmitTree, will annotate appropriately.
          * 'for (let x = i in o) ...' must evaluate i before the loop, and  
          * subject it to useless expression elimination.  The variable list  
          * in pn is a single let declaration if pn_op == JSOP_NOP.  We test  
          * the let local in order to break early in this case, as well as in  
          * the 'for (var x in o)' case.  
          *  
          * XXX Narcissus keeps track of variable declarations in the node  
          * for the script being compiled, so there's no need to share any  
          * conditional prolog code generation there.  We could do likewise,  
          * but it's a big change, requiring extra allocation, so probably  
          * not worth the trouble for SpiderMonkey.  
3771           */           */
3772          JS_ASSERT(pn3 == pn2->pn_expr);          JS_ASSERT(pn3 == pn2->pn_expr);
3773          if (forInVar && (!pn3 || let)) {          if (forInVar) {
3774              JS_ASSERT(pn->pn_count == 1);              JS_ASSERT(pn->pn_count == 1);
3775                JS_ASSERT(!pn3);
3776              break;              break;
3777          }          }
3778    
# Line 3893  Line 3850 
3850             js_Emit1(cx, cg, JSOP_NOP) >= 0;             js_Emit1(cx, cg, JSOP_NOP) >= 0;
3851  }  }
3852    
3853    /* See the SRC_FOR source note offsetBias comments later in this file. */
3854    JS_STATIC_ASSERT(JSOP_NOP_LENGTH == 1);
3855    JS_STATIC_ASSERT(JSOP_POP_LENGTH == 1);
3856    
3857  JSBool  JSBool
3858  js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)  js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
3859  {  {
# Line 3976  Line 3937 
3937          cg2->staticDepth = cg->staticDepth + 1;          cg2->staticDepth = cg->staticDepth + 1;
3938          cg2->parent = cg;          cg2->parent = cg;
3939    
3940          /* We metered the max scope depth when parsed the function. */          /* We metered the max scope depth when parsed the function. */
3941          JS_SCOPE_DEPTH_METERING(cg2->treeContext.maxScopeDepth = (uintN) -1);          JS_SCOPE_DEPTH_METERING(cg2->treeContext.maxScopeDepth = (uintN) -1);
3942          if (!js_EmitFunctionScript(cx, cg2, pn->pn_body)) {          if (!js_EmitFunctionScript(cx, cg2, pn->pn_body)) {
3943              pn = NULL;              pn = NULL;
# Line 4216  Line 4177 
4177          js_PushStatement(&cg->treeContext, &stmtInfo, STMT_FOR_LOOP, top);          js_PushStatement(&cg->treeContext, &stmtInfo, STMT_FOR_LOOP, top);
4178    
4179          if (pn2->pn_type == TOK_IN) {          if (pn2->pn_type == TOK_IN) {
             JSBool emitIFEQ;  
   
4180              /* Set stmtInfo type for later testing. */              /* Set stmtInfo type for later testing. */
4181              stmtInfo.type = STMT_FOR_IN_LOOP;              stmtInfo.type = STMT_FOR_IN_LOOP;
             noteIndex = -1;  
4182    
4183              /*              /*
4184               * If the left part is 'var x', emit code to define x if necessary               * If the left part is 'var x', emit code to define x if necessary
# Line 4264  Line 4222 
4222               * destructuring for-in).               * destructuring for-in).
4223               */               */
4224              JS_ASSERT(pn->pn_op == JSOP_ITER);              JS_ASSERT(pn->pn_op == JSOP_ITER);
4225              if (js_Emit2(cx, cg, PN_OP(pn), (uint8) pn->pn_iflags) < 0)              if (js_Emit2(cx, cg, JSOP_ITER, (uint8) pn->pn_iflags) < 0)
4226                    return JS_FALSE;
4227    
4228                /* Annotate so the decompiler can find the loop-closing jump. */
4229                noteIndex = js_NewSrcNote(cx, cg, SRC_FOR_IN);
4230                if (noteIndex < 0)
4231                    return JS_FALSE;
4232    
4233                /*
4234                 * Jump down to the loop condition to minimize overhead assuming at
4235                 * least one iteration, as the other loop forms do.
4236                 */
4237                jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
4238                if (jmp < 0)
4239                  return JS_FALSE;                  return JS_FALSE;
4240    
4241              top = CG_OFFSET(cg);              top = CG_OFFSET(cg);
4242              SET_STATEMENT_TOP(&stmtInfo, top);              SET_STATEMENT_TOP(&stmtInfo, top);
4243    
4244    #ifdef DEBUG
4245                intN loopDepth = cg->stackDepth;
4246    #endif
4247    
4248              /*              /*
4249               * Compile a JSOP_FOR* bytecode based on the left hand side.               * Compile a JSOP_FOR* bytecode based on the left hand side.
4250               *               *
# Line 4280  Line 4255 
4255               * assignment, so JSOP_SETNAME is not critical here; many similar               * assignment, so JSOP_SETNAME is not critical here; many similar
4256               * ops could be used -- just not JSOP_NOP (which means 'let').               * ops could be used -- just not JSOP_NOP (which means 'let').
4257               */               */
             emitIFEQ = JS_TRUE;  
4258              op = JSOP_SETNAME;              op = JSOP_SETNAME;
4259              switch (type) {              switch (type) {
4260  #if JS_HAS_BLOCK_SCOPE  #if JS_HAS_BLOCK_SCOPE
# Line 4301  Line 4275 
4275  #else  #else
4276                  JS_ASSERT(pn3->pn_type == TOK_NAME);                  JS_ASSERT(pn3->pn_type == TOK_NAME);
4277  #endif  #endif
4278                    /* FALL THROUGH */
4279    
4280                  case TOK_NAME:
4281                  /*                  /*
4282                   * Always annotate JSOP_FORLOCAL if given input of the form                   * Always annotate JSOP_FORLOCAL if given input of the form
4283                   * 'for (let x in * o)' -- the decompiler must not hoist the                   * 'for (let x in * o)' -- the decompiler must not hoist the
4284                   * 'let x' out of the loop head, or x will be bound in the                   * 'let x' out of the loop head, or x will be bound in the
4285                   * wrong scope.  Likewise, but in this case only for the sake                   * wrong scope.  Likewise, but in this case only for the sake
4286                   * of higher decompilation fidelity only, do not hoist 'var x'                   * of higher decompilation fidelity only, do not hoist 'var x'
4287                   * when given 'for (var x in o)'.  But 'for (var x = i in o)'                   * when given 'for (var x in o)'.
                  * requires hoisting in order to preserve the initializer i.  
                  * The decompiler can only handle so much!  
4288                   */                   */
4289                  if ((                  if ((
4290  #if JS_HAS_BLOCK_SCOPE  #if JS_HAS_BLOCK_SCOPE
4291                       type == TOK_LET ||                       type == TOK_LET ||
4292  #endif  #endif
4293                       !pn3->pn_expr) &&                       (type == TOK_VAR && !pn3->pn_expr)) &&
4294                      js_NewSrcNote2(cx, cg, SRC_DECL,                      js_NewSrcNote2(cx, cg, SRC_DECL,
4295                                     type == TOK_VAR                                     (type == TOK_VAR)
4296                                     ? SRC_DECL_VAR                                     ? SRC_DECL_VAR
4297                                     : SRC_DECL_LET) < 0) {                                     : SRC_DECL_LET) < 0) {
4298                      return JS_FALSE;                      return JS_FALSE;
4299                  }                  }
                 /* FALL THROUGH */  
               case TOK_NAME:  
4300                  if (pn3->pn_slot >= 0) {                  if (pn3->pn_slot >= 0) {
4301                      op = PN_OP(pn3);                      op = PN_OP(pn3);
4302                      switch (op) {                      switch (op) {
# Line 4344  Line 4317 
4317                  if (pn3->pn_slot >= 0) {                  if (pn3->pn_slot >= 0) {
4318                      if (pn3->pn_const) {                      if (pn3->pn_const) {
4319                          JS_ASSERT(op == JSOP_FORLOCAL);                          JS_ASSERT(op == JSOP_FORLOCAL);
4320                          op = JSOP_FORCONST;                          js_ReportCompileErrorNumber(cx, CG_TS(cg), pn3, JSREPORT_ERROR,
4321                                                        JSMSG_BAD_FOR_LEFTSIDE);
4322                            return JS_FALSE;
4323                      }                      }
4324                      atomIndex = (jsatomid) pn3->pn_slot;                      atomIndex = (jsatomid) pn3->pn_slot;
4325                      EMIT_UINT16_IMM_OP(op, atomIndex);                      EMIT_UINT16_IMM_OP(op, atomIndex);
# Line 4355  Line 4330 
4330                  break;                  break;
4331    
4332                case TOK_DOT:                case TOK_DOT:
4333                    /*
4334                     * 'for (o.p in q)' can use JSOP_FORPROP only if evaluating 'o'
4335                     * has no side effects.
4336                     */
4337                  useful = JS_FALSE;                  useful = JS_FALSE;
4338                  if (!CheckSideEffects(cx, cg, pn3->pn_expr, &useful))                  if (!CheckSideEffects(cx, cg, pn3->pn_expr, &useful))
4339                      return JS_FALSE;                      return JS_FALSE;
# Line 4366  Line 4345 
4345                  /* FALL THROUGH */                  /* FALL THROUGH */
4346    
4347  #if JS_HAS_DESTRUCTURING  #if JS_HAS_DESTRUCTURING
               case TOK_RB:  
               case TOK_RC:  
4348                destructuring_for:                destructuring_for:
4349  #endif  #endif
4350  #if JS_HAS_XML_SUPPORT                default:
               case TOK_UNARYOP:  
 #endif  
 #if JS_HAS_LVALUE_RETURN  
               case TOK_LP:  
 #endif  
               case TOK_LB:  
                 /*  
                  * We separate the first/next bytecode from the enumerator  
                  * variable binding to avoid any side-effects in the index  
                  * expression (e.g., for (x[i++] in {}) should not bind x[i]  
                  * or increment i at all).  
                  */  
                 emitIFEQ = JS_FALSE;  
4351                  if (js_Emit1(cx, cg, JSOP_FORELEM) < 0)                  if (js_Emit1(cx, cg, JSOP_FORELEM) < 0)
4352                      return JS_FALSE;                      return JS_FALSE;
4353                    JS_ASSERT(cg->stackDepth >= 3);
                 /*  
                  * Emit a SRC_WHILE note with offset telling the distance to  
                  * the loop-closing jump (we can't reckon from the branch at  
                  * the top of the loop, because the loop-closing jump might  
                  * need to be an extended jump, independent of whether the  
                  * branch is short or long).  
                  */  
                 noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);  
                 if (noteIndex < 0)  
                     return JS_FALSE;  
                 beq = EmitJump(cx, cg, JSOP_IFEQ, 0);  
                 if (beq < 0)  
                     return JS_FALSE;  
4354    
4355  #if JS_HAS_DESTRUCTURING  #if JS_HAS_DESTRUCTURING
4356                  if (pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC) {                  if (pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC) {
# Line 4407  Line 4358 
4358                          return JS_FALSE;                          return JS_FALSE;
4359                      if (js_Emit1(cx, cg, JSOP_POP) < 0)                      if (js_Emit1(cx, cg, JSOP_POP) < 0)
4360                          return JS_FALSE;                          return JS_FALSE;
4361                      break;                  } else
                 }  
4362  #endif  #endif
4363  #if JS_HAS_LVALUE_RETURN  #if JS_HAS_LVALUE_RETURN
4364                  if (pn3->pn_type == TOK_LP) {                  if (pn3->pn_type == TOK_LP) {
# Line 4417  Line 4367 
4367                          return JS_FALSE;                          return JS_FALSE;
4368                      if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0)                      if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0)
4369                          return JS_FALSE;                          return JS_FALSE;
4370                      break;                  } else
                 }  
4371  #endif  #endif
4372  #if JS_HAS_XML_SUPPORT  #if JS_HAS_XML_SUPPORT
4373                  if (pn3->pn_type == TOK_UNARYOP) {                  if (pn3->pn_type == TOK_UNARYOP) {
# Line 4427  Line 4376 
4376                          return JS_FALSE;                          return JS_FALSE;
4377                      if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0)                      if (js_Emit1(cx, cg, JSOP_ENUMELEM) < 0)
4378                          return JS_FALSE;                          return JS_FALSE;
4379                      break;                  } else
                 }  
4380  #endif  #endif
   
                 /* Now that we're safely past the IFEQ, commit side effects. */  
4381                  if (!EmitElemOp(cx, pn3, JSOP_ENUMELEM, cg))                  if (!EmitElemOp(cx, pn3, JSOP_ENUMELEM, cg))
4382                      return JS_FALSE;                      return JS_FALSE;
4383                  break;                  break;
   
               default:  
                 JS_ASSERT(0);  
4384              }              }
4385    
4386              if (emitIFEQ) {              /* The stack should be balanced around the JSOP_FOR* opcode sequence. */
4387                  /* Annotate so the decompiler can find the loop-closing jump. */              JS_ASSERT(cg->stackDepth == loopDepth);
                 noteIndex = js_NewSrcNote(cx, cg, SRC_WHILE);  
                 if (noteIndex < 0)  
                     return JS_FALSE;  
4388    
4389                  /* Pop and test the loop condition generated by JSOP_FOR*. */              /* Set the first srcnote offset so we can find the start of the loop body. */
4390                  beq = EmitJump(cx, cg, JSOP_IFEQ, 0);              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, CG_OFFSET(cg) - jmp))
4391                  if (beq < 0)                  return JS_FALSE;
                     return JS_FALSE;  
             }  
4392    
4393              /* Emit code for the loop body. */              /* Emit code for the loop body. */
4394              if (!js_EmitTree(cx, cg, pn->pn_right))              if (!js_EmitTree(cx, cg, pn->pn_right))
4395                  return JS_FALSE;                  return JS_FALSE;
4396    
4397              /* Emit the loop-closing jump and fixup all jump offsets. */              /* Set loop and enclosing "update" offsets, for continue. */
4398              jmp = EmitJump(cx, cg, JSOP_GOTO, top - CG_OFFSET(cg));              stmt = &stmtInfo;
4399              if (jmp < 0)              do {
4400                    stmt->update = CG_OFFSET(cg);
4401                } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
4402    
4403                /*
4404                 * Fixup the goto that starts the loop to jump down to JSOP_NEXTITER.
4405                 */
4406                CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
4407                if (js_Emit1(cx, cg, JSOP_NEXTITER) < 0)
4408                    return JS_FALSE;
4409                beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
4410                if (beq < 0)
4411                  return JS_FALSE;                  return JS_FALSE;
             if (beq > 0)  
                 CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);  
4412    
4413              /* Set the SRC_WHILE note offset so we can find the closing jump. */              /* Set the second srcnote offset so we can find the closing jump. */
4414              JS_ASSERT(noteIndex != -1);              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, beq - jmp))
             if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, jmp - beq))  
4415                  return JS_FALSE;                  return JS_FALSE;
4416          } else {          } else {
4417              /* C-style for (init; cond; update) ... loop. */              /* C-style for (init; cond; update) ... loop. */
# Line 4499  Line 4445 
4445                  }                  }
4446                  cg->treeContext.flags &= ~TCF_IN_FOR_INIT;                  cg->treeContext.flags &= ~TCF_IN_FOR_INIT;
4447              }              }
4448    
4449                /*
4450                 * NB: the SRC_FOR note has offsetBias 1 (JSOP_{NOP,POP}_LENGTH).
4451                 * Use tmp to hold the biased srcnote "top" offset, which differs
4452                 * from the top local variable by the length of the JSOP_GOTO{,X}
4453                 * emitted in between tmp and top if this loop has a condition.
4454                 */
4455              noteIndex = js_NewSrcNote(cx, cg, SRC_FOR);              noteIndex = js_NewSrcNote(cx, cg, SRC_FOR);
4456              if (noteIndex < 0 ||              if (noteIndex < 0 || js_Emit1(cx, cg, op) < 0)
                 js_Emit1(cx, cg, op) < 0) {  
4457                  return JS_FALSE;                  return JS_FALSE;
4458              }              tmp = CG_OFFSET(cg);
4459    
4460              if (pn2->pn_kid2) {              if (pn2->pn_kid2) {
4461                  /* Goto the loop condition, which branches back to iterate. */                  /* Goto the loop condition, which branches back to iterate. */
# Line 4511  Line 4463 
4463                  if (jmp < 0)                  if (jmp < 0)
4464                      return JS_FALSE;                      return JS_FALSE;
4465              }              }
4466    
4467              top = CG_OFFSET(cg);              top = CG_OFFSET(cg);
4468              SET_STATEMENT_TOP(&stmtInfo, top);              SET_STATEMENT_TOP(&stmtInfo, top);
4469    
# Line 4521  Line 4474 
4474              /* Set the second note offset so we can find the update part. */              /* Set the second note offset so we can find the update part. */
4475              JS_ASSERT(noteIndex != -1);              JS_ASSERT(noteIndex != -1);
4476              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1,              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1,
4477                                       CG_OFFSET(cg) - top)) {                                       CG_OFFSET(cg) - tmp)) {
4478                  return JS_FALSE;                  return JS_FALSE;
4479              }              }
4480    
# Line 4541  Line 4494 
4494                      return JS_FALSE;                      return JS_FALSE;
4495                  }                  }
4496  #endif  #endif
4497                  if (op == JSOP_POP) {                  if (op == JSOP_POP && !js_EmitTree(cx, cg, pn3))
4498                      if (!js_EmitTree(cx, cg, pn3))                      return JS_FALSE;
4499                          return JS_FALSE;  
4500                      if (js_Emit1(cx, cg, op) < 0)                  /* Always emit the POP or NOP, to help the decompiler. */
4501                          return JS_FALSE;                  if (js_Emit1(cx, cg, op) < 0)
4502                  }                      return JS_FALSE;
4503    
4504                  /* Restore the absolute line number for source note readers. */                  /* Restore the absolute line number for source note readers. */
4505                  off = (ptrdiff_t) pn->pn_pos.end.lineno;                  off = (ptrdiff_t) pn->pn_pos.end.lineno;
# Line 4559  Line 4512 
4512    
4513              /* Set the first note offset so we can find the loop condition. */              /* Set the first note offset so we can find the loop condition. */
4514              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0,              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0,
4515                                       CG_OFFSET(cg) - top)) {                                       CG_OFFSET(cg) - tmp)) {
4516                  return JS_FALSE;                  return JS_FALSE;
4517              }              }
4518    
# Line 4574  Line 4527 
4527    
4528              /* The third note offset helps us find the loop-closing jump. */              /* The third note offset helps us find the loop-closing jump. */
4529              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 2,              if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 2,
4530                                       CG_OFFSET(cg) - top)) {                                       CG_OFFSET(cg) - tmp)) {
4531                  return JS_FALSE;                  return JS_FALSE;
4532              }              }
4533    
# Line 4596  Line 4549 
4549    
4550          if (pn2->pn_type == TOK_IN) {          if (pn2->pn_type == TOK_IN) {
4551              /*              /*
4552               * JSOP_ENDITER needs a slot to save an exception thrown from the               * JSOP_ENDITER must have a slot to save an exception thrown from
4553               * body of for-in loop when closing the iterator object.               * the body of for-in loop when closing the iterator object, and
4554                 * fortunately it does: the slot that was set by JSOP_NEXTITER to
4555                 * the return value of iterator.next().
4556               */               */
4557              JS_ASSERT(js_CodeSpec[JSOP_ENDITER].format & JOF_TMPSLOT);              JS_ASSERT(js_CodeSpec[JSOP_ENDITER].nuses == 2);
4558              if (!NewTryNote(cx, cg, JSTN_ITER, cg->stackDepth, top,              if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top, CG_OFFSET(cg)) ||
                             CG_OFFSET(cg)) ||  
4559                  js_Emit1(cx, cg, JSOP_ENDITER) < 0) {                  js_Emit1(cx, cg, JSOP_ENDITER) < 0) {
4560                  return JS_FALSE;                  return JS_FALSE;
4561              }              }
# Line 4901  Line 4855 
4855           * (first to last for a given nesting level, inner to outer by level).           * (first to last for a given nesting level, inner to outer by level).
4856           */           */
4857          if (pn->pn_kid2 &&          if (pn->pn_kid2 &&
4858              !NewTryNote(cx, cg, JSTN_CATCH, depth, tryStart, tryEnd)) {              !NewTryNote(cx, cg, JSTRY_CATCH, depth, tryStart, tryEnd)) {
4859              return JS_FALSE;              return JS_FALSE;
4860          }          }
4861    
# Line 4911  Line 4865 
4865           * for the try{}finally{} case.           * for the try{}finally{} case.
4866           */           */
4867          if (pn->pn_kid3 &&          if (pn->pn_kid3 &&
4868              !NewTryNote(cx, cg, JSTN_FINALLY, depth, tryStart, finallyStart)) {              !NewTryNote(cx, cg, JSTRY_FINALLY, depth, tryStart, finallyStart)) {
4869              return JS_FALSE;              return JS_FALSE;
4870          }          }
4871          break;          break;
# Line 5133  Line 5087 
5087          ok = js_PopStatementCG(cx, cg);          ok = js_PopStatementCG(cx, cg);
5088          break;          break;
5089    
5090        case TOK_BODY:        case TOK_SEQ:
5091          JS_ASSERT(pn->pn_arity == PN_LIST);          JS_ASSERT(pn->pn_arity == PN_LIST);
5092          js_PushStatement(&cg->treeContext, &stmtInfo, STMT_BODY, top);          js_PushStatement(&cg->treeContext, &stmtInfo, STMT_SEQ, top);
5093          for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {          for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
5094              if (!js_EmitTree(cx, cg, pn2))              if (!js_EmitTree(cx, cg, pn2))
5095                  return JS_FALSE;                  return JS_FALSE;
# Line 5763  Line 5717 
5717            default:            default:
5718              /*              /*
5719               * If useless, just emit JSOP_TRUE; otherwise convert delete foo()               * If useless, just emit JSOP_TRUE; otherwise convert delete foo()
5720               * to foo(), true (a comma expression, requiring SRC_PCDELTA, and               * to foo(), true (a comma expression, requiring SRC_PCDELTA).
              * also JSOP_GROUP for correctly parenthesized decompilation).  
5721               */               */
5722              useful = JS_FALSE;              useful = JS_FALSE;
5723              if (!CheckSideEffects(cx, cg, pn2, &useful))              if (!CheckSideEffects(cx, cg, pn2, &useful))
# Line 5786  Line 5739 
5739                  if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off))                  if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp-off))
5740                      return JS_FALSE;                      return JS_FALSE;
5741              }              }
             if (js_Emit1(cx, cg, JSOP_GROUP) < 0)  
                 return JS_FALSE;  
5742          }          }
5743          break;          break;
5744    
# Line 5896  Line 5847 
5847          argc = pn->pn_count - 1;          argc = pn->pn_count - 1;
5848          if (js_Emit3(cx, cg, PN_OP(pn), ARGC_HI(argc), ARGC_LO(argc)) < 0)          if (js_Emit3(cx, cg, PN_OP(pn), ARGC_HI(argc), ARGC_LO(argc)) < 0)
5849              return JS_FALSE;              return JS_FALSE;
5850          if (js_Emit1(cx, cg, JSOP_RESUME) < 0)          if (PN_OP(pn) == JSOP_EVAL)
             return JS_FALSE;  
         if (PN_OP(pn) == JSOP_EVAL)  
5851              EMIT_UINT16_IMM_OP(JSOP_LINENO, pn->pn_pos.begin.lineno);              EMIT_UINT16_IMM_OP(JSOP_LINENO, pn->pn_pos.begin.lineno);
5852          break;          break;
5853        }        }
# Line 6208  Line 6157 
6157          if (!js_EmitTree(cx, cg, pn->pn_kid))          if (!js_EmitTree(cx, cg, pn->pn_kid))
6158              return JS_FALSE;              return JS_FALSE;
6159          cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT;          cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT;
         if (js_Emit1(cx, cg, JSOP_GROUP) < 0)  
             return JS_FALSE;  
6160          break;          break;
6161        }        }
6162    
# Line 6420  Line 6367 
6367      return ok;      return ok;
6368  }  }
6369    
6370  /* XXX get rid of offsetBias, it's used only by SRC_FOR and SRC_DECL */  /*
6371     * We should try to get rid of offsetBias (always 0 or 1, where 1 is
6372     * JSOP_{NOP,POP}_LENGTH), which is used only by SRC_FOR and SRC_DECL.
6373     */
6374  JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[] = {  JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[] = {
6375      {"null",            0,      0,      0},      {"null",            0,      0,      0},
6376      {"if",              0,      0,      0},      {"if",              0,      0,      0},
6377      {"if-else",         2,      0,      1},      {"if-else",         2,      0,      1},
     {"while",           1,      0,      1},  
6378      {"for",             3,      1,      1},      {"for",             3,      1,      1},
6379        {"while",           1,      0,      1},
6380      {"continue",        0,      0,      0},      {"continue",        0,      0,      0},
6381      {"decl",            1,      1,      1},      {"decl",            1,      1,      1},
6382      {"pcdelta",         1,      0,      1},      {"pcdelta",         1,      0,      1},

Legend:
Removed from v.332  
changed lines
  Added in v.399

  ViewVC Help
Powered by ViewVC 1.1.24