diff --git a/js/src/jit-test/tests/basic/bug623297.js b/js/src/jit-test/tests/basic/bug623297.js new file mode 100644 index 000000000000..20951c3c0eb4 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug623297.js @@ -0,0 +1,14 @@ +gczeal(2); + +function foo() { + return /foo/; +} + +function test() { + var obj = {}; + for (var i = 0; i < 50; i++) { + obj["_" + i] = "J"; + } +} + +test(); diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 18dc62a2a7e5..a3b202f66207 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -815,17 +815,6 @@ private: } /* namespace js */ -/* - * N.B. JS_ON_TRACE(cx) is true if JIT code is on the stack in the current - * thread, regardless of whether cx is the context in which that trace is - * executing. cx must be a context on the current thread. - */ -#ifdef JS_TRACER -# define JS_ON_TRACE(cx) (cx->compartment && JS_TRACE_MONITOR(cx).ontrace()) -#else -# define JS_ON_TRACE(cx) false -#endif - #ifdef DEBUG # define FUNCTION_KIND_METER_LIST(_) \ _(allfun), _(heavy), _(nofreeupvar), _(onlyfreevar), \ @@ -859,6 +848,18 @@ struct JSThreadData { unsigned requestDepth; #endif +#ifdef JS_TRACER + /* + * During trace execution (or during trace recording or + * profiling), this field points to the compartment doing the + * execution on this thread. At other times, it is NULL. If a + * thread tries to execute/record/profile one trace while another + * is still running, the initial one will abort. Therefore, we + * only need to track one tracerCompartment at a time. + */ + JSCompartment *tracerCompartment; +#endif + /* * If non-zero, we were been asked to call the operation callback as soon * as possible. If the thread has an active request, this contributes diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index a8882adc03e9..4a2a4e71f103 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -412,9 +412,34 @@ struct JS_FRIEND_API(JSCompartment) { } }; -#define JS_TRACE_MONITOR(cx) (cx->compartment->traceMonitor) #define JS_SCRIPTS_TO_GC(cx) (cx->compartment->scriptsToGC) +#ifdef JS_TRACER +static inline js::TraceMonitor & +JS_TRACE_MONITOR(JSContext *cx) +{ + JSCompartment *c = JS_THREAD_DATA(cx)->tracerCompartment; + if (c == NULL) + c = cx->compartment; + return c->traceMonitor; +} +#endif + +/* + * N.B. JS_ON_TRACE(cx) is true if JIT code is on the stack in the current + * thread, regardless of whether cx is the context in which that trace is + * executing. cx must be a context on the current thread. + */ +static inline bool +JS_ON_TRACE(JSContext *cx) +{ +#ifdef JS_TRACER + if (cx->compartment || JS_THREAD_DATA(cx)->tracerCompartment) + return JS_TRACE_MONITOR(cx).ontrace(); +#endif + return false; +} + namespace js { static inline MathCache * GetMathCache(JSContext *cx) diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index d42fb932cfb4..415d79b9f848 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -2311,6 +2311,8 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag JS_ASSERT(globalObj->hasOwnShape()); JS_ASSERT(cx->regs->pc == (jsbytecode*)fragment->ip); + JS_THREAD_DATA(cx)->tracerCompartment = cx->compartment; + #ifdef DEBUG lirbuf->printer = new (tempAlloc()) LInsPrinter(tempAlloc(), TM_NUM_USED_ACCS); #endif @@ -2460,6 +2462,8 @@ TraceRecorder::~TraceRecorder() /* Should already have been adjusted by callers before calling delete. */ JS_ASSERT(traceMonitor->recorder != this); + JS_THREAD_DATA(cx)->tracerCompartment = NULL; + if (trashSelf) TrashTree(fragment->root); @@ -6322,9 +6326,6 @@ public: JS_REQUIRES_STACK TreeFragment* TraceRecorder::findNestedCompatiblePeer(TreeFragment* f) { - TraceMonitor* tm; - - tm = &JS_TRACE_MONITOR(cx); unsigned int ngslots = tree->globalSlots->length(); for (; f != NULL; f = f->peer) { @@ -6489,6 +6490,8 @@ TracerState::TracerState(JSContext* cx, TraceMonitor* tm, TreeFragment* f, prev = tm->tracerState; tm->tracerState = this; + JS_THREAD_DATA(cx)->tracerCompartment = cx->compartment; + JS_ASSERT(eos == stackBase + MAX_NATIVE_STACK_SLOTS); JS_ASSERT(sp < eos); @@ -6517,6 +6520,8 @@ TracerState::~TracerState() TraceMonitor *tm = &JS_TRACE_MONITOR(cx); tm->tracerState = prev; tm->tracecx = NULL; + + JS_THREAD_DATA(cx)->tracerCompartment = NULL; } /* Call |f|, return the exit taken. */ @@ -16902,6 +16907,14 @@ LookupLoopProfile(JSContext *cx, jsbytecode *pc) return NULL; } +static void +StopProfiling(JSContext *cx) +{ + TraceMonitor* tm = &JS_TRACE_MONITOR(cx); + tm->profile = NULL; + JS_THREAD_DATA(cx)->tracerCompartment = NULL; +} + JS_REQUIRES_STACK TracePointAction MonitorTracePoint(JSContext *cx, uintN& inlineCallCount, bool* blacklist, void** traceData, uintN *traceEpoch, uint32 *loopCounter, uint32 hits) @@ -16945,6 +16958,8 @@ MonitorTracePoint(JSContext *cx, uintN& inlineCallCount, bool* blacklist, tm->profile = prof; + JS_THREAD_DATA(cx)->tracerCompartment = cx->compartment; + if (!Interpret(cx, cx->fp(), inlineCallCount, JSINTERP_PROFILE)) return TPA_Error; @@ -16979,7 +16994,7 @@ LoopProfile::profileOperation(JSContext* cx, JSOp op) TraceMonitor* tm = &JS_TRACE_MONITOR(cx); if (profiled) { - tm->profile = NULL; + StopProfiling(cx); return ProfComplete; } @@ -16991,7 +17006,7 @@ LoopProfile::profileOperation(JSContext* cx, JSOp op) debug_only_printf(LC_TMProfiler, "Profiling complete (loop exit) at line %u\n", js_FramePCToLineNumber(cx, cx->fp())); tm->profile->decide(cx); - tm->profile = NULL; + StopProfiling(cx); return ProfComplete; } @@ -17005,7 +17020,7 @@ LoopProfile::profileOperation(JSContext* cx, JSOp op) if (loopStackDepth == PROFILE_MAX_INNER_LOOPS) { debug_only_print0(LC_TMProfiler, "Profiling complete (maxnest)\n"); tm->profile->decide(cx); - tm->profile = NULL; + StopProfiling(cx); return ProfComplete; } @@ -17089,7 +17104,7 @@ LoopProfile::profileOperation(JSContext* cx, JSOp op) if (numAllOps >= MAX_PROFILE_OPS) { debug_only_print0(LC_TMProfiler, "Profiling complete (maxops)\n"); tm->profile->decide(cx); - tm->profile = NULL; + StopProfiling(cx); return ProfComplete; } @@ -17351,7 +17366,7 @@ AbortProfiling(JSContext *cx) tm->profile->profiled = true; tm->profile->traceOK = false; tm->profile->execOK = false; - tm->profile = NULL; + StopProfiling(cx); } #else /* JS_METHODJIT */