Leave a hint for GetProperty in the context so it can figure out the current bytecode location without de-optimizing (476238, r=jorendorff).
authorAndreas Gal <gal@mozilla.com>
Mon, 02 Feb 2009 17:25:59 -0800
changeset 24598 78da97bbec6894dd12e265ebbec2884ea3ef7516
parent 24591 e7fffaf1f9fa99745937e6e59a797e84d4654a42
child 24599 a556e7c0d6d7d39b250d22749ffdf651fad1531f
push id5132
push userrsayre@mozilla.com
push dateWed, 04 Feb 2009 20:48:09 +0000
treeherdermozilla-central@76ca30e94e5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs476238
milestone1.9.2a1pre
Leave a hint for GetProperty in the context so it can figure out the current bytecode location without de-optimizing (476238, r=jorendorff).
js/src/jscntxt.h
js/src/jsinterp.cpp
js/src/jsobj.cpp
js/src/jstracer.cpp
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -125,16 +125,17 @@ struct GlobalState {
 typedef struct JSTraceMonitor {
     /*
      * Flag set when running (or recording) JIT-compiled code. This prevents
      * both interpreter activation and last-ditch garbage collection when up
      * against our runtime's memory limits. This flag also suppresses calls to
      * JS_ReportOutOfMemory when failing due to runtime limits.
      */
     JSBool                  onTrace;
+
     CLS(nanojit::LirBuffer) lirbuf;
     CLS(nanojit::Fragmento) fragmento;
     CLS(TraceRecorder)      recorder;
     jsval                   *reservedDoublePool;
     jsval                   *reservedDoublePoolPtr;
 
     struct GlobalState globalStates[MONITOR_N_GLOBAL_STATES];
     struct VMFragment* vmfragments[FRAGMENT_TABLE_SIZE];
@@ -975,18 +976,24 @@ struct JSContext {
     /* Security callbacks that override any defined on the runtime. */
     JSSecurityCallbacks *securityCallbacks;
 
     /* Pinned regexp pool used for regular expressions. */
     JSArenaPool         regexpPool;
 
     /* Stored here to avoid passing it around as a parameter. */
     uintN               resolveFlags;
+    
+    /* Current bytecode location (or NULL if no hint was supplied). */
+    jsbytecode         *pcHint;
 };
 
+#define BEGIN_PC_HINT(pc)       cx->pcHint = pc
+#define END_PC_HINT()           cx->pcHint = NULL
+
 #ifdef JS_THREADSAFE
 # define JS_THREAD_ID(cx)       ((cx)->thread ? (cx)->thread->id : 0)
 #endif
 
 #ifdef __cplusplus
 
 static inline JSAtom **
 FrameAtomBase(JSContext *cx, JSStackFrame *fp)
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -4275,21 +4275,22 @@ js_Interpret(JSContext *cx)
                 } else {
                     entry = NULL;
                     if (i < 0)
                         atom = rt->atomState.lengthAtom;
                     else
                         LOAD_ATOM(i);
                 }
                 id = ATOM_TO_JSID(atom);
-                if (entry
-                    ? !js_GetPropertyHelper(cx, aobj, id, &rval, &entry)
-                    : !OBJ_GET_PROPERTY(cx, obj, id, &rval)) {
-                    goto error;
-                }
+                BEGIN_PC_HINT(regs.pc);
+                    if (entry
+                        ? !js_GetPropertyHelper(cx, aobj, id, &rval, &entry)
+                        : !OBJ_GET_PROPERTY(cx, obj, id, &rval)) 
+                        goto error;
+                END_PC_HINT();
             } while (0);
 
             STORE_OPND(-1, rval);
             JS_ASSERT(JSOP_GETPROP_LENGTH + i == js_CodeSpec[op].length);
             len = JSOP_GETPROP_LENGTH + i;
           END_VARLEN_CASE
 
           BEGIN_CASE(JSOP_LENGTH)
@@ -4383,27 +4384,30 @@ js_Interpret(JSContext *cx)
                     JSXMLObjectOps *ops;
 
                     ops = (JSXMLObjectOps *) obj->map->ops;
                     obj = ops->getMethod(cx, obj, id, &rval);
                     if (!obj)
                         goto error;
                 } else
 #endif
