diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 2271ea4c0bc..361ab237459 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -2510,7 +2510,7 @@ js_Interpret(JSContext *cx) # ifdef JS_TRACER # define CHECK_RECORDER() JS_BEGIN_MACRO \ - JS_ASSERT(!TRACE_RECORDER(cx) ^ \ + JS_ASSERT(!JS_TRACE_MONITOR(cx).recorder ^ \ (jumpTable == recordingJumpTable)); \ JS_END_MACRO # else @@ -2569,11 +2569,11 @@ js_Interpret(JSContext *cx) #ifdef JS_TRACER /* We had better not be entering the interpreter from JIT-compiled code. */ TraceRecorder *tr = NULL; - if (JS_ON_TRACE(cx)) { - tr = TRACE_RECORDER(cx); - SET_TRACE_RECORDER(cx, NULL); + if (JS_TRACE_MONITOR(cx).onTrace) { + tr = JS_TRACE_MONITOR(cx).recorder; + JS_TRACE_MONITOR(cx).recorder = NULL; } -#endif +#endif /* Check for too deep of a native thread stack. */ JS_CHECK_RECURSION(cx, return JS_FALSE); @@ -2695,13 +2695,13 @@ js_Interpret(JSContext *cx) # define LOAD_INTERRUPT_HANDLER(cx) \ ((void) (jumpTable = (cx)->debugHooks->interruptHandler \ ? interruptJumpTable \ - : TRACE_RECORDER(cx) \ + : JS_TRACE_MONITOR(cx).recorder \ ? recordingJumpTable \ : normalJumpTable)) # define ENABLE_TRACER(flag) \ JS_BEGIN_MACRO \ bool flag_ = (flag); \ - JS_ASSERT(flag_ == !!TRACE_RECORDER(cx)); \ + JS_ASSERT(flag_ == !!JS_TRACE_MONITOR(cx).recorder); \ jumpTable = flag_ ? recordingJumpTable : normalJumpTable; \ JS_END_MACRO #else /* !JS_TRACER */ @@ -2715,11 +2715,12 @@ js_Interpret(JSContext *cx) #ifdef JS_TRACER # define LOAD_INTERRUPT_HANDLER(cx) \ ((void) (switchMask = ((cx)->debugHooks->interruptHandler || \ - TRACE_RECORDER(cx)) ? 0 : 255)) + JS_TRACE_MONITOR(cx).recorder) \ + ? 0 : 255)) # define ENABLE_TRACER(flag) \ JS_BEGIN_MACRO \ bool flag_ = (flag); \ - JS_ASSERT(flag_ == !!TRACE_RECORDER(cx)); \ + JS_ASSERT(flag_ == !!JS_TRACE_MONITOR(cx).recorder); \ switchMask = flag_ ? 0 : 255; \ JS_END_MACRO #else /* !JS_TRACER */ @@ -3021,7 +3022,7 @@ js_Interpret(JSContext *cx) inlineCallCount--; if (JS_LIKELY(ok)) { #ifdef JS_TRACER - if (TRACE_RECORDER(cx)) + if (JS_TRACE_MONITOR(cx).recorder) RECORD(LeaveFrame); #endif JS_ASSERT(js_CodeSpec[*regs.pc].length == JSOP_CALL_LENGTH); @@ -3265,6 +3266,7 @@ js_Interpret(JSContext *cx) * that we take into account side effects of the iterator * call. See bug 372331. */ + if (!js_FindProperty(cx, id, &obj, &obj2, &prop)) goto error; if (prop) @@ -4437,7 +4439,8 @@ js_Interpret(JSContext *cx) * will (possibly after the first iteration) always exist * in native object o. */ - entry = &cache->table[PROPERTY_CACHE_HASH_PC(regs.pc, kshape)]; + entry = &cache->table[PROPERTY_CACHE_HASH_PC(regs.pc, + kshape)]; PCMETER(cache->tests++); PCMETER(cache->settests++); if (entry->kpc == regs.pc && entry->kshape == kshape) { @@ -4451,8 +4454,6 @@ js_Interpret(JSContext *cx) JS_ASSERT(!(sprop->attrs & JSPROP_READONLY)); JS_ASSERT(!SCOPE_IS_SEALED(OBJ_SCOPE(obj))); - TRACE_2(SetPropHit, kshape, sprop); - if (scope->object == obj) { /* * Fastest path: the cached sprop is already @@ -4907,7 +4908,7 @@ js_Interpret(JSContext *cx) cx->fp = fp = &newifp->frame; #ifdef JS_TRACER - if (TRACE_RECORDER(cx)) + if (JS_TRACE_MONITOR(cx).recorder) RECORD(EnterFrame); #endif @@ -6120,8 +6121,6 @@ js_Interpret(JSContext *cx) if (sprop->parent != scope->lastProp) goto do_initprop_miss; - TRACE_2(SetPropHit, kshape, sprop); - /* * Otherwise this entry must be for a direct property of * obj, not a proto-property, and there cannot have been @@ -7027,7 +7026,7 @@ js_Interpret(JSContext *cx) JS_ASSERT(inlineCallCount == 0); JS_ASSERT(fp->regs == ®s); #ifdef JS_TRACER - if (TRACE_RECORDER(cx)) + if (JS_TRACE_MONITOR(cx).recorder) js_AbortRecording(cx, regs.pc, "recording out of js_Interpret"); #endif if (JS_UNLIKELY(fp->flags & JSFRAME_YIELDING)) { @@ -7052,12 +7051,12 @@ js_Interpret(JSContext *cx) js_SetVersion(cx, originalVersion); --cx->interpLevel; -#ifdef JS_TRACER +#ifdef JS_TRACER if (tr) { - SET_TRACE_RECORDER(cx, tr); + JS_TRACE_MONITOR(cx).recorder = tr; tr->deepAbort(); } -#endif +#endif return ok; atom_not_defined: diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index a8c345ae26c..702be70838d 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -2526,9 +2526,9 @@ js_MonitorLoopEdge(JSContext* cx, jsbytecode* oldpc, uintN& inlineCallCount) } bool -js_MonitorRecording(TraceRecorder* tr) +js_MonitorRecording(JSContext* cx) { - JSContext* cx = tr->cx; + TraceRecorder *tr = JS_TRACE_MONITOR(cx).recorder; // Clear one-shot flag used to communicate between record_JSOP_CALL and record_EnterFrame. tr->applyingArguments = false; @@ -2540,12 +2540,11 @@ js_MonitorRecording(TraceRecorder* tr) } jsbytecode* pc = cx->fp->regs->pc; - /* If we hit a break, end the loop and generate an always taken loop exit guard. For other downward gotos (like if/else) continue recording. */ - if (*pc == JSOP_GOTO || *pc == JSOP_GOTOX) { + if ((*pc == JSOP_GOTO) || (*pc == JSOP_GOTOX)) { jssrcnote* sn = js_GetSrcNote(cx->fp->script, pc); - if (sn && SN_TYPE(sn) == SRC_BREAK) { + if ((sn != NULL) && (SN_TYPE(sn) == SRC_BREAK)) { AUDIT(breakLoopExits); tr->endLoop(JS_TRACE_MONITOR(cx).fragmento); js_DeleteRecorder(cx); @@ -4394,38 +4393,41 @@ TraceRecorder::record_JSOP_GETPROP() bool TraceRecorder::record_JSOP_SETPROP() { + jsval& r = stackval(-1); jsval& l = stackval(-2); + if (JSVAL_IS_PRIMITIVE(l)) ABORT_TRACE("primitive this for SETPROP"); JSObject* obj = JSVAL_TO_OBJECT(l); + if (obj->map->ops->setProperty != js_SetProperty) ABORT_TRACE("non-native JSObjectOps::setProperty"); - return true; -} -bool -TraceRecorder::record_SetPropHit(uint32 kshape, JSScopeProperty* sprop) -{ - jsval& r = stackval(-1); - jsval& l = stackval(-2); - - JS_ASSERT(!JSVAL_IS_PRIMITIVE(l)); - JSObject* obj = JSVAL_TO_OBJECT(l); LIns* obj_ins = get(&l); + JSPropertyCache* cache = &JS_PROPERTY_CACHE(cx); + uint32 kshape = OBJ_SHAPE(obj); + jsbytecode* pc = cx->fp->regs->pc; + + JSPropCacheEntry* entry = &cache->table[PROPERTY_CACHE_HASH_PC(pc, kshape)]; + if (entry->kpc != pc || entry->kshape != kshape) + ABORT_TRACE("cache miss"); + JS_ASSERT(PCVAL_IS_SPROP(entry->vword)); + + LIns* map_ins = lir->insLoad(LIR_ldp, obj_ins, (int)offsetof(JSObject, map)); + LIns* ops_ins; + if (!map_is_native(obj->map, map_ins, ops_ins, offsetof(JSObjectOps, setProperty))) + return false; + // The global object's shape is guarded at trace entry. if (obj != globalObj) { - LIns* map_ins = lir->insLoad(LIR_ldp, obj_ins, (int)offsetof(JSObject, map)); - LIns* ops_ins; - if (!map_is_native(obj->map, map_ins, ops_ins, offsetof(JSObjectOps, setProperty))) - return false; - LIns* shape_ins = addName(lir->insLoad(LIR_ld, map_ins, offsetof(JSScope, shape)), "shape"); guard(true, addName(lir->ins2i(LIR_eq, shape_ins, kshape), "guard(shape)"), MISMATCH_EXIT); } JSScope* scope = OBJ_SCOPE(obj); + JSScopeProperty* sprop = PCVAL_TO_SPROP(entry->vword); if (scope->object != obj || !SCOPE_HAS_PROPERTY(scope, sprop)) { LIns* args[] = { INS_CONSTPTR(sprop), obj_ins, cx_ins }; LIns* ok_ins = lir->insCall(F_AddProperty, args); @@ -4439,9 +4441,7 @@ TraceRecorder::record_SetPropHit(uint32 kshape, JSScopeProperty* sprop) return false; if (!native_set(obj_ins, sprop, dslots_ins, boxed_ins)) return false; - - jsbytecode* pc = cx->fp->regs->pc; - if (*pc != JSOP_INITPROP && pc[JSOP_SETPROP_LENGTH] != JSOP_POP) + if (*pc == JSOP_SETPROP && pc[JSOP_SETPROP_LENGTH] != JSOP_POP) stack(-2, v_ins); return true; } @@ -5368,8 +5368,8 @@ TraceRecorder::record_JSOP_ENDINIT() bool TraceRecorder::record_JSOP_INITPROP() { - // All the action is in record_SetPropHit. - return true; + // The common code avoids stacking the RHS if op is not JSOP_SETPROP. + return record_JSOP_SETPROP(); } bool @@ -5457,6 +5457,8 @@ TraceRecorder::record_JSOP_ITER() bool TraceRecorder::forInLoop(jsval* vp) { + if (!JSVAL_IS_STRING(*vp)) + ABORT_TRACE("for-in loop variable changed type from string"); jsval& iterobj_val = stackval(-1); if (!JSVAL_IS_PRIMITIVE(iterobj_val)) { LIns* args[] = { get(&iterobj_val), cx_ins }; @@ -5465,11 +5467,10 @@ TraceRecorder::forInLoop(jsval* vp) LIns* flag_ins = lir->ins_eq0(lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_HOLE))); LIns* iter_ins = get(vp); - jsval expected = JSVAL_IS_VOID(*vp) ? JSVAL_STRING : JSVAL_TAG(*vp); - if (!box_jsval(expected, iter_ins)) + if (!box_jsval(JSVAL_STRING, iter_ins)) return false; iter_ins = lir->ins_choose(flag_ins, v_ins, iter_ins, true); - if (!unbox_jsval(expected, iter_ins)) + if (!unbox_jsval(JSVAL_STRING, iter_ins)) return false; set(vp, iter_ins); stack(0, flag_ins); diff --git a/js/src/jstracer.h b/js/src/jstracer.h index dbb69d5b87f..a54a242b051 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -334,7 +334,7 @@ class TraceRecorder { void fuseIf(jsbytecode* pc, bool cond, nanojit::LIns* x); public: - friend bool js_MonitorRecording(TraceRecorder* tr); + friend bool js_MonitorRecording(JSContext* cx); TraceRecorder(JSContext* cx, nanojit::GuardRecord*, nanojit::Fragment*, TreeInfo*, unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap, @@ -358,7 +358,6 @@ public: bool record_EnterFrame(); bool record_LeaveFrame(); - bool record_SetPropHit(uint32 kshape, JSScopeProperty* sprop); void deepAbort() { deepAborted = true; } bool wasDeepAborted() { return deepAborted; } @@ -370,43 +369,23 @@ public: }; #define TRACING_ENABLED(cx) JS_HAS_OPTION(cx, JSOPTION_JIT) -#define TRACE_RECORDER(cx) (JS_TRACE_MONITOR(cx).recorder) -#define SET_TRACE_RECORDER(cx,tr) (JS_TRACE_MONITOR(cx).recorder = (tr)) -// See jsinterp.cpp for the ENABLE_TRACER definition. -#define RECORD_ARGS(x,args) \ +#define RECORD(x) \ JS_BEGIN_MACRO \ - TraceRecorder* tr_ = TRACE_RECORDER(cx); \ - if (!js_MonitorRecording(tr_)) \ + TraceRecorder* r = JS_TRACE_MONITOR(cx).recorder; \ + if (!js_MonitorRecording(cx)) { \ ENABLE_TRACER(0); \ - else \ - TRACE_ARGS_(tr_,x,args); \ - JS_END_MACRO - -#define TRACE_ARGS_(tr,x,args) \ - JS_BEGIN_MACRO \ - if (!tr->record_##x args) { \ + } else if (!r->record_##x()) { \ js_AbortRecording(cx, NULL, #x); \ ENABLE_TRACER(0); \ } \ JS_END_MACRO -#define TRACE_ARGS(x,args) \ - JS_BEGIN_MACRO \ - TraceRecorder* tr_ = TRACE_RECORDER(cx); \ - if (tr_) \ - TRACE_ARGS_(tr_, x, args); \ - JS_END_MACRO - -#define RECORD(x) RECORD_ARGS(x, ()) -#define TRACE_1(x,a) TRACE_ARGS(x, (a)) -#define TRACE_2(x,a,b) TRACE_ARGS(x, (a, b)) - extern bool js_MonitorLoopEdge(JSContext* cx, jsbytecode* oldpc, uintN& inlineCallCount); extern bool -js_MonitorRecording(TraceRecorder *tr); +js_MonitorRecording(JSContext* cx); extern void js_AbortRecording(JSContext* cx, jsbytecode* abortpc, const char* reason);