--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1685,28 +1685,28 @@ InitArrayObject(JSContext *cx, JSObject
}
#ifdef JS_TRACER
static JSString* FASTCALL
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());
}
static JSString* FASTCALL
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());
}
#endif
/*
* Perl-inspired join, reverse, and sort.
@@ -2312,17 +2312,17 @@ static jsval FASTCALL
Array_p_push1(JSContext* cx, JSObject* obj, jsval v)
{
JSAutoTempValueRooter tvr(cx, v);
if (OBJ_IS_DENSE_ARRAY(cx, obj)
? array_push1_dense(cx, obj, v, tvr.addr())
: array_push_slowly(cx, obj, 1, tvr.addr(), tvr.addr())) {
return tvr.value();
}
- cx->builtinStatus |= JSBUILTIN_ERROR;
+ js_SetBuiltinError(cx);
return JSVAL_VOID;
}
#endif
static JSBool
array_push(JSContext *cx, uintN argc, jsval *vp)
{
JSObject *obj;
@@ -2384,17 +2384,17 @@ static jsval FASTCALL
Array_p_pop(JSContext* cx, JSObject* obj)
{
JSAutoTempValueRooter tvr(cx);
if (OBJ_IS_DENSE_ARRAY(cx, obj)
? array_pop_dense(cx, obj, tvr.addr())
: array_pop_slowly(cx, obj, tvr.addr())) {
return tvr.value();
}
- cx->builtinStatus |= JSBUILTIN_ERROR;
+ js_SetBuiltinError(cx);
return JSVAL_VOID;
}
#endif
static JSBool
array_pop(JSContext *cx, uintN argc, jsval *vp)
{
JSObject *obj;
--- a/js/src/jsbuiltins.cpp
+++ b/js/src/jsbuiltins.cpp
@@ -58,16 +58,22 @@
#include "jsbuiltins.h"
#include "jstracer.h"
using namespace avmplus;
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!
*/
jsdouble FASTCALL
js_dmod(jsdouble a, jsdouble b)
{
--- a/js/src/jsbuiltins.h
+++ b/js/src/jsbuiltins.h
@@ -126,17 +126,17 @@ struct JSTraceableNative {
*
* - If a traceable native's return type ends with _FAIL, it always runs to
* completion. It can either succeed or fail with an error or exception;
* on success, it may or may not stay on trace. There may be side effects
* in any case. If the call succeeds but bails off trace, we resume in the
* 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
* and retry the call from the interpreter. The last case happens if the
* builtin discovers that it can't do its job without examining the JS
* stack, reentering the interpreter, accessing properties of the global
* object, etc.
*
@@ -149,17 +149,17 @@ struct JSTraceableNative {
*
* BOOL_RETRY: JSVAL_TO_BOOLEAN(JSVAL_VOID)
* INT32_RETRY: any negative value
* STRING_RETRY: NULL
* OBJECT_RETRY_NULL: NULL
* 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).
*
* Special builtins known to the tracer can have their own idiosyncratic
* error codes.
*
* When a traceable native returns a value indicating failure, we fall off
* trace. If an exception is pending, it is thrown; otherwise, we assume the
@@ -392,16 +392,20 @@ js_Int32ToId(JSContext* cx, int32 index,
return JS_TRUE;
}
JSString* str = js_NumberToString(cx, index);
if (!str)
return JS_FALSE;
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)
#define JS_DEFINE_CALLINFO_2(linkage, rt, op, at0, at1, cse, fold)
#define JS_DEFINE_CALLINFO_3(linkage, rt, op, at0, at1, at2, cse, fold)
#define JS_DEFINE_CALLINFO_4(linkage, rt, op, at0, at1, at2, at3, cse, fold)
#define JS_DEFINE_CALLINFO_5(linkage, rt, op, at0, at1, at2, at3, at4, cse, fold)
#define JS_DECLARE_CALLINFO(name)
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -295,24 +295,16 @@ typedef enum JSDestroyContextMode {
typedef enum JSRuntimeState {
JSRTS_DOWN,
JSRTS_LAUNCHING,
JSRTS_UP,
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,
JSBUILTIN_GetProperty,
JSBUILTIN_GetElement,
JSBUILTIN_SetProperty,
JSBUILTIN_SetElement,
JSBUILTIN_LIMIT
@@ -1003,23 +995,16 @@ struct JSContext {
#ifdef JS_TRACER
/*
* State for the current tree execution. bailExit is valid if the tree has
* called back into native code via a _FAIL builtin and has not yet bailed,
* else garbage (NULL in debug builds).
*/
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
};
#ifdef JS_THREADSAFE
# define JS_THREAD_ID(cx) ((cx)->thread ? (cx)->thread->id : 0)
#endif
#ifdef __cplusplus
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1692,17 +1692,17 @@ js_HasOwnProperty(JSContext *cx, JSLooku
static JSBool FASTCALL
Object_p_hasOwnProperty(JSContext* cx, JSObject* obj, JSString *str)
{
jsid id;
jsval v;
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);
}
JS_ASSERT(JSVAL_IS_BOOLEAN(v));
return JSVAL_TO_BOOLEAN(v);
}
#endif
@@ -1737,17 +1737,17 @@ obj_propertyIsEnumerable(JSContext *cx,
#ifdef JS_TRACER
static JSBool FASTCALL
Object_p_propertyIsEnumerable(JSContext* cx, JSObject* obj, JSString *str)
{
jsid id = ATOM_TO_JSID(STRING_TO_JSVAL(str));
jsval v;
if (!js_PropertyIsEnumerable(cx, obj, id, &v)) {
- cx->builtinStatus |= JSBUILTIN_ERROR;
+ js_SetBuiltinError(cx);
return JSVAL_TO_BOOLEAN(JSVAL_VOID);
}
JS_ASSERT(JSVAL_IS_BOOLEAN(v));
return JSVAL_TO_BOOLEAN(v);
}
#endif
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -3966,17 +3966,16 @@ LeaveTree(InterpState&, VMSideExit* lr);
/**
* Executes a tree.
*/
static JS_REQUIRES_STACK VMSideExit*
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);
TreeInfo* ti = (TreeInfo*)f->vmprivate;
unsigned ngslots = ti->globalSlots->length();
uint16* gslots = ti->globalSlots->data();
unsigned globalFrameSize = STOBJ_NSLOTS(globalObj);
@@ -3994,16 +3993,17 @@ js_ExecuteTree(JSContext* cx, Fragment*
InterpState* state = (InterpState*)alloca(sizeof(InterpState) + (globalFrameSize+1)*sizeof(double));
state->cx = cx;
state->inlineCallCountp = &inlineCallCount;
state->innermostNestedGuardp = innermostNestedGuardp;
state->outermostTree = ti;
state->lastTreeExitGuard = NULL;
state->lastTreeCallGuard = NULL;
state->rpAtLastTreeCall = NULL;
+ state->builtinStatus = 0;
/* Setup the native global frame. */
double* global = (double*)(state+1);
/* Setup the native stack frame. */
double stack_buffer[MAX_NATIVE_STACK_SLOTS];
state->stackBase = stack_buffer;
state->sp = stack_buffer + (ti->nativeStackBase/sizeof(double));
@@ -4115,32 +4115,31 @@ LeaveTree(InterpState& state, VMSideExit
if (state.innermostNestedGuardp)
*state.innermostNestedGuardp = nested;
JS_ASSERT(nested);
JS_ASSERT(nested->exitType == NESTED_EXIT);
JS_ASSERT(state.lastTreeExitGuard);
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) {
/*
* Deep-bail case.
*
* A _FAIL native already called LeaveTree. We already reconstructed
* the interpreter stack, in pre-call state, with pc pointing to the
* CALL/APPLY op, for correctness. Then we continued in native code.
*/
if (!(bs & JSBUILTIN_ERROR)) {
/*
* 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
* the top stack frame to resume on the next op.
*/
JS_ASSERT(*cx->fp->regs->pc == JSOP_CALL || *cx->fp->regs->pc == JSOP_APPLY);
uintN argc = GET_ARGC(cx->fp->regs->pc);
cx->fp->regs->pc += JSOP_CALL_LENGTH;
@@ -4938,17 +4937,17 @@ js_DeepBail(JSContext *cx)
/* It's a bug if a non-FAIL_STATUS builtin gets here. */
JS_ASSERT(cx->bailExit);
JS_TRACE_MONITOR(cx).onTrace = false;
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&
TraceRecorder::argval(unsigned n) const
{
JS_ASSERT(n < cx->fp->fun->nargs);
return cx->fp->argv[n];
}
@@ -7455,17 +7454,17 @@ GetProperty(JSContext *cx, uintN argc, j
static jsval FASTCALL
GetProperty_tn(JSContext *cx, jsbytecode *pc, JSObject *obj, JSString *name)
{
JSAutoTempIdRooter idr(cx);
JSAutoTempValueRooter tvr(cx);
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();
}
static JSBool
GetElement(JSContext *cx, uintN argc, jsval *vp)
{
@@ -7484,21 +7483,21 @@ GetElement(JSContext *cx, uintN argc, js
static jsval FASTCALL
GetElement_tn(JSContext* cx, jsbytecode *pc, JSObject* obj, int32 index)
{
JSAutoTempValueRooter tvr(cx);
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();
}
JS_DEFINE_TRCINFO_1(GetProperty,
(4, (static, JSVAL_FAIL, GetProperty_tn, CONTEXT, PC, THIS, STRING, 0, 0)))
JS_DEFINE_TRCINFO_1(GetElement,
@@ -7599,17 +7598,17 @@ SetProperty(JSContext *cx, uintN argc, j
static JSBool FASTCALL
SetProperty_tn(JSContext* cx, JSObject* obj, JSString* idstr, jsval v)
{
JSAutoTempValueRooter tvr(cx, v);
JSAutoTempIdRooter idr(cx);
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);
}
static JSBool
SetElement(JSContext *cx, uintN argc, jsval *vp)
{
jsval *argv;
@@ -7630,17 +7629,17 @@ SetElement(JSContext *cx, uintN argc, js
static JSBool FASTCALL
SetElement_tn(JSContext* cx, JSObject* obj, int32 index, jsval v)
{
JSAutoTempIdRooter idr(cx);
JSAutoTempValueRooter tvr(cx, 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);
}
JS_DEFINE_TRCINFO_1(SetProperty,
(4, (extern, BOOL_FAIL, SetProperty_tn, CONTEXT, THIS, STRING, JSVAL, 0, 0)))
JS_DEFINE_TRCINFO_1(SetElement,
(4, (extern, BOOL_FAIL, SetElement_tn, CONTEXT, THIS, INT32, JSVAL, 0, 0)))
@@ -8040,17 +8039,17 @@ TraceRecorder::record_FastNativeCallComp
type is jsval, snapshot() will also indicate in the type map that the
element on top of the stack is a boxed value which doesn't need to be
boxed if the type guard generated by unbox_jsval() fails. */
if (JSTN_ERRTYPE(pendingTraceableNative) == FAIL_STATUS) {
// 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;
/*
* Custom implementations of Iterator.next() throw a StopIteration exception.
* Catch and clear it and set the return value to JSVAL_HOLE in this case.
*/
if (uintptr_t(cx->fp->regs->pc - nextiter_imacros.custom_iter_next) <
@@ -8078,17 +8077,17 @@ TraceRecorder::record_FastNativeCallComp
JS_STATIC_ASSERT((1 - JS_FALSE) << 1 == JSBUILTIN_ERROR);
status = lir->ins2(LIR_or,
status,
lir->ins2i(LIR_lsh,
lir->ins2i(LIR_xor,
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),
STATUS_EXIT);
}
bool ok = true;
if (pendingTraceableNative->flags & JSTN_UNBOX_AFTER) {
@@ -9753,17 +9752,17 @@ ObjectToIterator(JSContext *cx, uintN ar
static JSObject* FASTCALL
ObjectToIterator_tn(JSContext* cx, jsbytecode* pc, JSObject *obj, int32 flags)
{
jsval v = OBJECT_TO_JSVAL(obj);
JSBool ok = js_ValueToIterator(cx, flags, &v);
if (!ok) {
- cx->builtinStatus |= JSBUILTIN_ERROR;
+ js_SetBuiltinError(cx);
return NULL;
}
return JSVAL_TO_OBJECT(v);
}
static JSBool
CallIteratorNext(JSContext *cx, uintN argc, jsval *vp)
{
@@ -9772,17 +9771,17 @@ CallIteratorNext(JSContext *cx, uintN ar
static jsval FASTCALL
CallIteratorNext_tn(JSContext* cx, jsbytecode* pc, JSObject* iterobj)
{
JSAutoTempValueRooter tvr(cx);
JSBool ok = js_CallIteratorNext(cx, iterobj, tvr.addr());
if (!ok) {
- cx->builtinStatus |= JSBUILTIN_ERROR;
+ js_SetBuiltinError(cx);
return JSVAL_ERROR_COOKIE;
}
return tvr.value();
}
JS_DEFINE_TRCINFO_1(ObjectToIterator,
(4, (static, OBJECT_FAIL, ObjectToIterator_tn, CONTEXT, PC, THIS, INT32, 0, 0)))
JS_DEFINE_TRCINFO_1(CallIteratorNext,
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -336,42 +336,60 @@ public:
return typeMap.data();
}
};
#if defined(JS_JIT_SPEW) && (defined(NANOJIT_IA32) || (defined(NANOJIT_AMD64) && defined(__GNUC__)))
# 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]
void *rp; // call stack pointer
JSContext *cx; // current VM context handle
double *eos; // first unusable word after the native stack
void *eor; // first unusable word after the call stack
VMSideExit* lastTreeExitGuard; // guard we exited on during a tree call
VMSideExit* lastTreeCallGuard; // guard we want to grow from if the tree
// call exit guard mismatched
void* rpAtLastTreeCall; // value of rp at innermost tree call guard
TreeInfo* outermostTree; // the outermost tree we initially invoked
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
uint64 startTime;
#endif
#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,
JSMRS_IMACRO
};
class TraceRecorder : public avmplus::GCObject {
JSContext* cx;
--- a/js/src/xpconnect/src/qsgen.py
+++ b/js/src/xpconnect/src/qsgen.py
@@ -866,17 +866,17 @@ def getTraceInfoType(type):
def getTraceInfoDefaultReturn(type):
traceType = traceTypeMap.get(type) or traceTypeMap.get("_default")
assert traceType
return traceType[2]
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))
ret += "}\n"
return ret
def writeFailure(f, retval, indent):
f.write(getFailureString(retval, indent))