mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 454039 - TM: don't abort TraceRecorder::record_JSOP_SETPROP on cache miss (r=mrbkap).
This commit is contained in:
parent
c84dcdc593
commit
4e02f9fc96
@ -2510,7 +2510,7 @@ js_Interpret(JSContext *cx)
|
||||
|
||||
# ifdef JS_TRACER
|
||||
# define CHECK_RECORDER() JS_BEGIN_MACRO \
|
||||
JS_ASSERT(!JS_TRACE_MONITOR(cx).recorder ^ \
|
||||
JS_ASSERT(!TRACE_RECORDER(cx) ^ \
|
||||
(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_TRACE_MONITOR(cx).onTrace) {
|
||||
tr = JS_TRACE_MONITOR(cx).recorder;
|
||||
JS_TRACE_MONITOR(cx).recorder = NULL;
|
||||
if (JS_ON_TRACE(cx)) {
|
||||
tr = TRACE_RECORDER(cx);
|
||||
SET_TRACE_RECORDER(cx, 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 \
|
||||
: JS_TRACE_MONITOR(cx).recorder \
|
||||
: TRACE_RECORDER(cx) \
|
||||
? recordingJumpTable \
|
||||
: normalJumpTable))
|
||||
# define ENABLE_TRACER(flag) \
|
||||
JS_BEGIN_MACRO \
|
||||
bool flag_ = (flag); \
|
||||
JS_ASSERT(flag_ == !!JS_TRACE_MONITOR(cx).recorder); \
|
||||
JS_ASSERT(flag_ == !!TRACE_RECORDER(cx)); \
|
||||
jumpTable = flag_ ? recordingJumpTable : normalJumpTable; \
|
||||
JS_END_MACRO
|
||||
#else /* !JS_TRACER */
|
||||
@ -2715,12 +2715,11 @@ js_Interpret(JSContext *cx)
|
||||
#ifdef JS_TRACER
|
||||
# define LOAD_INTERRUPT_HANDLER(cx) \
|
||||
((void) (switchMask = ((cx)->debugHooks->interruptHandler || \
|
||||
JS_TRACE_MONITOR(cx).recorder) \
|
||||
? 0 : 255))
|
||||
TRACE_RECORDER(cx)) ? 0 : 255))
|
||||
# define ENABLE_TRACER(flag) \
|
||||
JS_BEGIN_MACRO \
|
||||
bool flag_ = (flag); \
|
||||
JS_ASSERT(flag_ == !!JS_TRACE_MONITOR(cx).recorder); \
|
||||
JS_ASSERT(flag_ == !!TRACE_RECORDER(cx)); \
|
||||
switchMask = flag_ ? 0 : 255; \
|
||||
JS_END_MACRO
|
||||
#else /* !JS_TRACER */
|
||||
@ -3022,7 +3021,7 @@ js_Interpret(JSContext *cx)
|
||||
inlineCallCount--;
|
||||
if (JS_LIKELY(ok)) {
|
||||
#ifdef JS_TRACER
|
||||
if (JS_TRACE_MONITOR(cx).recorder)
|
||||
if (TRACE_RECORDER(cx))
|
||||
RECORD(LeaveFrame);
|
||||
#endif
|
||||
JS_ASSERT(js_CodeSpec[*regs.pc].length == JSOP_CALL_LENGTH);
|
||||
@ -3266,7 +3265,6 @@ 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)
|
||||
@ -4439,8 +4437,7 @@ 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) {
|
||||
@ -4454,6 +4451,8 @@ 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
|
||||
@ -4595,10 +4594,14 @@ js_Interpret(JSContext *cx)
|
||||
if (!atom)
|
||||
LOAD_ATOM(0);
|
||||
id = ATOM_TO_JSID(atom);
|
||||
if (entry
|
||||
? !js_SetPropertyHelper(cx, obj, id, &rval, &entry)
|
||||
: !OBJ_SET_PROPERTY(cx, obj, id, &rval)) {
|
||||
goto error;
|
||||
if (entry) {
|
||||
if (!js_SetPropertyHelper(cx, obj, id, &rval, &entry))
|
||||
goto error;
|
||||
if (entry)
|
||||
TRACE_1(SetPropMiss, entry);
|
||||
} else {
|
||||
if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
|
||||
goto error;
|
||||
}
|
||||
} while (0);
|
||||
END_SET_CASE_STORE_RVAL(JSOP_SETPROP, 2);
|
||||
@ -4908,7 +4911,7 @@ js_Interpret(JSContext *cx)
|
||||
cx->fp = fp = &newifp->frame;
|
||||
|
||||
#ifdef JS_TRACER
|
||||
if (JS_TRACE_MONITOR(cx).recorder)
|
||||
if (TRACE_RECORDER(cx))
|
||||
RECORD(EnterFrame);
|
||||
#endif
|
||||
|
||||
@ -6121,6 +6124,8 @@ 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
|
||||
@ -6186,6 +6191,8 @@ js_Interpret(JSContext *cx)
|
||||
}
|
||||
if (!js_SetPropertyHelper(cx, obj, id, &rval, &entry))
|
||||
goto error;
|
||||
if (entry)
|
||||
TRACE_1(SetPropMiss, entry);
|
||||
} while (0);
|
||||
|
||||
/* Common tail for property cache hit and miss cases. */
|
||||
@ -7026,7 +7033,7 @@ js_Interpret(JSContext *cx)
|
||||
JS_ASSERT(inlineCallCount == 0);
|
||||
JS_ASSERT(fp->regs == ®s);
|
||||
#ifdef JS_TRACER
|
||||
if (JS_TRACE_MONITOR(cx).recorder)
|
||||
if (TRACE_RECORDER(cx))
|
||||
js_AbortRecording(cx, regs.pc, "recording out of js_Interpret");
|
||||
#endif
|
||||
if (JS_UNLIKELY(fp->flags & JSFRAME_YIELDING)) {
|
||||
@ -7051,12 +7058,12 @@ js_Interpret(JSContext *cx)
|
||||
js_SetVersion(cx, originalVersion);
|
||||
--cx->interpLevel;
|
||||
|
||||
#ifdef JS_TRACER
|
||||
#ifdef JS_TRACER
|
||||
if (tr) {
|
||||
JS_TRACE_MONITOR(cx).recorder = tr;
|
||||
SET_TRACE_RECORDER(cx, tr);
|
||||
tr->deepAbort();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return ok;
|
||||
|
||||
atom_not_defined:
|
||||
|
@ -2526,9 +2526,9 @@ js_MonitorLoopEdge(JSContext* cx, jsbytecode* oldpc, uintN& inlineCallCount)
|
||||
}
|
||||
|
||||
bool
|
||||
js_MonitorRecording(JSContext* cx)
|
||||
js_MonitorRecording(TraceRecorder* tr)
|
||||
{
|
||||
TraceRecorder *tr = JS_TRACE_MONITOR(cx).recorder;
|
||||
JSContext* cx = tr->cx;
|
||||
|
||||
// Clear one-shot flag used to communicate between record_JSOP_CALL and record_EnterFrame.
|
||||
tr->applyingArguments = false;
|
||||
@ -2540,11 +2540,12 @@ js_MonitorRecording(JSContext* cx)
|
||||
}
|
||||
|
||||
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 != NULL) && (SN_TYPE(sn) == SRC_BREAK)) {
|
||||
if (sn && SN_TYPE(sn) == SRC_BREAK) {
|
||||
AUDIT(breakLoopExits);
|
||||
tr->endLoop(JS_TRACE_MONITOR(cx).fragmento);
|
||||
js_DeleteRecorder(cx);
|
||||
@ -3306,6 +3307,9 @@ TraceRecorder::map_is_native(JSObjectMap* map, LIns* map_ins, LIns*& ops_ins, si
|
||||
bool
|
||||
TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2, jsuword& pcval)
|
||||
{
|
||||
jsbytecode* pc = cx->fp->regs->pc;
|
||||
JS_ASSERT(*pc != JSOP_INITPROP && *pc != JSOP_SETNAME && *pc != JSOP_SETPROP);
|
||||
|
||||
// Mimic the interpreter's special case for dense arrays by skipping up one
|
||||
// hop along the proto chain when accessing a named (not indexed) property,
|
||||
// typically to find Array.prototype methods.
|
||||
@ -3327,7 +3331,7 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
|
||||
// We parameterize using offsetof and guard on match against the hook at
|
||||
// the given offset in js_ObjectOps. TraceRecorder::record_JSOP_SETPROP
|
||||
// guards the js_SetProperty case.
|
||||
uint32 format = js_CodeSpec[*cx->fp->regs->pc].format;
|
||||
uint32 format = js_CodeSpec[*pc].format;
|
||||
uint32 mode = JOF_MODE(format);
|
||||
|
||||
// No need to guard native-ness of global object.
|
||||
@ -3347,14 +3351,14 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
|
||||
|
||||
JSAtom* atom;
|
||||
JSPropCacheEntry* entry;
|
||||
PROPERTY_CACHE_TEST(cx, cx->fp->regs->pc, aobj, obj2, entry, atom);
|
||||
PROPERTY_CACHE_TEST(cx, pc, aobj, obj2, entry, atom);
|
||||
if (atom) {
|
||||
// Miss: pre-fill the cache for the interpreter, as well as for our needs.
|
||||
// FIXME: 452357 - correctly propagate exceptions into the interpreter from
|
||||
// js_FindPropertyHelper, js_LookupPropertyWithFlags, and elsewhere.
|
||||
jsid id = ATOM_TO_JSID(atom);
|
||||
JSProperty* prop;
|
||||
if (JOF_OPMODE(*cx->fp->regs->pc) == JOF_NAME) {
|
||||
if (JOF_OPMODE(*pc) == JOF_NAME) {
|
||||
JS_ASSERT(aobj == obj);
|
||||
if (js_FindPropertyHelper(cx, id, &obj, &obj2, &prop, &entry) < 0)
|
||||
ABORT_TRACE("failed to find name");
|
||||
@ -3374,24 +3378,9 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
|
||||
// via our obj2 out-parameter. If we are recording JSOP_SETNAME and
|
||||
// the global it's assigning does not yet exist, create it.
|
||||
obj2 = obj;
|
||||
if (JSOp(*cx->fp->regs->pc) == JSOP_SETNAME) {
|
||||
jsval v = JSVAL_VOID;
|
||||
if (!js_SetPropertyHelper(cx, obj, id, &v, &entry))
|
||||
return false;
|
||||
if (!entry || !PCVAL_IS_SPROP(entry->vword))
|
||||
ABORT_TRACE("can't create cacheable global for JSOP_SETNAME");
|
||||
JSScopeProperty* sprop = PCVAL_TO_SPROP(entry->vword);
|
||||
if (!SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj)))
|
||||
ABORT_TRACE("can't create slot-ful global for JSOP_SETNAME");
|
||||
pcval = SLOT_TO_PCVAL(sprop->slot);
|
||||
|
||||
// We are adding to the global object, so update its saved shape.
|
||||
JS_ASSERT(obj == globalObj);
|
||||
traceMonitor->globalShape = OBJ_SHAPE(obj);
|
||||
} else {
|
||||
// Use PCVAL_NULL to return "no such property" to our caller.
|
||||
pcval = PCVAL_NULL;
|
||||
}
|
||||
// Use PCVAL_NULL to return "no such property" to our caller.
|
||||
pcval = PCVAL_NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3420,10 +3409,10 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
|
||||
}
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
JSOp op = JSOp(*cx->fp->regs->pc);
|
||||
JSOp op = JSOp(*pc);
|
||||
ptrdiff_t pcoff = (op == JSOP_GETARGPROP) ? ARGNO_LEN :
|
||||
(op == JSOP_GETLOCALPROP) ? SLOTNO_LEN : 0;
|
||||
jsatomid index = js_GetIndexFromBytecode(cx, cx->fp->script, cx->fp->regs->pc, pcoff);
|
||||
jsatomid index = js_GetIndexFromBytecode(cx, cx->fp->script, pc, pcoff);
|
||||
JS_ASSERT(entry->kpc == (jsbytecode*) atoms[index]);
|
||||
JS_ASSERT(entry->kshape == jsuword(aobj));
|
||||
#endif
|
||||
@ -4393,41 +4382,52 @@ 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)
|
||||
{
|
||||
jsbytecode* pc = cx->fp->regs->pc;
|
||||
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;
|
||||
if (obj == globalObj) {
|
||||
JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj)));
|
||||
uint32 slot = sprop->slot;
|
||||
if (!lazilyImportGlobalSlot(slot))
|
||||
ABORT_TRACE("lazy import of global slot failed");
|
||||
|
||||
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* r_ins = get(&r);
|
||||
set(&STOBJ_GET_SLOT(obj, slot), r_ins);
|
||||
|
||||
JS_ASSERT(*pc != JSOP_INITPROP);
|
||||
if (pc[JSOP_SETPROP_LENGTH] != JSOP_POP)
|
||||
set(&l, r_ins);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The global object's shape is guarded at trace entry, all others need a guard here.
|
||||
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* 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);
|
||||
}
|
||||
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);
|
||||
@ -4441,11 +4441,19 @@ TraceRecorder::record_JSOP_SETPROP()
|
||||
return false;
|
||||
if (!native_set(obj_ins, sprop, dslots_ins, boxed_ins))
|
||||
return false;
|
||||
if (*pc == JSOP_SETPROP && pc[JSOP_SETPROP_LENGTH] != JSOP_POP)
|
||||
stack(-2, v_ins);
|
||||
|
||||
if (*pc != JSOP_INITPROP && pc[JSOP_SETPROP_LENGTH] != JSOP_POP)
|
||||
set(&l, v_ins);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_SetPropMiss(JSPropCacheEntry* entry)
|
||||
{
|
||||
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
|
||||
return record_SetPropHit(entry->kshape, PCVAL_TO_SPROP(entry->vword));
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_GETELEM()
|
||||
{
|
||||
@ -5368,8 +5376,8 @@ TraceRecorder::record_JSOP_ENDINIT()
|
||||
bool
|
||||
TraceRecorder::record_JSOP_INITPROP()
|
||||
{
|
||||
// The common code avoids stacking the RHS if op is not JSOP_SETPROP.
|
||||
return record_JSOP_SETPROP();
|
||||
// All the action is in record_SetPropHit.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -5457,8 +5465,6 @@ 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 };
|
||||
@ -5467,10 +5473,11 @@ 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);
|
||||
if (!box_jsval(JSVAL_STRING, iter_ins))
|
||||
jsval expected = JSVAL_IS_VOID(*vp) ? JSVAL_STRING : JSVAL_TAG(*vp);
|
||||
if (!box_jsval(expected, iter_ins))
|
||||
return false;
|
||||
iter_ins = lir->ins_choose(flag_ins, v_ins, iter_ins, true);
|
||||
if (!unbox_jsval(JSVAL_STRING, iter_ins))
|
||||
if (!unbox_jsval(expected, iter_ins))
|
||||
return false;
|
||||
set(vp, iter_ins);
|
||||
stack(0, flag_ins);
|
||||
@ -5554,7 +5561,6 @@ TraceRecorder::record_JSOP_BINDNAME()
|
||||
bool
|
||||
TraceRecorder::record_JSOP_SETNAME()
|
||||
{
|
||||
jsval& r = stackval(-1);
|
||||
jsval& l = stackval(-2);
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(l));
|
||||
|
||||
@ -5564,16 +5570,9 @@ TraceRecorder::record_JSOP_SETNAME()
|
||||
*/
|
||||
JSObject* obj = JSVAL_TO_OBJECT(l);
|
||||
if (obj != cx->fp->scopeChain || obj != globalObj)
|
||||
return false;
|
||||
ABORT_TRACE("JSOP_SETNAME left operand is not the global object");
|
||||
|
||||
jsval* vp;
|
||||
if (!name(vp))
|
||||
return false;
|
||||
LIns* r_ins = get(&r);
|
||||
set(vp, r_ins);
|
||||
|
||||
if (cx->fp->regs->pc[JSOP_SETNAME_LENGTH] != JSOP_POP)
|
||||
stack(-2, r_ins);
|
||||
// The rest of the work is in record_SetPropHit.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -334,7 +334,7 @@ class TraceRecorder {
|
||||
void fuseIf(jsbytecode* pc, bool cond, nanojit::LIns* x);
|
||||
|
||||
public:
|
||||
friend bool js_MonitorRecording(JSContext* cx);
|
||||
friend bool js_MonitorRecording(TraceRecorder* tr);
|
||||
|
||||
TraceRecorder(JSContext* cx, nanojit::GuardRecord*, nanojit::Fragment*, TreeInfo*,
|
||||
unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap,
|
||||
@ -358,6 +358,8 @@ public:
|
||||
|
||||
bool record_EnterFrame();
|
||||
bool record_LeaveFrame();
|
||||
bool record_SetPropHit(uint32 kshape, JSScopeProperty* sprop);
|
||||
bool record_SetPropMiss(JSPropCacheEntry* entry);
|
||||
|
||||
void deepAbort() { deepAborted = true; }
|
||||
bool wasDeepAborted() { return deepAborted; }
|
||||
@ -369,23 +371,43 @@ 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))
|
||||
|
||||
#define RECORD(x) \
|
||||
// See jsinterp.cpp for the ENABLE_TRACER definition.
|
||||
#define RECORD_ARGS(x,args) \
|
||||
JS_BEGIN_MACRO \
|
||||
TraceRecorder* r = JS_TRACE_MONITOR(cx).recorder; \
|
||||
if (!js_MonitorRecording(cx)) { \
|
||||
TraceRecorder* tr_ = TRACE_RECORDER(cx); \
|
||||
if (!js_MonitorRecording(tr_)) \
|
||||
ENABLE_TRACER(0); \
|
||||
} else if (!r->record_##x()) { \
|
||||
else \
|
||||
TRACE_ARGS_(tr_,x,args); \
|
||||
JS_END_MACRO
|
||||
|
||||
#define TRACE_ARGS_(tr,x,args) \
|
||||
JS_BEGIN_MACRO \
|
||||
if (!tr->record_##x args) { \
|
||||
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(JSContext* cx);
|
||||
js_MonitorRecording(TraceRecorder *tr);
|
||||
|
||||
extern void
|
||||
js_AbortRecording(JSContext* cx, jsbytecode* abortpc, const char* reason);
|
||||
|
Loading…
Reference in New Issue
Block a user