Merge tracemonkey to mozilla-central.

This commit is contained in:
Robert Sayre 2009-06-03 16:54:10 -04:00
commit cad15cadf1
5 changed files with 166 additions and 94 deletions

View File

@ -181,6 +181,7 @@ struct JSTraceableNative {
#define _JS_CTYPE_THIS_STRING _JS_CTYPE(JSString *, _JS_PTR,"S", "", INFALLIBLE)
#define _JS_CTYPE_CALLEE _JS_CTYPE(JSObject *, _JS_PTR,"f","", INFALLIBLE)
#define _JS_CTYPE_CALLEE_PROTOTYPE _JS_CTYPE(JSObject *, _JS_PTR,"p","", INFALLIBLE)
#define _JS_CTYPE_FUNCTION _JS_CTYPE(JSFunction *, _JS_PTR, --, --, INFALLIBLE)
#define _JS_CTYPE_PC _JS_CTYPE(jsbytecode *, _JS_PTR,"P", "", INFALLIBLE)
#define _JS_CTYPE_JSVALPTR _JS_CTYPE(jsval *, _JS_PTR,"P", "", INFALLIBLE)
#define _JS_CTYPE_JSVAL _JS_JSVAL_CTYPE( _JS_PTR, "","v", INFALLIBLE)
@ -451,6 +452,9 @@ JS_DECLARE_CALLINFO(js_NewEmptyArray)
JS_DECLARE_CALLINFO(js_NewUninitializedArray)
JS_DECLARE_CALLINFO(js_ArrayCompPush)
/* Defined in jsfun.cpp. */
JS_DECLARE_CALLINFO(js_AllocFlatClosure)
/* Defined in jsnum.cpp. */
JS_DECLARE_CALLINFO(js_NumberToString)

View File

@ -2179,13 +2179,19 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent)
return clone;
}
JSObject *
js_NewFlatClosure(JSContext *cx, JSFunction *fun)
/*
* Create a new flat closure, but don't initialize the imported upvar
* values. The tracer calls this function and then initializes the upvar
* slots on trace.
*/
JSObject * JS_FASTCALL
js_AllocFlatClosure(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
{
JS_ASSERT(FUN_FLAT_CLOSURE(fun));
JS_ASSERT(fun->u.i.script->upvarsOffset);
JSObject *closure = js_CloneFunctionObject(cx, fun, cx->fp->scopeChain);
if (!closure || fun->u.i.script->upvarsOffset == 0)
JSObject *closure = js_CloneFunctionObject(cx, fun, scopeChain);
if (!closure)
return closure;
uint32 nslots = JSSLOT_FREE(&js_FunctionClass);
@ -2194,6 +2200,17 @@ js_NewFlatClosure(JSContext *cx, JSFunction *fun)
if (!js_ReallocSlots(cx, closure, nslots, JS_TRUE))
return NULL;
return closure;
}
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_AllocFlatClosure,
CONTEXT, FUNCTION, OBJECT, 0, 0)
JSObject *
js_NewFlatClosure(JSContext *cx, JSFunction *fun)
{
JSObject *closure = js_AllocFlatClosure(cx, fun, cx->fp->scopeChain);
JSUpvarArray *uva = JS_SCRIPT_UPVARS(fun->u.i.script);
JS_ASSERT(uva->length <= size_t(closure->dslots[-1]));

View File

@ -1308,19 +1308,6 @@ TypeMap::matches(TypeMap& other) const
return !memcmp(data(), other.data(), length());
}
/* Use the provided storage area to create a new type map that contains the partial type map
with the rest of it filled up from the complete type map. */
static void
mergeTypeMaps(uint8** partial, unsigned* plength, uint8* complete, unsigned clength, uint8* mem)
{
unsigned l = *plength;
JS_ASSERT(l < clength);
memcpy(mem, *partial, l * sizeof(uint8));
memcpy(mem + l, complete + l, (clength - l) * sizeof(uint8));
*partial = mem;
*plength = clength;
}
/* Specializes a tree to any missing globals, including any dependent trees. */
static JS_REQUIRES_STACK void
specializeTreesToMissingGlobals(JSContext* cx, TreeInfo* root)
@ -2090,29 +2077,16 @@ JS_REQUIRES_STACK void
TraceRecorder::import(TreeInfo* treeInfo, LIns* sp, unsigned stackSlots, unsigned ngslots,
unsigned callDepth, uint8* typeMap)
{
/* If we get a partial list that doesn't have all the types (i.e. recording from a side
exit that was recorded but we added more global slots later), merge the missing types
from the entry type map. This is safe because at the loop edge we verify that we
have compatible types for all globals (entry type and loop edge type match). While
a different trace of the tree might have had a guard with a different type map for
these slots we just filled in here (the guard we continue from didn't know about them),
since we didn't take that particular guard the only way we could have ended up here
is if that other trace had at its end a compatible type distribution with the entry
map. Since thats exactly what we used to fill in the types our current side exit
didn't provide, this is always safe to do. */
uint8* globalTypeMap = typeMap + stackSlots;
unsigned length = treeInfo->nGlobalTypes();
/*
* This is potentially the typemap of the side exit and thus shorter than the tree's
* global type map.
* If we get a partial list that doesn't have all the types, capture the missing types
* from the current environment.
*/
if (ngslots < length) {
mergeTypeMaps(&globalTypeMap/*out param*/, &ngslots/*out param*/,
treeInfo->globalTypeMap(), length,
(uint8*)alloca(sizeof(uint8) * length));
TypeMap fullTypeMap(typeMap, stackSlots + ngslots);
if (ngslots < treeInfo->globalSlots->length()) {
fullTypeMap.captureMissingGlobalTypes(cx, *treeInfo->globalSlots, stackSlots);
ngslots = treeInfo->globalSlots->length();
}
uint8* globalTypeMap = fullTypeMap.data() + stackSlots;
JS_ASSERT(ngslots == treeInfo->nGlobalTypes());
/*
@ -8443,23 +8417,21 @@ TraceRecorder::record_JSOP_CALLNAME()
JS_DEFINE_CALLINFO_5(extern, UINT32, js_GetUpvarOnTrace, CONTEXT, UINT32, UINT32, UINT32,
DOUBLEPTR, 0, 0)
JS_REQUIRES_STACK JSRecordingStatus
TraceRecorder::record_JSOP_GETUPVAR()
/*
* Record LIR to get the given upvar. Return the LIR instruction for
* the upvar value. NULL is returned only on a can't-happen condition
* with an invalid typemap. The value of the upvar is returned as v.
*/
JS_REQUIRES_STACK LIns*
TraceRecorder::upvar(JSScript* script, JSUpvarArray* uva, uintN index, jsval& v)
{
uintN index = GET_UINT16(cx->fp->regs->pc);
JSScript *script = cx->fp->script;
JSUpvarArray* uva = JS_SCRIPT_UPVARS(script);
JS_ASSERT(index < uva->length);
/*
* Try to find the upvar in the current trace's tracker.
*/
jsval& v = js_GetUpvar(cx, script->staticLevel, uva->vector[index]);
v = js_GetUpvar(cx, script->staticLevel, uva->vector[index]);
LIns* upvar_ins = get(&v);
if (upvar_ins) {
stack(0, upvar_ins);
return JSRS_CONTINUE;
return upvar_ins;
}
/*
@ -8500,13 +8472,28 @@ TraceRecorder::record_JSOP_GETUPVAR()
case JSVAL_BOXED:
default:
JS_NOT_REACHED("found boxed type in an upvar type map entry");
return JSRS_STOP;
return NULL;
}
LIns* result = lir->insLoad(loadOp, outp, lir->insImm(0));
if (type == JSVAL_INT)
result = lir->ins1(LIR_i2f, result);
stack(0, result);
return result;
}
JS_REQUIRES_STACK JSRecordingStatus
TraceRecorder::record_JSOP_GETUPVAR()
{
uintN index = GET_UINT16(cx->fp->regs->pc);
JSScript *script = cx->fp->script;
JSUpvarArray* uva = JS_SCRIPT_UPVARS(script);
JS_ASSERT(index < uva->length);
jsval v;
LIns* upvar_ins = upvar(script, uva, index, v);
if (!upvar_ins)
return JSRS_STOP;
stack(0, upvar_ins);
return JSRS_CONTINUE;
}
@ -9786,7 +9773,36 @@ TraceRecorder::record_JSOP_LAMBDA()
JS_REQUIRES_STACK JSRecordingStatus
TraceRecorder::record_JSOP_LAMBDA_FC()
{
return JSRS_STOP;
JSFunction* fun;
JS_GET_SCRIPT_FUNCTION(cx->fp->script, getFullIndex(), fun);
LIns* scopeChain_ins = get(&cx->fp->argv[-2]);
JS_ASSERT(scopeChain_ins);
LIns* args[] = {
scopeChain_ins,
INS_CONSTPTR(fun),
cx_ins
};
LIns* call_ins = lir->insCall(&js_AllocFlatClosure_ci, args);
guard(false,
addName(lir->ins2(LIR_eq, call_ins, INS_CONSTPTR(0)),
"guard(js_AllocFlatClosure)"),
OOM_EXIT);
stack(0, call_ins);
JSUpvarArray *uva = JS_SCRIPT_UPVARS(fun->u.i.script);
for (uint32 i = 0, n = uva->length; i < n; i++) {
jsval v;
LIns* upvar_ins = upvar(fun->u.i.script, uva, i, v);
if (!upvar_ins)
return JSRS_STOP;
box_jsval(v, upvar_ins);
LIns* dslots_ins = NULL;
stobj_set_dslot(call_ins, i, dslots_ins, upvar_ins, "fc upvar");
}
return JSRS_CONTINUE;
}
JS_REQUIRES_STACK JSRecordingStatus

View File

@ -76,6 +76,13 @@ public:
this->_data = (T*)malloc(max * sizeof(T));
}
Queue(T* data, unsigned length) {
this->_max =
this->_len = length;
this->_data = (T*)malloc(length * sizeof(T));
memcpy(this->_data, data, length);
}
~Queue() {
free(_data);
}
@ -189,6 +196,12 @@ typedef Queue<uint16> SlotList;
class TypeMap : public Queue<uint8> {
public:
TypeMap() : Queue<uint8>() {
}
TypeMap(uint8* partial, unsigned length) : Queue<uint8>(partial, length) {
}
JS_REQUIRES_STACK void captureTypes(JSContext* cx, SlotList& slots, unsigned callDepth);
JS_REQUIRES_STACK void captureMissingGlobalTypes(JSContext* cx,
SlotList& slots,
@ -518,6 +531,7 @@ class TraceRecorder : public avmplus::GCObject {
JS_REQUIRES_STACK void arg(unsigned n, nanojit::LIns* i);
JS_REQUIRES_STACK nanojit::LIns* var(unsigned n);
JS_REQUIRES_STACK void var(unsigned n, nanojit::LIns* i);
JS_REQUIRES_STACK nanojit::LIns* upvar(JSScript* script, JSUpvarArray* uva, uintN index, jsval& v);
JS_REQUIRES_STACK nanojit::LIns* stack(int n);
JS_REQUIRES_STACK void stack(int n, nanojit::LIns* i);

View File

@ -1672,60 +1672,81 @@ TryNotes(JSContext *cx, JSScript *script)
return JS_TRUE;
}
static JSBool
Disassemble(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
static bool
DisassembleValue(JSContext *cx, jsval v, bool lines, bool recursive)
{
JSBool lines;
uintN i;
JSScript *script;
if (argc > 0 &&
JSVAL_IS_STRING(argv[0]) &&
!strcmp(JS_GetStringBytes(JSVAL_TO_STRING(argv[0])), "-l")) {
lines = JS_TRUE;
argv++, argc--;
} else {
lines = JS_FALSE;
}
for (i = 0; i < argc; i++) {
script = ValueToScript(cx, argv[i]);
if (!script)
return JS_FALSE;
if (VALUE_IS_FUNCTION(cx, argv[i])) {
JSFunction *fun = JS_ValueToFunction(cx, argv[i]);
if (fun && (fun->flags & ~7U)) {
uint16 flags = fun->flags;
fputs("flags:", stdout);
JSScript *script = ValueToScript(cx, v);
if (!script)
return false;
if (VALUE_IS_FUNCTION(cx, v)) {
JSFunction *fun = JS_ValueToFunction(cx, v);
if (fun && (fun->flags & ~7U)) {
uint16 flags = fun->flags;
fputs("flags:", stdout);
#define SHOW_FLAG(flag) if (flags & JSFUN_##flag) fputs(" " #flag, stdout);
SHOW_FLAG(LAMBDA);
SHOW_FLAG(SETTER);
SHOW_FLAG(GETTER);
SHOW_FLAG(BOUND_METHOD);
SHOW_FLAG(HEAVYWEIGHT);
SHOW_FLAG(THISP_STRING);
SHOW_FLAG(THISP_NUMBER);
SHOW_FLAG(THISP_BOOLEAN);
SHOW_FLAG(EXPR_CLOSURE);
SHOW_FLAG(TRACEABLE);
SHOW_FLAG(LAMBDA);
SHOW_FLAG(SETTER);
SHOW_FLAG(GETTER);
SHOW_FLAG(BOUND_METHOD);
SHOW_FLAG(HEAVYWEIGHT);
SHOW_FLAG(THISP_STRING);
SHOW_FLAG(THISP_NUMBER);
SHOW_FLAG(THISP_BOOLEAN);
SHOW_FLAG(EXPR_CLOSURE);
SHOW_FLAG(TRACEABLE);
#undef SHOW_FLAG
if (FUN_NULL_CLOSURE(fun))
fputs(" NULL_CLOSURE", stdout);
else if (FUN_FLAT_CLOSURE(fun))
fputs(" FLAT_CLOSURE", stdout);
if (FUN_NULL_CLOSURE(fun))
fputs(" NULL_CLOSURE", stdout);
else if (FUN_FLAT_CLOSURE(fun))
fputs(" FLAT_CLOSURE", stdout);
putchar('\n');
}
}
if (!js_Disassemble(cx, script, lines, stdout))
return false;
SrcNotes(cx, script);
TryNotes(cx, script);
if (recursive && script->objectsOffset != 0) {
JSObjectArray *objects = JS_SCRIPT_OBJECTS(script);
for (uintN i = 0; i != objects->length; ++i) {
JSObject *obj = objects->vector[i];
if (HAS_FUNCTION_CLASS(obj)) {
putchar('\n');
if (!DisassembleValue(cx, OBJECT_TO_JSVAL(obj),
lines, recursive)) {
return false;
}
}
}
if (!js_Disassemble(cx, script, lines, stdout))
return JS_FALSE;
SrcNotes(cx, script);
TryNotes(cx, script);
}
return JS_TRUE;
return true;
}
static JSBool
Disassemble(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
bool lines = false, recursive = false;
while (argc > 0 && JSVAL_IS_STRING(argv[0])) {
const char *bytes = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
lines = !strcmp(bytes, "-l");
recursive = !strcmp(bytes, "-r");
if (!lines && !recursive)
break;
argv++, argc--;
}
for (uintN i = 0; i < argc; i++) {
if (!DisassembleValue(cx, argv[i], lines, recursive))
return false;
}
return true;
}
static JSBool