Merge, style nits, no locking for tracing.

This commit is contained in:
Brendan Eich 2008-05-31 15:29:54 -07:00
commit 5b116ae998
6 changed files with 140 additions and 47 deletions

View File

@ -125,10 +125,15 @@ struct JSThread {
/* 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);
@ -395,10 +400,22 @@ struct JSRuntime {
/* 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.
*
@ -482,10 +499,6 @@ struct JSRuntime {
#ifdef JS_GCMETER
JSGCStats gcStats;
#endif
#ifdef JS_TRACER
JSTraceMonitor traceMonitor;
#endif
};
#ifdef DEBUG

View File

@ -3900,24 +3900,15 @@ 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;
}

View File

@ -2881,9 +2881,22 @@ js_TraceRuntime(JSTracer *trc, JSBool allAtoms)
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

View File

@ -2801,19 +2801,34 @@ JS_INTERPRET(JSContext *cx)
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. */

View File

@ -43,45 +43,38 @@
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);
}

68
js/src/jstracer.h Normal file
View File

@ -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___ */