mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge tracemonkey to mozilla-central.
This commit is contained in:
commit
cad15cadf1
@ -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)
|
||||
|
||||
|
@ -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]));
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user