Abort recording on some more global operations (bug 597940, r=luke).
authorDavid Anderson <danderson@mozilla.com>
Wed, 05 Jan 2011 19:53:08 -0800
changeset 60247 d8586631c5f07e5a92c1406cd46bf2580a47ee70
parent 60246 8a1715b0aeaeb2ba6553a5c2701249671032e4a8
child 60248 423d37840edf794d81092bacd609fcbcc46705aa
push idunknown
push userunknown
push dateunknown
reviewersluke
bugs597940
milestone2.0b9pre
Abort recording on some more global operations (bug 597940, r=luke).
js/src/jit-test/tests/basic/testChangingTypeDuringRecording.js
js/src/jstracer.h
js/src/shell/js.cpp
--- a/js/src/jit-test/tests/basic/testChangingTypeDuringRecording.js
+++ b/js/src/jit-test/tests/basic/testChangingTypeDuringRecording.js
@@ -1,19 +1,6 @@
-/* Touch/init early so global shape doesn't change in loop */
-var SetOnIter = HOTLOOP - 1;
-var x = 3;
-var i = 0;
-assertEq(true, true);
-
-for (i = 0; i < SetOnIter + 10; ++i) {
-    x = 3;
-    setGlobalPropIf(i == SetOnIter, 'x', 'pretty');
-    assertEq(x == 'pretty', i == SetOnIter);
-    x = 3;
+X = { value: "" }
+z = 0;
+for (var i = 0; i < 20; i++) {
+    Object.defineProperty(this, "z", X);
+    z = 1;
 }
-
-for (i = 0; i < SetOnIter + 10; ++i) {
-    x = 3;
-    defGlobalPropIf(i == SetOnIter, 'x', { value:'pretty' });
-    assertEq(x == 'pretty', i == SetOnIter);
-    x = 3;
-}
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -1607,17 +1607,30 @@ class TraceRecorder
     void forgetGuardedShapesForObject(JSObject* obj);
 
     bool globalSetExpected(unsigned slot) {
         if (pendingGlobalSlotToSet != (int)slot) {
             /*
              * Do slot arithmetic manually to avoid getSlotRef assertions which
              * do not need to be satisfied for this purpose.
              */
-            return !tracker.has(globalObj->getSlots() + slot);
+            Value *vp = globalObj->getSlots() + slot;
+
+            /* If this global is definitely being tracked, then the write is unexpected. */
+            if (tracker.has(vp))
+                return false;
+            
+            /*
+             * Otherwise, only abort if the global is not present in the
+             * import typemap. Just deep aborting false here is not acceptable,
+             * because the recorder does not guard on every operation that
+             * could lazily resolve. Since resolving adds properties to
+             * reserved slots, the tracer will never have imported them.
+             */
+            return tree->globalSlots->offsetOf(nativeGlobalSlot(vp)) == -1;
         }
         pendingGlobalSlotToSet = -1;
         return true;
     }
 
 #ifdef DEBUG
     /* Debug printing functionality to emit printf() on trace. */
     JS_REQUIRES_STACK void tprint(const char *format, int count, nanojit::LIns *insa[]);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -4242,69 +4242,16 @@ Deserialize(JSContext *cx, uintN argc, j
                                 JS_STRUCTURED_CLONE_VERSION, &v, NULL, NULL)) {
         return false;
     }
     JS_SET_RVAL(cx, vp, v);
     return true;
 }
 
 JSBool
-SetGlobalPropIf(JSContext *cx, uintN argc, jsval *vp)
-{
-    if (argc != 3) {
-        JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_INVALID_ARGS, "setGlobalPropIf");
-        return false;
-    }
-
-    jsval *argv = JS_ARGV(cx, vp);
-
-    JSBool doSet;
-    if (!JS_ValueToBoolean(cx, argv[0], &doSet))
-        return false;
-
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
-    if (!doSet)
-        return true;
-
-    jsid id;
-    if (!JS_ValueToId(cx, argv[1], &id))
-        return false;
-
-    JSObject *global = JS_GetGlobalForScopeChain(cx);
-    return global && JS_SetPropertyById(cx, global, id, &argv[2]);
-}
-
-JSBool
-DefGlobalPropIf(JSContext *cx, uintN argc, jsval *vp)
-{
-    if (argc != 3) {
-        JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_INVALID_ARGS, "setGlobalPropIf");
-        return false;
-    }
-
-    jsval *argv = JS_ARGV(cx, vp);
-
-    JSBool doSet;
-    if (!JS_ValueToBoolean(cx, argv[0], &doSet))
-        return false;
-
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
-    if (!doSet)
-        return true;
-
-    jsid id;
-    if (!JS_ValueToId(cx, argv[1], &id))
-        return false;
-
-    JSObject *global = JS_GetGlobalForScopeChain(cx);
-    JSBool ignore;
-    return global && JS_DefineOwnProperty(cx, global, id, argv[2], &ignore);
-}
-
-JSBool
 MJitStats(JSContext *cx, uintN argc, jsval *vp)
 {
     JS_SET_RVAL(cx, vp, INT_TO_JSVAL(cx->runtime->mjitMemoryUsed));
     return true;
 }
 
 JSBool
 StringStats(JSContext *cx, uintN argc, jsval *vp)
@@ -4405,18 +4352,16 @@ static JSFunctionSpec shell_functions[] 
     JS_FN("compile",        Compile,        1,0),
     JS_FN("parse",          Parse,          1,0),
     JS_FN("timeout",        Timeout,        1,0),
     JS_FN("elapsed",        Elapsed,        0,0),
     JS_FN("parent",         Parent,         1,0),
     JS_FN("wrap",           Wrap,           1,0),
     JS_FN("serialize",      Serialize,      1,0),
     JS_FN("deserialize",    Deserialize,    1,0),
-    JS_FN("setGlobalPropIf",SetGlobalPropIf,3,0),
-    JS_FN("defGlobalPropIf",DefGlobalPropIf,3,0),
 #ifdef JS_METHODJIT
     JS_FN("mjitstats",      MJitStats,      0,0),
 #endif
     JS_FN("stringstats",    StringStats,    0,0),
     JS_FS_END
 };
 
 static const char shell_help_header[] =
@@ -4540,19 +4485,16 @@ static const char *const shell_help_mess
 "timeout([seconds])\n"
 "  Get/Set the limit in seconds for the execution time for the current context.\n"
 "  A negative value (default) means that the execution time is unlimited.",
 "elapsed()                Execution time elapsed for the current context.",
 "parent(obj)              Returns the parent of obj.\n",
 "wrap(obj)                Wrap an object into a noop wrapper.\n",
 "serialize(sd)            Serialize sd using JS_WriteStructuredClone. Returns a TypedArray.\n",
 "deserialize(a)           Deserialize data generated by serialize.\n",
-"setGlobalPropIf(b,id,v)  If b, get the global object o and perform o[id] = v.\n",
-"defGlobalPropIf(b,id,dsc)If b, get the global object o and perform\n"
-"                         Object.defineProperty(o, id, dsc).\n",
 #ifdef JS_METHODJIT
 "mjitstats()             Return stats on mjit memory usage.\n",
 #endif
 "stringstats()           Return stats on string memory usage.\n"
 };
 
 /* Help messages must match shell functions. */
 JS_STATIC_ASSERT(JS_ARRAY_LENGTH(shell_help_messages) + 1 ==