mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 765956 - Remove the non-reentrant closure optimization (r=bhackett)
* * * imported patch fix-debugger-for-non-reentrant-removal --HG-- extra : rebase_source : d77f8e19d0674726fb4078a73b6a3cb57ac91d73
This commit is contained in:
parent
043fc7c6eb
commit
2c9d40f617
@ -41,8 +41,8 @@ EvalCache::purge()
|
||||
for (JSScript **listHeadp = &table_[i]; *listHeadp; ) {
|
||||
JSScript *script = *listHeadp;
|
||||
JS_ASSERT(GetGCThingTraceKind(script) == JSTRACE_SCRIPT);
|
||||
*listHeadp = script->evalHashLink();
|
||||
script->evalHashLink() = NULL;
|
||||
*listHeadp = script->evalHashLink;
|
||||
script->evalHashLink = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -118,8 +118,8 @@ EvalCacheLookup(JSContext *cx, JSLinearString *str, StackFrame *caller, unsigned
|
||||
if (script->objects()->length == 1 &&
|
||||
!script->hasRegexps()) {
|
||||
JS_ASSERT(staticLevel == script->staticLevel);
|
||||
*scriptp = script->evalHashLink();
|
||||
script->evalHashLink() = NULL;
|
||||
*scriptp = script->evalHashLink;
|
||||
script->evalHashLink = NULL;
|
||||
return script;
|
||||
}
|
||||
}
|
||||
@ -129,7 +129,7 @@ EvalCacheLookup(JSContext *cx, JSLinearString *str, StackFrame *caller, unsigned
|
||||
static const unsigned EVAL_CACHE_CHAIN_LIMIT = 4;
|
||||
if (++count == EVAL_CACHE_CHAIN_LIMIT)
|
||||
return NULL;
|
||||
scriptp = &script->evalHashLink();
|
||||
scriptp = script->evalHashLink.unsafeGet();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -163,7 +163,7 @@ class EvalScriptGuard
|
||||
CallDestroyScriptHook(cx_->runtime->defaultFreeOp(), script_);
|
||||
script_->isActiveEval = false;
|
||||
script_->isCachedEval = true;
|
||||
script_->evalHashLink() = *bucket_;
|
||||
script_->evalHashLink = *bucket_;
|
||||
*bucket_ = script_;
|
||||
}
|
||||
}
|
||||
@ -327,10 +327,9 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *c
|
||||
|
||||
bool compileAndGo = true;
|
||||
bool noScriptRval = false;
|
||||
bool needScriptGlobal = false;
|
||||
JSScript *compiled = frontend::CompileScript(cx, scopeobj, caller,
|
||||
principals, originPrincipals,
|
||||
compileAndGo, noScriptRval, needScriptGlobal,
|
||||
compileAndGo, noScriptRval,
|
||||
chars, length, filename,
|
||||
lineno, cx->findVersion(), linearStr,
|
||||
staticLevel);
|
||||
|
@ -21,54 +21,10 @@
|
||||
using namespace js;
|
||||
using namespace js::frontend;
|
||||
|
||||
bool
|
||||
MarkInnerAndOuterFunctions(JSContext *cx, JSScript* script)
|
||||
{
|
||||
AssertRootingUnnecessary safe(cx);
|
||||
|
||||
Vector<JSScript *, 16> worklist(cx);
|
||||
if (!worklist.append(script))
|
||||
return false;
|
||||
|
||||
while (worklist.length()) {
|
||||
JSScript *outer = worklist.back();
|
||||
worklist.popBack();
|
||||
|
||||
if (outer->hasObjects()) {
|
||||
ObjectArray *arr = outer->objects();
|
||||
|
||||
/*
|
||||
* If this is an eval script, don't treat the saved caller function
|
||||
* stored in the first object slot as an inner function.
|
||||
*/
|
||||
size_t start = outer->savedCallerFun ? 1 : 0;
|
||||
|
||||
for (size_t i = start; i < arr->length; i++) {
|
||||
JSObject *obj = arr->vector[i];
|
||||
if (!obj->isFunction())
|
||||
continue;
|
||||
JSFunction *fun = obj->toFunction();
|
||||
JS_ASSERT(fun->isInterpreted());
|
||||
JSScript *inner = fun->script();
|
||||
if (outer->function() && outer->function()->isHeavyweight()) {
|
||||
outer->isOuterFunction = true;
|
||||
inner->isInnerFunction = true;
|
||||
}
|
||||
if (!inner->hasObjects())
|
||||
continue;
|
||||
if (!worklist.append(inner))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JSScript *
|
||||
frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *callerFrame,
|
||||
JSPrincipals *principals, JSPrincipals *originPrincipals,
|
||||
bool compileAndGo, bool noScriptRval, bool needScriptGlobal,
|
||||
bool compileAndGo, bool noScriptRval,
|
||||
const jschar *chars, size_t length,
|
||||
const char *filename, unsigned lineno, JSVersion version,
|
||||
JSString *source_ /* = NULL */,
|
||||
@ -108,14 +64,12 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *call
|
||||
return NULL;
|
||||
|
||||
bool savedCallerFun = compileAndGo && callerFrame && callerFrame->isFunctionFrame();
|
||||
GlobalObject *globalObject = needScriptGlobal ? GetCurrentGlobal(cx) : NULL;
|
||||
Rooted<JSScript*> script(cx, JSScript::Create(cx,
|
||||
savedCallerFun,
|
||||
principals,
|
||||
originPrincipals,
|
||||
compileAndGo,
|
||||
noScriptRval,
|
||||
globalObject,
|
||||
version,
|
||||
staticLevel));
|
||||
if (!script)
|
||||
@ -249,9 +203,6 @@ frontend::CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *call
|
||||
|
||||
bce.tellDebuggerAboutCompiledScript(cx);
|
||||
|
||||
if (!MarkInnerAndOuterFunctions(cx, script))
|
||||
return NULL;
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
@ -279,14 +230,12 @@ frontend::CompileFunctionBody(JSContext *cx, HandleFunction fun,
|
||||
if (!funtc.init())
|
||||
return false;
|
||||
|
||||
GlobalObject *globalObject = fun->getParent() ? &fun->getParent()->global() : NULL;
|
||||
Rooted<JSScript*> script(cx, JSScript::Create(cx,
|
||||
/* savedCallerFun = */ false,
|
||||
principals,
|
||||
originPrincipals,
|
||||
/* compileAndGo = */ false,
|
||||
/* noScriptRval = */ false,
|
||||
globalObject,
|
||||
version,
|
||||
staticLevel));
|
||||
if (!script)
|
||||
|
@ -16,7 +16,7 @@ namespace frontend {
|
||||
JSScript *
|
||||
CompileScript(JSContext *cx, HandleObject scopeChain, StackFrame *callerFrame,
|
||||
JSPrincipals *principals, JSPrincipals *originPrincipals,
|
||||
bool compileAndGo, bool noScriptRval, bool needScriptGlobal,
|
||||
bool compileAndGo, bool noScriptRval,
|
||||
const jschar *chars, size_t length,
|
||||
const char *filename, unsigned lineno, JSVersion version,
|
||||
JSString *source_ = NULL, unsigned staticLevel = 0);
|
||||
|
@ -1650,11 +1650,8 @@ BytecodeEmitter::tellDebuggerAboutCompiledScript(JSContext *cx)
|
||||
js_CallNewScriptHook(cx, script, script->function());
|
||||
if (!parent) {
|
||||
GlobalObject *compileAndGoGlobal = NULL;
|
||||
if (script->compileAndGo) {
|
||||
compileAndGoGlobal = script->globalObject;
|
||||
if (!compileAndGoGlobal)
|
||||
compileAndGoGlobal = &sc->scopeChain()->global();
|
||||
}
|
||||
if (script->compileAndGo)
|
||||
compileAndGoGlobal = &script->global();
|
||||
Debugger::onNewScript(cx, script, compileAndGoGlobal);
|
||||
}
|
||||
}
|
||||
@ -4829,7 +4826,6 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
JS_ASSERT_IF(bce->sc->inStrictMode(), sc.inStrictMode());
|
||||
|
||||
// Inherit most things (principals, version, etc) from the parent.
|
||||
GlobalObject *globalObject = fun->getParent() ? &fun->getParent()->global() : NULL;
|
||||
Rooted<JSScript*> parent(cx, bce->script);
|
||||
Rooted<JSScript*> script(cx, JSScript::Create(cx,
|
||||
/* savedCallerFun = */ false,
|
||||
@ -4837,7 +4833,6 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
parent->originPrincipals,
|
||||
parent->compileAndGo,
|
||||
/* noScriptRval = */ false,
|
||||
globalObject,
|
||||
parent->getVersion(),
|
||||
parent->staticLevel + 1));
|
||||
if (!script)
|
||||
|
@ -330,17 +330,14 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
||||
case JSOP_DEFVAR:
|
||||
case JSOP_DEFCONST:
|
||||
case JSOP_SETCONST:
|
||||
extendsScope_ = true;
|
||||
isInlineable = canTrackVars = false;
|
||||
break;
|
||||
|
||||
case JSOP_EVAL:
|
||||
extendsScope_ = true;
|
||||
isInlineable = canTrackVars = false;
|
||||
break;
|
||||
|
||||
case JSOP_ENTERWITH:
|
||||
addsScopeObjects_ = true;
|
||||
isJaegerCompileable = isInlineable = canTrackVars = false;
|
||||
break;
|
||||
|
||||
@ -348,7 +345,6 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx)
|
||||
case JSOP_ENTERLET1:
|
||||
case JSOP_ENTERBLOCK:
|
||||
case JSOP_LEAVEBLOCK:
|
||||
addsScopeObjects_ = true;
|
||||
isInlineable = false;
|
||||
break;
|
||||
|
||||
|
@ -843,8 +843,6 @@ class ScriptAnalysis
|
||||
bool usesThisValue_:1;
|
||||
bool hasFunctionCalls_:1;
|
||||
bool modifiesArguments_:1;
|
||||
bool extendsScope_:1;
|
||||
bool addsScopeObjects_:1;
|
||||
bool localsAliasStack_:1;
|
||||
bool isInlineable:1;
|
||||
bool isJaegerCompileable:1;
|
||||
@ -900,15 +898,6 @@ class ScriptAnalysis
|
||||
*/
|
||||
bool modifiesArguments() { return modifiesArguments_; }
|
||||
|
||||
/*
|
||||
* True if the script may extend declarations in its top level scope with
|
||||
* dynamic fun/var declarations or through eval.
|
||||
*/
|
||||
bool extendsScope() { return extendsScope_; }
|
||||
|
||||
/* True if the script may add block or with objects to its scope chain. */
|
||||
bool addsScopeObjects() { return addsScopeObjects_; }
|
||||
|
||||
/*
|
||||
* True if there are any LOCAL opcodes aliasing values on the stack (above
|
||||
* script->nfixed).
|
||||
@ -1117,25 +1106,6 @@ class ScriptAnalysis
|
||||
return lifetimes[slot];
|
||||
}
|
||||
|
||||
/*
|
||||
* If a NAME or similar opcode is definitely accessing a particular slot
|
||||
* of a script this one is nested in, get that script/slot.
|
||||
*/
|
||||
struct NameAccess {
|
||||
JSScript *script;
|
||||
types::TypeScriptNesting *nesting;
|
||||
uint32_t slot;
|
||||
|
||||
/* Decompose the slot above. */
|
||||
bool arg;
|
||||
uint32_t index;
|
||||
|
||||
const Value **basePointer() const {
|
||||
return arg ? &nesting->argArray : &nesting->varArray;
|
||||
}
|
||||
};
|
||||
NameAccess resolveNameAccess(JSContext *cx, jsid id, bool addDependency = false);
|
||||
|
||||
void printSSA(JSContext *cx);
|
||||
void printTypes(JSContext *cx);
|
||||
|
||||
|
@ -4902,10 +4902,9 @@ CompileUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj_,
|
||||
|
||||
bool compileAndGo = cx->hasRunOption(JSOPTION_COMPILE_N_GO);
|
||||
bool noScriptRval = cx->hasRunOption(JSOPTION_NO_SCRIPT_RVAL);
|
||||
bool needScriptGlobal = true;
|
||||
return frontend::CompileScript(cx, obj, NULL, principals, originPrincipals,
|
||||
compileAndGo, noScriptRval, needScriptGlobal,
|
||||
chars, length, filename, lineno, version);
|
||||
compileAndGo, noScriptRval, chars, length,
|
||||
filename, lineno, version);
|
||||
}
|
||||
|
||||
extern JS_PUBLIC_API(JSScript *)
|
||||
@ -5108,10 +5107,9 @@ CompileUTF8FileHelper(JSContext *cx, JSObject *obj_, JSPrincipals *principals,
|
||||
if (JS_DecodeUTF8(cx, buf, len, decodebuf, &decodelen)) {
|
||||
bool compileAndGo = cx->hasRunOption(JSOPTION_COMPILE_N_GO);
|
||||
bool noScriptRval = cx->hasRunOption(JSOPTION_NO_SCRIPT_RVAL);
|
||||
bool needScriptGlobal = true;
|
||||
script = frontend::CompileScript(cx, obj, NULL, principals, NULL,
|
||||
compileAndGo, noScriptRval, needScriptGlobal,
|
||||
decodebuf, decodelen, filename, 1, cx->findVersion());
|
||||
compileAndGo, noScriptRval, decodebuf, decodelen,
|
||||
filename, 1, cx->findVersion());
|
||||
} else {
|
||||
script = NULL;
|
||||
}
|
||||
@ -5181,9 +5179,7 @@ JS_PUBLIC_API(JSObject *)
|
||||
JS_GetGlobalFromScript(JSScript *script)
|
||||
{
|
||||
JS_ASSERT(!script->isCachedEval);
|
||||
JS_ASSERT(script->globalObject);
|
||||
|
||||
return script->globalObject;
|
||||
return &script->global();
|
||||
}
|
||||
|
||||
static JSFunction *
|
||||
@ -5409,13 +5405,12 @@ EvaluateUCScriptForPrincipalsCommon(JSContext *cx, JSObject *obj_,
|
||||
|
||||
bool compileAndGo = true;
|
||||
bool noScriptRval = !rval;
|
||||
bool needScriptGlobal = true;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
AutoLastFrameCheck lfc(cx);
|
||||
JSScript *script = frontend::CompileScript(cx, obj, NULL, principals, originPrincipals,
|
||||
compileAndGo, noScriptRval, needScriptGlobal,
|
||||
chars, length, filename, lineno, compileVersion);
|
||||
compileAndGo, noScriptRval, chars, length,
|
||||
filename, lineno, compileVersion);
|
||||
if (!script)
|
||||
return false;
|
||||
|
||||
|
@ -293,11 +293,8 @@ class CompartmentChecker
|
||||
}
|
||||
|
||||
void check(JSScript *script) {
|
||||
if (script) {
|
||||
if (script)
|
||||
check(script->compartment());
|
||||
if (!script->isCachedEval && script->globalObject)
|
||||
check(script->globalObject);
|
||||
}
|
||||
}
|
||||
|
||||
void check(StackFrame *fp) {
|
||||
|
@ -535,7 +535,6 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
|
||||
if (releaseTypes) {
|
||||
script->types->destroy();
|
||||
script->types = NULL;
|
||||
script->typesPurged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc, JSTrapHandler handle
|
||||
if (!CheckDebugMode(cx))
|
||||
return false;
|
||||
|
||||
BreakpointSite *site = script->getOrCreateBreakpointSite(cx, pc, NULL);
|
||||
BreakpointSite *site = script->getOrCreateBreakpointSite(cx, pc);
|
||||
if (!site)
|
||||
return false;
|
||||
site->setTrap(cx->runtime->defaultFreeOp(), handler, closure);
|
||||
|
@ -1294,7 +1294,6 @@ js_CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent,
|
||||
if (!cscript)
|
||||
return NULL;
|
||||
|
||||
cscript->globalObject = &clone->global();
|
||||
clone->setScript(cscript);
|
||||
cscript->setFunction(clone);
|
||||
if (!clone->setTypeForScriptedFunction(cx))
|
||||
|
@ -1863,7 +1863,7 @@ TypeCompartment::newAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey ke
|
||||
JS_ASSERT(!p);
|
||||
|
||||
RootedObject proto(cx);
|
||||
RootedObject global(cx, key.script->global());
|
||||
RootedObject global(cx, &key.script->global());
|
||||
if (!js_GetClassPrototype(cx, global, key.kind, &proto, NULL))
|
||||
return NULL;
|
||||
|
||||
@ -1955,7 +1955,7 @@ types::UseNewTypeForInitializer(JSContext *cx, JSScript *script, jsbytecode *pc,
|
||||
|
||||
AutoEnterTypeInference enter(cx);
|
||||
|
||||
if (!script->ensureRanAnalysis(cx, NULL))
|
||||
if (!script->ensureRanAnalysis(cx))
|
||||
return false;
|
||||
|
||||
return !script->analysis()->getCode(pc).inLoop;
|
||||
@ -1967,7 +1967,7 @@ types::ArrayPrototypeHasIndexedProperty(JSContext *cx, JSScript *script)
|
||||
if (!cx->typeInferenceEnabled() || !script->hasGlobal())
|
||||
return true;
|
||||
|
||||
JSObject *proto = script->global()->getOrCreateArrayPrototype(cx);
|
||||
JSObject *proto = script->global().getOrCreateArrayPrototype(cx);
|
||||
if (!proto)
|
||||
return true;
|
||||
|
||||
@ -2889,8 +2889,6 @@ TypeObject::setFlags(JSContext *cx, TypeObjectFlags flags)
|
||||
/* Make sure flags are consistent with persistent object state. */
|
||||
JS_ASSERT_IF(flags & OBJECT_FLAG_UNINLINEABLE,
|
||||
interpretedFunction->script()->uninlineable);
|
||||
JS_ASSERT_IF(flags & OBJECT_FLAG_REENTRANT_FUNCTION,
|
||||
interpretedFunction->script()->reentrantOuterFunction);
|
||||
JS_ASSERT_IF(flags & OBJECT_FLAG_ITERATED,
|
||||
singleton->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON));
|
||||
}
|
||||
@ -3142,105 +3140,6 @@ GetInitializerType(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||
return TypeScript::InitObject(cx, script, pc, key);
|
||||
}
|
||||
|
||||
/*
|
||||
* Detach nesting state for script from its parent, removing it entirely if it
|
||||
* has no children of its own. This happens when walking type information while
|
||||
* initially resolving NAME accesses, thus will not invalidate any compiler
|
||||
* dependencies.
|
||||
*/
|
||||
static void
|
||||
DetachNestingParent(JSScript *script)
|
||||
{
|
||||
TypeScriptNesting *nesting = script->nesting();
|
||||
|
||||
if (!nesting || !nesting->parent)
|
||||
return;
|
||||
|
||||
/* Remove from parent's list of children. */
|
||||
JSScript **pscript = &nesting->parent->nesting()->children;
|
||||
while ((*pscript)->nesting() != nesting)
|
||||
pscript = &(*pscript)->nesting()->next;
|
||||
*pscript = nesting->next;
|
||||
|
||||
nesting->parent = NULL;
|
||||
|
||||
/* If this nesting can have no children of its own, destroy it. */
|
||||
if (!script->isOuterFunction)
|
||||
script->clearNesting();
|
||||
}
|
||||
|
||||
ScriptAnalysis::NameAccess
|
||||
ScriptAnalysis::resolveNameAccess(JSContext *cx, jsid id, bool addDependency)
|
||||
{
|
||||
JS_ASSERT(cx->typeInferenceEnabled());
|
||||
|
||||
NameAccess access;
|
||||
PodZero(&access);
|
||||
|
||||
if (!JSID_IS_ATOM(id))
|
||||
return access;
|
||||
JSAtom *atom = JSID_TO_ATOM(id);
|
||||
|
||||
JSScript *script = this->script;
|
||||
while (script->function() && script->nesting()) {
|
||||
if (!script->ensureRanInference(cx))
|
||||
return access;
|
||||
|
||||
/*
|
||||
* Don't resolve names in scripts which use 'let' or 'with'. New names
|
||||
* bound here can mask variables of the script itself.
|
||||
*
|
||||
* Also, don't resolve names in scripts which are generators. Frame
|
||||
* balancing works differently for generators and we do not maintain
|
||||
* active frame counts for such scripts.
|
||||
*/
|
||||
if (script->analysis()->addsScopeObjects() || script->isGenerator)
|
||||
return access;
|
||||
|
||||
/* Check if the script definitely binds the identifier. */
|
||||
unsigned index;
|
||||
BindingKind kind = script->bindings.lookup(cx, atom, &index);
|
||||
if (kind == ARGUMENT || kind == VARIABLE) {
|
||||
TypeObject *obj = script->function()->getType(cx);
|
||||
|
||||
if (addDependency) {
|
||||
/*
|
||||
* Record the dependency which compiled code has on the outer
|
||||
* function being non-reentrant.
|
||||
*/
|
||||
if (TypeSet::HasObjectFlags(cx, obj, OBJECT_FLAG_REENTRANT_FUNCTION))
|
||||
return access;
|
||||
}
|
||||
|
||||
if (!script->isOuterFunction)
|
||||
return access;
|
||||
|
||||
access.script = script;
|
||||
access.nesting = script->nesting();
|
||||
access.slot = (kind == ARGUMENT) ? ArgSlot(index) : LocalSlot(script, index);
|
||||
access.arg = (kind == ARGUMENT);
|
||||
access.index = index;
|
||||
return access;
|
||||
} else if (kind != NONE) {
|
||||
return access;
|
||||
}
|
||||
|
||||
/*
|
||||
* The script's bindings do not contain a name for the function itself,
|
||||
* don't resolve name accesses on lambdas in DeclEnv objects on the
|
||||
* scope chain.
|
||||
*/
|
||||
if (atom == CallObjectLambdaName(*script->function()))
|
||||
return access;
|
||||
|
||||
if (!script->nesting()->parent)
|
||||
return access;
|
||||
script = script->nesting()->parent;
|
||||
}
|
||||
|
||||
return access;
|
||||
}
|
||||
|
||||
/* Analyze type information for a single bytecode. */
|
||||
bool
|
||||
ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
|
||||
@ -3466,7 +3365,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
|
||||
seen->addType(cx, Type::DoubleType());
|
||||
|
||||
/* Handle as a property access. */
|
||||
PropertyAccess(cx, script, pc, script->global()->getType(cx), false, seen, id);
|
||||
PropertyAccess(cx, script, pc, script->global().getType(cx), false, seen, id);
|
||||
|
||||
if (op == JSOP_CALLGNAME)
|
||||
pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType());
|
||||
@ -3479,24 +3378,8 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
|
||||
case JSOP_NAME:
|
||||
case JSOP_CALLNAME: {
|
||||
TypeSet *seen = bytecodeTypes(pc);
|
||||
addTypeBarrier(cx, pc, seen, Type::UnknownType());
|
||||
seen->addSubset(cx, &pushed[0]);
|
||||
|
||||
/*
|
||||
* Try to resolve this name by walking the function's scope nesting.
|
||||
* If we succeed but the accessed script has had its TypeScript purged
|
||||
* in the past, we still must use a type barrier: the name access can
|
||||
* be on a call object which predated the purge, and whose types might
|
||||
* not be reflected in the reconstructed information.
|
||||
*/
|
||||
jsid id = GetAtomId(cx, script, pc, 0);
|
||||
NameAccess access = resolveNameAccess(cx, id);
|
||||
if (access.script && !access.script->typesPurged) {
|
||||
TypeSet *types = TypeScript::SlotTypes(access.script, access.slot);
|
||||
types->addSubsetBarrier(cx, script, pc, seen);
|
||||
} else {
|
||||
addTypeBarrier(cx, pc, seen, Type::UnknownType());
|
||||
}
|
||||
|
||||
if (op == JSOP_CALLNAME)
|
||||
pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType());
|
||||
break;
|
||||
@ -3508,25 +3391,13 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
|
||||
|
||||
case JSOP_SETGNAME: {
|
||||
jsid id = GetAtomId(cx, script, pc, 0);
|
||||
PropertyAccess(cx, script, pc, script->global()->getType(cx),
|
||||
PropertyAccess(cx, script, pc, script->global().getType(cx),
|
||||
true, poppedTypes(pc, 0), id);
|
||||
poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
case JSOP_SETNAME: {
|
||||
jsid id = GetAtomId(cx, script, pc, 0);
|
||||
NameAccess access = resolveNameAccess(cx, id);
|
||||
if (access.script) {
|
||||
TypeSet *types = TypeScript::SlotTypes(access.script, access.slot);
|
||||
poppedTypes(pc, 0)->addSubset(cx, types);
|
||||
} else {
|
||||
cx->compartment->types.monitorBytecode(cx, script, offset);
|
||||
}
|
||||
poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
case JSOP_SETNAME:
|
||||
case JSOP_SETCONST:
|
||||
cx->compartment->types.monitorBytecode(cx, script, offset);
|
||||
poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
|
||||
@ -3972,7 +3843,7 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
|
||||
case JSOP_GENERATOR:
|
||||
if (script->function()) {
|
||||
if (script->hasGlobal()) {
|
||||
JSObject *proto = script->global()->getOrCreateGeneratorPrototype(cx);
|
||||
JSObject *proto = script->global().getOrCreateGeneratorPrototype(cx);
|
||||
if (!proto)
|
||||
return false;
|
||||
TypeObject *object = proto->getNewType(cx);
|
||||
@ -4075,45 +3946,6 @@ ScriptAnalysis::analyzeTypes(JSContext *cx)
|
||||
for (unsigned i = 0; i < script->nfixed; i++)
|
||||
TypeScript::LocalTypes(script, i)->addType(cx, Type::UndefinedType());
|
||||
|
||||
TypeScriptNesting *nesting = script->function() ? script->nesting() : NULL;
|
||||
if (nesting && nesting->parent) {
|
||||
/*
|
||||
* Check whether NAME accesses can be resolved in parent scopes, and
|
||||
* detach from the parent if so. Even if outdated activations of this
|
||||
* function are live when the parent is called again, we do not need to
|
||||
* consider this reentrance as no state in the parent will be used.
|
||||
*/
|
||||
if (!nesting->parent->ensureRanInference(cx))
|
||||
return;
|
||||
|
||||
bool detached = false;
|
||||
|
||||
/* Don't track for leaf scripts which have no free variables. */
|
||||
if (!usesScopeChain() && !script->isOuterFunction) {
|
||||
DetachNestingParent(script);
|
||||
detached = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the names bound by the script are extensible (DEFFUN, EVAL, ...),
|
||||
* don't resolve NAME accesses into the parent.
|
||||
*/
|
||||
if (!detached && extendsScope()) {
|
||||
DetachNestingParent(script);
|
||||
detached = true;
|
||||
}
|
||||
|
||||
|
||||
if (!detached) {
|
||||
/*
|
||||
* Don't track for parents which add call objects or are generators,
|
||||
* don't resolve NAME accesses into the parent.
|
||||
*/
|
||||
if (nesting->parent->analysis()->addsScopeObjects() || nesting->parent->isGenerator)
|
||||
DetachNestingParent(script);
|
||||
}
|
||||
}
|
||||
|
||||
TypeInferenceState state(cx);
|
||||
|
||||
unsigned offset = 0;
|
||||
@ -4277,9 +4109,7 @@ AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun, JSO
|
||||
}
|
||||
|
||||
JSScript *script = fun->script();
|
||||
JS_ASSERT(!script->isInnerFunction);
|
||||
|
||||
if (!script->ensureRanAnalysis(cx, fun) || !script->ensureRanInference(cx)) {
|
||||
if (!script->ensureRanAnalysis(cx) || !script->ensureRanInference(cx)) {
|
||||
*pbaseobj = NULL;
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
return false;
|
||||
@ -4515,7 +4345,6 @@ AnalyzePoppedThis(JSContext *cx, Vector<SSAUseChain *> *pendingPoppedThis,
|
||||
}
|
||||
|
||||
JSFunction *function = scriptObj->toFunction();
|
||||
JS_ASSERT(!function->script()->isInnerFunction);
|
||||
|
||||
/*
|
||||
* Generate constraints to clear definite properties from the type
|
||||
@ -4566,7 +4395,7 @@ AnalyzePoppedThis(JSContext *cx, Vector<SSAUseChain *> *pendingPoppedThis,
|
||||
static void
|
||||
CheckNewScriptProperties(JSContext *cx, HandleTypeObject type, JSFunction *fun)
|
||||
{
|
||||
if (type->unknownProperties() || fun->script()->isInnerFunction)
|
||||
if (type->unknownProperties())
|
||||
return;
|
||||
|
||||
/* Strawman object to add properties to and watch for duplicates. */
|
||||
@ -4882,7 +4711,7 @@ TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, Type type)
|
||||
|
||||
/* Directly update associated type sets for applicable bytecodes. */
|
||||
if (js_CodeSpec[*pc].format & JOF_TYPESET) {
|
||||
if (!script->ensureRanAnalysis(cx, NULL)) {
|
||||
if (!script->ensureRanAnalysis(cx)) {
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
@ -4988,7 +4817,7 @@ TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Val
|
||||
|
||||
AutoEnterTypeInference enter(cx);
|
||||
|
||||
if (!script->ensureRanAnalysis(cx, NULL)) {
|
||||
if (!script->ensureRanAnalysis(cx)) {
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
@ -5003,247 +4832,6 @@ TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Val
|
||||
types->addType(cx, type);
|
||||
}
|
||||
|
||||
bool
|
||||
TypeScript::SetScope(JSContext *cx, JSScript *script_, JSObject *scope_)
|
||||
{
|
||||
Rooted<JSScript*> script(cx, script_);
|
||||
RootedObject scope(cx, scope_);
|
||||
|
||||
JS_ASSERT(script->types && !script->types->hasScope());
|
||||
|
||||
JSFunction *fun = script->function();
|
||||
bool nullClosure = fun && fun->isNullClosure();
|
||||
|
||||
JS_ASSERT_IF(!fun, !script->isOuterFunction && !script->isInnerFunction);
|
||||
JS_ASSERT_IF(!scope, fun && !script->isInnerFunction);
|
||||
|
||||
/*
|
||||
* The scope object must be the initial one for the script, before any call
|
||||
* object has been created in the heavyweight case.
|
||||
*/
|
||||
JS_ASSERT_IF(scope && scope->isCall() && !scope->asCall().isForEval(),
|
||||
&scope->asCall().callee() != fun);
|
||||
|
||||
if (!script->compileAndGo) {
|
||||
script->types->global = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_ASSERT_IF(fun && scope, fun->global() == scope->global());
|
||||
script->types->global = fun ? &fun->global() : &scope->global();
|
||||
|
||||
if (!cx->typeInferenceEnabled())
|
||||
return true;
|
||||
|
||||
if (!script->isInnerFunction || nullClosure) {
|
||||
/*
|
||||
* Outermost functions need nesting information if there are inner
|
||||
* functions directly nested in them.
|
||||
*/
|
||||
if (script->isOuterFunction) {
|
||||
script->types->nesting = cx->new_<TypeScriptNesting>();
|
||||
if (!script->types->nesting)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk the scope chain to the next call object, which will be the function
|
||||
* the script is nested inside.
|
||||
*/
|
||||
while (!scope->isCall())
|
||||
scope = &scope->asScope().enclosingScope();
|
||||
|
||||
CallObject &call = scope->asCall();
|
||||
|
||||
/* The isInnerFunction test ensures there is no intervening strict eval call object. */
|
||||
JS_ASSERT(!call.isForEval());
|
||||
|
||||
/* Don't track non-heavyweight parents, NAME ops won't reach into them. */
|
||||
JSFunction *parentFun = &call.callee();
|
||||
if (!parentFun || !parentFun->isHeavyweight())
|
||||
return true;
|
||||
JSScript *parent = parentFun->script();
|
||||
JS_ASSERT(parent->isOuterFunction);
|
||||
|
||||
/*
|
||||
* We only need the nesting in the child if it has NAME accesses going
|
||||
* into the parent. We won't know for sure whether this is the case until
|
||||
* analyzing the script's types, which we don't want to do yet. The nesting
|
||||
* info we make here may get pruned if/when we eventually do such analysis.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Scopes are set when scripts first execute, and the parent script must
|
||||
* have executed first. It is still possible for the parent script to not
|
||||
* have a scope, however, as we occasionally purge all TypeScripts from the
|
||||
* compartment and there may be inner function objects parented to an
|
||||
* activation of the outer function sticking around. In such cases, treat
|
||||
* the parent's call object as the most recent one, so that it is not
|
||||
* marked as reentrant.
|
||||
*/
|
||||
if (!parent->ensureHasTypes(cx))
|
||||
return false;
|
||||
if (!parent->types->hasScope()) {
|
||||
if (!SetScope(cx, parent, &call.enclosingScope()))
|
||||
return false;
|
||||
parent->nesting()->activeCall = &call;
|
||||
parent->nesting()->argArray = Valueify(call.argArray());
|
||||
parent->nesting()->varArray = Valueify(call.varArray());
|
||||
}
|
||||
|
||||
JS_ASSERT(!script->types->nesting);
|
||||
|
||||
/* Construct and link nesting information for the two functions. */
|
||||
|
||||
script->types->nesting = cx->new_<TypeScriptNesting>();
|
||||
if (!script->types->nesting)
|
||||
return false;
|
||||
|
||||
script->nesting()->parent = parent;
|
||||
script->nesting()->next = parent->nesting()->children;
|
||||
parent->nesting()->children = script;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TypeScriptNesting::~TypeScriptNesting()
|
||||
{
|
||||
/*
|
||||
* Unlink from any parent/child. Nesting info on a script does not keep
|
||||
* either the parent or children live during GC.
|
||||
*/
|
||||
|
||||
if (parent) {
|
||||
JSScript **pscript = &parent->nesting()->children;
|
||||
while ((*pscript)->nesting() != this)
|
||||
pscript = &(*pscript)->nesting()->next;
|
||||
*pscript = next;
|
||||
}
|
||||
|
||||
while (children) {
|
||||
TypeScriptNesting *child = children->nesting();
|
||||
children = child->next;
|
||||
child->parent = NULL;
|
||||
child->next = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ClearActiveNesting(JSScript *start)
|
||||
{
|
||||
/*
|
||||
* Clear active call information for script and any outer functions
|
||||
* inner to it. Return false if an inner function has frames on the stack.
|
||||
*/
|
||||
|
||||
/* Traverse children, then parent, avoiding recursion. */
|
||||
JSScript *script = start;
|
||||
bool traverseChildren = true;
|
||||
while (true) {
|
||||
TypeScriptNesting *nesting = script->nesting();
|
||||
if (nesting->children && traverseChildren) {
|
||||
script = nesting->children;
|
||||
continue;
|
||||
}
|
||||
if (nesting->activeFrames)
|
||||
return false;
|
||||
if (script->isOuterFunction) {
|
||||
nesting->activeCall = NULL;
|
||||
nesting->argArray = NULL;
|
||||
nesting->varArray = NULL;
|
||||
}
|
||||
if (script == start)
|
||||
break;
|
||||
if (nesting->next) {
|
||||
script = nesting->next;
|
||||
traverseChildren = true;
|
||||
} else {
|
||||
script = nesting->parent;
|
||||
traverseChildren = false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* For the specified scope and script with an outer function, check if the
|
||||
* scope represents a reentrant activation on an inner function of the parent
|
||||
* or any of its transitive parents.
|
||||
*/
|
||||
static void
|
||||
CheckNestingParent(JSContext *cx, JSObject *scope, JSScript *script)
|
||||
{
|
||||
restart:
|
||||
JSScript *parent = script->nesting()->parent;
|
||||
JS_ASSERT(parent);
|
||||
|
||||
while (!scope->isCall() || scope->asCall().callee().script() != parent)
|
||||
scope = &scope->asScope().enclosingScope();
|
||||
|
||||
if (scope != parent->nesting()->activeCall) {
|
||||
parent->reentrantOuterFunction = true;
|
||||
MarkTypeObjectFlags(cx, parent->function(), OBJECT_FLAG_REENTRANT_FUNCTION);
|
||||
|
||||
/*
|
||||
* Continue checking parents to see if this is reentrant for them too.
|
||||
* We don't need to check this in for non-reentrant calls on the outer
|
||||
* function: when we entered any outer function to the immediate parent
|
||||
* we cleared the active call for its transitive children, so a
|
||||
* non-reentrant call on a child is also a non-reentrant call on the
|
||||
* parent.
|
||||
*/
|
||||
if (parent->nesting()->parent) {
|
||||
scope = &scope->asScope().enclosingScope();
|
||||
script = parent;
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NestingPrologue(JSContext *cx, StackFrame *fp)
|
||||
{
|
||||
JSScript *script = fp->fun()->script();
|
||||
TypeScriptNesting *nesting = script->nesting();
|
||||
|
||||
if (nesting->parent)
|
||||
CheckNestingParent(cx, fp->scopeChain(), script);
|
||||
|
||||
if (script->isOuterFunction) {
|
||||
/*
|
||||
* Check the stack has no frames for this activation, any of its inner
|
||||
* functions or any of their transitive inner functions.
|
||||
*
|
||||
* Also, if the script has an extensible scope, then the arg/var array
|
||||
* can be moved unexpectedly, so abort the optimization.
|
||||
*/
|
||||
if (!ClearActiveNesting(script) || script->funHasExtensibleScope) {
|
||||
script->reentrantOuterFunction = true;
|
||||
MarkTypeObjectFlags(cx, fp->fun(), OBJECT_FLAG_REENTRANT_FUNCTION);
|
||||
}
|
||||
|
||||
nesting->activeCall = &fp->callObj();
|
||||
nesting->argArray = Valueify(nesting->activeCall->argArray());
|
||||
nesting->varArray = Valueify(nesting->activeCall->varArray());
|
||||
}
|
||||
|
||||
/* Maintain stack frame count for the function. */
|
||||
nesting->activeFrames++;
|
||||
}
|
||||
|
||||
void
|
||||
NestingEpilogue(StackFrame *fp)
|
||||
{
|
||||
JSScript *script = fp->fun()->script();
|
||||
TypeScriptNesting *nesting = script->nesting();
|
||||
|
||||
JS_ASSERT(nesting->activeFrames != 0);
|
||||
nesting->activeFrames--;
|
||||
}
|
||||
|
||||
} } /* namespace js::types */
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
@ -5578,8 +5166,6 @@ JSObject::makeLazyType(JSContext *cx)
|
||||
JSScript *script = type->interpretedFunction->script();
|
||||
if (script->uninlineable)
|
||||
type->flags |= OBJECT_FLAG_UNINLINEABLE;
|
||||
if (script->reentrantOuterFunction)
|
||||
type->flags |= OBJECT_FLAG_REENTRANT_FUNCTION;
|
||||
}
|
||||
|
||||
if (self->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON))
|
||||
@ -6080,15 +5666,6 @@ TypeScript::Sweep(FreeOp *fop, JSScript *script)
|
||||
presult = &result->next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the script has nesting state with a most recent activation, we do not
|
||||
* need either to mark the call object or clear it if not live. Even with
|
||||
* a dead pointer in the nesting, we can't get a spurious match while
|
||||
* testing for reentrancy: if previous activations are still live, they
|
||||
* cannot alias the most recent one, and future activations will overwrite
|
||||
* activeCall on creation.
|
||||
*/
|
||||
}
|
||||
|
||||
void
|
||||
@ -6100,9 +5677,6 @@ TypeScript::destroy()
|
||||
dynamicList = next;
|
||||
}
|
||||
|
||||
if (nesting)
|
||||
Foreground::delete_(nesting);
|
||||
|
||||
Foreground::free_(this);
|
||||
}
|
||||
|
||||
@ -6158,8 +5732,6 @@ SizeOfScriptTypeInferenceData(JSScript *script, TypeInferenceSizes *sizes,
|
||||
return;
|
||||
}
|
||||
|
||||
sizes->scripts += mallocSizeOf(typeScript->nesting);
|
||||
|
||||
unsigned count = TypeScript::NumTypeSets(script);
|
||||
sizes->scripts += mallocSizeOf(typeScript);
|
||||
|
||||
|
111
js/src/jsinfer.h
111
js/src/jsinfer.h
@ -286,14 +286,11 @@ enum {
|
||||
/* Whether any objects have been iterated over. */
|
||||
OBJECT_FLAG_ITERATED = 0x00200000,
|
||||
|
||||
/* Outer function which has been marked reentrant. */
|
||||
OBJECT_FLAG_REENTRANT_FUNCTION = 0x00400000,
|
||||
|
||||
/* For a global object, whether flags were set on the RegExpStatics. */
|
||||
OBJECT_FLAG_REGEXP_FLAGS_SET = 0x00800000,
|
||||
OBJECT_FLAG_REGEXP_FLAGS_SET = 0x00400000,
|
||||
|
||||
/* Flags which indicate dynamic properties of represented objects. */
|
||||
OBJECT_FLAG_DYNAMIC_MASK = 0x00ff0000,
|
||||
OBJECT_FLAG_DYNAMIC_MASK = 0x007f0000,
|
||||
|
||||
/*
|
||||
* Whether all properties of this object are considered unknown.
|
||||
@ -802,7 +799,7 @@ struct TypeObject : gc::Cell
|
||||
* Get the global object which all objects of this type are parented to,
|
||||
* or NULL if there is none known.
|
||||
*/
|
||||
inline JSObject *getGlobal();
|
||||
//inline JSObject *getGlobal();
|
||||
|
||||
/* Helpers */
|
||||
|
||||
@ -907,89 +904,6 @@ struct TypeCallsite
|
||||
bool isNew, unsigned argumentCount);
|
||||
};
|
||||
|
||||
/*
|
||||
* Information attached to outer and inner function scripts nested in one
|
||||
* another for tracking the reentrance state for outer functions. This state is
|
||||
* used to generate fast accesses to the args and vars of the outer function.
|
||||
*
|
||||
* A function is non-reentrant if, at any point in time, only the most recent
|
||||
* activation (i.e. call object) is live. An activation is live if either the
|
||||
* activation is on the stack, or a transitive inner function parented to the
|
||||
* activation is on the stack.
|
||||
*
|
||||
* Because inner functions can be (and, quite often, are) stored in object
|
||||
* properties and it is difficult to build a fast and robust escape analysis
|
||||
* to cope with such flow, we detect reentrance dynamically. For the outer
|
||||
* function, we keep track of the call object for the most recent activation,
|
||||
* and the number of frames for the function and its inner functions which are
|
||||
* on the stack.
|
||||
*
|
||||
* If the outer function is called while frames associated with a previous
|
||||
* activation are on the stack, the outer function is reentrant. If an inner
|
||||
* function is called whose scope does not match the most recent activation,
|
||||
* the outer function is reentrant.
|
||||
*
|
||||
* The situation gets trickier when there are several levels of nesting.
|
||||
*
|
||||
* function foo() {
|
||||
* var a;
|
||||
* function bar() {
|
||||
* var b;
|
||||
* function baz() { return a + b; }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* At calls to 'baz', we don't want to do the scope check for the activations
|
||||
* of both 'foo' and 'bar', but rather 'bar' only. For this to work, a call to
|
||||
* 'baz' which is a reentrant call on 'foo' must also be a reentrant call on
|
||||
* 'bar'. When 'foo' is called, we clear the most recent call object for 'bar'.
|
||||
*/
|
||||
struct TypeScriptNesting
|
||||
{
|
||||
/*
|
||||
* If this is an inner function, the outer function. If non-NULL, this will
|
||||
* be the immediate nested parent of the script (even if that parent has
|
||||
* been marked reentrant). May be NULL even if the script has a nested
|
||||
* parent, if NAME accesses cannot be tracked into the parent (either the
|
||||
* script extends its scope with eval() etc., or the parent can make new
|
||||
* scope chain objects with 'let' or 'with').
|
||||
*/
|
||||
JSScript *parent;
|
||||
|
||||
/* If this is an outer function, list of inner functions. */
|
||||
JSScript *children;
|
||||
|
||||
/* Link for children list of parent. */
|
||||
JSScript *next;
|
||||
|
||||
/* If this is an outer function, the most recent activation. */
|
||||
CallObject *activeCall;
|
||||
|
||||
/*
|
||||
* If this is an outer function, pointers to the most recent activation's
|
||||
* arguments and variables arrays. These could be referring either to stack
|
||||
* values in activeCall's frame (if it has not finished yet) or to the
|
||||
* internal slots of activeCall (if the frame has finished). Pointers to
|
||||
* these fields can be embedded directly in JIT code (though remember to
|
||||
* use 'addDependency == true' when calling resolveNameAccess).
|
||||
*/
|
||||
const Value *argArray;
|
||||
const Value *varArray;
|
||||
|
||||
/* Number of frames for this function on the stack. */
|
||||
uint32_t activeFrames;
|
||||
|
||||
TypeScriptNesting() { PodZero(this); }
|
||||
~TypeScriptNesting();
|
||||
};
|
||||
|
||||
/* Construct nesting information for script wrt its parent. */
|
||||
bool CheckScriptNesting(JSContext *cx, JSScript *script);
|
||||
|
||||
/* Track nesting state when calling or finishing an outer/inner function. */
|
||||
void NestingPrologue(JSContext *cx, StackFrame *fp);
|
||||
void NestingEpilogue(StackFrame *fp);
|
||||
|
||||
/* Persistent type information for a script, retained across GCs. */
|
||||
class TypeScript
|
||||
{
|
||||
@ -998,28 +912,10 @@ class TypeScript
|
||||
/* Analysis information for the script, cleared on each GC. */
|
||||
analyze::ScriptAnalysis *analysis;
|
||||
|
||||
/*
|
||||
* Information about the scope in which a script executes. This information
|
||||
* is not set until the script has executed at least once and SetScope
|
||||
* called, before that 'global' will be poisoned per GLOBAL_MISSING_SCOPE.
|
||||
*/
|
||||
static const size_t GLOBAL_MISSING_SCOPE = 0x1;
|
||||
|
||||
/* Global object for the script, if compileAndGo. */
|
||||
HeapPtr<GlobalObject> global;
|
||||
|
||||
public:
|
||||
|
||||
/* Nesting state for outer or inner function scripts. */
|
||||
TypeScriptNesting *nesting;
|
||||
|
||||
/* Dynamic types generated at points within this script. */
|
||||
TypeResult *dynamicList;
|
||||
|
||||
inline TypeScript();
|
||||
|
||||
bool hasScope() { return size_t(global.get()) != GLOBAL_MISSING_SCOPE; }
|
||||
|
||||
/* Array of type type sets for variables and JOF_TYPESET ops. */
|
||||
TypeSet *typeArray() { return (TypeSet *) (uintptr_t(this) + sizeof(TypeScript)); }
|
||||
|
||||
@ -1082,7 +978,6 @@ class TypeScript
|
||||
static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value);
|
||||
|
||||
static void Sweep(FreeOp *fop, JSScript *script);
|
||||
inline void trace(JSTracer *trc);
|
||||
void destroy();
|
||||
};
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "jsinfer.h"
|
||||
#include "jsprf.h"
|
||||
|
||||
#include "gc/Marking.h"
|
||||
#include "gc/Root.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
|
||||
@ -312,7 +311,7 @@ TypeMonitorCall(JSContext *cx, const js::CallArgs &args, bool constructing)
|
||||
JSFunction *fun = callee->toFunction();
|
||||
if (fun->isInterpreted()) {
|
||||
RootedScript script(cx, fun->script());
|
||||
if (!script->ensureRanAnalysis(cx, fun->environment()))
|
||||
if (!script->ensureRanAnalysis(cx))
|
||||
return false;
|
||||
if (cx->typeInferenceEnabled())
|
||||
TypeMonitorCallSlow(cx, callee, args, constructing);
|
||||
@ -449,12 +448,6 @@ UseNewTypeAtEntry(JSContext *cx, StackFrame *fp)
|
||||
// Script interface functions
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline
|
||||
TypeScript::TypeScript()
|
||||
{
|
||||
this->global = (js::GlobalObject *) GLOBAL_MISSING_SCOPE;
|
||||
}
|
||||
|
||||
/* static */ inline unsigned
|
||||
TypeScript::NumTypeSets(JSScript *script)
|
||||
{
|
||||
@ -504,7 +497,7 @@ TypeScript::SlotTypes(JSScript *script, unsigned slot)
|
||||
TypeScript::StandardType(JSContext *cx, JSScript *script, JSProtoKey key)
|
||||
{
|
||||
RootedObject proto(cx);
|
||||
RootedObject global(cx, script->global());
|
||||
RootedObject global(cx, &script->global());
|
||||
if (!js_GetClassPrototype(cx, global, key, &proto, NULL))
|
||||
return NULL;
|
||||
return proto->getNewType(cx);
|
||||
@ -694,7 +687,7 @@ TypeScript::SetThis(JSContext *cx, JSScript *script, Type type)
|
||||
script->id(), TypeString(type));
|
||||
ThisTypes(script)->addType(cx, type);
|
||||
|
||||
if (analyze && script->types->hasScope())
|
||||
if (analyze)
|
||||
script->ensureRanInference(cx);
|
||||
}
|
||||
}
|
||||
@ -756,15 +749,6 @@ TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js:
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TypeScript::trace(JSTracer *trc)
|
||||
{
|
||||
if (hasScope() && global)
|
||||
gc::MarkObject(trc, &global, "script_global");
|
||||
|
||||
/* Note: nesting does not keep anything alive. */
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// TypeCompartment
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
@ -1367,16 +1351,6 @@ TypeObject::setFlagsFromKey(JSContext *cx, JSProtoKey key)
|
||||
setFlags(cx, flags);
|
||||
}
|
||||
|
||||
inline JSObject *
|
||||
TypeObject::getGlobal()
|
||||
{
|
||||
if (singleton)
|
||||
return &singleton->global();
|
||||
if (interpretedFunction && interpretedFunction->script()->compileAndGo)
|
||||
return &interpretedFunction->global();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline void
|
||||
TypeObject::writeBarrierPre(TypeObject *type)
|
||||
{
|
||||
@ -1452,7 +1426,7 @@ JSScript::ensureHasTypes(JSContext *cx)
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSScript::ensureRanAnalysis(JSContext *cx, JSObject *scope)
|
||||
JSScript::ensureRanAnalysis(JSContext *cx)
|
||||
{
|
||||
js::analyze::AutoEnterAnalysis aea(cx->compartment);
|
||||
JSScript *self = this;
|
||||
@ -1460,12 +1434,6 @@ JSScript::ensureRanAnalysis(JSContext *cx, JSObject *scope)
|
||||
|
||||
if (!self->ensureHasTypes(cx))
|
||||
return false;
|
||||
if (!self->types->hasScope()) {
|
||||
js::RootedObject scopeRoot(cx, scope);
|
||||
if (!js::types::TypeScript::SetScope(cx, self, scope))
|
||||
return false;
|
||||
scope = scopeRoot;
|
||||
}
|
||||
if (!self->hasAnalysis() && !self->makeAnalysis(cx))
|
||||
return false;
|
||||
JS_ASSERT(self->analysis()->ranBytecode());
|
||||
@ -1476,7 +1444,7 @@ inline bool
|
||||
JSScript::ensureRanInference(JSContext *cx)
|
||||
{
|
||||
JS::RootedScript self(cx, this);
|
||||
if (!ensureRanAnalysis(cx, NULL))
|
||||
if (!ensureRanAnalysis(cx))
|
||||
return false;
|
||||
if (!self->analysis()->ranInference()) {
|
||||
js::types::AutoEnterTypeInference enter(cx);
|
||||
|
@ -479,7 +479,7 @@ js::ExecuteKernel(JSContext *cx, JSScript *script_, JSObject &scopeChain, const
|
||||
if (!cx->stack.pushExecuteFrame(cx, script, thisv, scopeChain, type, evalInFrame, &efg))
|
||||
return false;
|
||||
|
||||
if (!script->ensureRanAnalysis(cx, &scopeChain))
|
||||
if (!script->ensureRanAnalysis(cx))
|
||||
return false;
|
||||
TypeScript::SetThis(cx, script, efg.fp()->thisValue());
|
||||
|
||||
|
@ -6379,7 +6379,7 @@ GetPCCountScriptContents(JSContext *cx, size_t index)
|
||||
|
||||
{
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, script->function() ? (JSObject *) script->function() : script->global()))
|
||||
if (!ac.enter(cx, &script->global()))
|
||||
return NULL;
|
||||
|
||||
if (!GetPCCountJSON(cx, sac, buf))
|
||||
|
@ -278,35 +278,12 @@ Shape::getChildBinding(JSContext *cx, const StackShape &child)
|
||||
{
|
||||
JS_ASSERT(!inDictionary());
|
||||
|
||||
Shape *shape = cx->propertyTree().getChild(cx, this, numFixedSlots(), child);
|
||||
if (shape) {
|
||||
//JS_ASSERT(shape->parent == this); // XXX 'this' is not rooted here
|
||||
/* Try to allocate all slots inline. */
|
||||
uint32_t slots = child.slotSpan();
|
||||
gc::AllocKind kind = gc::GetGCObjectKind(slots);
|
||||
uint32_t nfixed = gc::GetGCKindSlots(kind);
|
||||
|
||||
/*
|
||||
* Update the number of fixed slots which bindings of this shape will
|
||||
* have. Bindings are constructed as new properties come in, so the
|
||||
* call object allocation class is not known ahead of time. Compute
|
||||
* the fixed slot count here, which will feed into call objects created
|
||||
* off of the bindings.
|
||||
*/
|
||||
uint32_t slots = child.slotSpan();
|
||||
gc::AllocKind kind = gc::GetGCObjectKind(slots);
|
||||
|
||||
/*
|
||||
* Make sure that the arguments and variables in the call object all
|
||||
* end up in a contiguous range of slots. We need this to be able to
|
||||
* embed the args/vars arrays in the TypeScriptNesting for the function
|
||||
* after the call object's frame has finished.
|
||||
*/
|
||||
uint32_t nfixed = gc::GetGCKindSlots(kind);
|
||||
if (nfixed < slots) {
|
||||
nfixed = CallObject::RESERVED_SLOTS;
|
||||
JS_ASSERT(gc::GetGCKindSlots(gc::GetGCObjectKind(nfixed)) == CallObject::RESERVED_SLOTS);
|
||||
}
|
||||
|
||||
shape->setNumFixedSlots(nfixed);
|
||||
}
|
||||
return shape;
|
||||
return cx->propertyTree().getChild(cx, this, nfixed, child);
|
||||
}
|
||||
|
||||
/* static */ Shape *
|
||||
|
@ -569,7 +569,6 @@ js::XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript)
|
||||
/* originPrincipals = */ NULL,
|
||||
/* compileAndGo = */ false,
|
||||
!!(scriptBits & (1 << NoScriptRval)),
|
||||
/* globalObject = */ NULL,
|
||||
version_,
|
||||
/* staticLevel = */ 0);
|
||||
if (!script || !JSScript::partiallyInit(cx, script,
|
||||
@ -1076,9 +1075,8 @@ ScriptDataSize(uint32_t length, uint32_t nsrcnotes, uint32_t natoms,
|
||||
JSScript *
|
||||
JSScript::Create(JSContext *cx, bool savedCallerFun, JSPrincipals *principals,
|
||||
JSPrincipals *originPrincipals, bool compileAndGo, bool noScriptRval,
|
||||
GlobalObject *globalObject_, JSVersion version, unsigned staticLevel)
|
||||
JSVersion version, unsigned staticLevel)
|
||||
{
|
||||
Rooted<GlobalObject*> globalObject(cx, globalObject_);
|
||||
JSScript *script = js_NewGCScript(cx);
|
||||
if (!script)
|
||||
return NULL;
|
||||
@ -1101,8 +1099,6 @@ JSScript::Create(JSContext *cx, bool savedCallerFun, JSPrincipals *principals,
|
||||
script->compileAndGo = compileAndGo;
|
||||
script->noScriptRval = noScriptRval;
|
||||
|
||||
script->globalObject = globalObject;
|
||||
|
||||
script->version = version;
|
||||
JS_ASSERT(script->getVersion() == version); // assert that no overflow occurred
|
||||
|
||||
@ -1729,8 +1725,7 @@ js::CloneScript(JSContext *cx, HandleScript src)
|
||||
JSScript *dst = JSScript::Create(cx, src->savedCallerFun,
|
||||
cx->compartment->principals, src->originPrincipals,
|
||||
src->compileAndGo, src->noScriptRval,
|
||||
/* globalObject = */ NULL, src->getVersion(),
|
||||
src->staticLevel);
|
||||
src->getVersion(), src->staticLevel);
|
||||
if (!dst) {
|
||||
Foreground::free_(data);
|
||||
return NULL;
|
||||
@ -1949,8 +1944,7 @@ JSScript::changeStepModeCount(JSContext *cx, int delta)
|
||||
}
|
||||
|
||||
BreakpointSite *
|
||||
JSScript::getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc,
|
||||
GlobalObject *scriptGlobal)
|
||||
JSScript::getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc)
|
||||
{
|
||||
JS_ASSERT(size_t(pc - code) < length);
|
||||
|
||||
@ -1969,11 +1963,6 @@ JSScript::getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc,
|
||||
debug->numSites++;
|
||||
}
|
||||
|
||||
if (site->scriptGlobal)
|
||||
JS_ASSERT_IF(scriptGlobal, site->scriptGlobal == scriptGlobal);
|
||||
else
|
||||
site->scriptGlobal = scriptGlobal;
|
||||
|
||||
return site;
|
||||
}
|
||||
|
||||
@ -2060,17 +2049,11 @@ JSScript::markChildren(JSTracer *trc)
|
||||
if (function())
|
||||
MarkObject(trc, &function_, "function");
|
||||
|
||||
if (!isCachedEval && globalObject)
|
||||
MarkObject(trc, &globalObject, "object");
|
||||
|
||||
if (IS_GC_MARKING_TRACER(trc) && filename)
|
||||
MarkScriptFilename(trc->runtime, filename);
|
||||
|
||||
bindings.trace(trc);
|
||||
|
||||
if (types)
|
||||
types->trace(trc);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
for (int constructing = 0; constructing <= 1; constructing++) {
|
||||
for (int barriers = 0; barriers <= 1; barriers++) {
|
||||
|
@ -407,18 +407,8 @@ struct JSScript : public js::gc::Cell
|
||||
JSPrincipals *principals;/* principals for this script */
|
||||
JSPrincipals *originPrincipals; /* see jsapi.h 'originPrincipals' comment */
|
||||
|
||||
/*
|
||||
* A global object for the script.
|
||||
* - All scripts returned by JSAPI functions (JS_CompileScript,
|
||||
* JS_CompileUTF8File, etc.) have a non-null globalObject.
|
||||
* - A function script has a globalObject if the function comes from a
|
||||
* compile-and-go script.
|
||||
* - Temporary scripts created by obj_eval, JS_EvaluateScript, and
|
||||
* similar functions never have the globalObject field set; for such
|
||||
* scripts the global should be extracted from the JS frame that
|
||||
* execute scripts.
|
||||
*/
|
||||
js::HeapPtr<js::GlobalObject, JSScript*> globalObject;
|
||||
/* The next link in the eval cache */
|
||||
js::HeapPtrScript evalHashLink;
|
||||
|
||||
/* Persistent type information retained across GCs. */
|
||||
js::types::TypeScript *types;
|
||||
@ -508,14 +498,9 @@ struct JSScript : public js::gc::Cell
|
||||
undefined properties in this
|
||||
script */
|
||||
bool hasSingletons:1; /* script has singleton objects */
|
||||
bool isOuterFunction:1; /* function is heavyweight, with inner functions */
|
||||
bool isInnerFunction:1; /* function is directly nested in a heavyweight
|
||||
* outer function */
|
||||
bool isActiveEval:1; /* script came from eval(), and is still active */
|
||||
bool isCachedEval:1; /* script came from eval(), and is in eval cache */
|
||||
bool uninlineable:1; /* script is considered uninlineable by analysis */
|
||||
bool reentrantOuterFunction:1; /* outer function marked reentrant */
|
||||
bool typesPurged:1; /* TypeScript has been purged at some point */
|
||||
#ifdef JS_METHODJIT
|
||||
bool debugMode:1; /* script was compiled in debug mode */
|
||||
bool failedBoundsCheck:1; /* script has had hoisted bounds checks fail */
|
||||
@ -543,8 +528,7 @@ struct JSScript : public js::gc::Cell
|
||||
static JSScript *Create(JSContext *cx, bool savedCallerFun,
|
||||
JSPrincipals *principals, JSPrincipals *originPrincipals,
|
||||
bool compileAndGo, bool noScriptRval,
|
||||
js::GlobalObject *globalObject, JSVersion version,
|
||||
unsigned staticLevel);
|
||||
JSVersion version, unsigned staticLevel);
|
||||
|
||||
// Three ways ways to initialize a JSScript. Callers of partiallyInit()
|
||||
// and fullyInitTrivial() are responsible for notifying the debugger after
|
||||
@ -592,9 +576,6 @@ struct JSScript : public js::gc::Cell
|
||||
return needsArgsObj() && !strictModeCode;
|
||||
}
|
||||
|
||||
/* Hash table chaining for JSCompartment::evalCache. */
|
||||
JSScript *&evalHashLink() { return *globalObject.unsafeGetUnioned(); }
|
||||
|
||||
/*
|
||||
* Original compiled function for the script, if it has a function.
|
||||
* NULL for global and eval scripts.
|
||||
@ -602,6 +583,9 @@ struct JSScript : public js::gc::Cell
|
||||
JSFunction *function() const { return function_; }
|
||||
void setFunction(JSFunction *fun);
|
||||
|
||||
/* Return whether this script was compiled for 'eval' */
|
||||
bool isForEval() { return isCachedEval || isActiveEval; }
|
||||
|
||||
#ifdef DEBUG
|
||||
unsigned id();
|
||||
#else
|
||||
@ -612,12 +596,10 @@ struct JSScript : public js::gc::Cell
|
||||
inline bool ensureHasTypes(JSContext *cx);
|
||||
|
||||
/*
|
||||
* Ensure the script has scope and bytecode analysis information.
|
||||
* Performed when the script first runs, or first runs after a TypeScript
|
||||
* GC purge. If scope is NULL then the script must already have types with
|
||||
* scope information.
|
||||
* Ensure the script has bytecode analysis information. Performed when the
|
||||
* script first runs, or first runs after a TypeScript GC purge.
|
||||
*/
|
||||
inline bool ensureRanAnalysis(JSContext *cx, JSObject *scope);
|
||||
inline bool ensureRanAnalysis(JSContext *cx);
|
||||
|
||||
/* Ensure the script has type inference analysis information. */
|
||||
inline bool ensureRanInference(JSContext *cx);
|
||||
@ -629,15 +611,7 @@ struct JSScript : public js::gc::Cell
|
||||
inline bool hasGlobal() const;
|
||||
inline bool hasClearedGlobal() const;
|
||||
|
||||
inline js::GlobalObject * global() const;
|
||||
inline js::types::TypeScriptNesting *nesting() const;
|
||||
|
||||
inline void clearNesting();
|
||||
|
||||
/* Return creation time global or null. */
|
||||
js::GlobalObject *getGlobalObjectOrNull() const {
|
||||
return (isCachedEval || isActiveEval) ? NULL : globalObject.get();
|
||||
}
|
||||
inline js::GlobalObject &global() const;
|
||||
|
||||
private:
|
||||
bool makeTypes(JSContext *cx);
|
||||
@ -873,8 +847,7 @@ struct JSScript : public js::gc::Cell
|
||||
return hasDebugScript ? debugScript()->breakpoints[pc - code] : NULL;
|
||||
}
|
||||
|
||||
js::BreakpointSite *getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc,
|
||||
js::GlobalObject *scriptGlobal);
|
||||
js::BreakpointSite *getOrCreateBreakpointSite(JSContext *cx, jsbytecode *pc);
|
||||
|
||||
void destroyBreakpointSite(js::FreeOp *fop, jsbytecode *pc);
|
||||
|
||||
|
@ -191,41 +191,24 @@ JSScript::hasGlobal() const
|
||||
* which have had their scopes cleared. compileAndGo code should not run
|
||||
* anymore against such globals.
|
||||
*/
|
||||
JS_ASSERT(types && types->hasScope());
|
||||
js::GlobalObject *obj = types->global;
|
||||
return obj && !obj->isCleared();
|
||||
return compileAndGo && !global().isCleared();
|
||||
}
|
||||
|
||||
inline js::GlobalObject *
|
||||
inline js::GlobalObject &
|
||||
JSScript::global() const
|
||||
{
|
||||
JS_ASSERT(hasGlobal());
|
||||
return types->global;
|
||||
/*
|
||||
* A JSScript always marks its compartment's global (via bindings) so we
|
||||
* can assert that maybeGlobal is non-null here.
|
||||
*/
|
||||
return *compartment()->maybeGlobal();
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSScript::hasClearedGlobal() const
|
||||
{
|
||||
JS_ASSERT(types && types->hasScope());
|
||||
js::GlobalObject *obj = types->global;
|
||||
return obj && obj->isCleared();
|
||||
}
|
||||
|
||||
inline js::types::TypeScriptNesting *
|
||||
JSScript::nesting() const
|
||||
{
|
||||
JS_ASSERT(function() && types && types->hasScope());
|
||||
return types->nesting;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSScript::clearNesting()
|
||||
{
|
||||
js::types::TypeScriptNesting *nesting = this->nesting();
|
||||
if (nesting) {
|
||||
js::Foreground::delete_(nesting);
|
||||
types->nesting = NULL;
|
||||
}
|
||||
JS_ASSERT(types);
|
||||
return global().isCleared();
|
||||
}
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
|
@ -59,7 +59,7 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript,
|
||||
isConstructing(isConstructing),
|
||||
outerChunk(outerJIT()->chunkDescriptor(chunkIndex)),
|
||||
ssa(cx, outerScript),
|
||||
globalObj(cx, outerScript->hasGlobal() ? outerScript->global() : NULL),
|
||||
globalObj(cx, 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),
|
||||
@ -135,7 +135,7 @@ mjit::Compiler::checkAnalysis(HandleScript script)
|
||||
return Compile_Abort;
|
||||
}
|
||||
|
||||
if (!script->ensureRanAnalysis(cx, NULL))
|
||||
if (!script->ensureRanAnalysis(cx))
|
||||
return Compile_Error;
|
||||
|
||||
if (!script->analysis()->jaegerCompileable()) {
|
||||
@ -190,7 +190,7 @@ mjit::Compiler::scanInlineCalls(uint32_t index, uint32_t depth)
|
||||
|
||||
/* Don't inline from functions which could have a non-global scope object. */
|
||||
if (!script->hasGlobal() ||
|
||||
script->global() != globalObj ||
|
||||
&script->global() != globalObj ||
|
||||
(script->function() && script->function()->getParent() != globalObj) ||
|
||||
(script->function() && script->function()->isHeavyweight()) ||
|
||||
script->isActiveEval) {
|
||||
@ -316,7 +316,7 @@ mjit::Compiler::scanInlineCalls(uint32_t index, uint32_t depth)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!script->types || !script->types->hasScope()) {
|
||||
if (!script->types) {
|
||||
okay = false;
|
||||
break;
|
||||
}
|
||||
@ -633,7 +633,7 @@ mjit::SetChunkLimit(uint32_t limit)
|
||||
JITScript *
|
||||
MakeJITScript(JSContext *cx, JSScript *script)
|
||||
{
|
||||
if (!script->ensureRanAnalysis(cx, NULL))
|
||||
if (!script->ensureRanAnalysis(cx))
|
||||
return NULL;
|
||||
|
||||
ScriptAnalysis *analysis = script->analysis();
|
||||
@ -1097,9 +1097,7 @@ mjit::Compiler::generatePrologue()
|
||||
* set for global and eval frames, and will have been set by
|
||||
* HeavyweightFunctionPrologue for heavyweight function frames.
|
||||
*/
|
||||
if (!script->function()->isHeavyweight() &&
|
||||
(analysis->usesScopeChain() || script->nesting()))
|
||||
{
|
||||
if (!script->function()->isHeavyweight() && analysis->usesScopeChain()) {
|
||||
RegisterID t0 = Registers::ReturnReg;
|
||||
Jump hasScope = masm.branchTest32(Assembler::NonZero,
|
||||
FrameFlagsAddress(), Imm32(StackFrame::HAS_SCOPECHAIN));
|
||||
@ -1145,42 +1143,10 @@ mjit::Compiler::generatePrologue()
|
||||
if (script->function()->isHeavyweight()) {
|
||||
prepareStubCall(Uses(0));
|
||||
INLINE_STUBCALL(stubs::HeavyweightFunctionPrologue, REJOIN_FUNCTION_PROLOGUE);
|
||||
} else if (types::TypeScriptNesting *nesting = script->nesting()) {
|
||||
/*
|
||||
* Inline the common case for the nesting prologue: the
|
||||
* function is a non-heavyweight inner function with no
|
||||
* children of its own. We ensure during inference that the
|
||||
* outer function does not add scope objects for 'let' or
|
||||
* 'with', so that the frame's scope chain will be
|
||||
* the parent's call object, and if it differs from the
|
||||
* parent's current activation then the parent is reentrant.
|
||||
*/
|
||||
JSScript *parent = nesting->parent;
|
||||
JS_ASSERT(parent);
|
||||
JS_ASSERT_IF(parent->hasAnalysis() && parent->analysis()->ranBytecode(),
|
||||
!parent->analysis()->addsScopeObjects());
|
||||
|
||||
RegisterID t0 = Registers::ReturnReg;
|
||||
masm.move(ImmPtr(&parent->nesting()->activeCall), t0);
|
||||
masm.loadPtr(Address(t0), t0);
|
||||
|
||||
Address scopeChain(JSFrameReg, StackFrame::offsetOfScopeChain());
|
||||
Jump mismatch = masm.branchPtr(Assembler::NotEqual, t0, scopeChain);
|
||||
masm.add32(Imm32(1), AbsoluteAddress(&nesting->activeFrames));
|
||||
|
||||
masm.load32(FrameFlagsAddress(), t0);
|
||||
masm.or32(Imm32(StackFrame::HAS_NESTING), t0);
|
||||
masm.store32(t0, FrameFlagsAddress());
|
||||
|
||||
stubcc.linkExitDirect(mismatch, stubcc.masm.label());
|
||||
OOL_STUBCALL(stubs::TypeNestingPrologue, REJOIN_FUNCTION_PROLOGUE);
|
||||
stubcc.crossJump(stubcc.masm.jump(), masm.label());
|
||||
}
|
||||
|
||||
if (isConstructing) {
|
||||
if (!constructThis())
|
||||
return Compile_Error;
|
||||
}
|
||||
if (isConstructing && !constructThis())
|
||||
return Compile_Error;
|
||||
}
|
||||
|
||||
CompileStatus status = methodEntryHelper();
|
||||
@ -3808,10 +3774,6 @@ mjit::Compiler::emitReturn(FrameEntry *fe)
|
||||
INLINE_STUBCALL(stubs::Epilogue, REJOIN_NONE);
|
||||
} else {
|
||||
profilingPopHelper();
|
||||
|
||||
if (script->function() && script->nesting()) {
|
||||
masm.sub32(Imm32(1), AbsoluteAddress(&script->nesting()->activeFrames));
|
||||
}
|
||||
}
|
||||
|
||||
emitReturnValue(&masm, fe);
|
||||
@ -5397,42 +5359,6 @@ mjit::Compiler::jsop_setprop(PropertyName *name, bool popGuaranteed)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a SETNAME to a variable of a non-reentrant outer function,
|
||||
* set the variable's slot directly for the active call object.
|
||||
*/
|
||||
if (cx->typeInferenceEnabled() && js_CodeSpec[*PC].format & JOF_NAME) {
|
||||
ScriptAnalysis::NameAccess access =
|
||||
analysis->resolveNameAccess(cx, NameToId(name), true);
|
||||
if (access.nesting) {
|
||||
/* Use a SavedReg so it isn't clobbered by the stub call. */
|
||||
RegisterID nameReg = frame.allocReg(Registers::SavedRegs).reg();
|
||||
Address address = frame.loadNameAddress(access, nameReg);
|
||||
|
||||
#ifdef JSGC_INCREMENTAL_MJ
|
||||
/* Write barrier. */
|
||||
if (cx->compartment->needsBarrier()) {
|
||||
stubcc.linkExit(masm.jump(), Uses(0));
|
||||
stubcc.leave();
|
||||
|
||||
/* sync() may have overwritten nameReg, so we reload its data. */
|
||||
JS_ASSERT(address.base == nameReg);
|
||||
stubcc.masm.move(ImmPtr(access.basePointer()), nameReg);
|
||||
stubcc.masm.loadPtr(Address(nameReg), nameReg);
|
||||
stubcc.masm.addPtr(Imm32(address.offset), nameReg, Registers::ArgReg1);
|
||||
|
||||
OOL_STUBCALL(stubs::WriteBarrier, REJOIN_NONE);
|
||||
stubcc.rejoin(Changes(0));
|
||||
}
|
||||
#endif
|
||||
|
||||
frame.storeTo(rhs, address, popGuaranteed);
|
||||
frame.shimmy(1);
|
||||
frame.freeReg(address.base);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the property directly if we are accessing a known object which
|
||||
* always has the property in a particular inline slot.
|
||||
@ -5619,24 +5545,6 @@ mjit::Compiler::jsop_setprop(PropertyName *name, bool popGuaranteed)
|
||||
void
|
||||
mjit::Compiler::jsop_name(PropertyName *name, JSValueType type)
|
||||
{
|
||||
/*
|
||||
* If this is a NAME for a variable of a non-reentrant outer function, get
|
||||
* the variable's slot directly for the active call object. We always need
|
||||
* to check for undefined, however.
|
||||
*/
|
||||
if (cx->typeInferenceEnabled()) {
|
||||
ScriptAnalysis::NameAccess access =
|
||||
analysis->resolveNameAccess(cx, NameToId(name), true);
|
||||
if (access.nesting) {
|
||||
Address address = frame.loadNameAddress(access);
|
||||
JSValueType type = knownPushedType(0);
|
||||
BarrierState barrier = pushAddressMaybeBarrier(address, type, true,
|
||||
/* testUndefined = */ true);
|
||||
finishBarrier(barrier, REJOIN_GETTER, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PICGenInfo pic(ic::PICInfo::NAME, JSOp(*PC));
|
||||
|
||||
RESERVE_IC_SPACE(masm);
|
||||
@ -5693,24 +5601,6 @@ mjit::Compiler::jsop_name(PropertyName *name, JSValueType type)
|
||||
bool
|
||||
mjit::Compiler::jsop_xname(PropertyName *name)
|
||||
{
|
||||
/*
|
||||
* If this is a GETXPROP for a variable of a non-reentrant outer function,
|
||||
* treat in the same way as a NAME.
|
||||
*/
|
||||
if (cx->typeInferenceEnabled()) {
|
||||
ScriptAnalysis::NameAccess access =
|
||||
analysis->resolveNameAccess(cx, NameToId(name), true);
|
||||
if (access.nesting) {
|
||||
frame.pop();
|
||||
Address address = frame.loadNameAddress(access);
|
||||
JSValueType type = knownPushedType(0);
|
||||
BarrierState barrier = pushAddressMaybeBarrier(address, type, true,
|
||||
/* testUndefined = */ true);
|
||||
finishBarrier(barrier, REJOIN_GETTER, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
PICGenInfo pic(ic::PICInfo::XNAME, JSOp(*PC));
|
||||
|
||||
FrameEntry *fe = frame.peek(-1);
|
||||
@ -5773,23 +5663,6 @@ mjit::Compiler::jsop_xname(PropertyName *name)
|
||||
void
|
||||
mjit::Compiler::jsop_bindname(PropertyName *name)
|
||||
{
|
||||
/*
|
||||
* If this is a BINDNAME for a variable of a non-reentrant outer function,
|
||||
* the object is definitely the outer function's active call object.
|
||||
*/
|
||||
if (cx->typeInferenceEnabled()) {
|
||||
ScriptAnalysis::NameAccess access =
|
||||
analysis->resolveNameAccess(cx, NameToId(name), true);
|
||||
if (access.nesting) {
|
||||
RegisterID reg = frame.allocReg();
|
||||
CallObject **pobj = &access.nesting->activeCall;
|
||||
masm.move(ImmPtr(pobj), reg);
|
||||
masm.loadPtr(Address(reg), reg);
|
||||
frame.pushTypedPayload(JSVAL_TYPE_OBJECT, reg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PICGenInfo pic(ic::PICInfo::BIND, JSOp(*PC));
|
||||
|
||||
// This code does not check the frame flags to see if scopeChain has been
|
||||
@ -5930,38 +5803,18 @@ mjit::Compiler::jsop_aliasedVar(ScopeCoordinate sc, bool get, bool poppedAfter)
|
||||
for (unsigned i = 0; i < sc.hops; i++)
|
||||
masm.loadPayload(Address(reg, ScopeObject::offsetOfEnclosingScope()), reg);
|
||||
|
||||
/*
|
||||
* TODO bug 753158: Call and Block objects should use the same layout
|
||||
* strategy: up to the maximum numFixedSlots and overflow (if any) in
|
||||
* dynamic slots. For now, we special case for different layouts:
|
||||
*/
|
||||
Shape *shape;
|
||||
if (StaticBlockObject *block = ScopeCoordinateBlockChain(script, PC))
|
||||
shape = block->lastProperty();
|
||||
else
|
||||
shape = script->bindings.lastShape();
|
||||
|
||||
Address addr;
|
||||
StaticBlockObject *block = ScopeCoordinateBlockChain(script, PC);
|
||||
if (block) {
|
||||
/*
|
||||
* Block objects use a fixed AllocKind which means an invariant number
|
||||
* of fixed slots. Any slot below the fixed slot count is inline, any
|
||||
* slot over is in the dynamic slots.
|
||||
*/
|
||||
uint32_t nfixed = gc::GetGCKindSlots(BlockObject::FINALIZE_KIND);
|
||||
if (nfixed <= sc.slot) {
|
||||
masm.loadPtr(Address(reg, JSObject::offsetOfSlots()), reg);
|
||||
addr = Address(reg, (sc.slot - nfixed) * sizeof(Value));
|
||||
} else {
|
||||
addr = Address(reg, JSObject::getFixedSlotOffset(sc.slot));
|
||||
}
|
||||
if (shape->numFixedSlots() <= sc.slot) {
|
||||
masm.loadPtr(Address(reg, JSObject::offsetOfSlots()), reg);
|
||||
addr = Address(reg, (sc.slot - shape->numFixedSlots()) * sizeof(Value));
|
||||
} else {
|
||||
/*
|
||||
* Using special-case hackery in Shape::getChildBinding, CallObject
|
||||
* slots are either altogether in fixed slots or altogether in dynamic
|
||||
* slots (by having numFixed == RESERVED_SLOTS).
|
||||
*/
|
||||
if (script->bindings.lastShape()->numFixedSlots() <= sc.slot) {
|
||||
masm.loadPtr(Address(reg, JSObject::offsetOfSlots()), reg);
|
||||
addr = Address(reg, (sc.slot - CallObject::RESERVED_SLOTS) * sizeof(Value));
|
||||
} else {
|
||||
addr = Address(reg, JSObject::getFixedSlotOffset(sc.slot));
|
||||
}
|
||||
addr = Address(reg, JSObject::getFixedSlotOffset(sc.slot));
|
||||
}
|
||||
|
||||
if (get) {
|
||||
|
@ -882,24 +882,6 @@ FrameState::syncAndForgetFe(FrameEntry *fe, bool markSynced)
|
||||
fe->data.setMemory();
|
||||
}
|
||||
|
||||
inline JSC::MacroAssembler::Address
|
||||
FrameState::loadNameAddress(const analyze::ScriptAnalysis::NameAccess &access, RegisterID reg)
|
||||
{
|
||||
JS_ASSERT(access.script && access.nesting);
|
||||
|
||||
masm.move(ImmPtr(access.basePointer()), reg);
|
||||
masm.loadPtr(Address(reg), reg);
|
||||
|
||||
return Address(reg, access.index * sizeof(Value));
|
||||
}
|
||||
|
||||
inline JSC::MacroAssembler::Address
|
||||
FrameState::loadNameAddress(const analyze::ScriptAnalysis::NameAccess &access)
|
||||
{
|
||||
RegisterID reg = allocReg();
|
||||
return loadNameAddress(access, reg);
|
||||
}
|
||||
|
||||
inline void
|
||||
FrameState::forgetLoopReg(FrameEntry *fe)
|
||||
{
|
||||
|
@ -929,14 +929,6 @@ class FrameState
|
||||
inline void syncAndForgetFe(FrameEntry *fe, bool markSynced = false);
|
||||
inline void forgetLoopReg(FrameEntry *fe);
|
||||
|
||||
/*
|
||||
* Get an address for the specified name access in another script.
|
||||
* The compiler owns the result's base register.
|
||||
*/
|
||||
inline Address loadNameAddress(const analyze::ScriptAnalysis::NameAccess &access);
|
||||
inline Address loadNameAddress(const analyze::ScriptAnalysis::NameAccess &access,
|
||||
RegisterID reg);
|
||||
|
||||
private:
|
||||
inline AnyRegisterID allocAndLoadReg(FrameEntry *fe, bool fp, RematInfo::RematType type);
|
||||
inline void forgetReg(AnyRegisterID reg);
|
||||
|
@ -562,7 +562,7 @@ js_InternalThrow(VMFrame &f)
|
||||
*/
|
||||
cx->jaegerRuntime().setLastUnfinished(Jaeger_Unfinished);
|
||||
|
||||
if (!script->ensureRanAnalysis(cx, NULL)) {
|
||||
if (!script->ensureRanAnalysis(cx)) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
}
|
||||
@ -736,7 +736,7 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
|
||||
JSOp op = JSOp(*pc);
|
||||
const JSCodeSpec *cs = &js_CodeSpec[op];
|
||||
|
||||
if (!script->ensureRanAnalysis(cx, NULL)) {
|
||||
if (!script->ensureRanAnalysis(cx)) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return js_InternalThrow(f);
|
||||
}
|
||||
|
@ -1618,12 +1618,6 @@ stubs::HeavyweightFunctionPrologue(VMFrame &f)
|
||||
THROW();
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
stubs::TypeNestingPrologue(VMFrame &f)
|
||||
{
|
||||
f.fp()->jitTypeNestingPrologue(f.cx);
|
||||
}
|
||||
|
||||
void JS_FASTCALL
|
||||
stubs::Epilogue(VMFrame &f)
|
||||
{
|
||||
|
@ -170,7 +170,6 @@ void JS_FASTCALL Exception(VMFrame &f);
|
||||
|
||||
void JS_FASTCALL StrictEvalPrologue(VMFrame &f);
|
||||
void JS_FASTCALL HeavyweightFunctionPrologue(VMFrame &f);
|
||||
void JS_FASTCALL TypeNestingPrologue(VMFrame &f);
|
||||
|
||||
void JS_FASTCALL AnyFrameEpilogue(VMFrame &f);
|
||||
void JS_FASTCALL Epilogue(VMFrame &f);
|
||||
|
@ -221,7 +221,7 @@ class Debugger::FrameRange
|
||||
/*** Breakpoints *********************************************************************************/
|
||||
|
||||
BreakpointSite::BreakpointSite(JSScript *script, jsbytecode *pc)
|
||||
: script(script), pc(pc), scriptGlobal(NULL), enabledCount(0),
|
||||
: script(script), pc(pc), enabledCount(0),
|
||||
trapHandler(NULL), trapClosure(UndefinedValue())
|
||||
{
|
||||
JS_ASSERT(!script->hasBreakpointsAt(pc));
|
||||
@ -2105,9 +2105,10 @@ class Debugger::ScriptQuery {
|
||||
for (CompartmentSet::Range r = compartments.all(); !r.empty(); r.popFront()) {
|
||||
for (gc::CellIter i(r.front(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
GlobalObject *global = script->getGlobalObjectOrNull();
|
||||
if (global && !consider(script, global, vector))
|
||||
return false;
|
||||
if (script->hasGlobal() && !script->isForEval()) {
|
||||
if (!consider(script, &script->global(), vector))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2120,11 +2121,10 @@ class Debugger::ScriptQuery {
|
||||
JSScript *script = fri.script();
|
||||
|
||||
/*
|
||||
* If eval scripts never have global objects set, then we don't need
|
||||
* to check the existing script vector for duplicates, since we only
|
||||
* include scripts with globals above.
|
||||
* Eval scripts were not considered above so we don't need to
|
||||
* check the existing script vector for duplicates.
|
||||
*/
|
||||
JS_ASSERT(!script->getGlobalObjectOrNull());
|
||||
JS_ASSERT(script->isForEval());
|
||||
|
||||
GlobalObject *global = &fri.fp()->global();
|
||||
if (!consider(script, global, vector))
|
||||
@ -2861,19 +2861,7 @@ Debugger::observesScript(JSScript *script) const
|
||||
{
|
||||
if (!enabled)
|
||||
return false;
|
||||
|
||||
/* Does the script have a global stored in it? */
|
||||
if (GlobalObject *global = script->getGlobalObjectOrNull())
|
||||
return observesGlobal(global);
|
||||
|
||||
/* Is the script in a compartment this Debugger is debugging? */
|
||||
JSCompartment *comp = script->compartment();
|
||||
for (GlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
|
||||
if (r.front()->compartment() == comp)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return observesGlobal(&script->global());
|
||||
}
|
||||
|
||||
static JSBool
|
||||
@ -2897,8 +2885,7 @@ DebuggerScript_setBreakpoint(JSContext *cx, unsigned argc, Value *vp)
|
||||
return false;
|
||||
|
||||
jsbytecode *pc = script->code + offset;
|
||||
Rooted<GlobalObject *> scriptGlobal(cx, script->getGlobalObjectOrNull());
|
||||
BreakpointSite *site = script->getOrCreateBreakpointSite(cx, pc, scriptGlobal);
|
||||
BreakpointSite *site = script->getOrCreateBreakpointSite(cx, pc);
|
||||
if (!site)
|
||||
return false;
|
||||
site->inc(cx->runtime->defaultFreeOp());
|
||||
@ -3422,9 +3409,8 @@ js::EvaluateInEnv(JSContext *cx, Handle<Env*> env, StackFrame *fp, const jschar
|
||||
JSPrincipals *prin = fp->scopeChain()->principals(cx);
|
||||
bool compileAndGo = true;
|
||||
bool noScriptRval = false;
|
||||
bool needScriptGlobal = true;
|
||||
JSScript *script = frontend::CompileScript(cx, env, fp, prin, prin,
|
||||
compileAndGo, noScriptRval, needScriptGlobal,
|
||||
compileAndGo, noScriptRval,
|
||||
chars, length, filename, lineno,
|
||||
cx->findVersion(), NULL, /* staticLimit = */ 1);
|
||||
if (!script)
|
||||
|
@ -355,13 +355,6 @@ class BreakpointSite {
|
||||
jsbytecode * const pc;
|
||||
|
||||
private:
|
||||
/*
|
||||
* The holder object for script, if known, else NULL. This is NULL for
|
||||
* cached eval scripts and for JSD1 traps. It is always non-null for JSD2
|
||||
* breakpoints in held scripts.
|
||||
*/
|
||||
GlobalObject *scriptGlobal;
|
||||
|
||||
JSCList breakpoints; /* cyclic list of all js::Breakpoints at this instruction */
|
||||
size_t enabledCount; /* number of breakpoints in the list that are enabled */
|
||||
JSTrapHandler trapHandler; /* jsdbgapi trap state */
|
||||
@ -374,7 +367,6 @@ class BreakpointSite {
|
||||
Breakpoint *firstBreakpoint() const;
|
||||
bool hasBreakpoint(Breakpoint *bp);
|
||||
bool hasTrap() const { return !!trapHandler; }
|
||||
GlobalObject *getScriptGlobal() const { return scriptGlobal; }
|
||||
|
||||
void inc(FreeOp *fop);
|
||||
void dec(FreeOp *fop);
|
||||
|
@ -119,7 +119,6 @@ GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
|
||||
/* originPrincipals = */ NULL,
|
||||
/* compileAndGo = */ false,
|
||||
/* noScriptRval = */ true,
|
||||
/* globalObject = */ NULL,
|
||||
JSVERSION_DEFAULT,
|
||||
/* staticLevel = */ 0));
|
||||
if (!script || !JSScript::fullyInitTrivial(cx, script))
|
||||
|
@ -150,17 +150,6 @@ js::ObjectImpl::getSlotRange(uint32_t start, uint32_t length,
|
||||
getSlotRangeUnchecked(start, length, fixedStart, fixedEnd, slotsStart, slotsEnd);
|
||||
}
|
||||
|
||||
inline bool
|
||||
js::ObjectImpl::hasContiguousSlots(uint32_t start, uint32_t count) const
|
||||
{
|
||||
/*
|
||||
* Check that the range [start, start+count) is either all inline or all
|
||||
* out of line.
|
||||
*/
|
||||
MOZ_ASSERT(slotInRange(start + count, SENTINEL_ALLOWED));
|
||||
return start + count <= numFixedSlots() || start >= numFixedSlots();
|
||||
}
|
||||
|
||||
inline void
|
||||
js::ObjectImpl::invalidateSlotRange(uint32_t start, uint32_t length)
|
||||
{
|
||||
|
@ -1043,8 +1043,6 @@ class ObjectImpl : public gc::Cell
|
||||
friend struct Shape;
|
||||
friend class NewObjectCache;
|
||||
|
||||
inline bool hasContiguousSlots(uint32_t start, uint32_t count) const;
|
||||
|
||||
inline void invalidateSlotRange(uint32_t start, uint32_t count);
|
||||
inline void initializeSlotRange(uint32_t start, uint32_t count);
|
||||
|
||||
|
@ -101,25 +101,6 @@ CallObject::setVar(unsigned i, const Value &v, MaybeCheckAliasing checkAliasing)
|
||||
setSlot(RESERVED_SLOTS + fun.nargs + i, v);
|
||||
}
|
||||
|
||||
inline HeapSlotArray
|
||||
CallObject::argArray()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
JSFunction &fun = callee();
|
||||
JS_ASSERT(hasContiguousSlots(RESERVED_SLOTS, fun.nargs));
|
||||
#endif
|
||||
return HeapSlotArray(getSlotAddress(RESERVED_SLOTS));
|
||||
}
|
||||
|
||||
inline HeapSlotArray
|
||||
CallObject::varArray()
|
||||
{
|
||||
JSFunction &fun = callee();
|
||||
JS_ASSERT(hasContiguousSlots(RESERVED_SLOTS + fun.nargs,
|
||||
fun.script()->bindings.numVars()));
|
||||
return HeapSlotArray(getSlotAddress(RESERVED_SLOTS + fun.nargs));
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
NestedScopeObject::stackDepth() const
|
||||
{
|
||||
|
@ -111,18 +111,7 @@ CallObject::create(JSContext *cx, JSScript *script, HandleObject enclosing, Hand
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Update the parent for bindings associated with non-compileAndGo scripts,
|
||||
* whose call objects do not have a consistent global variable and need
|
||||
* to be updated dynamically.
|
||||
*/
|
||||
if (&enclosing->global() != obj->getParent()) {
|
||||
JS_ASSERT(obj->getParent() == NULL);
|
||||
Rooted<GlobalObject*> global(cx, &enclosing->global());
|
||||
if (!JSObject::setParent(cx, obj, global))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JS_ASSERT(enclosing->global() == obj->global());
|
||||
if (!obj->asScope().setEnclosingScope(cx, enclosing))
|
||||
return NULL;
|
||||
|
||||
|
@ -152,14 +152,6 @@ class CallObject : public ScopeObject
|
||||
inline const Value &var(unsigned i, MaybeCheckAliasing = CHECK_ALIASING) const;
|
||||
inline void setVar(unsigned i, const Value &v, MaybeCheckAliasing = CHECK_ALIASING);
|
||||
|
||||
/*
|
||||
* Get the actual arrays of arguments and variables. Only call if type
|
||||
* inference is enabled, where we ensure that call object variables are in
|
||||
* contiguous slots (see NewCallObject).
|
||||
*/
|
||||
inline HeapSlotArray argArray();
|
||||
inline HeapSlotArray varArray();
|
||||
|
||||
static JSBool setArgOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp);
|
||||
static JSBool setVarOp(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp);
|
||||
|
||||
|
@ -186,21 +186,9 @@ StackFrame::jitHeavyweightFunctionPrologue(JSContext *cx)
|
||||
pushOnScopeChain(*callobj);
|
||||
flags_ |= HAS_CALL_OBJ;
|
||||
|
||||
if (script()->nesting()) {
|
||||
types::NestingPrologue(cx, this);
|
||||
flags_ |= HAS_NESTING;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void
|
||||
StackFrame::jitTypeNestingPrologue(JSContext *cx)
|
||||
{
|
||||
types::NestingPrologue(cx, this);
|
||||
flags_ |= HAS_NESTING;
|
||||
}
|
||||
|
||||
inline void
|
||||
StackFrame::initVarsToUndefined()
|
||||
{
|
||||
|
@ -256,11 +256,6 @@ StackFrame::prologue(JSContext *cx, bool newType)
|
||||
flags_ |= HAS_CALL_OBJ;
|
||||
}
|
||||
|
||||
if (script()->nesting()) {
|
||||
types::NestingPrologue(cx, this);
|
||||
flags_ |= HAS_NESTING;
|
||||
}
|
||||
|
||||
if (isConstructing()) {
|
||||
RootedObject callee(cx, &this->callee());
|
||||
JSObject *obj = js_CreateThisForFunction(cx, callee, newType);
|
||||
@ -314,8 +309,6 @@ StackFrame::epilogue(JSContext *cx)
|
||||
if (cx->compartment->debugMode())
|
||||
cx->runtime->debugScopes->onPopCall(this, cx);
|
||||
|
||||
if (script()->nesting() && (flags_ & HAS_NESTING))
|
||||
types::NestingEpilogue(this);
|
||||
|
||||
if (isConstructing() && returnValue().isPrimitive())
|
||||
setReturnValue(ObjectValue(constructorThis()));
|
||||
|
@ -207,7 +207,7 @@ enum MaybeCheckAliasing { CHECK_ALIASING = true, DONT_CHECK_ALIASING = false };
|
||||
enum InitialFrameFlags {
|
||||
INITIAL_NONE = 0,
|
||||
INITIAL_CONSTRUCT = 0x40, /* == StackFrame::CONSTRUCTING, asserted below */
|
||||
INITIAL_LOWERED = 0x200000 /* == StackFrame::LOWERED_CALL_APPLY, asserted below */
|
||||
INITIAL_LOWERED = 0x100000 /* == StackFrame::LOWERED_CALL_APPLY, asserted below */
|
||||
};
|
||||
|
||||
enum ExecuteType {
|
||||
@ -245,25 +245,24 @@ class StackFrame
|
||||
/* Function prologue state */
|
||||
HAS_CALL_OBJ = 0x800, /* CallObject created for heavyweight fun */
|
||||
HAS_ARGS_OBJ = 0x1000, /* ArgumentsObject created for needsArgsObj script */
|
||||
HAS_NESTING = 0x2000, /* NestingPrologue called for frame */
|
||||
|
||||
/* Lazy frame initialization */
|
||||
HAS_HOOK_DATA = 0x4000, /* frame has hookData_ set */
|
||||
HAS_ANNOTATION = 0x8000, /* frame has annotation_ set */
|
||||
HAS_RVAL = 0x10000, /* frame has rval_ set */
|
||||
HAS_SCOPECHAIN = 0x20000, /* frame has scopeChain_ set */
|
||||
HAS_PREVPC = 0x40000, /* frame has prevpc_ and prevInline_ set */
|
||||
HAS_BLOCKCHAIN = 0x80000, /* frame has blockChain_ set */
|
||||
HAS_HOOK_DATA = 0x2000, /* frame has hookData_ set */
|
||||
HAS_ANNOTATION = 0x4000, /* frame has annotation_ set */
|
||||
HAS_RVAL = 0x8000, /* frame has rval_ set */
|
||||
HAS_SCOPECHAIN = 0x10000, /* frame has scopeChain_ set */
|
||||
HAS_PREVPC = 0x20000, /* frame has prevpc_ and prevInline_ set */
|
||||
HAS_BLOCKCHAIN = 0x40000, /* frame has blockChain_ set */
|
||||
|
||||
/* Method JIT state */
|
||||
DOWN_FRAMES_EXPANDED = 0x100000, /* inlining in down frames has been expanded */
|
||||
LOWERED_CALL_APPLY = 0x200000, /* Pushed by a lowered call/apply */
|
||||
DOWN_FRAMES_EXPANDED = 0x80000, /* inlining in down frames has been expanded */
|
||||
LOWERED_CALL_APPLY = 0x100000, /* Pushed by a lowered call/apply */
|
||||
|
||||
/* Debugger state */
|
||||
PREV_UP_TO_DATE = 0x400000, /* see DebugScopes::updateLiveScopes */
|
||||
PREV_UP_TO_DATE = 0x200000, /* see DebugScopes::updateLiveScopes */
|
||||
|
||||
/* Used in tracking calls and profiling (see vm/SPSProfiler.cpp) */
|
||||
HAS_PUSHED_SPS_FRAME = 0x800000 /* SPS was notified of enty */
|
||||
HAS_PUSHED_SPS_FRAME = 0x400000 /* SPS was notified of enty */
|
||||
};
|
||||
|
||||
private:
|
||||
@ -370,7 +369,6 @@ class StackFrame
|
||||
|
||||
/* Subsets of 'prologue' called from jit code. */
|
||||
inline bool jitHeavyweightFunctionPrologue(JSContext *cx);
|
||||
inline void jitTypeNestingPrologue(JSContext *cx);
|
||||
bool jitStrictEvalPrologue(JSContext *cx);
|
||||
|
||||
/* Initialize local variables of newly-pushed frame. */
|
||||
|
@ -143,7 +143,6 @@ XDRState<mode>::codeScript(JSScript **scriptp)
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
JS_ASSERT(!script->compileAndGo);
|
||||
script->globalObject = GetCurrentGlobal(cx());
|
||||
js_CallNewScriptHook(cx(), script, NULL);
|
||||
Debugger::onNewScript(cx(), script, NULL);
|
||||
*scriptp = script;
|
||||
|
Loading…
Reference in New Issue
Block a user