-                if (entry
-                    ? !js_GetPropertyHelper(cx, aobj, id, &rval, &entry)
-                    : !OBJ_GET_PROPERTY(cx, obj, id, &rval)) {
-                    goto error;
-                }
+                BEGIN_PC_HINT(regs.pc);
+                    if (entry
+                        ? !js_GetPropertyHelper(cx, aobj, id, &rval, &entry)
+                        : !OBJ_GET_PROPERTY(cx, obj, id, &rval))
+                        goto error;
+                END_PC_HINT();
                 STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
                 STORE_OPND(-2, rval);
             } else {
                 JS_ASSERT(obj->map->ops->getProperty == js_GetProperty);
-                if (!js_GetPropertyHelper(cx, obj, id, &rval, &entry))
-                    goto error;
+                BEGIN_PC_HINT(regs.pc);
+                    if (!js_GetPropertyHelper(cx, obj, id, &rval, &entry))
+                        goto error;
+                END_PC_HINT();
                 STORE_OPND(-1, lval);
                 STORE_OPND(-2, rval);
             }
 
           end_callprop:
             /* Wrap primitive lval in object clothing if necessary. */
             if (JSVAL_IS_PRIMITIVE(lval)) {
                 /* FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=412571 */
@@ -6872,16 +6876,19 @@ js_Interpret(JSContext *cx)
           }
 
 #if !JS_THREADED_INTERP
         } /* switch (op) */
     } /* for (;;) */
 #endif /* !JS_THREADED_INTERP */
 
   error:
+    // Reset current pc location hinting.
+    cx->pcHint = NULL;
+
     if (fp->imacpc && cx->throwing) {
         // To keep things simple, we hard-code imacro exception handlers here.
         if (*fp->imacpc == JSOP_NEXTITER) {
             // pc may point to JSOP_DUP here due to bug 474854.
             JS_ASSERT(*regs.pc == JSOP_CALL || *regs.pc == JSOP_DUP);
             if (js_ValueIsStopIteration(cx->exception)) {
                 cx->throwing = JS_FALSE;
                 cx->exception = JSVAL_VOID;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3891,59 +3891,72 @@ js_NativeSet(JSContext *cx, JSObject *ob
          SCOPE_GET_PROPERTY(scope, sprop->id) == sprop)) {
   set_slot:
         LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, *vp);
     }
 
     return JS_TRUE;
 }
 
