[INFER] Apply arguments and script review comments, bug 657412.

This commit is contained in:
Brian Hackett 2011-06-06 08:32:41 -07:00
parent de9c3c81f6
commit b0ae81df4a
24 changed files with 581 additions and 536 deletions

View File

@ -1023,7 +1023,7 @@ class ScriptAnalysis
case SSAValue::VAR:
JS_ASSERT(!slotEscapes(v.varSlot()));
if (v.varInitial()) {
return script->slotTypes(v.varSlot());
return script->types.slotTypes(v.varSlot());
} else {
/*
* Results of intermediate assignments have the same type as

View File

@ -4302,7 +4302,7 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
Value v;
if (!obj->getProperty(cx, r.front().propid, &v))
return NULL;
fun->script()->typeSetUpvar(cx, i, v);
fun->script()->types.setUpvar(cx, i, v);
clone->getFlatClosureUpvars()[i] = v;
}

View File

@ -3241,7 +3241,7 @@ array_TypeConcat(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
TypeCallsite *site = Valueify(jssite);
if (!site->hasGlobal()) {
if (!site->script->hasGlobal()) {
site->returnTypes->addType(cx, TYPE_UNKNOWN);
return;
}
@ -3283,7 +3283,7 @@ array_TypeExtra(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite,
case MAP:
case FILTER:
if (site->hasGlobal()) {
if (site->script->hasGlobal()) {
/* Makes a new array whose element type will be filled in as the code runs. */
TypeObject *object = site->getInitObject(cx, true);
if (!object)
@ -3434,7 +3434,7 @@ array_TypeNew(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
{
TypeCallsite *site = Valueify(jssite);
if (!site->hasGlobal()) {
if (!site->script->hasGlobal()) {
site->returnTypes->addType(cx, TYPE_UNKNOWN);
return;
}

View File

@ -566,7 +566,7 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
for (JSCList *cursor = scripts.next; ok && cursor != &scripts; cursor = cursor->next) {
JSScript *script = reinterpret_cast<JSScript *>(cursor);
ok = script->condenseTypes(cx);
ok = script->types.condenseTypes(cx);
}
if (ok)

View File

@ -223,12 +223,6 @@ JS_SetDebugModeForCompartment(JSContext *cx, JSCompartment *comp, JSBool debug)
mjit::ReleaseScriptCode(cx, script, true);
mjit::ReleaseScriptCode(cx, script, false);
script->debugMode = !!debug;
/* Mark arguments objects as escaping in all scripts if debug mode is on. */
if (script->usesArguments && debug) {
types::MarkTypeObjectFlags(cx, script->fun->getType(),
types::OBJECT_FLAG_CREATED_ARGUMENTS);
}
}
#endif

View File

@ -2821,7 +2821,10 @@ EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg,
op = JSOP_CALLPROP;
} else if (op == JSOP_GETPROP && pn->pn_type == TOK_DOT) {
if (pn2->pn_type == TOK_NAME) {
/* Try to optimize arguments.length into JSOP_ARGCNT */
/*
* Try to optimize arguments.length into JSOP_ARGCNT. If type
* inference is enabled this is optimized separately.
*/
if (!BindNameToSlot(cx, cg, pn2))
return JS_FALSE;
if (!cx->typeInferenceEnabled() &&
@ -2909,7 +2912,8 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
/*
* Try to optimize arguments[0][j]... into JSOP_ARGSUB<0> followed by
* one or more index expression and JSOP_GETELEM op pairs.
* one or more index expression and JSOP_GETELEM op pairs. If type
* inference is enabled this is optimized separately.
*/
if (left->pn_type == TOK_NAME && next->pn_type == TOK_NUMBER) {
if (!BindNameToSlot(cx, cg, left))
@ -2985,7 +2989,10 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
right = pn->pn_right;
}
/* Try to optimize arguments[0] (e.g.) into JSOP_ARGSUB<0>. */
/*
* Try to optimize arguments[0] (e.g.) into JSOP_ARGSUB<0>. If type
* inference is enabled this is optimized separately.
*/
if (op == JSOP_GETELEM &&
left->pn_type == TOK_NAME &&
right->pn_type == TOK_NUMBER) {

View File

@ -108,10 +108,6 @@ JSBool
js_GetArgsValue(JSContext *cx, StackFrame *fp, Value *vp)
{
JSObject *argsobj;
MarkTypeObjectFlags(cx, fp->fun()->getType(),
OBJECT_FLAG_CREATED_ARGUMENTS | OBJECT_FLAG_UNINLINEABLE);
if (fp->hasOverriddenArgs()) {
JS_ASSERT(fp->hasCallObj());
jsid id = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
@ -256,6 +252,13 @@ js_GetArgsObject(JSContext *cx, StackFrame *fp)
*/
JS_ASSERT_IF(fp->fun()->isHeavyweight(), fp->hasCallObj());
/*
* Mark all functions which have ever had arguments objects constructed,
* which will prevent lazy arguments optimizations in the method JIT.
*/
MarkTypeObjectFlags(cx, fp->fun()->getType(),
OBJECT_FLAG_CREATED_ARGUMENTS | OBJECT_FLAG_UNINLINEABLE);
while (fp->isDirectEvalOrDebuggerFrame())
fp = fp->prev();
@ -599,7 +602,7 @@ ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
JSScript *script = fp->functionScript();
if (script->usesArguments) {
if (arg < fp->numFormalArgs())
script->typeSetArgument(cx, arg, *vp);
script->types.setArgument(cx, arg, *vp);
fp->canonicalActualArg(arg) = *vp;
}
return true;
@ -1245,7 +1248,7 @@ SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
argp = &obj->callObjArg(i);
JSScript *script = obj->getCallObjCalleeFunction()->script();
script->typeSetArgument(cx, i, *vp);
script->types.setArgument(cx, i, *vp);
GCPoke(cx, *argp);
*argp = *vp;
@ -1328,7 +1331,7 @@ SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
varp = &obj->callObjVar(i);
JSScript *script = obj->getCallObjCalleeFunction()->script();
script->typeSetLocal(cx, i, *vp);
script->types.setLocal(cx, i, *vp);
GCPoke(cx, *varp);
*varp = *vp;
@ -2981,7 +2984,7 @@ js_NewFlatClosure(JSContext *cx, JSFunction *fun, JSOp op, size_t oplen)
for (uint32 i = 0, n = uva->length; i < n; i++) {
upvars[i] = GetUpvar(cx, level, uva->vector[i]);
fun->script()->typeSetUpvar(cx, i, upvars[i]);
fun->script()->types.setUpvar(cx, i, upvars[i]);
}
return closure;

View File

@ -914,15 +914,15 @@ GetPropertyObject(JSContext *cx, JSScript *script, jstype type)
case TYPE_INT32:
case TYPE_DOUBLE:
object = script->getTypeNewObject(cx, JSProto_Number);
object = script->types.standardType(cx, JSProto_Number);
break;
case TYPE_BOOLEAN:
object = script->getTypeNewObject(cx, JSProto_Boolean);
object = script->types.standardType(cx, JSProto_Boolean);
break;
case TYPE_STRING:
object = script->getTypeNewObject(cx, JSProto_String);
object = script->types.standardType(cx, JSProto_String);
break;
default:
@ -1001,7 +1001,7 @@ TypeConstraintProp::newType(JSContext *cx, TypeSet *source, jstype type)
{
UntrapOpcode untrap(cx, script, pc);
if (type == TYPE_UNKNOWN || (!TypeIsObject(type) && !script->global)) {
if (type == TYPE_UNKNOWN || (!TypeIsObject(type) && !script->hasGlobal())) {
/*
* Access on an unknown object. Reads produce an unknown result, writes
* need to be monitored. Note: this isn't a problem for handling overflows
@ -1044,7 +1044,7 @@ TypeConstraintCallProp::newType(JSContext *cx, TypeSet *source, jstype type)
* get their 'this' types updated.
*/
if (type == TYPE_UNKNOWN || (!TypeIsObject(type) && !script->global)) {
if (type == TYPE_UNKNOWN || (!TypeIsObject(type) && !script->hasGlobal())) {
cx->compartment->types.monitorBytecode(cx, script, callpc - script->code);
return;
}
@ -1088,10 +1088,10 @@ TypeConstraintNewObject::newType(JSContext *cx, TypeSet *source, jstype type)
* native constructors with immutable non-primitive prototypes.
* Disregard primitives here.
*/
} else if (!fun->script->global) {
} else if (!fun->script->hasGlobal()) {
target->addType(cx, TYPE_UNKNOWN);
} else {
TypeObject *object = fun->script->getTypeNewObject(cx, JSProto_Object);
TypeObject *object = fun->script->types.standardType(cx, JSProto_Object);
if (!object) {
cx->compartment->types.setPendingNukeTypes(cx);
return;
@ -1140,7 +1140,7 @@ TypeConstraintCall::newType(JSContext *cx, TypeSet *source, jstype type)
* :FIXME: bug 631135. Rather than try to model this, just mark the
* result of cross-global native calls as unknown.
*/
if (!script->global || script->global != function->singleton->getGlobal()) {
if (!script->hasGlobal() || script->global() != function->singleton->getGlobal()) {
callsite->returnTypes->addType(cx, TYPE_UNKNOWN);
return;
}
@ -1187,42 +1187,38 @@ TypeConstraintCall::newType(JSContext *cx, TypeSet *source, jstype type)
JSScript *callee = function->script;
unsigned nargs = callee->fun->nargs;
if (!callee->ensureTypeArray(cx))
if (!callee->types.ensureTypeArray(cx))
return;
/* Analyze the function if we have not already done so. */
if (!callee->ranInference) {
ScriptAnalysis *calleeAnalysis = callee->analysis(cx);
if (!calleeAnalysis) {
cx->compartment->types.setPendingNukeTypes(cx);
return;
}
calleeAnalysis->analyzeTypes(cx);
if (!callee->ensureRanInference(cx)) {
cx->compartment->types.setPendingNukeTypes(cx);
return;
}
/* Add bindings for the arguments of the call. */
for (unsigned i = 0; i < callsite->argumentCount && i < nargs; i++) {
TypeSet *argTypes = callsite->argumentTypes[i];
TypeSet *types = callee->argTypes(i);
TypeSet *types = callee->types.argTypes(i);
argTypes->addSubsetBarrier(cx, script, pc, types);
}
/* Add void type for any formals in the callee not supplied at the call site. */
for (unsigned i = callsite->argumentCount; i < nargs; i++) {
TypeSet *types = callee->argTypes(i);
TypeSet *types = callee->types.argTypes(i);
types->addType(cx, TYPE_UNDEFINED);
}
if (callsite->isNew) {
/* Mark the callee as having been invoked with 'new'. */
callee->typeSetNewCalled(cx);
callee->types.setNewCalled(cx);
/*
* If the script does not return a value then the pushed value is the new
* object (typical case).
*/
callee->thisTypes()->addSubset(cx, script, callsite->returnTypes);
callee->returnTypes()->addFilterPrimitives(cx, script, callsite->returnTypes, false);
callee->types.thisTypes()->addSubset(cx, script, callsite->returnTypes);
callee->types.returnTypes()->addFilterPrimitives(cx, script, callsite->returnTypes, false);
} else {
/*
* Add a binding for the return value of the call. We don't add a
@ -1232,7 +1228,7 @@ TypeConstraintCall::newType(JSContext *cx, TypeSet *source, jstype type)
* in the 'this' and 'callee' sets, which we want to maintain for
* polymorphic JSOP_CALLPROP invocations.
*/
callee->returnTypes()->addSubset(cx, script, callsite->returnTypes);
callee->types.returnTypes()->addSubset(cx, script, callsite->returnTypes);
}
}
@ -1265,10 +1261,10 @@ TypeConstraintPropagateThis::newType(JSContext *cx, TypeSet *source, jstype type
JSScript *callee = function->script;
if (!callee->ensureTypeArray(cx))
if (!callee->types.ensureTypeArray(cx))
return;
callee->thisTypes()->addType(cx, this->type);
callee->types.thisTypes()->addType(cx, this->type);
}
void
@ -1342,7 +1338,7 @@ TypeConstraintTransformThis::newType(JSContext *cx, TypeSet *source, jstype type
* Note: if |this| is null or undefined, the pushed value is the outer window. We
* can't use script->getGlobalType() here because it refers to the inner window.
*/
if (!script->global || type == TYPE_NULL || type == TYPE_UNDEFINED) {
if (!script->hasGlobal() || type == TYPE_NULL || type == TYPE_UNDEFINED) {
target->addType(cx, TYPE_UNKNOWN);
return;
}
@ -1351,13 +1347,13 @@ TypeConstraintTransformThis::newType(JSContext *cx, TypeSet *source, jstype type
switch (type) {
case TYPE_INT32:
case TYPE_DOUBLE:
object = script->getTypeNewObject(cx, JSProto_Number);
object = script->types.standardType(cx, JSProto_Number);
break;
case TYPE_BOOLEAN:
object = script->getTypeNewObject(cx, JSProto_Boolean);
object = script->types.standardType(cx, JSProto_Boolean);
break;
case TYPE_STRING:
object = script->getTypeNewObject(cx, JSProto_String);
object = script->types.standardType(cx, JSProto_String);
break;
default:
return;
@ -1675,7 +1671,6 @@ FixLazyArguments(JSContext *cx, JSScript *script)
mjit::ExpandInlineFrames(cx, FRAME_EXPAND_ALL);
#endif
/* :FIXME: handle OOM at calls here. */
ScriptAnalysis *analysis = script->analysis(cx);
if (analysis && !analysis->ranBytecode())
analysis->analyzeBytecode(cx);
@ -1696,9 +1691,8 @@ FixLazyArguments(JSContext *cx, JSScript *script)
Value *sp = fp->base() + analysis->getCode(pc).stackDepth;
for (Value *vp = fp->slots(); vp < sp; vp++) {
if (vp->isMagicCheck(JS_LAZY_ARGUMENTS)) {
if (!js_GetArgsValue(cx, fp, vp)) {
/* FIXME */
}
if (!js_GetArgsValue(cx, fp, vp))
vp->setNull();
}
}
}
@ -1881,7 +1875,7 @@ TypeCompartment::newTypeObject(JSContext *cx, JSScript *script,
if (!object)
return NULL;
TypeObject *&objects = script ? script->typeObjects : this->objects;
TypeObject *&objects = script ? script->types.typeObjects : this->objects;
object->next = objects;
objects = object;
@ -1914,7 +1908,7 @@ TypeCompartment::newInitializerTypeObject(JSContext *cx, JSScript *script,
JSObject *proto;
JSProtoKey key = isArray ? JSProto_Array : JSProto_Object;
if (!js_GetClassPrototype(cx, script->getGlobal(), key, &proto, NULL))
if (!js_GetClassPrototype(cx, script->global(), key, &proto, NULL))
return NULL;
TypeObject *res = newTypeObject(cx, script, name, "", false, isArray, proto);
@ -2266,7 +2260,7 @@ TypeCompartment::print(JSContext *cx, JSCompartment *compartment)
script = (JSScript *)script->links.next) {
if (script->hasAnalysis() && script->analysis(cx)->ranInference())
script->analysis(cx)->printTypes(cx);
TypeObject *object = script->typeObjects;
TypeObject *object = script->types.typeObjects;
while (object) {
object->print(cx);
object = object->next;
@ -3088,7 +3082,7 @@ CheckNextTest(jsbytecode *pc)
static inline TypeObject *
GetInitializerType(JSContext *cx, JSScript *script, jsbytecode *pc)
{
if (!script->global)
if (!script->hasGlobal())
return NULL;
UntrapOpcode untrap(cx, script, pc);
@ -3097,7 +3091,7 @@ GetInitializerType(JSContext *cx, JSScript *script, jsbytecode *pc)
JS_ASSERT(op == JSOP_NEWARRAY || op == JSOP_NEWOBJECT || op == JSOP_NEWINIT);
bool isArray = (op == JSOP_NEWARRAY || (op == JSOP_NEWINIT && pc[1] == JSProto_Array));
return script->getTypeInitObject(cx, pc, isArray);
return script->types.initObject(cx, pc, isArray);
}
inline void
@ -3292,8 +3286,8 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
break;
case JSOP_REGEXP:
if (script->global) {
TypeObject *object = script->getTypeNewObject(cx, JSProto_RegExp);
if (script->hasGlobal()) {
TypeObject *object = script->types.standardType(cx, JSProto_RegExp);
if (!object)
return false;
pushed[0].addType(cx, (jstype) object);
@ -3311,7 +3305,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
case JSOP_STOP:
/* If a stop is reachable then the return type may be void. */
if (script->fun)
script->returnTypes()->addType(cx, TYPE_UNDEFINED);
script->types.returnTypes()->addType(cx, TYPE_UNDEFINED);
break;
case JSOP_OR:
@ -3344,7 +3338,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
else
id = GetAtomId(cx, script, pc, 0);
TypeSet *seen = script->bytecodeTypes(pc);
TypeSet *seen = script->types.bytecodeTypes(pc);
seen->addSubset(cx, script, &pushed[0]);
/*
@ -3360,7 +3354,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
seen->addType(cx, TYPE_DOUBLE);
/* Handle as a property access. */
PropertyAccess(cx, script, pc, script->getGlobalType(), false, seen, id);
PropertyAccess(cx, script, pc, script->global()->getType(), false, seen, id);
if (op == JSOP_CALLGLOBAL || op == JSOP_CALLGNAME) {
pushed[1].addType(cx, TYPE_UNKNOWN);
@ -3384,8 +3378,8 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
case JSOP_GNAMEINC:
case JSOP_GNAMEDEC: {
jsid id = GetAtomId(cx, script, pc, 0);
PropertyAccess(cx, script, pc, script->getGlobalType(), true, NULL, id);
PropertyAccess(cx, script, pc, script->getGlobalType(), false, &pushed[0], id);
PropertyAccess(cx, script, pc, script->global()->getType(), true, NULL, id);
PropertyAccess(cx, script, pc, script->global()->getType(), false, &pushed[0], id);
if (cx->compartment->debugMode)
pushed[0].addType(cx, TYPE_UNKNOWN);
@ -3398,7 +3392,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
* The first value pushed by NAME/CALLNAME must always be added to the
* bytecode types, we don't model these opcodes with inference.
*/
TypeSet *seen = script->bytecodeTypes(pc);
TypeSet *seen = script->types.bytecodeTypes(pc);
seen->addSubset(cx, script, &pushed[0]);
if (op == JSOP_CALLNAME) {
pushed[1].addType(cx, TYPE_UNKNOWN);
@ -3413,7 +3407,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
case JSOP_SETGNAME: {
jsid id = GetAtomId(cx, script, pc, 0);
PropertyAccess(cx, script, pc, script->getGlobalType(),
PropertyAccess(cx, script, pc, script->global()->getType(),
true, poppedTypes(pc, 0), id);
poppedTypes(pc, 0)->addSubset(cx, script, &pushed[0]);
break;
@ -3433,7 +3427,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
break;
case JSOP_GETXPROP: {
TypeSet *seen = script->bytecodeTypes(pc);
TypeSet *seen = script->types.bytecodeTypes(pc);
seen->addSubset(cx, script, &pushed[0]);
break;
}
@ -3441,7 +3435,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
case JSOP_GETFCSLOT:
case JSOP_CALLFCSLOT: {
unsigned index = GET_UINT16(pc);
TypeSet *types = script->upvarTypes(index);
TypeSet *types = script->types.upvarTypes(index);
types->addSubset(cx, script, &pushed[0]);
if (op == JSOP_CALLFCSLOT) {
pushed[1].addType(cx, TYPE_UNDEFINED);
@ -3472,7 +3466,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
*/
poppedTypes(pc, 0)->addSubset(cx, script, &pushed[0]);
} else if (slot < TotalSlots(script)) {
TypeSet *types = script->slotTypes(slot);
TypeSet *types = script->types.slotTypes(slot);
types->addSubset(cx, script, &pushed[0]);
} else {
/* Local 'let' variable. Punt on types for these, for now. */
@ -3490,7 +3484,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
case JSOP_SETLOCALPOP: {
uint32 slot = GetBytecodeSlot(script, pc);
if (!trackSlot(slot) && slot < TotalSlots(script)) {
TypeSet *types = script->slotTypes(slot);
TypeSet *types = script->types.slotTypes(slot);
poppedTypes(pc, 0)->addSubset(cx, script, types);
}
@ -3515,7 +3509,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
if (trackSlot(slot)) {
poppedTypes(pc, 0)->addArith(cx, script, &pushed[0]);
} else if (slot < TotalSlots(script)) {
TypeSet *types = script->slotTypes(slot);
TypeSet *types = script->types.slotTypes(slot);
types->addArith(cx, script, types);
types->addSubset(cx, script, &pushed[0]);
} else {
@ -3551,7 +3545,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
case JSOP_GETPROP:
case JSOP_CALLPROP: {
jsid id = GetAtomId(cx, script, pc, 0);
TypeSet *seen = script->bytecodeTypes(pc);
TypeSet *seen = script->types.bytecodeTypes(pc);
poppedTypes(pc, 0)->addGetProperty(cx, script, pc, seen, id);
if (op == JSOP_CALLPROP)
@ -3581,7 +3575,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
case JSOP_GETELEM:
case JSOP_CALLELEM: {
TypeSet *seen = script->bytecodeTypes(pc);
TypeSet *seen = script->types.bytecodeTypes(pc);
poppedTypes(pc, 1)->addGetProperty(cx, script, pc, seen, JSID_VOID);
if (op == JSOP_CALLELEM)
@ -3609,13 +3603,13 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
break;
case JSOP_THIS:
script->thisTypes()->addTransformThis(cx, script, &pushed[0]);
script->types.thisTypes()->addTransformThis(cx, script, &pushed[0]);
break;
case JSOP_RETURN:
case JSOP_SETRVAL:
if (script->fun)
poppedTypes(pc, 0)->addSubset(cx, script, script->returnTypes());
poppedTypes(pc, 0)->addSubset(cx, script, script->types.returnTypes());
break;
case JSOP_ADD:
@ -3655,12 +3649,12 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
} else {
/* Should not see 'let' vars here. */
JS_ASSERT(slot < TotalSlots(script));
res = script->slotTypes(slot);
res = script->types.slotTypes(slot);
}
}
if (res) {
if (script->global)
if (script->hasGlobal())
res->addType(cx, (jstype) obj->getType());
else
res->addType(cx, TYPE_UNKNOWN);
@ -3708,7 +3702,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
case JSOP_NEWARRAY:
case JSOP_NEWOBJECT: {
TypeObject *initializer = GetInitializerType(cx, script, pc);
if (script->global) {
if (script->hasGlobal()) {
if (!initializer)
return false;
pushed[0].addType(cx, (jstype) initializer);
@ -3816,7 +3810,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
case JSOP_FORGNAME: {
jsid id = GetAtomId(cx, script, pc, 0);
TypeObject *global = script->getGlobalType();
TypeObject *global = script->global()->getType();
if (!global->unknownProperties()) {
TypeSet *types = global->getProperty(cx, id, true);
if (!types)
@ -3837,7 +3831,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
setForTypes(cx, pc, &pushed[1]);
} else {
if (slot < TotalSlots(script))
setForTypes(cx, pc, script->slotTypes(slot));
setForTypes(cx, pc, script->types.slotTypes(slot));
}
break;
}
@ -3887,13 +3881,13 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
case JSOP_GENERATOR:
if (script->fun) {
if (script->global) {
TypeObject *object = script->getTypeNewObject(cx, JSProto_Generator);
if (script->hasGlobal()) {
TypeObject *object = script->types.standardType(cx, JSProto_Generator);
if (!object)
return false;
script->returnTypes()->addType(cx, (jstype) object);
script->types.returnTypes()->addType(cx, (jstype) object);
} else {
script->returnTypes()->addType(cx, TYPE_UNKNOWN);
script->types.returnTypes()->addType(cx, TYPE_UNKNOWN);
}
}
break;
@ -3948,7 +3942,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
break;
case JSOP_CALLEE:
if (script->global)
if (script->hasGlobal())
pushed[0].addType(cx, (jstype) script->fun->getType());
else
pushed[0].addType(cx, TYPE_UNKNOWN);
@ -3981,7 +3975,7 @@ ScriptAnalysis::analyzeTypes(JSContext *cx)
* script and trying to reanalyze here can cause reentrance problems if we
* try to reinitialize standard classes that were cleared).
*/
if (script->global && script->global->isCleared())
if (script->hasClearedGlobal())
return;
if (!ranSSA()) {
@ -3990,7 +3984,7 @@ ScriptAnalysis::analyzeTypes(JSContext *cx)
return;
}
if (!script->ensureTypeArray(cx)) {
if (!script->types.ensureTypeArray(cx)) {
setOOM(cx);
return;
}
@ -4018,7 +4012,7 @@ ScriptAnalysis::analyzeTypes(JSContext *cx)
/* Make sure the initial type set of all local vars includes void. */
for (unsigned i = 0; i < script->nfixed; i++)
script->localTypes(i)->addType(cx, TYPE_UNDEFINED);
script->types.localTypes(i)->addType(cx, TYPE_UNDEFINED);
TypeInferenceState state(cx);
@ -4050,7 +4044,7 @@ ScriptAnalysis::analyzeTypes(JSContext *cx)
* the script either because we ran the interpreter some before analyzing
* or because we are reanalyzing after a GC.
*/
TypeIntermediate *result = script->intermediateTypes;
TypeIntermediate *result = script->types.intermediateList;
while (result) {
result->replay(cx, script);
result = result->next;
@ -4190,8 +4184,8 @@ ScriptAnalysis::analyzeTypesNew(JSContext *cx)
if (script->fun->getType()->unknownProperties() ||
script->fun->isFunctionPrototype() ||
!script->global) {
script->thisTypes()->addType(cx, TYPE_UNKNOWN);
!script->hasGlobal()) {
script->types.thisTypes()->addType(cx, TYPE_UNKNOWN);
return;
}
@ -4199,7 +4193,7 @@ ScriptAnalysis::analyzeTypesNew(JSContext *cx)
TypeSet *prototypeTypes = funType->getProperty(cx, id_prototype(cx), false);
if (!prototypeTypes)
return;
prototypeTypes->addNewObject(cx, script, funType, script->thisTypes());
prototypeTypes->addNewObject(cx, script, funType, script->types.thisTypes());
}
/*
@ -4298,14 +4292,12 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSScript *script, JS
return false;
}
ScriptAnalysis *analysis = script->analysis(cx);
if (analysis && !analysis->ranInference())
analysis->analyzeTypes(cx);
if (!analysis || analysis->OOM()) {
if (!script->ensureRanInference(cx)) {
*pbaseobj = NULL;
cx->compartment->types.setPendingNukeTypes(cx);
return false;
}
ScriptAnalysis *analysis = script->analysis(cx);
/*
* Offset of the last bytecode which popped 'this' and which we have
@ -4493,8 +4485,8 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSScript *script, JS
*pbaseobj = NULL;
return false;
}
script->addIntermediateType(funcallTrap);
script->addIntermediateType(calleeTrap);
script->types.addIntermediate(funcallTrap);
script->types.addIntermediate(calleeTrap);
funcallTrap->replay(cx, script);
calleeTrap->replay(cx, script);
@ -4656,23 +4648,23 @@ ScriptAnalysis::printTypes(JSContext *cx)
printf("locals:");
printf("\n return:");
script->returnTypes()->print(cx);
script->types.returnTypes()->print(cx);
printf("\n this:");
script->thisTypes()->print(cx);
script->types.thisTypes()->print(cx);
for (unsigned i = 0; script->fun && i < script->fun->nargs; i++) {
printf("\n arg%u:", i);
script->argTypes(i)->print(cx);
script->types.argTypes(i)->print(cx);
}
for (unsigned i = 0; i < script->nfixed; i++) {
if (!trackSlot(LocalSlot(script, i))) {
printf("\n local%u:", i);
script->localTypes(i)->print(cx);
script->types.localTypes(i)->print(cx);
}
}
for (unsigned i = 0; i < script->bindings.countUpvars(); i++) {
printf("\n upvar%u:", i);
script->upvarTypes(i)->print(cx);
script->types.upvarTypes(i)->print(cx);
}
printf("\n");
@ -4686,8 +4678,8 @@ ScriptAnalysis::printTypes(JSContext *cx)
PrintBytecode(cx, script, pc);
if (js_CodeSpec[*pc].format & JOF_TYPESET) {
TypeSet *types = script->bytecodeTypes(pc);
printf(" typeset %d:", (int) (types - script->typeArray));
TypeSet *types = script->types.bytecodeTypes(pc);
printf(" typeset %d:", (int) (types - script->types.typeArray));
types->print(cx);
printf("\n");
}
@ -4723,7 +4715,8 @@ ScriptAnalysis::printTypes(JSContext *cx)
// Interface functions
/////////////////////////////////////////////////////////////////////
namespace js { namespace types {
namespace js {
namespace types {
void
MarkTypeCallerUnexpectedSlow(JSContext *cx, jstype type)
@ -4781,14 +4774,14 @@ TypeMonitorCallSlow(JSContext *cx, JSObject *callee,
unsigned nargs = callee->getFunctionPrivate()->nargs;
JSScript *script = callee->getFunctionPrivate()->script();
if (!script->ensureTypeArray(cx))
if (!script->types.ensureTypeArray(cx))
return;
if (constructing) {
script->typeSetNewCalled(cx);
script->types.setNewCalled(cx);
} else {
jstype type = GetValueType(cx, args.thisv());
script->typeSetThis(cx, type);
script->types.setThis(cx, type);
}
/*
@ -4798,11 +4791,11 @@ TypeMonitorCallSlow(JSContext *cx, JSObject *callee,
*/
unsigned arg = 0;
for (; arg < args.argc() && arg < nargs; arg++)
script->typeSetArgument(cx, arg, args[arg]);
script->types.setArgument(cx, arg, args[arg]);
/* Watch for fewer actuals than formals to the call. */
for (; arg < nargs; arg++)
script->typeSetArgument(cx, arg, UndefinedValue());
script->types.setArgument(cx, arg, UndefinedValue());
}
/* Intermediate type information for a dynamic type pushed in a script. */
@ -4854,7 +4847,7 @@ TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, jstype type)
/* Directly update associated type sets for applicable bytecodes. */
if (CanHaveReadBarrier(pc)) {
TypeSet *types = script->bytecodeTypes(pc);
TypeSet *types = script->types.bytecodeTypes(pc);
if (!types->hasType(type)) {
InferSpew(ISpewOps, "externalType: monitorResult #%u:%05u: %s",
script->id(), pc - script->code, TypeString(type));
@ -4880,7 +4873,7 @@ TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, jstype type)
case JSOP_GNAMEINC:
case JSOP_GNAMEDEC: {
jsid id = GetAtomId(cx, script, pc, 0);
TypeObject *global = script->getGlobalType();
TypeObject *global = script->global()->getType();
if (!global->unknownProperties()) {
TypeSet *types = global->getProperty(cx, id, true);
if (!types)
@ -4906,7 +4899,7 @@ TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, jstype type)
*/
uint32 slot = GetBytecodeSlot(script, pc);
if (slot < TotalSlots(script)) {
TypeSet *types = script->slotTypes(slot);
TypeSet *types = script->types.slotTypes(slot);
types->addType(cx, type);
}
break;
@ -4927,15 +4920,15 @@ TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, jstype type)
return;
} else {
/* Scan all intermediate types on the script to check for a dupe. */
TypeIntermediate *result, **presult = &script->intermediateTypes;
TypeIntermediate *result, **pstart = &script->types.intermediateList, **presult = pstart;
while (*presult) {
result = *presult;
if (result->hasDynamicResult(pc - script->code, type)) {
if (presult != &script->intermediateTypes) {
if (presult != pstart) {
/* Move to the head of the list, maintain LRU order. */
*presult = result->next;
result->next = script->intermediateTypes;
script->intermediateTypes = result;
result->next = *pstart;
*pstart = result;
}
return;
}
@ -4951,19 +4944,17 @@ TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, jstype type)
cx->compartment->types.setPendingNukeTypes(cx);
return;
}
script->addIntermediateType(result);
script->types.addIntermediate(result);
if (script->hasAnalysis() && script->analysis(cx)->ranInference()) {
TypeSet *pushed = script->analysis(cx)->pushedTypes(pc, 0);
pushed->addType(cx, type);
} else if (script->ranInference) {
/* Any new dynamic result triggers reanalysis and recompilation. */
ScriptAnalysis *analysis = script->analysis(cx);
if (!analysis) {
if (!script->ensureRanInference(cx)) {
cx->compartment->types.setPendingNukeTypes(cx);
return;
}
analysis->analyzeTypes(cx);
}
/* Trigger recompilation of any inline callers. */
@ -4981,7 +4972,7 @@ TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Val
return;
jstype type = GetValueType(cx, rval);
TypeSet *types = script->bytecodeTypes(pc);
TypeSet *types = script->types.bytecodeTypes(pc);
if (types->hasType(type))
return;
@ -5001,7 +4992,7 @@ TypeConstraintPushAll::newType(JSContext *cx, TypeSet *source, jstype type)
}
/////////////////////////////////////////////////////////////////////
// JSScript
// TypeScript
/////////////////////////////////////////////////////////////////////
/*
@ -5084,31 +5075,32 @@ IgnorePushed(const jsbytecode *pc, unsigned index)
}
bool
JSScript::makeTypeArray(JSContext *cx)
TypeScript::makeTypeArray(JSContext *cx)
{
JS_ASSERT(!typeArray);
AutoEnterTypeInference enter(cx);
unsigned count = nTypeSets + TotalSlots(this) + bindings.countUpvars();
unsigned count = numTypeSets();
typeArray = (TypeSet *) cx->calloc_(sizeof(TypeSet) * count);
if (!typeArray) {
compartment->types.setPendingNukeTypes(cx);
cx->compartment->types.setPendingNukeTypes(cx);
return false;
}
#ifdef DEBUG
for (unsigned i = 0; i < nTypeSets; i++)
InferSpew(ISpewOps, "typeSet: T%p bytecode%u #%u", &typeArray[i], i, id());
InferSpew(ISpewOps, "typeSet: T%p return #%u", returnTypes(), id());
InferSpew(ISpewOps, "typeSet: T%p this #%u", thisTypes(), id());
unsigned nargs = fun ? fun->nargs : 0;
unsigned id = script()->id();
for (unsigned i = 0; i < script()->nTypeSets; i++)
InferSpew(ISpewOps, "typeSet: T%p bytecode%u #%u", &typeArray[i], i, id);
InferSpew(ISpewOps, "typeSet: T%p return #%u", returnTypes(), id);
InferSpew(ISpewOps, "typeSet: T%p this #%u", thisTypes(), id);
unsigned nargs = script()->fun ? script()->fun->nargs : 0;
for (unsigned i = 0; i < nargs; i++)
InferSpew(ISpewOps, "typeSet: T%p arg%u #%u", argTypes(i), i, id());
for (unsigned i = 0; i < nfixed; i++)
InferSpew(ISpewOps, "typeSet: T%p local%u #%u", localTypes(i), i, id());
for (unsigned i = 0; i < bindings.countUpvars(); i++)
InferSpew(ISpewOps, "typeSet: T%p upvar%u #%u", upvarTypes(i), i, id());
InferSpew(ISpewOps, "typeSet: T%p arg%u #%u", argTypes(i), i, id);
for (unsigned i = 0; i < script()->nfixed; i++)
InferSpew(ISpewOps, "typeSet: T%p local%u #%u", localTypes(i), i, id);
for (unsigned i = 0; i < script()->bindings.countUpvars(); i++)
InferSpew(ISpewOps, "typeSet: T%p upvar%u #%u", upvarTypes(i), i, id);
#endif
return true;
@ -5144,18 +5136,20 @@ JSScript::typeSetFunction(JSContext *cx, JSFunction *fun)
#ifdef DEBUG
void
JSScript::typeCheckBytecode(JSContext *cx, const jsbytecode *pc, const js::Value *sp)
TypeScript::checkBytecode(JSContext *cx, jsbytecode *pc, const js::Value *sp)
{
AutoEnterTypeInference enter(cx);
UntrapOpcode untrap(cx, script(), pc);
if (!(analysis_ && analysis_->ranInference()))
if (!script()->hasAnalysis() || !script()->analysis(cx)->ranInference())
return;
ScriptAnalysis *analysis = script()->analysis(cx);
int defCount = GetDefCount(this, pc - code);
int defCount = GetDefCount(script(), pc - script()->code);
for (int i = 0; i < defCount; i++) {
const js::Value &val = sp[-defCount + i];
TypeSet *types = analysis_->pushedTypes(pc, i);
TypeSet *types = analysis->pushedTypes(pc, i);
if (IgnorePushed(pc, i))
continue;
@ -5164,7 +5158,7 @@ JSScript::typeCheckBytecode(JSContext *cx, const jsbytecode *pc, const js::Value
if (!TypeMatches(cx, types, type)) {
/* Display fine-grained debug information first */
fprintf(stderr, "Missing type at #%u:%05u pushed %u: %s\n",
id(), pc - code, i, TypeString(type));
script()->id(), pc - script()->code, i, TypeString(type));
TypeFailure(cx, "Missing type pushed %u: %s", i, TypeString(type));
}
@ -5185,7 +5179,7 @@ JSScript::typeCheckBytecode(JSContext *cx, const jsbytecode *pc, const js::Value
/* Display fine-grained debug information first */
fprintf(stderr, "Object not %s array at #%u:%05u popped %u: %s\n",
packed ? "packed" : "dense",
id(), pc - code, i, object->name());
script()->id(), pc - script()->code, i, object->name());
TypeFailure(cx, "Object not %s array, popped %u: %s",
packed ? "packed" : "dense", i, object->name());
}
@ -5535,8 +5529,10 @@ TypeCompartment::~TypeCompartment()
}
bool
JSScript::condenseTypes(JSContext *cx)
TypeScript::condenseTypes(JSContext *cx)
{
JSCompartment *compartment = script()->compartment;
if (!CondenseTypeObjectList(cx, compartment, typeObjects))
return false;
@ -5549,16 +5545,16 @@ JSScript::condenseTypes(JSContext *cx)
return false;
}
unsigned num = nTypeSets + TotalSlots(this) + bindings.countUpvars();
unsigned num = numTypeSets();
if (isCachedEval ||
(u.object && IsAboutToBeFinalized(cx, u.object)) ||
(fun && IsAboutToBeFinalized(cx, fun))) {
if (script()->isAboutToBeFinalized(cx)) {
/* Release all memory associated with the persistent type sets. */
for (unsigned i = 0; i < num; i++)
typeArray[i].destroy(cx);
cx->free_(typeArray);
typeArray = NULL;
} else {
/* Condense all constraints in the persistent type sets. */
for (unsigned i = 0; i < num; i++) {
if (!TypeSet::CondenseSweepTypeSet(cx, compartment, condensed, &typeArray[i]))
return false;
@ -5566,7 +5562,7 @@ JSScript::condenseTypes(JSContext *cx)
}
}
TypeIntermediate **presult = &intermediateTypes;
TypeIntermediate **presult = &intermediateList;
while (*presult) {
TypeIntermediate *result = *presult;
if (result->sweep(cx, compartment)) {
@ -5580,10 +5576,45 @@ JSScript::condenseTypes(JSContext *cx)
return true;
}
void
TypeScript::trace(JSTracer *trc)
{
/*
* Trace all type objects associated with the script, these can be freely
* referenced from JIT code without needing to be pinned against GC.
*/
types::TypeObject *obj = typeObjects;
while (obj) {
if (!obj->marked)
obj->trace(trc);
obj = obj->next;
}
}
void
TypeScript::destroy(JSContext *cx)
{
/* Migrate any type objects associated with this script to the compartment. */
while (typeObjects) {
types::TypeObject *next = typeObjects->next;
typeObjects->next = script()->compartment->types.objects;
script()->compartment->types.objects = typeObjects;
typeObjects = next;
}
while (intermediateList) {
TypeIntermediate *next = intermediateList->next;
cx->delete_(intermediateList);
intermediateList = next;
}
cx->free_(typeArray);
}
void
JSScript::sweepAnalysis(JSContext *cx)
{
SweepTypeObjectList(cx, typeObjects);
SweepTypeObjectList(cx, types.typeObjects);
if (analysis_ && !compartment->activeAnalysis) {
/*

View File

@ -785,8 +785,83 @@ struct TypeCallsite
/* Get the new object at this callsite. */
inline TypeObject* getInitObject(JSContext *cx, bool isArray);
};
inline bool hasGlobal();
/* Persistent type information for a script, retained across GCs. */
struct TypeScript
{
inline JSScript *script();
/* Lazily constructed types of variables and JOF_TYPESET ops in this script. */
TypeSet *typeArray;
inline unsigned numTypeSets();
/* Any type objects associated with this script, including initializer objects. */
TypeObject *typeObjects;
/* Persistent information about stack types in this script. */
TypeIntermediate *intermediateList;
void addIntermediate(TypeIntermediate *type) {
type->next = intermediateList;
intermediateList = type;
}
/* Make sure there the type array has been constructed. */
inline bool ensureTypeArray(JSContext *cx);
inline TypeSet *bytecodeTypes(const jsbytecode *pc);
inline TypeSet *returnTypes();
inline TypeSet *thisTypes();
inline TypeSet *argTypes(unsigned i);
inline TypeSet *localTypes(unsigned i);
inline TypeSet *upvarTypes(unsigned i);
/* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */
inline TypeSet *slotTypes(unsigned slot);
private:
bool makeTypeArray(JSContext *cx);
public:
#ifdef DEBUG
/* Check that correct types were inferred for the values pushed by this bytecode. */
void checkBytecode(JSContext *cx, jsbytecode *pc, const js::Value *sp);
#endif
/* Get the default 'new' object for a given standard class, per the script's global. */
inline TypeObject *standardType(JSContext *cx, JSProtoKey key);
/* Get a type object for an allocation site in this script. */
inline TypeObject *initObject(JSContext *cx, const jsbytecode *pc, bool isArray);
/* Monitor a bytecode pushing an unexpected value. */
inline void monitorOverflow(JSContext *cx, jsbytecode *pc);
inline void monitorString(JSContext *cx, jsbytecode *pc);
inline void monitorUnknown(JSContext *cx, jsbytecode *pc);
/* Monitor a JOF_TYPESET bytecode pushing any value into its pushed type set. */
inline void monitor(JSContext *cx, jsbytecode *pc, const js::Value &val);
/* Monitor an assignment at a SETELEM on a non-integer identifier. */
inline void monitorAssign(JSContext *cx, jsbytecode *pc,
JSObject *obj, jsid id, const js::Value &val);
/* Add a type for a variable in this script. */
inline void setThis(JSContext *cx, jstype type);
inline void setThis(JSContext *cx, const js::Value &value);
inline void setThis(JSContext *cx, ClonedTypeSet *types);
inline void setNewCalled(JSContext *cx);
inline void setLocal(JSContext *cx, unsigned local, jstype type);
inline void setLocal(JSContext *cx, unsigned local, const js::Value &value);
inline void setLocal(JSContext *cx, unsigned local, ClonedTypeSet *types);
inline void setArgument(JSContext *cx, unsigned arg, jstype type);
inline void setArgument(JSContext *cx, unsigned arg, const js::Value &value);
inline void setArgument(JSContext *cx, unsigned arg, ClonedTypeSet *types);
inline void setUpvar(JSContext *cx, unsigned upvar, const js::Value &value);
bool condenseTypes(JSContext *cx);
void trace(JSTracer *trc);
void destroy(JSContext *cx);
};
struct ArrayTableKey;

View File

@ -270,7 +270,7 @@ GetTypeCallerInitObject(JSContext *cx, bool isArray)
jsbytecode *pc;
JSScript *script = cx->stack.currentScript(&pc);
if (script && script->compartment == cx->compartment)
return script->getTypeInitObject(cx, pc, isArray);
return script->types.initObject(cx, pc, isArray);
}
return GetTypeNewObject(cx, isArray ? JSProto_Array : JSProto_Object);
}
@ -428,22 +428,37 @@ FixObjectType(JSContext *cx, JSObject *obj)
extern void TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval);
extern void TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, js::types::jstype type);
} } /* namespace js::types */
/////////////////////////////////////////////////////////////////////
// Script interface functions
/////////////////////////////////////////////////////////////////////
inline JSScript *
TypeScript::script()
{
/*
* Each TypeScript is embedded as the 'types' field of a JSScript. They
* have the same lifetime, the distinction is made for code separation.
* Obtain the base pointer of the outer JSScript.
*/
return (JSScript *)((char *)this - offsetof(JSScript, types));
}
inline unsigned
TypeScript::numTypeSets()
{
return script()->nTypeSets + analyze::TotalSlots(script()) + script()->bindings.countUpvars();
}
inline bool
JSScript::ensureTypeArray(JSContext *cx)
TypeScript::ensureTypeArray(JSContext *cx)
{
if (typeArray)
return true;
return makeTypeArray(cx);
}
inline js::types::TypeSet *
JSScript::bytecodeTypes(const jsbytecode *pc)
inline TypeSet *
TypeScript::bytecodeTypes(const jsbytecode *pc)
{
JS_ASSERT(typeArray);
@ -452,24 +467,27 @@ JSScript::bytecodeTypes(const jsbytecode *pc)
JS_ASSERT(js_CodeSpec[op].format & JOF_TYPESET);
/* All bytecodes with type sets are JOF_ATOM, except JSOP_{GET,CALL}ELEM */
uint16 index = (op == JSOP_GETELEM || op == JSOP_CALLELEM) ? GET_UINT16(pc) : GET_UINT16(pc + 2);
JS_ASSERT(index < nTypeSets);
const jsbytecode *npc = (op == JSOP_GETELEM || op == JSOP_CALLELEM) ? pc : pc + 2;
JS_ASSERT(npc - pc + 3 == js_CodeSpec[op].length);
uint16 index = GET_UINT16(npc);
JS_ASSERT(index < script()->nTypeSets);
return &typeArray[index];
}
inline js::types::TypeSet *
JSScript::returnTypes()
inline TypeSet *
TypeScript::returnTypes()
{
JS_ASSERT(typeArray);
return &typeArray[nTypeSets + js::analyze::CalleeSlot()];
return &typeArray[script()->nTypeSets + js::analyze::CalleeSlot()];
}
inline js::types::TypeSet *
JSScript::thisTypes()
inline TypeSet *
TypeScript::thisTypes()
{
JS_ASSERT(typeArray);
return &typeArray[nTypeSets + js::analyze::ThisSlot()];
return &typeArray[script()->nTypeSets + js::analyze::ThisSlot()];
}
/*
@ -478,64 +496,51 @@ JSScript::thisTypes()
* or undefined for localTypes) and not types from subsequent assignments.
*/
inline js::types::TypeSet *
JSScript::argTypes(unsigned i)
inline TypeSet *
TypeScript::argTypes(unsigned i)
{
JS_ASSERT(typeArray && fun && i < fun->nargs);
return &typeArray[nTypeSets + js::analyze::ArgSlot(i)];
JS_ASSERT(typeArray && script()->fun && i < script()->fun->nargs);
return &typeArray[script()->nTypeSets + js::analyze::ArgSlot(i)];
}
inline js::types::TypeSet *
JSScript::localTypes(unsigned i)
inline TypeSet *
TypeScript::localTypes(unsigned i)
{
JS_ASSERT(typeArray && i < nfixed);
return &typeArray[nTypeSets + js::analyze::LocalSlot(this, i)];
JS_ASSERT(typeArray && i < script()->nfixed);
return &typeArray[script()->nTypeSets + js::analyze::LocalSlot(script(), i)];
}
inline js::types::TypeSet *
JSScript::upvarTypes(unsigned i)
inline TypeSet *
TypeScript::upvarTypes(unsigned i)
{
JS_ASSERT(typeArray && i < bindings.countUpvars());
return &typeArray[nTypeSets + js::analyze::TotalSlots(this) + i];
JS_ASSERT(typeArray && i < script()->bindings.countUpvars());
return &typeArray[script()->nTypeSets + js::analyze::TotalSlots(script()) + i];
}
inline js::types::TypeSet *
JSScript::slotTypes(unsigned slot)
inline TypeSet *
TypeScript::slotTypes(unsigned slot)
{
JS_ASSERT(typeArray && slot < js::analyze::TotalSlots(this));
return &typeArray[nTypeSets + slot];
JS_ASSERT(typeArray && slot < js::analyze::TotalSlots(script()));
return &typeArray[script()->nTypeSets + slot];
}
inline JSObject *
JSScript::getGlobal()
{
JS_ASSERT(global && !global->isCleared());
return global;
}
inline js::types::TypeObject *
JSScript::getGlobalType()
{
return getGlobal()->getType();
}
inline js::types::TypeObject *
JSScript::getTypeNewObject(JSContext *cx, JSProtoKey key)
inline TypeObject *
TypeScript::standardType(JSContext *cx, JSProtoKey key)
{
JSObject *proto;
if (!js_GetClassPrototype(cx, getGlobal(), key, &proto, NULL))
if (!js_GetClassPrototype(cx, script()->global(), key, &proto, NULL))
return NULL;
return proto->getNewType(cx);
}
inline js::types::TypeObject *
JSScript::getTypeInitObject(JSContext *cx, const jsbytecode *pc, bool isArray)
inline TypeObject *
TypeScript::initObject(JSContext *cx, const jsbytecode *pc, bool isArray)
{
if (!cx->typeInferenceEnabled() || !global)
return js::types::GetTypeNewObject(cx, isArray ? JSProto_Array : JSProto_Object);
if (!cx->typeInferenceEnabled() || !script()->hasGlobal())
return GetTypeNewObject(cx, isArray ? JSProto_Array : JSProto_Object);
uint32 offset = pc - code;
js::types::TypeObject *prev = NULL, *obj = typeObjects;
uint32 offset = pc - script()->code;
TypeObject *prev = NULL, *obj = typeObjects;
while (obj) {
if (isArray ? obj->initializerArray : obj->initializerObject) {
if (obj->initializerOffset == offset) {
@ -552,40 +557,40 @@ JSScript::getTypeInitObject(JSContext *cx, const jsbytecode *pc, bool isArray)
obj = obj->next;
}
return cx->compartment->types.newInitializerTypeObject(cx, this, offset, isArray);
return cx->compartment->types.newInitializerTypeObject(cx, script(), offset, isArray);
}
inline void
JSScript::typeMonitor(JSContext *cx, jsbytecode *pc, const js::Value &rval)
TypeScript::monitor(JSContext *cx, jsbytecode *pc, const js::Value &rval)
{
if (cx->typeInferenceEnabled())
js::types::TypeMonitorResult(cx, this, pc, rval);
TypeMonitorResult(cx, script(), pc, rval);
}
inline void
JSScript::typeMonitorOverflow(JSContext *cx, jsbytecode *pc)
TypeScript::monitorOverflow(JSContext *cx, jsbytecode *pc)
{
if (cx->typeInferenceEnabled())
js::types::TypeDynamicResult(cx, this, pc, js::types::TYPE_DOUBLE);
TypeDynamicResult(cx, script(), pc, TYPE_DOUBLE);
}
inline void
JSScript::typeMonitorString(JSContext *cx, jsbytecode *pc)
TypeScript::monitorString(JSContext *cx, jsbytecode *pc)
{
if (cx->typeInferenceEnabled())
js::types::TypeDynamicResult(cx, this, pc, js::types::TYPE_STRING);
TypeDynamicResult(cx, script(), pc, TYPE_STRING);
}
inline void
JSScript::typeMonitorUnknown(JSContext *cx, jsbytecode *pc)
TypeScript::monitorUnknown(JSContext *cx, jsbytecode *pc)
{
if (cx->typeInferenceEnabled())
js::types::TypeDynamicResult(cx, this, pc, js::types::TYPE_UNKNOWN);
TypeDynamicResult(cx, script(), pc, TYPE_UNKNOWN);
}
inline void
JSScript::typeMonitorAssign(JSContext *cx, jsbytecode *pc,
JSObject *obj, jsid id, const js::Value &rval)
TypeScript::monitorAssign(JSContext *cx, jsbytecode *pc,
JSObject *obj, jsid id, const js::Value &rval)
{
if (cx->typeInferenceEnabled()) {
/*
@ -597,74 +602,69 @@ JSScript::typeMonitorAssign(JSContext *cx, jsbytecode *pc,
uint32 i;
if (js_IdIsIndex(id, &i))
return;
js::types::MarkTypeObjectUnknownProperties(cx, obj->getType());
MarkTypeObjectUnknownProperties(cx, obj->getType());
}
}
inline void
JSScript::typeSetThis(JSContext *cx, js::types::jstype type)
TypeScript::setThis(JSContext *cx, jstype type)
{
JS_ASSERT(cx->typeInferenceEnabled());
if (!ensureTypeArray(cx))
return;
/* Analyze the script regardless if -a was used. */
bool analyze = !(analysis_ && analysis_->ranInference()) &&
cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS) && !isUncachedEval;
bool analyze = cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS) && !script()->isUncachedEval;
if (!thisTypes()->hasType(type) || analyze) {
js::types::AutoEnterTypeInference enter(cx);
AutoEnterTypeInference enter(cx);
js::types::InferSpew(js::types::ISpewOps, "externalType: setThis #%u: %s",
id(), js::types::TypeString(type));
InferSpew(ISpewOps, "externalType: setThis #%u: %s",
script()->id(), TypeString(type));
thisTypes()->addType(cx, type);
if (analyze && !(analysis_ && analysis_->ranInference())) {
js::analyze::ScriptAnalysis *analysis = this->analysis(cx);
if (!analysis)
return;
analysis->analyzeTypes(cx);
}
if (analyze)
script()->ensureRanInference(cx);
}
}
inline void
JSScript::typeSetThis(JSContext *cx, const js::Value &value)
TypeScript::setThis(JSContext *cx, const js::Value &value)
{
if (cx->typeInferenceEnabled())
typeSetThis(cx, js::types::GetValueType(cx, value));
setThis(cx, GetValueType(cx, value));
}
inline void
JSScript::typeSetThis(JSContext *cx, js::types::ClonedTypeSet *set)
TypeScript::setThis(JSContext *cx, ClonedTypeSet *set)
{
JS_ASSERT(cx->typeInferenceEnabled());
if (!ensureTypeArray(cx))
return;
js::types::AutoEnterTypeInference enter(cx);
AutoEnterTypeInference enter(cx);
js::types::InferSpew(js::types::ISpewOps, "externalType: setThis #%u", id());
InferSpew(ISpewOps, "externalType: setThis #%u", script()->id());
thisTypes()->addTypeSet(cx, set);
}
inline void
JSScript::typeSetNewCalled(JSContext *cx)
TypeScript::setNewCalled(JSContext *cx)
{
if (!cx->typeInferenceEnabled() || calledWithNew)
if (!cx->typeInferenceEnabled() || script()->calledWithNew)
return;
calledWithNew = true;
script()->calledWithNew = true;
/*
* Determining the 'this' type used when the script is invoked with 'new'
* happens during the script's prologue, so we don't try to pick it up from
* dynamic calls. Instead, generate constraints modeling the construction
* of 'this' when the script is analyzed or reanalyzed after an invoke with 'new',
* and if 'new' is first invoked after the script has already been analyzed.
* of 'this' when the script is analyzed or reanalyzed after an invoke with
* 'new', and if 'new' is first invoked after the script has already been
* analyzed.
*/
if (ranInference) {
/* Regenerate types for the function. */
js::types::AutoEnterTypeInference enter(cx);
js::analyze::ScriptAnalysis *analysis = this->analysis(cx);
if (script()->ranInference) {
AutoEnterTypeInference enter(cx);
analyze::ScriptAnalysis *analysis = script()->analysis(cx);
if (!analysis)
return;
analysis->analyzeTypesNew(cx);
@ -672,93 +672,90 @@ JSScript::typeSetNewCalled(JSContext *cx)
}
inline void
JSScript::typeSetLocal(JSContext *cx, unsigned local, js::types::jstype type)
TypeScript::setLocal(JSContext *cx, unsigned local, jstype type)
{
if (!cx->typeInferenceEnabled() || !ensureTypeArray(cx))
return;
if (!localTypes(local)->hasType(type)) {
js::types::AutoEnterTypeInference enter(cx);
AutoEnterTypeInference enter(cx);
js::types::InferSpew(js::types::ISpewOps, "externalType: setLocal #%u %u: %s",
id(), local, js::types::TypeString(type));
InferSpew(ISpewOps, "externalType: setLocal #%u %u: %s",
script()->id(), local, TypeString(type));
localTypes(local)->addType(cx, type);
}
}
inline void
JSScript::typeSetLocal(JSContext *cx, unsigned local, const js::Value &value)
TypeScript::setLocal(JSContext *cx, unsigned local, const js::Value &value)
{
if (cx->typeInferenceEnabled()) {
js::types::jstype type = js::types::GetValueType(cx, value);
typeSetLocal(cx, local, type);
jstype type = GetValueType(cx, value);
setLocal(cx, local, type);
}
}
inline void
JSScript::typeSetLocal(JSContext *cx, unsigned local, js::types::ClonedTypeSet *set)
TypeScript::setLocal(JSContext *cx, unsigned local, ClonedTypeSet *set)
{
JS_ASSERT(cx->typeInferenceEnabled());
if (!ensureTypeArray(cx))
return;
js::types::AutoEnterTypeInference enter(cx);
AutoEnterTypeInference enter(cx);
js::types::InferSpew(js::types::ISpewOps, "externalType: setLocal #%u %u", id(), local);
InferSpew(ISpewOps, "externalType: setLocal #%u %u", script()->id(), local);
localTypes(local)->addTypeSet(cx, set);
}
inline void
JSScript::typeSetArgument(JSContext *cx, unsigned arg, js::types::jstype type)
TypeScript::setArgument(JSContext *cx, unsigned arg, jstype type)
{
if (!cx->typeInferenceEnabled() || !ensureTypeArray(cx))
return;
if (!argTypes(arg)->hasType(type)) {
js::types::AutoEnterTypeInference enter(cx);
AutoEnterTypeInference enter(cx);
js::types::InferSpew(js::types::ISpewOps, "externalType: setArg #%u %u: %s",
id(), arg, js::types::TypeString(type));
InferSpew(ISpewOps, "externalType: setArg #%u %u: %s",
script()->id(), arg, TypeString(type));
argTypes(arg)->addType(cx, type);
}
}
inline void
JSScript::typeSetArgument(JSContext *cx, unsigned arg, const js::Value &value)
TypeScript::setArgument(JSContext *cx, unsigned arg, const js::Value &value)
{
if (cx->typeInferenceEnabled()) {
js::types::jstype type = js::types::GetValueType(cx, value);
typeSetArgument(cx, arg, type);
jstype type = GetValueType(cx, value);
setArgument(cx, arg, type);
}
}
inline void
JSScript::typeSetArgument(JSContext *cx, unsigned arg, js::types::ClonedTypeSet *set)
TypeScript::setArgument(JSContext *cx, unsigned arg, ClonedTypeSet *set)
{
JS_ASSERT(cx->typeInferenceEnabled());
if (!ensureTypeArray(cx))
return;
js::types::AutoEnterTypeInference enter(cx);
AutoEnterTypeInference enter(cx);
js::types::InferSpew(js::types::ISpewOps, "externalType: setArg #%u %u", id(), arg);
InferSpew(ISpewOps, "externalType: setArg #%u %u", script()->id(), arg);
argTypes(arg)->addTypeSet(cx, set);
}
inline void
JSScript::typeSetUpvar(JSContext *cx, unsigned upvar, const js::Value &value)
TypeScript::setUpvar(JSContext *cx, unsigned upvar, const js::Value &value)
{
if (!cx->typeInferenceEnabled() || !ensureTypeArray(cx))
return;
js::types::jstype type = js::types::GetValueType(cx, value);
jstype type = GetValueType(cx, value);
if (!upvarTypes(upvar)->hasType(type)) {
js::types::AutoEnterTypeInference enter(cx);
AutoEnterTypeInference enter(cx);
js::types::InferSpew(js::types::ISpewOps, "externalType: setUpvar #%u %u: %s",
id(), upvar, js::types::TypeString(type));
InferSpew(ISpewOps, "externalType: setUpvar #%u %u: %s",
script()->id(), upvar, TypeString(type));
upvarTypes(upvar)->addType(cx, type);
}
}
namespace js {
namespace types {
/////////////////////////////////////////////////////////////////////
// TypeCompartment
/////////////////////////////////////////////////////////////////////
@ -1160,18 +1157,12 @@ TypeCallsite::TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
inline TypeObject *
TypeCallsite::getInitObject(JSContext *cx, bool isArray)
{
TypeObject *type = script->getTypeInitObject(cx, pc, isArray);
TypeObject *type = script->types.initObject(cx, pc, isArray);
if (!type)
cx->compartment->types.setPendingNukeTypes(cx);
return type;
}
inline bool
TypeCallsite::hasGlobal()
{
return script->global;
}
/////////////////////////////////////////////////////////////////////
// TypeObject
/////////////////////////////////////////////////////////////////////
@ -1293,6 +1284,25 @@ class AutoTypeRooter : private AutoGCRooter {
} } /* namespace js::types */
inline bool
JSScript::isAboutToBeFinalized(JSContext *cx)
{
return isCachedEval ||
(u.object && IsAboutToBeFinalized(cx, u.object)) ||
(fun && IsAboutToBeFinalized(cx, fun));
}
inline bool
JSScript::ensureRanInference(JSContext *cx)
{
js::analyze::ScriptAnalysis *analysis = this->analysis(cx);
if (analysis && !analysis->ranInference()) {
js::types::AutoEnterTypeInference enter(cx);
analysis->analyzeTypes(cx);
}
return analysis && !analysis->OOM();
}
inline void
js::analyze::ScriptAnalysis::addPushedType(JSContext *cx, uint32 offset, uint32 which,
js::types::jstype type)

View File

@ -534,7 +534,7 @@ js_OnUnknownMethod(JSContext *cx, Value *vp)
AutoValueRooter tvr(cx);
if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, tvr.addr()))
return false;
cx->fp()->script()->typeMonitorUnknown(cx, cx->regs().pc);
cx->fp()->script()->types.monitorUnknown(cx, cx->regs().pc);
if (tvr.value().isPrimitive()) {
vp[0] = tvr.value();
@ -768,9 +768,9 @@ InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &this
* possible values the InvokeSession's client could pass in.
*/
jstype type = GetValueType(cx, thisv);
script_->typeSetThis(cx, type);
script_->types.setThis(cx, type);
for (unsigned i = 0; i < fun->nargs; i++)
script_->typeSetArgument(cx, i, TYPE_UNKNOWN);
script_->types.setArgument(cx, i, TYPE_UNKNOWN);
}
#ifdef JS_METHODJIT
@ -998,7 +998,7 @@ Execute(JSContext *cx, JSObject &chain, JSScript *script, StackFrame *prev, uint
if (cx->typeInferenceEnabled()) {
jstype type = GetValueType(cx, frame.fp()->thisValue());
script->typeSetThis(cx, type);
script->types.setThis(cx, type);
}
/* Run script until JSOP_STOP or error. */
@ -2185,7 +2185,7 @@ TypeCheckNextBytecode(JSContext *cx, JSScript *script, unsigned n, const FrameRe
if (cx->typeInferenceEnabled() &&
*regs.pc != JSOP_TRAP &&
n == analyze::GetBytecodeLength(regs.pc)) {
script->typeCheckBytecode(cx, regs.pc, regs.sp);
script->types.checkBytecode(cx, regs.pc, regs.sp);
}
#endif
}
@ -2565,7 +2565,7 @@ Interpret(JSContext *cx, StackFrame *entryFrame, uintN inlineCallCount, InterpMo
#endif
/* Any script we interpret needs to have its type sets filled in. */
if (cx->typeInferenceEnabled() && !script->ensureTypeArray(cx))
if (cx->typeInferenceEnabled() && !script->types.ensureTypeArray(cx))
goto error;
/* Don't call the script prologue if executing between Method and Trace JIT. */
@ -3585,7 +3585,7 @@ BEGIN_CASE(JSOP_URSH)
regs.sp--;
if (!regs.sp[-1].setNumber(uint32(u)))
script->typeMonitorOverflow(cx, regs.pc);
script->types.monitorOverflow(cx, regs.pc);
}
END_CASE(JSOP_URSH)
@ -3600,7 +3600,7 @@ BEGIN_CASE(JSOP_ADD)
regs.sp--;
if (JS_UNLIKELY(bool((l ^ sum) & (r ^ sum) & 0x80000000))) {
regs.sp[-1].setDouble(double(l) + double(r));
script->typeMonitorOverflow(cx, regs.pc);
script->types.monitorOverflow(cx, regs.pc);
} else {
regs.sp[-1].setInt32(sum);
}
@ -3611,7 +3611,7 @@ BEGIN_CASE(JSOP_ADD)
goto error;
regs.sp--;
regs.sp[-1] = rval;
script->typeMonitorUnknown(cx, regs.pc);
script->types.monitorUnknown(cx, regs.pc);
} else
#endif
{
@ -3643,7 +3643,7 @@ BEGIN_CASE(JSOP_ADD)
if (!str)
goto error;
if (lIsObject || rIsObject)
script->typeMonitorString(cx, regs.pc);
script->types.monitorString(cx, regs.pc);
regs.sp--;
regs.sp[-1].setString(str);
} else {
@ -3654,7 +3654,7 @@ BEGIN_CASE(JSOP_ADD)
regs.sp--;
if (!regs.sp[-1].setNumber(l) &&
(lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
script->typeMonitorOverflow(cx, regs.pc);
script->types.monitorOverflow(cx, regs.pc);
}
}
}
@ -3674,7 +3674,7 @@ END_CASE(JSOP_ADD)
regs.sp--; \
if (!regs.sp[-1].setNumber(d) && \
!(lval.isDouble() || rval.isDouble())) { \
script->typeMonitorOverflow(cx, regs.pc); \
script->types.monitorOverflow(cx, regs.pc); \
} \
JS_END_MACRO
@ -3713,12 +3713,12 @@ BEGIN_CASE(JSOP_DIV)
else
vp = &rt->positiveInfinityValue;
regs.sp[-1] = *vp;
script->typeMonitorOverflow(cx, regs.pc);
script->types.monitorOverflow(cx, regs.pc);
} else {
d1 /= d2;
if (!regs.sp[-1].setNumber(d1) &&
!(lval.isDouble() || rval.isDouble())) {
script->typeMonitorOverflow(cx, regs.pc);
script->types.monitorOverflow(cx, regs.pc);
}
}
}
@ -3747,7 +3747,7 @@ BEGIN_CASE(JSOP_MOD)
d1 = js_fmod(d1, d2);
regs.sp[-1].setDouble(d1);
}
script->typeMonitorOverflow(cx, regs.pc);
script->types.monitorOverflow(cx, regs.pc);
}
}
END_CASE(JSOP_MOD)
@ -3789,7 +3789,7 @@ BEGIN_CASE(JSOP_NEG)
goto error;
d = -d;
if (!regs.sp[-1].setNumber(d) && !ref.isDouble())
script->typeMonitorOverflow(cx, regs.pc);
script->types.monitorOverflow(cx, regs.pc);
}
}
END_CASE(JSOP_NEG)
@ -3798,7 +3798,7 @@ BEGIN_CASE(JSOP_POS)
if (!ValueToNumber(cx, &regs.sp[-1]))
goto error;
if (!regs.sp[-1].isInt32())
script->typeMonitorOverflow(cx, regs.pc);
script->types.monitorOverflow(cx, regs.pc);
END_CASE(JSOP_POS)
BEGIN_CASE(JSOP_DELNAME)
@ -3904,7 +3904,7 @@ BEGIN_CASE(JSOP_PROPDEC)
if (JSID_IS_VOID(id)) {
FETCH_ELEMENT_ID(obj, -1, id);
if (!JSID_IS_INT(id))
script->typeMonitorUnknown(cx, regs.pc);
script->types.monitorUnknown(cx, regs.pc);
}
goto do_incop;
@ -3966,7 +3966,7 @@ do_incop:
/*
* Add undefined to the object itself when read out during an incop.
* The getProperty can produce undefined without being accounted for by
* type information, and typeMonitor will not be update the object itself.
* type information, and types.monitor will not be update the object itself.
*/
if (regs.sp[-1].isUndefined())
AddTypePropertyId(cx, obj->getType(), id, types::TYPE_UNDEFINED);
@ -4006,7 +4006,7 @@ do_incop:
if (!js_DoIncDec(cx, cs, &regs.sp[-2], &regs.sp[-1]))
goto error;
script->typeMonitorOverflow(cx, regs.pc);
script->types.monitorOverflow(cx, regs.pc);
{
JSAutoResolveFlags rf(cx, setPropFlags);
@ -4081,7 +4081,7 @@ BEGIN_CASE(JSOP_LOCALINC)
PUSH_COPY(*vp);
if (!js_DoIncDec(cx, &js_CodeSpec[op], &regs.sp[-1], vp))
goto error;
script->typeMonitorOverflow(cx, regs.pc);
script->types.monitorOverflow(cx, regs.pc);
}
len = JSOP_INCARG_LENGTH;
JS_ASSERT(len == js_CodeSpec[op].length);
@ -4188,7 +4188,7 @@ BEGIN_CASE(JSOP_LENGTH)
}
} while (0);
script->typeMonitor(cx, regs.pc, rval);
script->types.monitor(cx, regs.pc, rval);
regs.sp[-1] = rval;
assertSameCompartment(cx, regs.sp[-1]);
@ -4283,7 +4283,7 @@ BEGIN_CASE(JSOP_CALLPROP)
goto error;
}
#endif
script->typeMonitor(cx, regs.pc, rval);
script->types.monitor(cx, regs.pc, rval);
}
END_CASE(JSOP_CALLPROP)
@ -4461,7 +4461,7 @@ BEGIN_CASE(JSOP_GETELEM)
goto error;
regs.sp--;
regs.sp[-1].setString(str);
script->typeMonitor(cx, regs.pc, regs.sp[-1]);
script->types.monitor(cx, regs.pc, regs.sp[-1]);
len = JSOP_GETELEM_LENGTH;
DO_NEXT_OP(len);
}
@ -4471,7 +4471,7 @@ BEGIN_CASE(JSOP_GETELEM)
if (rref.isInt32() && size_t(rref.toInt32()) < regs.fp()->numActualArgs()) {
regs.sp--;
regs.sp[-1] = regs.fp()->canonicalActualArg(rref.toInt32());
script->typeMonitor(cx, regs.pc, regs.sp[-1]);
script->types.monitor(cx, regs.pc, regs.sp[-1]);
len = JSOP_GETELEM_LENGTH;
DO_NEXT_OP(len);
}
@ -4528,13 +4528,13 @@ BEGIN_CASE(JSOP_GETELEM)
copyFrom = &rval;
if (!JSID_IS_INT(id))
script->typeMonitorUnknown(cx, regs.pc);
script->types.monitorUnknown(cx, regs.pc);
end_getelem:
regs.sp--;
regs.sp[-1] = *copyFrom;
assertSameCompartment(cx, regs.sp[-1]);
script->typeMonitor(cx, regs.pc, regs.sp[-1]);
script->types.monitor(cx, regs.pc, regs.sp[-1]);
}
END_CASE(JSOP_GETELEM)
@ -4568,8 +4568,8 @@ BEGIN_CASE(JSOP_CALLELEM)
}
if (!JSID_IS_INT(id))
script->typeMonitorUnknown(cx, regs.pc);
script->typeMonitor(cx, regs.pc, regs.sp[-2]);
script->types.monitorUnknown(cx, regs.pc);
script->types.monitor(cx, regs.pc, regs.sp[-2]);
}
END_CASE(JSOP_CALLELEM)
@ -4581,7 +4581,7 @@ BEGIN_CASE(JSOP_SETHOLE)
jsid id;
FETCH_ELEMENT_ID(obj, -2, id);
Value rval;
script->typeMonitorAssign(cx, regs.pc, obj, id, regs.sp[-1]);
script->types.monitorAssign(cx, regs.pc, obj, id, regs.sp[-1]);
do {
if (obj->isDenseArray() && JSID_IS_INT(id)) {
jsuint length = obj->getDenseArrayInitializedLength();
@ -4842,7 +4842,7 @@ BEGIN_CASE(JSOP_CALLNAME)
PUSH_COPY(rval);
}
script->typeMonitor(cx, regs.pc, regs.sp[-1]);
script->types.monitor(cx, regs.pc, regs.sp[-1]);
JS_ASSERT(obj->isGlobal() || IsCacheableNonGlobalScope(obj));
if (op == JSOP_CALLNAME || op == JSOP_CALLGNAME)
@ -4861,7 +4861,7 @@ BEGIN_CASE(JSOP_CALLNAME)
JSOp op2 = js_GetOpcode(cx, script, regs.pc + JSOP_NAME_LENGTH);
if (op2 == JSOP_TYPEOF) {
PUSH_UNDEFINED();
script->typeMonitor(cx, regs.pc, regs.sp[-1]);
script->types.monitor(cx, regs.pc, regs.sp[-1]);
len = JSOP_NAME_LENGTH;
DO_NEXT_OP(len);
}
@ -4882,7 +4882,7 @@ BEGIN_CASE(JSOP_CALLNAME)
}
PUSH_COPY(rval);
script->typeMonitor(cx, regs.pc, rval);
script->types.monitor(cx, regs.pc, rval);
/* obj must be on the scope chain, thus not a function. */
if (op == JSOP_CALLNAME || op == JSOP_CALLGNAME)
@ -5179,12 +5179,7 @@ BEGIN_CASE(JSOP_ARGUMENTS)
{
Value rval;
if (cx->typeInferenceEnabled() && !script->strictModeCode) {
analyze::ScriptAnalysis *analysis = script->analysis(cx);
if (analysis && !analysis->ranInference()) {
AutoEnterTypeInference enter(cx);
analysis->analyzeTypes(cx);
}
if (!analysis || analysis->OOM())
if (!script->ensureRanInference(cx))
goto error;
if (script->fun->getType()->hasAnyFlags(types::OBJECT_FLAG_CREATED_ARGUMENTS)) {
if (!js_GetArgsValue(cx, regs.fp(), &rval))
@ -5340,7 +5335,7 @@ BEGIN_CASE(JSOP_CALLGLOBAL)
JSObject *obj = regs.fp()->scopeChain().getGlobal();
JS_ASSERT(obj->containsSlot(slot));
PUSH_COPY(obj->getSlot(slot));
script->typeMonitor(cx, regs.pc, regs.sp[-1]);
script->types.monitor(cx, regs.pc, regs.sp[-1]);
if (op == JSOP_CALLGLOBAL)
PUSH_UNDEFINED();
}
@ -5895,7 +5890,7 @@ BEGIN_CASE(JSOP_NEWINIT)
if (!obj)
goto error;
TypeObject *type = script->getTypeInitObject(cx, regs.pc, i == JSProto_Array);
TypeObject *type = script->types.initObject(cx, regs.pc, i == JSProto_Array);
if (!type)
goto error;
if (i == JSProto_Array) {
@ -5917,7 +5912,7 @@ BEGIN_CASE(JSOP_NEWARRAY)
if (!obj)
goto error;
TypeObject *type = script->getTypeInitObject(cx, regs.pc, true);
TypeObject *type = script->types.initObject(cx, regs.pc, true);
if (!type)
goto error;
obj->setType(type);
@ -5932,7 +5927,7 @@ BEGIN_CASE(JSOP_NEWOBJECT)
JSObject *baseobj;
LOAD_OBJECT(0, baseobj);
TypeObject *type = script->getTypeInitObject(cx, regs.pc, false);
TypeObject *type = script->types.initObject(cx, regs.pc, false);
if (!type)
goto error;

View File

@ -1252,7 +1252,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
jsbytecode *yieldpc = gen->regs.pc - JSOP_YIELD_LENGTH;
JS_ASSERT(JSOp(*yieldpc) == JSOP_YIELD || JSOp(*yieldpc) == JSOP_TRAP);
script->typeMonitorUnknown(cx, yieldpc);
script->types.monitorUnknown(cx, yieldpc);
/*
* Store the argument to send as the result of the yield

View File

@ -3039,7 +3039,7 @@ js_CreateThisForFunction(JSContext *cx, JSObject *callee, bool newType)
type->singleton = obj;
if (type->newScript)
obj->setMap((Shape *) type->newScript->shape);
calleeScript->typeSetThis(cx, (types::jstype) type);
calleeScript->types.setThis(cx, (types::jstype) type);
}
return obj;

View File

@ -1341,9 +1341,9 @@ JSScript::NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
if (script->compileAndGo) {
GlobalScope *globalScope = cg->compiler()->globalScope;
if (globalScope->globalObj && globalScope->globalObj->isGlobal())
script->global = globalScope->globalObj->asGlobal();
script->global_ = globalScope->globalObj->asGlobal();
else if (cx->globalObject->isGlobal())
script->global = cx->globalObject->asGlobal();
script->global_ = cx->globalObject->asGlobal();
}
if (cg->globalUses.length()) {
@ -1511,23 +1511,7 @@ DestroyScript(JSContext *cx, JSScript *script)
JS_ASSERT(!script->hasAnalysis());
/* Migrate any type objects associated with this script to the compartment. */
types::TypeObject *obj = script->typeObjects;
while (obj) {
types::TypeObject *next = obj->next;
obj->next = script->compartment->types.objects;
script->compartment->types.objects = obj;
obj = next;
}
types::TypeIntermediate *result = script->intermediateTypes;
while (result) {
types::TypeIntermediate *next = result->next;
cx->delete_(result);
result = next;
}
cx->free_(script->typeArray);
script->types.destroy(cx);
#if defined(JS_METHODJIT)
mjit::ReleaseScriptCode(cx, script, true);
@ -1609,17 +1593,7 @@ js_TraceScript(JSTracer *trc, JSScript *script)
js_MarkScriptFilename(script->filename);
script->bindings.trace(trc);
/*
* Trace all type objects associated with the script, these can be freely
* referenced from JIT code without needing to be pinned against GC.
*/
types::TypeObject *obj = script->typeObjects;
while (obj) {
if (!obj->marked)
obj->trace(trc);
obj = obj->next;
}
script->types.trace(trc);
#ifdef JS_METHODJIT
if (script->jitNormal)

View File

@ -514,34 +514,37 @@ struct JSScript {
public:
/* Function this script is the body for, if there is one. */
JSFunction *fun;
/*
* Associates this script with a specific function, constructing a new type
* object for the function.
*/
bool typeSetFunction(JSContext *cx, JSFunction *fun);
/* Global object for this script, if compileAndGo. */
js::GlobalObject *global_;
inline bool hasGlobal() const;
inline js::GlobalObject *global() const;
inline bool hasClearedGlobal() const;
#ifdef DEBUG
/* Unique identifier within the compartment for this script. */
/*
* Unique identifier within the compartment for this script, used for
* printing analysis information.
*/
unsigned id_;
unsigned id() { return id_; }
#else
unsigned id() { return 0; }
#endif
/* Function this script is the body for, if there is one. */
JSFunction *fun;
/* Global object for this script, if compileAndGo. */
js::GlobalObject *global;
/* Lazily constructed types of variables and JOF_TYPESET ops in this script. */
js::types::TypeSet *typeArray;
/* Any type objects associated with this script, including initializer objects. */
js::types::TypeObject *typeObjects;
/* Persistent information about stack types in this script. */
js::types::TypeIntermediate *intermediateTypes;
void addIntermediateType(js::types::TypeIntermediate *type) {
type->next = intermediateTypes;
intermediateTypes = type;
}
/* Bytecode analysis and type inference results for this script. Destroyed on GC. */
/*
* Bytecode analysis and type inference results for this script. Destroyed
* on every GC.
*/
private:
js::analyze::ScriptAnalysis *analysis_;
void makeAnalysis(JSContext *cx);
@ -555,72 +558,15 @@ struct JSScript {
return analysis_;
}
inline JSObject *getGlobal();
inline js::types::TypeObject *getGlobalType();
/* Ensure the script has current type inference results. */
inline bool ensureRanInference(JSContext *cx);
/* Make sure there the type array has been constructed. */
inline bool ensureTypeArray(JSContext *cx);
/* Persistent type information retained across GCs. */
js::types::TypeScript types;
inline js::types::TypeSet *bytecodeTypes(const jsbytecode *pc);
inline js::types::TypeSet *returnTypes();
inline js::types::TypeSet *thisTypes();
inline js::types::TypeSet *argTypes(unsigned i);
inline js::types::TypeSet *localTypes(unsigned i);
inline js::types::TypeSet *upvarTypes(unsigned i);
/* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */
inline js::types::TypeSet *slotTypes(unsigned slot);
private:
bool makeTypeArray(JSContext *cx);
public:
#ifdef DEBUG
/* Check that correct types were inferred for the values pushed by this bytecode. */
void typeCheckBytecode(JSContext *cx, const jsbytecode *pc, const js::Value *sp);
#endif
/* Get the default 'new' object for a given standard class, per the script's global. */
inline js::types::TypeObject *getTypeNewObject(JSContext *cx, JSProtoKey key);
bool condenseTypes(JSContext *cx);
inline bool isAboutToBeFinalized(JSContext *cx);
void sweepAnalysis(JSContext *cx);
/* Get a type object for an allocation site in this script. */
inline js::types::TypeObject *
getTypeInitObject(JSContext *cx, const jsbytecode *pc, bool isArray);
/* Monitor a bytecode pushing an unexpected value. */
inline void typeMonitorOverflow(JSContext *cx, jsbytecode *pc);
inline void typeMonitorString(JSContext *cx, jsbytecode *pc);
inline void typeMonitorUnknown(JSContext *cx, jsbytecode *pc);
/* Monitor a JOF_TYPESET bytecode pushing any value into its pushed type set. */
inline void typeMonitor(JSContext *cx, jsbytecode *pc, const js::Value &val);
/* Monitor an assignment at a SETELEM on a non-integer identifier. */
inline void typeMonitorAssign(JSContext *cx, jsbytecode *pc,
JSObject *obj, jsid id, const js::Value &val);
/* Add a type for a variable in this script. */
inline void typeSetThis(JSContext *cx, js::types::jstype type);
inline void typeSetThis(JSContext *cx, const js::Value &value);
inline void typeSetThis(JSContext *cx, js::types::ClonedTypeSet *types);
inline void typeSetNewCalled(JSContext *cx);
inline void typeSetLocal(JSContext *cx, unsigned local, js::types::jstype type);
inline void typeSetLocal(JSContext *cx, unsigned local, const js::Value &value);
inline void typeSetLocal(JSContext *cx, unsigned local, js::types::ClonedTypeSet *types);
inline void typeSetArgument(JSContext *cx, unsigned arg, js::types::jstype type);
inline void typeSetArgument(JSContext *cx, unsigned arg, const js::Value &value);
inline void typeSetArgument(JSContext *cx, unsigned arg, js::types::ClonedTypeSet *types);
inline void typeSetUpvar(JSContext *cx, unsigned upvar, const js::Value &value);
/*
* Associates this script with a specific function, constructing a new type
* object for the function.
*/
bool typeSetFunction(JSContext *cx, JSFunction *fun);
#ifdef JS_METHODJIT
// Fast-cached pointers to make calls faster. These are also used to
// quickly test whether there is JIT code; a NULL value means no

View File

@ -48,6 +48,7 @@
#include "jsregexp.h"
#include "jsscript.h"
#include "jsscope.h"
#include "vm/GlobalObject.h"
namespace js {
@ -161,4 +162,28 @@ JSScript::isEmpty() const
return JSOp(*pc) == JSOP_STOP;
}
inline bool
JSScript::hasGlobal() const
{
/*
* Make sure that we don't try to query information about global objects
* which have had their scopes cleared. compileAndGo code should not run
* anymore against such globals.
*/
return global_ && !global_->isCleared();
}
inline js::GlobalObject *
JSScript::global() const
{
JS_ASSERT(hasGlobal());
return global_;
}
inline bool
JSScript::hasClearedGlobal() const
{
return global_ && global_->isCleared();
}
#endif /* jsscriptinlines_h___ */

View File

@ -3127,7 +3127,7 @@ static void type_StringSplit(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsit
{
TypeCallsite *site = Valueify(jssite);
if (!site->hasGlobal()) {
if (!site->script->hasGlobal()) {
site->returnTypes->addType(cx, TYPE_UNKNOWN);
return;
}

View File

@ -95,7 +95,7 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructi
outerScript(outerScript),
isConstructing(isConstructing),
ssa(cx, outerScript),
globalObj(outerScript->global),
globalObj(outerScript->hasGlobal() ? outerScript->global() : NULL),
globalSlots(globalObj ? globalObj->getRawSlots() : NULL),
frame(cx, *thisFromCtor(), masm, stubcc),
a(NULL), outer(NULL), script(NULL), PC(NULL), loop(NULL),
@ -183,33 +183,16 @@ mjit::Compiler::compile()
CompileStatus
mjit::Compiler::checkAnalysis(JSScript *script)
{
if (cx->typeInferenceEnabled() && !script->ensureRanInference(cx))
return Compile_Error;
ScriptAnalysis *analysis = script->analysis(cx);
if (!analysis)
return Compile_Error;
if (!analysis->failed() && !analysis->ranBytecode())
analysis->analyzeBytecode(cx);
if (analysis->OOM())
return Compile_Error;
if (analysis->failed()) {
JaegerSpew(JSpew_Abort, "couldn't analyze bytecode; probably switchX or OOM\n");
return Compile_Abort;
}
if (cx->typeInferenceEnabled()) {
if (!analysis->ranSSA())
analysis->analyzeSSA(cx);
if (!analysis->failed() && !analysis->ranLifetimes())
analysis->analyzeLifetimes(cx);
if (!analysis->failed() && !analysis->ranInference())
analysis->analyzeTypes(cx);
if (analysis->failed()) {
js_ReportOutOfMemory(cx);
return Compile_Error;
}
}
return Compile_Okay;
}
@ -246,7 +229,8 @@ mjit::Compiler::scanInlineCalls(uint32 index, uint32 depth)
ScriptAnalysis *analysis = script->analysis(cx);
/* Don't inline from functions which could have a non-global scope object. */
if (script->global != globalObj ||
if (!script->hasGlobal() ||
script->global() != globalObj ||
(script->fun && script->fun->getParent() != globalObj) ||
(script->fun && script->fun->isHeavyweight()) ||
script->isActiveEval) {
@ -365,7 +349,7 @@ mjit::Compiler::scanInlineCalls(uint32 index, uint32 depth)
* caller.
*/
if (script->analysis(cx)->usesThisValue() &&
script->thisTypes()->getKnownTypeTag(cx) != JSVAL_TYPE_OBJECT) {
script->types.thisTypes()->getKnownTypeTag(cx) != JSVAL_TYPE_OBJECT) {
okay = false;
break;
}
@ -622,7 +606,7 @@ mjit::Compiler::prepareInferenceTypes(JSScript *script, ActiveFrame *a)
for (uint32 slot = ArgSlot(0); slot < TotalSlots(script); slot++) {
VarType &vt = a->varTypes[slot];
vt.types = script->slotTypes(slot);
vt.types = script->types.slotTypes(slot);
vt.type = vt.types->getKnownTypeTag(cx);
}
@ -1852,7 +1836,7 @@ mjit::Compiler::generateMethod()
/* Watch for overflow in constant propagation. */
types::TypeSet *pushed = pushedTypeSet(0);
if (!v.isInt32() && pushed && !pushed->hasType(types::TYPE_DOUBLE)) {
script->typeMonitorOverflow(cx, PC);
script->types.monitorOverflow(cx, PC);
return Compile_Retry;
}
@ -5374,7 +5358,7 @@ mjit::Compiler::jsop_this()
if (!thisFe->isType(JSVAL_TYPE_OBJECT)) {
JSValueType type = cx->typeInferenceEnabled()
? script->thisTypes()->getKnownTypeTag(cx)
? script->types.thisTypes()->getKnownTypeTag(cx)
: JSVAL_TYPE_UNKNOWN;
if (type != JSVAL_TYPE_OBJECT) {
Jump notObj = frame.testObject(Assembler::NotEqual, thisFe);
@ -6380,7 +6364,7 @@ mjit::Compiler::jsop_newinit()
/* Don't bake in types for non-compileAndGo scripts. */
types::TypeObject *type = NULL;
if (globalObj) {
type = script->getTypeInitObject(cx, PC, isArray);
type = script->types.initObject(cx, PC, isArray);
if (!type)
return false;
}
@ -7363,7 +7347,7 @@ mjit::Compiler::testBarrier(RegisterID typeReg, RegisterID dataReg, bool testUnd
return state;
#endif
types::TypeSet *types = script->bytecodeTypes(PC);
types::TypeSet *types = script->types.bytecodeTypes(PC);
types->addFreeze(cx);
/* Cannot have type barriers when the result of the operation is already unknown. */

View File

@ -200,10 +200,10 @@ mjit::Compiler::jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::Typ
if (!v.isInt32() && typeSet && !typeSet->hasType(types::TYPE_DOUBLE)) {
/*
* OK to ignore failure here, we aren't performing the operation
* itself. Note that typeMonitorResult will propagate the type
* as necessary if a *INC operation overflowed.
* itself. Note that monitorOverflow will propagate the type as
* necessary if a *INC operation overflowed.
*/
script->typeMonitorOverflow(cx, PC);
script->types.monitorOverflow(cx, PC);
return false;
}
frame.popn(2);
@ -947,7 +947,7 @@ mjit::Compiler::jsop_mod()
if (tryBinaryConstantFold(cx, frame, JSOP_MOD, lhs, rhs, &v)) {
types::TypeSet *pushed = pushedTypeSet(0);
if (!v.isInt32() && pushed && !pushed->hasType(types::TYPE_DOUBLE)) {
script->typeMonitorOverflow(cx, PC);
script->types.monitorOverflow(cx, PC);
return false;
}
frame.popn(2);

View File

@ -1152,7 +1152,7 @@ FinishVarIncOp(VMFrame &f, RejoinState rejoin, Value ov, Value nv, Value *vp)
double d = ov.toNumber();
double N = (cs->format & JOF_INC) ? 1 : -1;
if (!nv.setNumber(d + N))
f.script()->typeMonitorOverflow(cx, f.pc());
f.script()->types.monitorOverflow(cx, f.pc());
}
*var = nv;
@ -1195,7 +1195,7 @@ FinishObjIncOp(VMFrame &f, RejoinState rejoin, Value objv, Value ov, Value nv, V
double d = ov.toNumber();
double N = (cs->format & JOF_INC) ? 1 : -1;
if (!nv.setNumber(d + N))
f.script()->typeMonitorOverflow(cx, f.pc());
f.script()->types.monitorOverflow(cx, f.pc());
}
uint32 setPropFlags = (cs->format & JOF_NAME)

View File

@ -1368,13 +1368,13 @@ ic::GenerateArgumentCheckStub(VMFrame &f)
if (!f.fp()->isConstructing()) {
Address address(JSFrameReg, StackFrame::offsetOfThis(fun));
if (!GenerateTypeCheck(f.cx, masm, address, script->thisTypes(), &mismatches))
if (!GenerateTypeCheck(f.cx, masm, address, script->types.thisTypes(), &mismatches))
return;
}
for (unsigned i = 0; i < fun->nargs; i++) {
Address address(JSFrameReg, StackFrame::offsetOfFormalArg(fun, i));
if (!GenerateTypeCheck(f.cx, masm, address, script->argTypes(i), &mismatches))
if (!GenerateTypeCheck(f.cx, masm, address, script->types.argTypes(i), &mismatches))
return;
}

View File

@ -642,12 +642,12 @@ class SetPropCompiler : public PICStubCompiler
RecompilationMonitor monitor(cx);
JSScript *script = obj->getCallObjCalleeFunction()->script();
uint16 slot = uint16(shape->shortid);
if (!script->ensureTypeArray(cx))
if (!script->types.ensureTypeArray(cx))
return error();
if (shape->setterOp() == SetCallArg)
script->typeSetArgument(cx, slot, pic.rhsTypes);
script->types.setArgument(cx, slot, pic.rhsTypes);
else
script->typeSetLocal(cx, slot, pic.rhsTypes);
script->types.setLocal(cx, slot, pic.rhsTypes);
if (monitor.recompiled())
return Lookup_Uncacheable;
}
@ -929,7 +929,7 @@ class GetPropCompiler : public PICStubCompiler
JS_ASSERT(pic.hasTypeCheck());
JS_ASSERT(pic.kind == ic::PICInfo::CALL);
if (!f.fp()->script()->global)
if (!f.fp()->script()->hasGlobal())
return disable("String.prototype without compile-and-go global");
GetPropertyHelper<GetPropCompiler> getprop(cx, obj, atom, *this, f);
@ -1626,20 +1626,17 @@ class ScopeNameCompiler : public PICStubCompiler
* does not keep track of this information, so ensure that we ran type
* inference on the parent script before doing propagation.
*/
analyze::ScriptAnalysis *analysis = newscript->analysis(cx);
if (analysis && !analysis->ranInference())
analysis->analyzeTypes(cx);
if (!analysis || analysis->OOM())
if (!newscript->ensureRanInference(cx))
return false;
if (shape->getterOp() == GetCallArg)
types = newscript->argTypes(slot);
types = newscript->types.argTypes(slot);
else if (shape->getterOp() == GetCallVar)
types = newscript->localTypes(slot);
types = newscript->types.localTypes(slot);
} else {
JS_ASSERT(!getprop.obj->getParent());
if (getprop.obj->getType()->unknownProperties()) {
f.script()->typeMonitorUnknown(cx, f.pc());
f.script()->types.monitorUnknown(cx, f.pc());
return true;
}
types = getprop.obj->getType()->getProperty(cx, shape->propid, false);
@ -1807,11 +1804,11 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic)
THROW();
JSString *str = f.regs.sp[-1].toString();
f.regs.sp[-1].setInt32(str->length());
f.script()->typeMonitor(f.cx, f.pc(), f.regs.sp[-1]);
f.script()->types.monitor(f.cx, f.pc(), f.regs.sp[-1]);
return;
} else if (f.regs.sp[-1].isMagic(JS_LAZY_ARGUMENTS)) {
f.regs.sp[-1].setInt32(f.regs.fp()->numActualArgs());
f.script()->typeMonitor(f.cx, f.pc(), f.regs.sp[-1]);
f.script()->types.monitor(f.cx, f.pc(), f.regs.sp[-1]);
return;
} else if (!f.regs.sp[-1].isPrimitive()) {
JSObject *obj = &f.regs.sp[-1].toObject();
@ -1836,7 +1833,7 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic)
JSString *str = obj->getPrimitiveThis().toString();
f.regs.sp[-1].setInt32(str->length());
}
f.script()->typeMonitor(f.cx, f.pc(), f.regs.sp[-1]);
f.script()->types.monitor(f.cx, f.pc(), f.regs.sp[-1]);
return;
}
}
@ -1879,7 +1876,7 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic)
* reads of the prototype.
*/
if (usePropCache)
f.script()->typeMonitor(f.cx, f.pc(), v);
f.script()->types.monitor(f.cx, f.pc(), v);
f.regs.sp[-1] = v;
}
@ -2045,7 +2042,7 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic)
}
#endif
f.script()->typeMonitor(cx, f.pc(), regs.sp[-2]);
f.script()->types.monitor(cx, f.pc(), regs.sp[-2]);
if (monitor.recompiled())
return;
@ -2099,7 +2096,7 @@ ic::XName(VMFrame &f, ic::PICInfo *pic)
THROW();
f.regs.sp[-1] = rval;
f.script()->typeMonitor(f.cx, f.pc(), rval);
f.script()->types.monitor(f.cx, f.pc(), rval);
}
void JS_FASTCALL
@ -2120,7 +2117,7 @@ ic::Name(VMFrame &f, ic::PICInfo *pic)
if (status == Lookup_Cacheable && !cc.updateTypes())
THROW();
f.script()->typeMonitor(f.cx, f.pc(), rval);
f.script()->types.monitor(f.cx, f.pc(), rval);
}
static void JS_FASTCALL
@ -2149,7 +2146,7 @@ ic::CallName(VMFrame &f, ic::PICInfo *pic)
if (status == Lookup_Cacheable && !cc.updateTypes())
THROW();
f.script()->typeMonitor(f.cx, f.pc(), rval);
f.script()->types.monitor(f.cx, f.pc(), rval);
}
static void JS_FASTCALL
@ -2607,8 +2604,8 @@ ic::CallElement(VMFrame &f, ic::GetElementIC *ic)
JS_ASSERT(!f.regs.sp[-2].isMagic());
f.regs.sp[-1].setObject(*thisObj);
if (!JSID_IS_INT(id))
f.script()->typeMonitorUnknown(cx, f.pc());
f.script()->typeMonitor(cx, f.pc(), f.regs.sp[-2]);
f.script()->types.monitorUnknown(cx, f.pc());
f.script()->types.monitor(cx, f.pc(), f.regs.sp[-2]);
return;
}
}
@ -2629,8 +2626,8 @@ ic::CallElement(VMFrame &f, ic::GetElementIC *ic)
f.regs.sp[-1] = thisv;
}
if (!JSID_IS_INT(id))
f.script()->typeMonitorUnknown(cx, f.pc());
f.script()->typeMonitor(cx, f.pc(), f.regs.sp[-2]);
f.script()->types.monitorUnknown(cx, f.pc());
f.script()->types.monitor(cx, f.pc(), f.regs.sp[-2]);
}
void JS_FASTCALL
@ -2673,8 +2670,8 @@ ic::GetElement(VMFrame &f, ic::GetElementIC *ic)
// If the result can be cached, the value was already retrieved.
JS_ASSERT(!f.regs.sp[-2].isMagic());
if (!JSID_IS_INT(id))
f.script()->typeMonitorUnknown(cx, f.pc());
f.script()->typeMonitor(cx, f.pc(), f.regs.sp[-2]);
f.script()->types.monitorUnknown(cx, f.pc());
f.script()->types.monitor(cx, f.pc(), f.regs.sp[-2]);
return;
}
}
@ -2682,8 +2679,8 @@ ic::GetElement(VMFrame &f, ic::GetElementIC *ic)
if (!obj->getProperty(cx, id, &f.regs.sp[-2]))
THROW();
if (!JSID_IS_INT(id))
f.script()->typeMonitorUnknown(cx, f.pc());
f.script()->typeMonitor(cx, f.pc(), f.regs.sp[-2]);
f.script()->types.monitorUnknown(cx, f.pc());
f.script()->types.monitor(cx, f.pc(), f.regs.sp[-2]);
}
#define APPLY_STRICTNESS(f, s) \

View File

@ -370,7 +370,7 @@ NameOp(VMFrame &f, JSObject *obj, bool callname)
if (op2 == JSOP_TYPEOF) {
f.regs.sp++;
f.regs.sp[-1].setUndefined();
f.script()->typeMonitor(cx, f.pc(), f.regs.sp[-1]);
f.script()->types.monitor(cx, f.pc(), f.regs.sp[-1]);
return obj;
}
ReportAtomNotDefined(cx, atom);
@ -397,7 +397,7 @@ NameOp(VMFrame &f, JSObject *obj, bool callname)
AddTypePropertyId(cx, obj->getType(), id, TYPE_UNDEFINED);
}
f.script()->typeMonitor(cx, f.pc(), rval);
f.script()->types.monitor(cx, f.pc(), rval);
*f.regs.sp++ = rval;
@ -438,7 +438,7 @@ stubs::GetElem(VMFrame &f)
if (!str)
THROW();
f.regs.sp[-2].setString(str);
f.script()->typeMonitor(cx, f.pc(), f.regs.sp[-2]);
f.script()->types.monitor(cx, f.pc(), f.regs.sp[-2]);
return;
}
}
@ -446,7 +446,7 @@ stubs::GetElem(VMFrame &f)
if (lref.isMagic(JS_LAZY_ARGUMENTS)) {
if (rref.isInt32() && size_t(rref.toInt32()) < regs.fp()->numActualArgs()) {
regs.sp[-2] = regs.fp()->canonicalActualArg(rref.toInt32());
f.script()->typeMonitor(cx, f.pc(), regs.sp[-2]);
f.script()->types.monitor(cx, f.pc(), regs.sp[-2]);
return;
}
MarkTypeObjectFlags(cx, f.script()->fun->getType(),
@ -505,11 +505,11 @@ stubs::GetElem(VMFrame &f)
copyFrom = &rval;
if (!JSID_IS_INT(id))
f.script()->typeMonitorUnknown(cx, f.pc());
f.script()->types.monitorUnknown(cx, f.pc());
end_getelem:
f.regs.sp[-2] = *copyFrom;
f.script()->typeMonitor(cx, f.pc(), f.regs.sp[-2]);
f.script()->types.monitor(cx, f.pc(), f.regs.sp[-2]);
}
static inline bool
@ -556,8 +556,8 @@ stubs::CallElem(VMFrame &f)
regs.sp[-1] = thisv;
}
if (!JSID_IS_INT(id))
f.script()->typeMonitorUnknown(cx, f.pc());
f.script()->typeMonitor(cx, f.pc(), regs.sp[-2]);
f.script()->types.monitorUnknown(cx, f.pc());
f.script()->types.monitor(cx, f.pc(), regs.sp[-2]);
}
template<JSBool strict>
@ -581,7 +581,7 @@ stubs::SetElem(VMFrame &f)
if (!FetchElementId(f, obj, idval, id, &regs.sp[-2]))
THROW();
f.script()->typeMonitorAssign(cx, f.pc(), obj, id, rval);
f.script()->types.monitorAssign(cx, f.pc(), obj, id, rval);
do {
if (obj->isDenseArray() && JSID_IS_INT(id)) {
@ -727,7 +727,7 @@ stubs::Ursh(VMFrame &f)
u >>= (j & 31);
if (!f.regs.sp[-2].setNumber(uint32(u)))
f.script()->typeMonitorOverflow(f.cx, f.pc());
f.script()->types.monitorOverflow(f.cx, f.pc());
}
template<JSBool strict>
@ -1054,7 +1054,7 @@ MonitorArithmeticOverflow(VMFrame &f, const Value &v)
JSContext *cx = f.cx;
JS_ASSERT(v.isDouble());
f.script()->typeMonitorOverflow(cx, f.pc());
f.script()->types.monitorOverflow(cx, f.pc());
/*
* Monitoring the overflow is not enough for fused INC operations on NAME/PROP,
@ -1113,7 +1113,7 @@ stubs::Add(VMFrame &f)
THROW();
regs.sp--;
regs.sp[-1] = rval;
f.script()->typeMonitorUnknown(cx, f.pc());
f.script()->types.monitorUnknown(cx, f.pc());
} else
#endif
{
@ -1141,7 +1141,7 @@ stubs::Add(VMFrame &f)
regs.sp[-1].setString(rstr);
}
if (lIsObject || rIsObject)
f.script()->typeMonitorString(cx, f.pc());
f.script()->types.monitorString(cx, f.pc());
goto string_concat;
} else {
@ -1193,7 +1193,7 @@ stubs::Mul(VMFrame &f)
}
double d = d1 * d2;
if (!regs.sp[-2].setNumber(d))
f.script()->typeMonitorOverflow(cx, f.pc());
f.script()->types.monitorOverflow(cx, f.pc());
}
void JS_FASTCALL
@ -1223,11 +1223,11 @@ stubs::Div(VMFrame &f)
else
vp = &rt->positiveInfinityValue;
regs.sp[-2] = *vp;
f.script()->typeMonitorOverflow(cx, f.pc());
f.script()->types.monitorOverflow(cx, f.pc());
} else {
d1 /= d2;
if (!regs.sp[-2].setNumber(d1))
f.script()->typeMonitorOverflow(cx, f.pc());
f.script()->types.monitorOverflow(cx, f.pc());
}
}
@ -1256,7 +1256,7 @@ stubs::Mod(VMFrame &f)
d1 = js_fmod(d1, d2);
regs.sp[-2].setDouble(d1);
}
f.script()->typeMonitorOverflow(cx, f.pc());
f.script()->types.monitorOverflow(cx, f.pc());
}
}
@ -1373,7 +1373,7 @@ stubs::Neg(VMFrame &f)
THROW();
d = -d;
if (!f.regs.sp[-1].setNumber(d))
f.script()->typeMonitorOverflow(f.cx, f.pc());
f.script()->types.monitorOverflow(f.cx, f.pc());
}
JSObject * JS_FASTCALL
@ -1679,7 +1679,7 @@ ObjIncOp(VMFrame &f, JSObject *obj, jsid id)
}
v.setNumber(d);
f.script()->typeMonitorOverflow(cx, f.pc());
f.script()->types.monitorOverflow(cx, f.pc());
{
JSAutoResolveFlags rf(cx, setPropFlags);
@ -1804,7 +1804,7 @@ stubs::ElemInc(VMFrame &f)
f.regs.sp[-3] = f.regs.sp[-1];
if (!JSID_IS_INT(id))
f.script()->typeMonitorUnknown(f.cx, f.pc());
f.script()->types.monitorUnknown(f.cx, f.pc());
}
template void JS_FASTCALL stubs::ElemInc<true>(VMFrame &f);
@ -1825,7 +1825,7 @@ stubs::ElemDec(VMFrame &f)
f.regs.sp[-3] = f.regs.sp[-1];
if (!JSID_IS_INT(id))
f.script()->typeMonitorUnknown(f.cx, f.pc());
f.script()->types.monitorUnknown(f.cx, f.pc());
}
template void JS_FASTCALL stubs::ElemDec<true>(VMFrame &f);
@ -1846,7 +1846,7 @@ stubs::IncElem(VMFrame &f)
f.regs.sp[-3] = f.regs.sp[-1];
if (!JSID_IS_INT(id))
f.script()->typeMonitorUnknown(f.cx, f.pc());
f.script()->types.monitorUnknown(f.cx, f.pc());
}
template void JS_FASTCALL stubs::IncElem<true>(VMFrame &f);
@ -1867,7 +1867,7 @@ stubs::DecElem(VMFrame &f)
f.regs.sp[-3] = f.regs.sp[-1];
if (!JSID_IS_INT(id))
f.script()->typeMonitorUnknown(f.cx, f.pc());
f.script()->types.monitorUnknown(f.cx, f.pc());
}
template void JS_FASTCALL stubs::DecElem<true>(VMFrame &f);
@ -1980,7 +1980,7 @@ InlineGetProp(VMFrame &f)
if (vp->isMagic(JS_LAZY_ARGUMENTS)) {
JS_ASSERT(js_GetOpcode(cx, f.script(), f.pc()) == JSOP_LENGTH);
regs.sp[-1] = Int32Value(regs.fp()->numActualArgs());
f.script()->typeMonitor(cx, f.pc(), regs.sp[-1]);
f.script()->types.monitor(cx, f.pc(), regs.sp[-1]);
return true;
}
@ -2029,7 +2029,7 @@ InlineGetProp(VMFrame &f)
}
} while(0);
f.script()->typeMonitor(cx, f.pc(), rval);
f.script()->types.monitor(cx, f.pc(), rval);
regs.sp[-1] = rval;
return true;
@ -2149,7 +2149,7 @@ stubs::CallProp(VMFrame &f, JSAtom *origAtom)
THROW();
}
#endif
f.script()->typeMonitor(cx, f.pc(), rval);
f.script()->types.monitor(cx, f.pc(), rval);
}
void JS_FASTCALL
@ -2601,7 +2601,7 @@ stubs::Pos(VMFrame &f)
if (!ValueToNumber(f.cx, &f.regs.sp[-1]))
THROW();
if (!f.regs.sp[-1].isInt32())
f.script()->typeMonitorOverflow(f.cx, f.pc());
f.script()->types.monitorOverflow(f.cx, f.pc());
}
void JS_FASTCALL
@ -2781,14 +2781,14 @@ stubs::TypeBarrierHelper(VMFrame &f, uint32 which)
f.script()->analysis(f.cx)->breakTypeBarriers(f.cx, f.pc() - f.script()->code, false);
}
f.script()->typeMonitor(f.cx, f.pc(), result);
f.script()->types.monitor(f.cx, f.pc(), result);
}
void JS_FASTCALL
stubs::NegZeroHelper(VMFrame &f)
{
f.regs.sp[-1].setDouble(-0.0);
f.script()->typeMonitorOverflow(f.cx, f.pc());
f.script()->types.monitorOverflow(f.cx, f.pc());
}
void JS_FASTCALL
@ -2823,9 +2823,9 @@ stubs::CheckArgumentTypes(VMFrame &f)
types::AutoEnterTypeInference enter(f.cx);
if (!f.fp()->isConstructing())
script->typeSetThis(f.cx, fp->thisValue());
script->types.setThis(f.cx, fp->thisValue());
for (unsigned i = 0; i < fun->nargs; i++)
script->typeSetArgument(f.cx, i, fp->formalArg(i));
script->types.setArgument(f.cx, i, fp->formalArg(i));
}
if (monitor.recompiled())
@ -2845,12 +2845,12 @@ stubs::AssertArgumentTypes(VMFrame &f)
JSScript *script = fun->script();
jstype type = GetValueType(f.cx, fp->thisValue());
if (!TypeMatches(f.cx, script->thisTypes(), type))
if (!TypeMatches(f.cx, script->types.thisTypes(), type))
TypeFailure(f.cx, "Missing type for this: %s", TypeString(type));
for (unsigned i = 0; i < fun->nargs; i++) {
type = GetValueType(f.cx, fp->formalArg(i));
if (!TypeMatches(f.cx, script->argTypes(i), type))
if (!TypeMatches(f.cx, script->types.argTypes(i), type))
TypeFailure(f.cx, "Missing type for arg %d: %s", i, TypeString(type));
}
}

View File

@ -726,9 +726,13 @@ FrameRegsIter::incSlow(StackFrame *oldfp)
/*****************************************************************************/
AllFramesIter::AllFramesIter(JSContext *cx)
: seg_(cx->stack.currentSegment()),
fp_(seg_ ? seg_->currentFrame() : NULL)
: seg_(cx->stack.currentSegment())
{
#ifdef JS_METHODJIT
mjit::ExpandInlineFrames(cx, true);
#endif
fp_ = seg_ ? seg_->currentFrame() : NULL;
}
AllFramesIter&