Merge TM -> JM. Last merge from TM to grab 4 changesets prior to the start of the experiment to use mozilla-inbound instead of tracemonkey.
authorGary Kwong <gary@rumblingedge.com>
Fri, 15 Jul 2011 23:18:10 +0800
changeset 76041 f2ca662099dac226136749631b5f7f0448bbe7d8
parent 76036 d7d452b4b90bcbd6321b02c397da4be876475cb9 (current diff)
parent 76040 ab57a16c66fc6df3b72542de6470d949e94f87f0 (diff)
child 76042 b769a2b79e6b3192c33f01b9016ab91659f4304f
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
milestone8.0a1
Merge TM -> JM. Last merge from TM to grab 4 changesets prior to the start of the experiment to use mozilla-inbound instead of tracemonkey.
js/src/jsemit.cpp
js/src/jsopcode.cpp
js/src/jstracer.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testBug667915.js
@@ -0,0 +1,8 @@
+for each(let y in [0, 0]) {
+    eval("\
+        for each(e in[0,0,0,0,0,0,0,0]) {\
+            x = undefined\
+        }\
+    ")
+}
+
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -4113,17 +4113,17 @@ MaybeEmitGroupAssignment(JSContext *cx, 
 #endif /* JS_HAS_DESTRUCTURING */
 
 static JSBool
 EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
               JSBool inLetHead, ptrdiff_t *headNoteIndex)
 {
     bool let, forInVar, first;
 #if JS_HAS_BLOCK_SCOPE
-    bool forInLet, popScope;
+    bool popScope;
     JSStmtInfo *stmt, *scopeStmt;
 #endif
     ptrdiff_t off, noteIndex, tmp;
     JSParseNode *pn2, *pn3, *next;
     JSOp op;
     jsatomid atomIndex;
     uintN oldflags;
 
@@ -4140,17 +4140,16 @@ EmitVariables(JSContext *cx, JSCodeGener
      * The same goes for let declarations in the head of any kind of for loop.
      * Unlike a let declaration 'let x = i' within a block, where x is hoisted
      * to the start of the block, a 'for (let x = i...) ...' loop evaluates i
      * in the containing scope, and puts x in the loop body's scope.
      */
     let = (pn->pn_op == JSOP_NOP);
     forInVar = (pn->pn_xflags & PNX_FORINVAR) != 0;
 #if JS_HAS_BLOCK_SCOPE
-    forInLet = let && forInVar;
     popScope = (inLetHead || (let && (cg->flags & TCF_IN_FOR_INIT)));
     if (popScope) {
         stmt = cg->topStmt;
         scopeStmt = cg->topScopeStmt;
     }
 # ifdef __GNUC__
     else stmt = scopeStmt = NULL;   /* quell GCC overwarning */
 # endif
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -238,39 +238,52 @@ js_GetEnterBlockStackDefs(JSContext *cx,
     return OBJ_BLOCK_COUNT(cx, obj);
 }
 
 class AutoScriptUntrapper {
     JSContext *cx;
     JSScript *script;
     jsbytecode *origPC;
     jsbytecode *newPC;
+#ifdef DEBUG
+    bool assertionBefore;
+#endif
 
 public:
     AutoScriptUntrapper(JSContext *cx, JSScript *script, jsbytecode **pc)
         : cx(cx), script(script), origPC(*pc)
+#ifdef DEBUG
+          , assertionBefore(false)
+#endif
     {
         jsbytecode *newCode = js_UntrapScriptCode(cx, script);
         if (newCode == script->code) {
             // No change needed
             newPC = origPC;
         } else {
             script->main += newCode - script->code;
             *pc = newPC = origPC + (newCode - script->code);
             script->code = newCode;
+#ifdef DEBUG
+            assertionBefore = cx->stackIterAssertionEnabled;
+            cx->stackIterAssertionEnabled = false;
+#endif
         }
     }
     ~AutoScriptUntrapper()
     {
         ptrdiff_t delta = newPC - origPC;
         if (delta) {
             jsbytecode *oldCode = script->code - delta;
             cx->free_(script->code);
             script->code = oldCode;
             script->main -= delta;
+#ifdef DEBUG
+            cx->stackIterAssertionEnabled = assertionBefore;
+#endif
         }
     }
 };
 
 #ifdef DEBUG
 
 /*
  * If pc != NULL, include a prefix indicating whether the PC is at the current line.
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -15163,23 +15163,35 @@ TraceRecorder::record_JSOP_BINDNAME()
 {
     TraceMonitor *localtm = traceMonitor;
     StackFrame* const fp = cx->fp();
     JSObject *obj;
 
     if (!fp->isFunctionFrame()) {
         obj = &fp->scopeChain();
 
+#ifdef DEBUG
+        StackFrame *fp2 = fp;
+#endif
+
         /*
          * In global code, fp->scopeChain can only contain blocks whose values
          * are still on the stack.  We never use BINDNAME to refer to these.
          */
         while (obj->isBlock()) {
             // The block's values are still on the stack.
-            JS_ASSERT(obj->getPrivate() == fp);
+#ifdef DEBUG
+            // NB: fp2 can't be a generator frame, because !fp->hasFunction.
+            while (obj->getPrivate() != fp2) {
+                JS_ASSERT(fp2->isEvalFrame());
+                fp2 = fp2->prev();
+                if (!fp2)
+                    JS_NOT_REACHED("bad stack frame");
+            }
+#endif
             obj = obj->getParent();
             // Blocks always have parents.
             JS_ASSERT(obj);
         }
 
         /*
          * If this is a strict mode eval frame, we will have a Call object for
          * it. For now just don't trace this case.