mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 488018: Propagate errors from tracer to interpreter. r=igor
Rename JSMonitorRecordingStatus to JSRecordingStatus. The JSMRS_ prefix becomes JSRS_, accordingly. Make 'record_' functions return JSRecordingStatus, not bool. 'false' becomes 'JSRS_STOP'; 'true' becomes 'JSRS_CONTINUE'. Since subsequent patches will begin to use more than two values (the next assigns meaning to JSRS_IMACRO), take care to propagate values to callers accurately. Define a new recording status, JSRS_ERROR. Return it from recording functions when appropriate. Check for it at appropriate bottlenecks in tracer and interpreter. ABORT_TRACE becomes one of: . ABORT_TRACE, for when we're simply aborting the recording process . ABORT_TRACE_ERROR, for aborting due to an error . ABORT_TRACE_CV, for producing an error message and returning something other than JSRS_STOP --- some contexts require boolean values. Conditionally provide an alternative definition for the JSRecordingStatus type that cannot be converted to 'bool', so that we can use the C++ compiler to catch improperly converted code. Use recording function return value for imacro invocation. Eliminate the JSFRAME_IMACRO_START frame flag. Instead, return JSRS_IMACRO directly from recording functions.
This commit is contained in:
parent
cafa156d52
commit
56af1e088d
@ -3046,15 +3046,23 @@ js_Interpret(JSContext *cx)
|
||||
#ifdef JS_TRACER
|
||||
TraceRecorder* tr = TRACE_RECORDER(cx);
|
||||
if (tr) {
|
||||
JSMonitorRecordingStatus status = TraceRecorder::monitorRecording(cx, tr, op);
|
||||
if (status == JSMRS_CONTINUE) {
|
||||
JSRecordingStatus status = TraceRecorder::monitorRecording(cx, tr, op);
|
||||
switch (status) {
|
||||
case JSRS_CONTINUE:
|
||||
moreInterrupts = true;
|
||||
} else if (status == JSMRS_IMACRO) {
|
||||
break;
|
||||
case JSRS_IMACRO:
|
||||
atoms = COMMON_ATOMS_START(&rt->atomState);
|
||||
op = JSOp(*regs.pc);
|
||||
DO_OP(); /* keep interrupting for op. */
|
||||
} else {
|
||||
JS_ASSERT(status == JSMRS_STOP);
|
||||
break;
|
||||
case JSRS_ERROR:
|
||||
// The code at 'error:' aborts the recording.
|
||||
goto error;
|
||||
case JSRS_STOP:
|
||||
break;
|
||||
default:
|
||||
JS_NOT_REACHED("Bad recording status");
|
||||
}
|
||||
}
|
||||
#endif /* !JS_TRACER */
|
||||
|
@ -189,7 +189,6 @@ typedef struct JSInlineFrame {
|
||||
#define JSFRAME_YIELDING 0x40 /* js_Interpret dispatched JSOP_YIELD */
|
||||
#define JSFRAME_ITERATOR 0x80 /* trying to get an iterator for for-in */
|
||||
#define JSFRAME_GENERATOR 0x200 /* frame belongs to generator-iterator */
|
||||
#define JSFRAME_IMACRO_START 0x400 /* imacro starting -- see jstracer.h */
|
||||
|
||||
#define JSFRAME_OVERRIDE_SHIFT 24 /* override bit-set params; see jsfun.c */
|
||||
#define JSFRAME_OVERRIDE_BITS 8
|
||||
|
1292
js/src/jstracer.cpp
1292
js/src/jstracer.cpp
File diff suppressed because it is too large
Load Diff
@ -382,11 +382,35 @@ js_SetBuiltinError(JSContext *cx)
|
||||
cx->interpState->builtinStatus |= JSBUILTIN_ERROR;
|
||||
}
|
||||
|
||||
enum JSMonitorRecordingStatus {
|
||||
JSMRS_CONTINUE,
|
||||
JSMRS_STOP,
|
||||
JSMRS_IMACRO
|
||||
#ifdef DEBUG_JSRS_NOT_BOOL
|
||||
struct JSRecordingStatus {
|
||||
int code;
|
||||
bool operator==(JSRecordingStatus &s) { return this->code == s.code; };
|
||||
bool operator!=(JSRecordingStatus &s) { return this->code != s.code; };
|
||||
};
|
||||
enum JSRScodes {
|
||||
JSRS_ERROR_code,
|
||||
JSRS_STOP_code,
|
||||
JSRS_CONTINUE_code,
|
||||
JSRS_IMACRO_code
|
||||
};
|
||||
struct JSRecordingStatus JSRS_CONTINUE = { JSRS_CONTINUE_code };
|
||||
struct JSRecordingStatus JSRS_STOP = { JSRS_STOP_code };
|
||||
struct JSRecordingStatus JSRS_IMACRO = { JSRS_IMACRO_code };
|
||||
struct JSRecordingStatus JSRS_ERROR = { JSRS_ERROR_code };
|
||||
#define STATUS_ABORTS_RECORDING(s) ((s) == JSRS_STOP || (s) == JSRS_ERROR)
|
||||
#else
|
||||
enum JSRecordingStatus {
|
||||
JSRS_ERROR, // Error; propagate to interpreter.
|
||||
JSRS_STOP, // Abort recording.
|
||||
JSRS_CONTINUE, // Continue recording.
|
||||
JSRS_IMACRO // Entered imacro; continue recording.
|
||||
// Only JSOP_IS_IMACOP opcodes may return this.
|
||||
};
|
||||
#define STATUS_ABORTS_RECORDING(s) ((s) <= JSRS_STOP)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
class TraceRecorder : public avmplus::GCObject {
|
||||
JSContext* cx;
|
||||
@ -461,7 +485,7 @@ class TraceRecorder : public avmplus::GCObject {
|
||||
JS_REQUIRES_STACK jsval& stackval(int n) const;
|
||||
|
||||
JS_REQUIRES_STACK nanojit::LIns* scopeChain() const;
|
||||
JS_REQUIRES_STACK bool activeCallOrGlobalSlot(JSObject* obj, jsval*& vp);
|
||||
JS_REQUIRES_STACK JSRecordingStatus activeCallOrGlobalSlot(JSObject* obj, jsval*& vp);
|
||||
|
||||
JS_REQUIRES_STACK nanojit::LIns* arg(unsigned n);
|
||||
JS_REQUIRES_STACK void arg(unsigned n, nanojit::LIns* i);
|
||||
@ -476,29 +500,30 @@ class TraceRecorder : public avmplus::GCObject {
|
||||
JS_REQUIRES_STACK nanojit::LIns* makeNumberInt32(nanojit::LIns* f);
|
||||
JS_REQUIRES_STACK nanojit::LIns* stringify(jsval& v);
|
||||
|
||||
JS_REQUIRES_STACK bool call_imacro(jsbytecode* imacro);
|
||||
JS_REQUIRES_STACK JSRecordingStatus call_imacro(jsbytecode* imacro);
|
||||
|
||||
JS_REQUIRES_STACK bool ifop();
|
||||
JS_REQUIRES_STACK bool switchop();
|
||||
JS_REQUIRES_STACK JSRecordingStatus ifop();
|
||||
JS_REQUIRES_STACK JSRecordingStatus switchop();
|
||||
#ifdef NANOJIT_IA32
|
||||
JS_REQUIRES_STACK nanojit::LIns* tableswitch();
|
||||
#endif
|
||||
JS_REQUIRES_STACK bool inc(jsval& v, jsint incr, bool pre = true);
|
||||
JS_REQUIRES_STACK bool inc(jsval& v, nanojit::LIns*& v_ins, jsint incr, bool pre = true);
|
||||
JS_REQUIRES_STACK bool incProp(jsint incr, bool pre = true);
|
||||
JS_REQUIRES_STACK bool incElem(jsint incr, bool pre = true);
|
||||
JS_REQUIRES_STACK bool incName(jsint incr, bool pre = true);
|
||||
JS_REQUIRES_STACK JSRecordingStatus inc(jsval& v, jsint incr, bool pre = true);
|
||||
JS_REQUIRES_STACK JSRecordingStatus inc(jsval& v, nanojit::LIns*& v_ins, jsint incr,
|
||||
bool pre = true);
|
||||
JS_REQUIRES_STACK JSRecordingStatus incProp(jsint incr, bool pre = true);
|
||||
JS_REQUIRES_STACK JSRecordingStatus incElem(jsint incr, bool pre = true);
|
||||
JS_REQUIRES_STACK JSRecordingStatus incName(jsint incr, bool pre = true);
|
||||
|
||||
JS_REQUIRES_STACK void strictEquality(bool equal, bool cmpCase);
|
||||
JS_REQUIRES_STACK bool equality(bool negate, bool tryBranchAfterCond);
|
||||
JS_REQUIRES_STACK bool equalityHelper(jsval l, jsval r,
|
||||
nanojit::LIns* l_ins, nanojit::LIns* r_ins,
|
||||
bool negate, bool tryBranchAfterCond,
|
||||
jsval& rval);
|
||||
JS_REQUIRES_STACK bool relational(nanojit::LOpcode op, bool tryBranchAfterCond);
|
||||
JS_REQUIRES_STACK JSRecordingStatus equality(bool negate, bool tryBranchAfterCond);
|
||||
JS_REQUIRES_STACK JSRecordingStatus equalityHelper(jsval l, jsval r,
|
||||
nanojit::LIns* l_ins, nanojit::LIns* r_ins,
|
||||
bool negate, bool tryBranchAfterCond,
|
||||
jsval& rval);
|
||||
JS_REQUIRES_STACK JSRecordingStatus relational(nanojit::LOpcode op, bool tryBranchAfterCond);
|
||||
|
||||
JS_REQUIRES_STACK bool unary(nanojit::LOpcode op);
|
||||
JS_REQUIRES_STACK bool binary(nanojit::LOpcode op);
|
||||
JS_REQUIRES_STACK JSRecordingStatus unary(nanojit::LOpcode op);
|
||||
JS_REQUIRES_STACK JSRecordingStatus binary(nanojit::LOpcode op);
|
||||
|
||||
bool ibinary(nanojit::LOpcode op);
|
||||
bool iunary(nanojit::LOpcode op);
|
||||
@ -507,8 +532,8 @@ class TraceRecorder : public avmplus::GCObject {
|
||||
|
||||
JS_REQUIRES_STACK bool map_is_native(JSObjectMap* map, nanojit::LIns* map_ins,
|
||||
nanojit::LIns*& ops_ins, size_t op_offset = 0);
|
||||
JS_REQUIRES_STACK bool test_property_cache(JSObject* obj, nanojit::LIns* obj_ins,
|
||||
JSObject*& obj2, jsuword& pcval);
|
||||
JS_REQUIRES_STACK JSRecordingStatus test_property_cache(JSObject* obj, nanojit::LIns* obj_ins,
|
||||
JSObject*& obj2, jsuword& pcval);
|
||||
void stobj_set_slot(nanojit::LIns* obj_ins, unsigned slot, nanojit::LIns*& dslots_ins,
|
||||
nanojit::LIns* v_ins);
|
||||
void stobj_set_dslot(nanojit::LIns *obj_ins, unsigned slot, nanojit::LIns*& dslots_ins,
|
||||
@ -519,21 +544,22 @@ class TraceRecorder : public avmplus::GCObject {
|
||||
nanojit::LIns*& dslots_ins);
|
||||
nanojit::LIns* stobj_get_slot(nanojit::LIns* obj_ins, unsigned slot,
|
||||
nanojit::LIns*& dslots_ins);
|
||||
bool native_set(nanojit::LIns* obj_ins, JSScopeProperty* sprop,
|
||||
nanojit::LIns*& dslots_ins, nanojit::LIns* v_ins);
|
||||
bool native_get(nanojit::LIns* obj_ins, nanojit::LIns* pobj_ins, JSScopeProperty* sprop,
|
||||
nanojit::LIns*& dslots_ins, nanojit::LIns*& v_ins);
|
||||
JSRecordingStatus native_set(nanojit::LIns* obj_ins, JSScopeProperty* sprop,
|
||||
nanojit::LIns*& dslots_ins, nanojit::LIns* v_ins);
|
||||
JSRecordingStatus native_get(nanojit::LIns* obj_ins, nanojit::LIns* pobj_ins,
|
||||
JSScopeProperty* sprop, nanojit::LIns*& dslots_ins,
|
||||
nanojit::LIns*& v_ins);
|
||||
|
||||
nanojit::LIns* getStringLength(nanojit::LIns* str_ins);
|
||||
|
||||
JS_REQUIRES_STACK bool name(jsval*& vp);
|
||||
JS_REQUIRES_STACK bool prop(JSObject* obj, nanojit::LIns* obj_ins, uint32& slot,
|
||||
nanojit::LIns*& v_ins);
|
||||
JS_REQUIRES_STACK bool elem(jsval& oval, jsval& idx, jsval*& vp, nanojit::LIns*& v_ins,
|
||||
nanojit::LIns*& addr_ins);
|
||||
JS_REQUIRES_STACK bool getProp(JSObject* obj, nanojit::LIns* obj_ins);
|
||||
JS_REQUIRES_STACK bool getProp(jsval& v);
|
||||
JS_REQUIRES_STACK bool getThis(nanojit::LIns*& this_ins);
|
||||
JS_REQUIRES_STACK JSRecordingStatus name(jsval*& vp);
|
||||
JS_REQUIRES_STACK JSRecordingStatus prop(JSObject* obj, nanojit::LIns* obj_ins, uint32& slot,
|
||||
nanojit::LIns*& v_ins);
|
||||
JS_REQUIRES_STACK JSRecordingStatus elem(jsval& oval, jsval& idx, jsval*& vp,
|
||||
nanojit::LIns*& v_ins, nanojit::LIns*& addr_ins);
|
||||
JS_REQUIRES_STACK JSRecordingStatus getProp(JSObject* obj, nanojit::LIns* obj_ins);
|
||||
JS_REQUIRES_STACK JSRecordingStatus getProp(jsval& v);
|
||||
JS_REQUIRES_STACK JSRecordingStatus getThis(nanojit::LIns*& this_ins);
|
||||
|
||||
JS_REQUIRES_STACK void box_jsval(jsval v, nanojit::LIns*& v_ins);
|
||||
JS_REQUIRES_STACK void unbox_jsval(jsval v, nanojit::LIns*& v_ins, VMSideExit* exit);
|
||||
@ -541,27 +567,33 @@ class TraceRecorder : public avmplus::GCObject {
|
||||
VMSideExit* exit);
|
||||
JS_REQUIRES_STACK bool guardDenseArray(JSObject* obj, nanojit::LIns* obj_ins,
|
||||
ExitType exitType = MISMATCH_EXIT);
|
||||
JS_REQUIRES_STACK bool guardPrototypeHasNoIndexedProperties(JSObject* obj, nanojit::LIns* obj_ins,
|
||||
ExitType exitType);
|
||||
JS_REQUIRES_STACK bool guardNotGlobalObject(JSObject* obj, nanojit::LIns* obj_ins);
|
||||
JS_REQUIRES_STACK JSRecordingStatus guardPrototypeHasNoIndexedProperties(JSObject* obj,
|
||||
nanojit::LIns* obj_ins,
|
||||
ExitType exitType);
|
||||
JS_REQUIRES_STACK JSRecordingStatus guardNotGlobalObject(JSObject* obj,
|
||||
nanojit::LIns* obj_ins);
|
||||
void clearFrameSlotsFromCache();
|
||||
JS_REQUIRES_STACK bool guardCallee(jsval& callee);
|
||||
JS_REQUIRES_STACK bool getClassPrototype(JSObject* ctor, nanojit::LIns*& proto_ins);
|
||||
JS_REQUIRES_STACK bool getClassPrototype(JSProtoKey key, nanojit::LIns*& proto_ins);
|
||||
JS_REQUIRES_STACK bool newArray(JSObject* ctor, uint32 argc, jsval* argv, jsval* vp);
|
||||
JS_REQUIRES_STACK bool newString(JSObject* ctor, jsval& arg, jsval* rval);
|
||||
JS_REQUIRES_STACK bool interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc,
|
||||
bool constructing);
|
||||
JS_REQUIRES_STACK bool emitNativeCall(JSTraceableNative* known, uintN argc,
|
||||
nanojit::LIns* args[]);
|
||||
JS_REQUIRES_STACK bool callTraceableNative(JSFunction* fun, uintN argc, bool constructing);
|
||||
JS_REQUIRES_STACK bool callNative(JSFunction* fun, uintN argc, bool constructing);
|
||||
JS_REQUIRES_STACK bool functionCall(bool constructing, uintN argc);
|
||||
JS_REQUIRES_STACK JSRecordingStatus guardCallee(jsval& callee);
|
||||
JS_REQUIRES_STACK JSRecordingStatus getClassPrototype(JSObject* ctor,
|
||||
nanojit::LIns*& proto_ins);
|
||||
JS_REQUIRES_STACK JSRecordingStatus getClassPrototype(JSProtoKey key,
|
||||
nanojit::LIns*& proto_ins);
|
||||
JS_REQUIRES_STACK JSRecordingStatus newArray(JSObject* ctor, uint32 argc, jsval* argv,
|
||||
jsval* vp);
|
||||
JS_REQUIRES_STACK JSRecordingStatus newString(JSObject* ctor, jsval& arg, jsval* rval);
|
||||
JS_REQUIRES_STACK JSRecordingStatus interpretedFunctionCall(jsval& fval, JSFunction* fun,
|
||||
uintN argc, bool constructing);
|
||||
JS_REQUIRES_STACK JSRecordingStatus emitNativeCall(JSTraceableNative* known, uintN argc,
|
||||
nanojit::LIns* args[]);
|
||||
JS_REQUIRES_STACK JSRecordingStatus callTraceableNative(JSFunction* fun, uintN argc,
|
||||
bool constructing);
|
||||
JS_REQUIRES_STACK JSRecordingStatus callNative(JSFunction* fun, uintN argc, bool constructing);
|
||||
JS_REQUIRES_STACK JSRecordingStatus functionCall(bool constructing, uintN argc);
|
||||
|
||||
JS_REQUIRES_STACK void trackCfgMerges(jsbytecode* pc);
|
||||
JS_REQUIRES_STACK void emitIf(jsbytecode* pc, bool cond, nanojit::LIns* x);
|
||||
JS_REQUIRES_STACK void fuseIf(jsbytecode* pc, bool cond, nanojit::LIns* x);
|
||||
JS_REQUIRES_STACK bool checkTraceEnd(jsbytecode* pc);
|
||||
JS_REQUIRES_STACK JSRecordingStatus checkTraceEnd(jsbytecode* pc);
|
||||
|
||||
bool hasMethod(JSObject* obj, jsid id);
|
||||
JS_REQUIRES_STACK bool hasIteratorMethod(JSObject* obj);
|
||||
@ -575,7 +607,8 @@ public:
|
||||
VMSideExit* expectedInnerExit, jsbytecode* outerTree);
|
||||
~TraceRecorder();
|
||||
|
||||
static JS_REQUIRES_STACK JSMonitorRecordingStatus monitorRecording(JSContext* cx, TraceRecorder* tr, JSOp op);
|
||||
static JS_REQUIRES_STACK JSRecordingStatus monitorRecording(JSContext* cx, TraceRecorder* tr,
|
||||
JSOp op);
|
||||
|
||||
JS_REQUIRES_STACK uint8 determineSlotType(jsval* vp);
|
||||
|
||||
@ -618,17 +651,18 @@ public:
|
||||
void removeFragmentoReferences();
|
||||
void deepAbort();
|
||||
|
||||
JS_REQUIRES_STACK bool record_EnterFrame();
|
||||
JS_REQUIRES_STACK bool record_LeaveFrame();
|
||||
JS_REQUIRES_STACK bool record_SetPropHit(JSPropCacheEntry* entry, JSScopeProperty* sprop);
|
||||
JS_REQUIRES_STACK bool record_DefLocalFunSetSlot(uint32 slot, JSObject* obj);
|
||||
JS_REQUIRES_STACK bool record_FastNativeCallComplete();
|
||||
JS_REQUIRES_STACK JSRecordingStatus record_EnterFrame();
|
||||
JS_REQUIRES_STACK JSRecordingStatus record_LeaveFrame();
|
||||
JS_REQUIRES_STACK JSRecordingStatus record_SetPropHit(JSPropCacheEntry* entry,
|
||||
JSScopeProperty* sprop);
|
||||
JS_REQUIRES_STACK JSRecordingStatus record_DefLocalFunSetSlot(uint32 slot, JSObject* obj);
|
||||
JS_REQUIRES_STACK JSRecordingStatus record_FastNativeCallComplete();
|
||||
|
||||
bool wasDeepAborted() { return deepAborted; }
|
||||
TreeInfo* getTreeInfo() { return treeInfo; }
|
||||
|
||||
#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
|
||||
JS_REQUIRES_STACK bool record_##op();
|
||||
JS_REQUIRES_STACK JSRecordingStatus record_##op();
|
||||
# include "jsopcode.tbl"
|
||||
#undef OPDEF
|
||||
};
|
||||
@ -644,8 +678,15 @@ public:
|
||||
#define TRACE_ARGS_(x,args) \
|
||||
JS_BEGIN_MACRO \
|
||||
TraceRecorder* tr_ = TRACE_RECORDER(cx); \
|
||||
if (tr_ && !tr_->wasDeepAborted() && !tr_->record_##x args) \
|
||||
js_AbortRecording(cx, #x); \
|
||||
if (tr_ && !tr_->wasDeepAborted()) { \
|
||||
JSRecordingStatus status = tr_->record_##x args; \
|
||||
if (STATUS_ABORTS_RECORDING(status)) { \
|
||||
js_AbortRecording(cx, #x); \
|
||||
if (status == JSRS_ERROR) \
|
||||
goto error; \
|
||||
} \
|
||||
JS_ASSERT(status != JSRS_IMACRO); \
|
||||
} \
|
||||
JS_END_MACRO
|
||||
|
||||
#define TRACE_ARGS(x,args) TRACE_ARGS_(x, args)
|
||||
|
Loading…
Reference in New Issue
Block a user