Bug 487676 - Nesting deep-aborting trace calls don't work. r=gal.

--HG--
extra : rebase_source : 436164485bd5e981e5ae8997eed2c371f3ecd77b
This commit is contained in:
Jason Orendorff 2009-04-09 18:07:00 -05:00
Родитель 4d0e6ab006
Коммит 99d96af6fb
8 изменённых файлов: 51 добавлений и 39 удалений

Просмотреть файл

@ -1690,7 +1690,7 @@ Array_p_join(JSContext* cx, JSObject* obj, JSString *str)
{
JSAutoTempValueRooter tvr(cx);
if (!array_join_sub(cx, obj, TO_STRING, str, tvr.addr())) {
cx->builtinStatus |= JSBUILTIN_ERROR;
js_SetBuiltinError(cx);
return NULL;
}
return JSVAL_TO_STRING(tvr.value());
@ -1701,7 +1701,7 @@ Array_p_toString(JSContext* cx, JSObject* obj)
{
JSAutoTempValueRooter tvr(cx);
if (!array_join_sub(cx, obj, TO_STRING, NULL, tvr.addr())) {
cx->builtinStatus |= JSBUILTIN_ERROR;
js_SetBuiltinError(cx);
return NULL;
}
return JSVAL_TO_STRING(tvr.value());
@ -2317,7 +2317,7 @@ Array_p_push1(JSContext* cx, JSObject* obj, jsval v)
: array_push_slowly(cx, obj, 1, tvr.addr(), tvr.addr())) {
return tvr.value();
}
cx->builtinStatus |= JSBUILTIN_ERROR;
js_SetBuiltinError(cx);
return JSVAL_VOID;
}
#endif
@ -2389,7 +2389,7 @@ Array_p_pop(JSContext* cx, JSObject* obj)
: array_pop_slowly(cx, obj, tvr.addr())) {
return tvr.value();
}
cx->builtinStatus |= JSBUILTIN_ERROR;
js_SetBuiltinError(cx);
return JSVAL_VOID;
}
#endif

Просмотреть файл

@ -63,6 +63,12 @@ using namespace nanojit;
extern jsdouble js_NaN;
JS_FRIEND_API(void)
js_SetTraceableNativeFailed(JSContext *cx)
{
js_SetBuiltinError(cx);
}
/*
* NB: bool FASTCALL is not compatible with Nanojit's calling convention usage.
* Do not use bool FASTCALL, use JSBool only!

Просмотреть файл

@ -131,7 +131,7 @@ struct JSTraceableNative {
* interpreter at the next opcode.
*
* _FAIL builtins indicate failure or bailing off trace by setting bits in
* cx->builtinStatus.
* cx->interpState->builtinStatus.
*
* - If a traceable native's return type contains _RETRY, it can either
* succeed, fail with a JS exception, or tell the caller to bail off trace
@ -154,7 +154,7 @@ struct JSTraceableNative {
* JSVAL_RETRY: JSVAL_ERROR_COOKIE
*
* _RETRY function calls are faster than _FAIL calls. Each _RETRY call
* saves a write to cx->bailExit and a read from cx->builtinStatus.
* saves two writes to cx->bailExit and a read from state->builtinStatus.
*
* - All other traceable natives are infallible (e.g. Date.now, Math.log).
*
@ -397,6 +397,10 @@ js_Int32ToId(JSContext* cx, int32 index, jsid* id)
return js_ValueToStringId(cx, STRING_TO_JSVAL(str), id);
}
/* Extern version of js_SetBuiltinError. */
extern JS_FRIEND_API(void)
js_SetTraceableNativeFailed(JSContext *cx);
#else
#define JS_DEFINE_CALLINFO_1(linkage, rt, op, at0, cse, fold)

Просмотреть файл