+/*
+ * Find out where we currently are in the code. If no hint was supplied,
+ * de-optimize and consult the stack frame.
+ */
+static jsbytecode*
+js_GetCurrentBytecodePC(JSContext* cx)
+{
+    jsbytecode *pc = cx->pcHint;
+    if (!pc) {
+        JSStackFrame* fp = js_GetTopStackFrame(cx);
+        if (fp && fp->regs)
+            pc = fp->regs->pc;
+    }
+    return pc;
+}
+
 JSBool
 js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
                      JSPropCacheEntry **entryp)
 {
     uint32 shape;
     int protoIndex;
     JSObject *obj2;
     JSProperty *prop;
-    JSStackFrame *fp;
     JSScopeProperty *sprop;
 
     JS_ASSERT_IF(entryp, !JS_ON_TRACE(cx));
     /* Convert string indices to integers if appropriate. */
     CHECK_FOR_STRING_INDEX(id);
     JS_COUNT_OPERATION(cx, JSOW_GET_PROPERTY);
 
     shape = OBJ_SHAPE(obj);
     protoIndex = js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags,
                                             &obj2, &prop);
     if (protoIndex < 0)
         return JS_FALSE;
     if (!prop) {
-        jsbytecode *pc;
-
         *vp = JSVAL_VOID;
 
         if (!OBJ_GET_CLASS(cx, obj)->getProperty(cx, obj, ID_TO_VALUE(id), vp))
             return JS_FALSE;
 
         if (entryp) {
             PCMETER(JS_PROPERTY_CACHE(cx).nofills++);
             *entryp = NULL;
         }
 
         /*
          * Give a strict warning if foo.bar is evaluated by a script for an
          * object foo with no property named 'bar'.
          */
-        if (JSVAL_IS_VOID(*vp) && (fp = js_GetTopStackFrame(cx)) && fp->regs) {
+        jsbytecode *pc;
+        if (JSVAL_IS_VOID(*vp) && ((pc = js_GetCurrentBytecodePC(cx)) != NULL)) {
             JSOp op;
             uintN flags;
 
-            pc = fp->regs->pc;
             op = (JSOp) *pc;
             if (op == JSOP_GETXPROP) {
                 flags = JSREPORT_ERROR;
             } else {
                 if (!JS_HAS_STRICT_OPTION(cx) ||
                     (op != JSOP_GETPROP && op != JSOP_GETELEM)) {
                     return JS_TRUE;
                 }
@@ -3951,17 +3964,16 @@ js_GetPropertyHelper(JSContext *cx, JSOb
                 /*
                  * XXX do not warn about missing __iterator__ as the function
                  * may be called from JS_GetMethodById. See bug 355145.
                  */
                 if (id == ATOM_TO_JSID(cx->runtime->atomState.iteratorAtom))
                     return JS_TRUE;
 
                 /* Kludge to allow (typeof foo == "undefined") tests. */
-                JS_ASSERT(fp->script);
                 pc += js_CodeSpec[op].length;
                 if (Detecting(cx, pc))
                     return JS_TRUE;
 
                 flags = JSREPORT_WARNING | JSREPORT_STRICT;
             }
 
             /* Ok, bad undefined property reference: whine about it. */
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -6882,25 +6882,26 @@ GetProperty(JSContext *cx, uintN argc, j
     JS_ASSERT(JSVAL_IS_STRING(argv[0]));
     if (!js_ValueToStringId(cx, argv[0], &id))
         return JS_FALSE;
     argv[0] = ID_TO_VALUE(id);
     return OBJ_GET_PROPERTY(cx, JS_THIS_OBJECT(cx, vp), id, &JS_RVAL(cx, vp));
 }
 
 static jsval FASTCALL
-GetProperty_tn(JSContext *cx, JSObject *obj, JSString *name)
+GetProperty_tn(JSContext *cx, jsbytecode *pc, JSObject *obj, JSString *name)
 {
     jsid id;
     jsval v;
 
-    if (!js_ValueToStringId(cx, STRING_TO_JSVAL(name), &id) ||
-        !OBJ_GET_PROPERTY(cx, obj, id, &v)) {
-        return JSVAL_ERROR_COOKIE;
-    }
+    BEGIN_PC_HINT(pc);
+        if (!js_ValueToStringId(cx, STRING_TO_JSVAL(name), &id) ||
+            !OBJ_GET_PROPERTY(cx, obj, id, &v))
+            v = JSVAL_ERROR_COOKIE;
+    END_PC_HINT();
     return v;
 }
 
 static JSBool
 GetElement(JSContext *cx, uintN argc, jsval *vp)
 {
     jsval *argv;
     jsid id;
@@ -6910,32 +6911,34 @@ GetElement(JSContext *cx, uintN argc, js
     JS_ASSERT(JSVAL_IS_NUMBER(argv[0]));
     if (!JS_ValueToId(cx, argv[0], &id))
         return JS_FALSE;
     argv[0] = ID_TO_VALUE(id);
     return OBJ_GET_PROPERTY(cx, JS_THIS_OBJECT(cx, vp), id, &JS_RVAL(cx, vp));
 }
 
 static jsval FASTCALL
-GetElement_tn(JSContext* cx, JSObject* obj, int32 index)
+GetElement_tn(JSContext* cx, jsbytecode *pc, JSObject* obj, int32 index)
 {
     jsval v;
     jsid id;
 
     if (!js_Int32ToId(cx, index, &id))
         return JSVAL_ERROR_COOKIE;
-    if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
-        return JSVAL_ERROR_COOKIE;
+    BEGIN_PC_HINT(pc);
+        if (!OBJ_GET_PROPERTY(cx, obj, id, &v))
+            v = JSVAL_ERROR_COOKIE;
+    END_PC_HINT();
     return v;
 }
 
 JS_DEFINE_TRCINFO_1(GetProperty,
-    (3, (static, JSVAL_FAIL,    GetProperty_tn, CONTEXT, THIS, STRING,          0, 0)))
+    (4, (static, JSVAL_FAIL,    GetProperty_tn, CONTEXT, PC, THIS, STRING,      0, 0)))
 JS_DEFINE_TRCINFO_1(GetElement,
-    (3, (extern, JSVAL_FAIL,    GetElement_tn,  CONTEXT, THIS, INT32,           0, 0)))
+    (4, (extern, JSVAL_FAIL,    GetElement_tn,  CONTEXT, PC, THIS, INT32,       0, 0)))
 
 JS_REQUIRES_STACK bool
 TraceRecorder::record_JSOP_GETELEM()
 {
     jsval& idx = stackval(-1);
     jsval& lval = stackval(-2);
 
     LIns* obj_ins = get(&lval);