Merge, style nits, no locking for tracing.
Merge, style nits, no locking for tracing.
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -120,20 +120,25 @@ struct JSThread {
* or another Gecko application) that uses many contexts per thread is
* unlikely to interleave js_GetSrcNote-intensive loops in the decompiler
* among two or more contexts running script in one thread.
*/
JSGSNCache gsnCache;
/* Property cache for faster call/get/set invocation. */
JSPropertyCache propertyCache;
+
+#ifdef JS_TRACER
+ JSTraceMonitor traceMonitor;
+#endif
};
#define JS_GSN_CACHE(cx) ((cx)->thread->gsnCache)
#define JS_PROPERTY_CACHE(cx) ((cx)->thread->propertyCache)
+#define JS_TRACE_MONITOR(cx) ((cx)->thread->traceMonitor)
extern void JS_DLL_CALLBACK
js_ThreadDestructorCB(void *ptr);
extern JSBool
js_SetContextThread(JSContext *cx);
extern void
@@ -390,21 +395,33 @@ struct JSRuntime {
* a longer script, then hit repeatedly as js_GetSrcNote is called during
* the decompiler activation that filled it.
*/
JSGSNCache gsnCache;
/* Property cache for faster call/get/set invocation. */
JSPropertyCache propertyCache;
+#ifdef JS_TRACER
+ JSTraceMonitor traceMonitor;
+#endif
+
#define JS_GSN_CACHE(cx) ((cx)->runtime->gsnCache)
#define JS_PROPERTY_CACHE(cx) ((cx)->runtime->propertyCache)
+#define JS_TRACE_MONITOR(cx) ((cx)->runtime->traceMonitor)
#endif
/*
+ * Loops are globally numbered (per runtime) using this counter. The actual
+ * loop table that tracks loop statistics is per-thread in a multi-threaded
+ * environment.
+ */
+ uint32 loopTableIndexGen;
+
+ /*
* Object shape (property cache structural type) identifier generator.
*
* Type 0 stands for the empty scope, and must not be regenerated due to
* uint32 wrap-around. Since we use atomic pre-increment, the initial
* value for the first typed non-empty scope will be 1.
*
* The GC compresses live types, minimizing rt->shapeGen in the process.
* If this counter overflows into SHAPE_OVERFLOW_BIT (in jsinterp.h), the
@@ -477,20 +494,16 @@ struct JSRuntime {
*/
JSBasicStats hostenvScopeDepthStats;
JSBasicStats lexicalScopeDepthStats;
#endif
#ifdef JS_GCMETER
JSGCStats gcStats;
#endif
-
-#ifdef JS_TRACER
- JSTraceMonitor traceMonitor;
-#endif
};
#ifdef DEBUG
# define JS_RUNTIME_METER(rt, which) JS_ATOMIC_INCREMENT(&(rt)->which)
# define JS_RUNTIME_UNMETER(rt, which) JS_ATOMIC_DECREMENT(&(rt)->which)
#else
# define JS_RUNTIME_METER(rt, which) /* nothing */
# define JS_RUNTIME_UNMETER(rt, which) /* nothing */
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -3895,34 +3895,25 @@ EmitFunctionDefNop(JSContext *cx, JSCode
return js_NewSrcNote2(cx, cg, SRC_FUNCDEF, (ptrdiff_t)index) >= 0 &&
js_Emit1(cx, cg, JSOP_NOP) >= 0;
}
static JSBool
EmitLoopHeader(JSContext *cx, JSCodeGenerator *cg)
{
#ifdef JS_TRACER
- JSTraceMonitor *tm = &cx->runtime->traceMonitor;
ptrdiff_t off;
jsbytecode *pc;
- /*
- * Atomically increment the index generator and get us a unique index
- * number. If we get an index that exceeds the size of the loop table,
- * we request for its size to be increased.
- */
- uint32 index = JS_ATOMIC_INCREMENT(&tm->loopIndexGen);
- JS_ASSERT(index < JS_BITMASK(24));
- if (index >= tm->loopTableSize)
- js_GrowLoopTableIfNeeded(cx->runtime, index);
+ uint32 slot = js_AllocateLoopTableSlot(cx->runtime);
off = js_EmitN(cx, cg, JSOP_HEADER, 3);
if (off < 0)
return JS_FALSE;
pc = CG_CODE(cg, off);
- SET_UINT24(pc, index);
+ SET_UINT24(pc, slot);
#endif
return JS_TRUE;
}
JSBool
js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
{
JSBool ok, useful, wantval;
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2876,19 +2876,32 @@ js_TraceRuntime(JSTracer *trc, JSBool al
iter = NULL;
while ((acx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL)
js_TraceContext(trc, acx);
if (rt->gcExtraRootsTraceOp)
rt->gcExtraRootsTraceOp(trc, rt->gcExtraRootsData);
- /* Trace the loop table which can contain pointers to code objects. */
- JSTraceMonitor* tm = &rt->traceMonitor;
- TRACE_JSVALS(trc, tm->loopIndexGen, tm->loopTable, "rt->traceMonitor.loopTable");
+#ifdef JS_TRACER
+#ifdef JS_THREADSAFE
+ /* Trace the loop table(s) which can contain pointers to code objects. */
+ while ((acx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) {
+ if (!acx->thread || acx->thread == cx->thread)
+ continue;
+ JSTraceMonitor* tm = &acx->thread->traceMonitor;
+ TRACE_JSVALS(trc, tm->loopTableSize, tm->loopTable,
+ "thread->traceMonitor.loopTable");
+ }
+#else
+ JSTraceMonitor* tm = &rt->traceMonitor;
+ TRACE_JSVALS(trc, tm->loopTableSize, tm->loopTable,
+ "rt->traceMonitor.loopTable");
+#endif
+#endif
}
static void
ProcessSetSlotRequest(JSContext *cx, JSSetSlotRequest *ssr)
{
JSObject *obj, *pobj;
uint32 slot;
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -2796,29 +2796,44 @@ JS_INTERPRET(JSContext *cx)
#if JS_HAS_XML_SUPPORT
ADD_EMPTY_CASE(JSOP_STARTXML)
ADD_EMPTY_CASE(JSOP_STARTXMLEXPR)
#endif
END_EMPTY_CASES
BEGIN_CASE(JSOP_HEADER)
i = GET_UINT24(regs.pc);
- JS_ASSERT(((uint32)i) <= rt->traceMonitor.loopIndexGen);
+ JS_ASSERT((i > 0) && (i <= (jsint)rt->loopTableIndexGen));
+ JSTraceMonitor *tm = &JS_TRACE_MONITOR(cx);
+ if (i >= (jsint)tm->loopTableSize)
+ js_GrowLoopTableIfNeeded(cx, i);
vp = &rt->traceMonitor.loopTable[i];
rval = *vp;
- if (JSVAL_IS_INT(rval)) {
- /*
- * Try to atomically fast-increment (search for FAST_INC_DEC)
- * the counter. If another thread beats us to this and
- * changes the slot to a tree pointer, undo our write (which
- * just replaced the pointer with a counter value).
+ if (JSVAL_IS_INT(rval)) {
+ /*
+ * There are no concurrent writes to slots. This point in
+ * the program is the only place a slot is updated from.
*/
- lval = JS_ATOMIC_SET(vp, rval + 2);
- if (!JSVAL_IS_INT(lval))
- JS_ATOMIC_SET(vp, lval);
+ if (JSVAL_TO_INT(rval) >= TRACE_THRESHOLD) {
+ /*
+ * Once a thread hits the threshold, it should first consult
+ * (read) the other threads' loop tables to see if anyone
+ * already compiled a tree for us, and in that case reuse
+ * that tree instead of recording a new one.
+ */
+ *vp = OBJECT_TO_JSVAL(js_NewObject(cx, &js_ObjectClass, NULL, NULL, 0));
+ } else {
+ /*
+ * We use FAST_INC_DEC to increment the jsval counter, which
+ * currently contains a jsint. *vp += 2 is equivalent to
+ * INT_TO_JSVAL(JSVAL_TO_INT(*vp) + 1). JS_ATOMIC_ADD(v, 2)
+ * is the atomic version of *vp += 2.
+ */
+ JS_ATOMIC_ADD(vp, 2);
+ }
} else {
JS_ASSERT(JSVAL_IS_GCTHING(rval));
/* Execute the tree. */
}
END_CASE(JSOP_HEADER)
/* ADD_EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */
TRACE_CASE(JSOP_LINENO)
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -38,50 +38,43 @@
#define jstracer_cpp___
#include "jsinterp.cpp"
JSBool
js_InitTracer(JSRuntime *rt)
{
-#ifdef JS_THREADSAFE
- JSTraceMonitor *tm = &rt->traceMonitor;
- JS_ASSERT(!tm->lock);
- tm->lock = JS_NEW_LOCK();
- if (!tm->lock)
- return JS_FALSE;
-#endif
return JS_TRUE;
}
/*
* To grow the loop table that we take the traceMonitor lock, double check
- * that no other thread grew the table while we were deciding to grow the
- * table, and only then double the size of the loop table.
- *
- * The initial size of the table is 2^8 and grows to at most 2^24 entries.
- * It is extended at most a constant number of times (C=16) by doubling its
- * size every time. When extending the table, each slot is initially filled
- * with JS_ZERO.
+ * that no other thread grew the table while we were deciding to grow the
+ * table, and only then double the size of the loop table.
+ *
+ * The initial size of the table is 2^8 and grows to at most 2^24 entries. It
+ * is extended at most a constant number of times (C=16) by doubling its size
+ * every time. When extending the table, each slot is initially filled with
+ * JS_ZERO.
*/
void
js_GrowLoopTableIfNeeded(JSRuntime* rt, uint32 index)
{
JSTraceMonitor *tm = &rt->traceMonitor;
- JS_ACQUIRE_LOCK(&tm->lock);
- uint32 oldSize;
- if (index >= (oldSize = tm->loopTableSize)) {
+ uint32 oldSize = tm->loopTableSize;
+
+ if (index >= oldSize) {
uint32 newSize = oldSize << 1;
jsval* t = tm->loopTable;
if (t == NULL) {
JS_ASSERT(oldSize == 0);
newSize = 256;
t = (jsval*)malloc(newSize * sizeof(jsval));
- } else
+ } else {
t = (jsval*)realloc(tm->loopTable, newSize * sizeof(jsval));
+ }
for (uint32 n = oldSize; n < newSize; ++n)
t[n] = JSVAL_ZERO;
tm->loopTable = t;
tm->loopTableSize = newSize;
}
- JS_RELEASE_LOCK(&tm->lock);
}
new file mode 100644
--- /dev/null
+++ b/js/src/jstracer.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=78:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
+ * May 28, 2008.
+ *
+ * The Initial Developer of the Original Code is
+ * Brendan Eich <brendan@mozilla.org
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jstracer_h___
+#define jstracer_h___
+
+#include "jsstddef.h"
+#include "jslock.h"
+
+/*
+ * Trace monitor. Every runtime is associated with a trace monitor that
+ * keeps track of loop frequencies for all JavaScript code loaded into
+ * that runtime. For this we use a loop table. Entries in the loop
+ * table are requested by jsemit.c during compilation. By using atomic
+ * pre-increment obtaining the next index is lock free, but to allocate
+ * more table space the trace monitor lock has to be aquired first.
+ *
+ * The loop table also doubles as tree pointer table once a loop
+ * achieves a certain number of iterations and we recorded a tree for
+ * that loop.
+ */
+struct JSTraceMonitor {
+ jsval *loopTable;
+ uint32 loopTableSize;
+};
+
+#define TRACE_THRESHOLD 10
+
+JSBool js_InitTracer(JSRuntime *rt);
+uint32 js_AllocateLoopTableSlot(JSRuntime *rt);
+void js_GrowLoopTableIfNeeded(JSContext *cx, uint32 index);
+
+#endif /* jstracer_h___ */