@ -300,14 +300,6 @@ typedef enum JSRuntimeState {
JSRTS_LANDING
} JSRuntimeState;
#ifdef JS_TRACER
typedef enum JSBuiltinStatus {
JSBUILTIN_OK = 0,
JSBUILTIN_BAILED = 1,
JSBUILTIN_ERROR = 2
} JSBuiltinStatus;
#endif
typedef enum JSBuiltinFunctionId {
JSBUILTIN_ObjectToIterator,
JSBUILTIN_CallIteratorNext,
@ -1008,13 +1000,6 @@ struct JSContext {
*/
InterpState *interpState;
VMSideExit *bailExit;
/*
* Used by _FAIL builtins; see jsbuiltins.h. The builtin sets the
* JSBUILTIN_BAILED bit if it bails off trace and the JSBUILTIN_ERROR bit
* if an error or exception occurred. Cleared on side exit.
*/
uint32 builtinStatus;
#endif
};

Просмотреть файл

@ -1697,7 +1697,7 @@ Object_p_hasOwnProperty(JSContext* cx, JSObject* obj, JSString *str)
if (!js_ValueToStringId(cx, STRING_TO_JSVAL(str), &id) ||
!js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &v)) {
cx->builtinStatus |= JSBUILTIN_ERROR;
js_SetBuiltinError(cx);
return JSVAL_TO_BOOLEAN(JSVAL_VOID);
}
@ -1742,7 +1742,7 @@ Object_p_propertyIsEnumerable(JSContext* cx, JSObject* obj, JSString *str)
jsval v;
if (!js_PropertyIsEnumerable(cx, obj, id, &v)) {
cx->builtinStatus |= JSBUILTIN_ERROR;
js_SetBuiltinError(cx);
return JSVAL_TO_BOOLEAN(JSVAL_VOID);
}

Просмотреть файл

@ -3971,7 +3971,6 @@ js_ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount,
VMSideExit** innermostNestedGuardp)
{
JS_ASSERT(f->root == f && f->code() && f->vmprivate);
JS_ASSERT(cx->builtinStatus == 0);
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
JSObject* globalObj = JS_GetGlobalForObject(cx, cx->fp->scopeChain);
@ -3999,6 +3998,7 @@ js_ExecuteTree(JSContext* cx, Fragment* f, uintN& inlineCallCount,
state->lastTreeExitGuard = NULL;
state->lastTreeCallGuard = NULL;
state->rpAtLastTreeCall = NULL;
state->builtinStatus = 0;
/* Setup the native global frame. */
double* global = (double*)(state+1);
@ -4120,8 +4120,7 @@ LeaveTree(InterpState& state, VMSideExit* lr)
JS_ASSERT(state.lastTreeExitGuard->exitType != NESTED_EXIT);
}
int32_t bs = cx->builtinStatus;
cx->builtinStatus = 0;
int32_t bs = state.builtinStatus;
bool bailed = innermost->exitType == STATUS_EXIT && (bs & JSBUILTIN_BAILED);
if (bailed) {
/*
@ -4135,7 +4134,7 @@ LeaveTree(InterpState& state, VMSideExit* lr)
/*
* The native succeeded (no exception or error). After it returned, the
* trace stored the return value (at the top of the native stack) and
* then immediately flunked the guard on cx->builtinStatus.
* then immediately flunked the guard on state->builtinStatus.
*
* Now LeaveTree has been called again from the tail of
* js_ExecuteTree. We are about to return to the interpreter. Adjust
@ -4943,7 +4942,7 @@ js_DeepBail(JSContext *cx)
JS_TRACE_MONITOR(cx).prohibitRecording = true;
LeaveTree(*cx->interpState, cx->bailExit);
cx->bailExit = NULL;
cx->builtinStatus |= JSBUILTIN_BAILED;
cx->interpState->builtinStatus |= JSBUILTIN_BAILED;
}
JS_REQUIRES_STACK jsval&
@ -7460,7 +7459,7 @@ GetProperty_tn(JSContext *cx, jsbytecode *pc, JSObject *obj, JSString *name)
if (!js_ValueToStringId(cx, STRING_TO_JSVAL(name), idr.addr()) ||
!OBJ_GET_PROPERTY(cx, obj, idr.id(), tvr.addr())) {
cx->builtinStatus |= JSBUILTIN_ERROR;
js_SetBuiltinError(cx);
*tvr.addr() = JSVAL_ERROR_COOKIE;
}
return tvr.value();
@ -7489,11 +7488,11 @@ GetElement_tn(JSContext* cx, jsbytecode *pc, JSObject* obj, int32 index)
JSAutoTempIdRooter idr(cx);
if (!js_Int32ToId(cx, index, idr.addr())) {
cx->builtinStatus |= JSBUILTIN_ERROR;
js_SetBuiltinError(cx);
return JSVAL_ERROR_COOKIE;
}
if (!OBJ_GET_PROPERTY(cx, obj, idr.id(), tvr.addr())) {
cx->builtinStatus |= JSBUILTIN_ERROR;
js_SetBuiltinError(cx);
*tvr.addr() = JSVAL_ERROR_COOKIE;
}
return tvr.value();
@ -7604,7 +7603,7 @@ SetProperty_tn(JSContext* cx, JSObject* obj, JSString* idstr, jsval v)
if (!js_ValueToStringId(cx, STRING_TO_JSVAL(idstr), idr.addr()) ||
!OBJ_SET_PROPERTY(cx, obj, idr.id(), tvr.addr())) {
cx->builtinStatus |= JSBUILTIN_ERROR;
js_SetBuiltinError(cx);
}
return JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID);
}
@ -7635,7 +7634,7 @@ SetElement_tn(JSContext* cx, JSObject* obj, int32 index, jsval v)
if (!js_Int32ToId(cx, index, idr.addr()) ||
!OBJ_SET_PROPERTY(cx, obj, idr.id(), tvr.addr())) {
cx->builtinStatus |= JSBUILTIN_ERROR;
js_SetBuiltinError(cx);
}
return JSVAL_TO_PSEUDO_BOOLEAN(JSVAL_VOID);
}
@ -8045,7 +8044,7 @@ TraceRecorder::record_FastNativeCallComplete()
// Keep cx->bailExit null when it's invalid.
lir->insStorei(INS_CONSTPTR(NULL), cx_ins, (int) offsetof(JSContext, bailExit));
LIns* status = lir->insLoad(LIR_ld, cx_ins, (int) offsetof(JSContext, builtinStatus));
LIns* status = lir->insLoad(LIR_ld, lirbuf->state, (int) offsetof(InterpState, builtinStatus));
if (pendingTraceableNative == generatedTraceableNative) {
LIns* ok_ins = v_ins;
@ -8083,7 +8082,7 @@ TraceRecorder::record_FastNativeCallComplete()
lir->ins2i(LIR_and, ok_ins, 1),
1),
1));
lir->insStorei(status, cx_ins, (int) offsetof(JSContext, builtinStatus));
lir->insStorei(status, lirbuf->state, (int) offsetof(InterpState, builtinStatus));
}
guard(true,
lir->ins_eq0(status),
@ -9758,7 +9757,7 @@ ObjectToIterator_tn(JSContext* cx, jsbytecode* pc, JSObject *obj, int32 flags)
JSBool ok = js_ValueToIterator(cx, flags, &v);
if (!ok) {
cx->builtinStatus |= JSBUILTIN_ERROR;
js_SetBuiltinError(cx);
return NULL;
}
return JSVAL_TO_OBJECT(v);
@ -9777,7 +9776,7 @@ CallIteratorNext_tn(JSContext* cx, jsbytecode* pc, JSObject* iterobj)
JSBool ok = js_CallIteratorNext(cx, iterobj, tvr.addr());
if (!ok) {
cx->builtinStatus |= JSBUILTIN_ERROR;
js_SetBuiltinError(cx);
return JSVAL_ERROR_COOKIE;
}
return tvr.value();

Просмотреть файл

@ -341,6 +341,11 @@ public:
# define EXECUTE_TREE_TIMER
#endif
typedef enum JSBuiltinStatus {
JSBUILTIN_BAILED = 1,
JSBUILTIN_ERROR = 2
} JSBuiltinStatus;
struct InterpState
{
double *sp; // native stack pointer, stack[0] is spbase[0]
@ -356,7 +361,7 @@ struct InterpState
double* stackBase; // native stack base
FrameInfo** callstackBase; // call stack base
uintN* inlineCallCountp; // inline call count counter
VMSideExit** innermostNestedGuardp;
VMSideExit** innermostNestedGuardp;
void* stackMark;
VMSideExit* innermost;
#ifdef EXECUTE_TREE_TIMER
@ -365,8 +370,21 @@ struct InterpState
#ifdef DEBUG
bool jsframe_pop_blocks_set_on_entry;
#endif
/*
* Used by _FAIL builtins; see jsbuiltins.h. The builtin sets the
* JSBUILTIN_BAILED bit if it bails off trace and the JSBUILTIN_ERROR bit
* if an error or exception occurred.
*/
uint32 builtinStatus;
};
static JS_INLINE void
js_SetBuiltinError(JSContext *cx)
{
cx->interpState->builtinStatus |= JSBUILTIN_ERROR;
}
enum JSMonitorRecordingStatus {
JSMRS_CONTINUE,
JSMRS_STOP,

Просмотреть файл

@ -871,7 +871,7 @@ def getTraceInfoDefaultReturn(type):
def getFailureString(retval, indent):
assert indent > 0
ret = " " * (4 * indent)
ret += "cx->builtinStatus |= JSBUILTIN_ERROR;\n"
ret += "js_SetTraceableNativeFailed(cx);\n"
ret += " " * (4 * indent)
ret += "return %s;\n" % retval
ret += " " * (4 * (indent - 1))