mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1202902 - Support non-syntactic extensible lexical scopes. (r=billm)
This commit is contained in:
parent
939c9e2109
commit
31d13da12c
@ -696,7 +696,8 @@ struct CompartmentStats
|
||||
macro(Other, MallocHeap, objectMetadataTable) \
|
||||
macro(Other, MallocHeap, crossCompartmentWrappersTable) \
|
||||
macro(Other, MallocHeap, regexpCompartment) \
|
||||
macro(Other, MallocHeap, savedStacksSet)
|
||||
macro(Other, MallocHeap, savedStacksSet) \
|
||||
macro(Other, MallocHeap, nonSyntacticLexicalScopesTable)
|
||||
|
||||
CompartmentStats()
|
||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||
|
@ -495,8 +495,10 @@ js::ExecuteInGlobalAndReturnScope(JSContext* cx, HandleObject global, HandleScri
|
||||
MOZ_RELEASE_ASSERT(scriptArg->hasNonSyntacticScope());
|
||||
|
||||
RootedScript script(cx, scriptArg);
|
||||
Rooted<GlobalObject*> globalRoot(cx, &global->as<GlobalObject>());
|
||||
if (script->compartment() != cx->compartment()) {
|
||||
Rooted<ScopeObject*> staticScope(cx, StaticNonSyntacticScopeObjects::create(cx, nullptr));
|
||||
Rooted<ScopeObject*> staticScope(cx, &globalRoot->lexicalScope().staticBlock());
|
||||
staticScope = StaticNonSyntacticScopeObjects::create(cx, staticScope);
|
||||
if (!staticScope)
|
||||
return false;
|
||||
script = CloneGlobalScript(cx, staticScope, script);
|
||||
@ -506,8 +508,15 @@ js::ExecuteInGlobalAndReturnScope(JSContext* cx, HandleObject global, HandleScri
|
||||
Debugger::onNewScript(cx, script);
|
||||
}
|
||||
|
||||
Rooted<GlobalObject*> globalRoot(cx, &global->as<GlobalObject>());
|
||||
Rooted<ScopeObject*> scope(cx, NonSyntacticVariablesObject::create(cx, globalRoot));
|
||||
Rooted<ClonedBlockObject*> globalLexical(cx, &globalRoot->lexicalScope());
|
||||
Rooted<ScopeObject*> scope(cx, NonSyntacticVariablesObject::create(cx, globalLexical));
|
||||
if (!scope)
|
||||
return false;
|
||||
|
||||
// Unlike the non-syntactic scope chain API used by the subscript loader,
|
||||
// this API creates a fresh block scope each time.
|
||||
RootedObject enclosingStaticScope(cx, script->enclosingStaticScope());
|
||||
scope = ClonedBlockObject::createNonSyntactic(cx, enclosingStaticScope, scope);
|
||||
if (!scope)
|
||||
return false;
|
||||
|
||||
|
@ -2344,7 +2344,8 @@ EvalReturningScope(JSContext* cx, unsigned argc, Value* vp)
|
||||
global = JS::CurrentGlobalOrNull(cx);
|
||||
}
|
||||
|
||||
RootedObject scope(cx);
|
||||
RootedObject varObj(cx);
|
||||
RootedObject lexicalScope(cx);
|
||||
|
||||
{
|
||||
// If we're switching globals here, ExecuteInGlobalAndReturnScope will
|
||||
@ -2352,14 +2353,29 @@ EvalReturningScope(JSContext* cx, unsigned argc, Value* vp)
|
||||
// executing it.
|
||||
AutoCompartment ac(cx, global);
|
||||
|
||||
if (!js::ExecuteInGlobalAndReturnScope(cx, global, script, &scope))
|
||||
if (!js::ExecuteInGlobalAndReturnScope(cx, global, script, &lexicalScope))
|
||||
return false;
|
||||
|
||||
varObj = lexicalScope->enclosingScope();
|
||||
}
|
||||
|
||||
if (!cx->compartment()->wrap(cx, &scope))
|
||||
RootedObject rv(cx, JS_NewPlainObject(cx));
|
||||
if (!rv)
|
||||
return false;
|
||||
|
||||
args.rval().setObject(*scope);
|
||||
RootedValue varObjVal(cx, ObjectValue(*varObj));
|
||||
if (!cx->compartment()->wrap(cx, &varObjVal))
|
||||
return false;
|
||||
if (!JS_SetProperty(cx, rv, "vars", varObjVal))
|
||||
return false;
|
||||
|
||||
RootedValue lexicalScopeVal(cx, ObjectValue(*lexicalScope));
|
||||
if (!cx->compartment()->wrap(cx, &lexicalScopeVal))
|
||||
return false;
|
||||
if (!JS_SetProperty(cx, rv, "lexicals", lexicalScopeVal))
|
||||
return false;
|
||||
|
||||
args.rval().setObject(*rv);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,8 @@ dbg.onDebuggerStatement = function (frame) {
|
||||
};
|
||||
|
||||
assertEq(log, '');
|
||||
var evalScope = g.evalReturningScope("canary = 'dead'; debugger; // nee", g2);
|
||||
var evalScopes = g.evalReturningScope("canary = 'dead'; let lex = 42; debugger; // nee", g2);
|
||||
assertEq(log, 'ecbd');
|
||||
assertEq(canary, 42);
|
||||
assertEq(evalScope.canary, 'dead');
|
||||
|
||||
assertEq(evalScopes.vars.canary, 'dead');
|
||||
assertEq(evalScopes.lexicals.lex, 42);
|
||||
|
@ -2481,8 +2481,8 @@ BaselineCompiler::emit_JSOP_DEFVAR()
|
||||
return callVM(DefVarInfo);
|
||||
}
|
||||
|
||||
typedef bool (*DefLexicalFn)(JSContext*, HandlePropertyName, unsigned);
|
||||
static const VMFunction DefLexicalInfo = FunctionInfo<DefLexicalFn>(DefLexicalOperation);
|
||||
typedef bool (*DefLexicalFn)(JSContext*, HandlePropertyName, unsigned, HandleObject);
|
||||
static const VMFunction DefLexicalInfo = FunctionInfo<DefLexicalFn>(DefLexical);
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_DEFCONST()
|
||||
@ -2500,8 +2500,11 @@ BaselineCompiler::emit_JSOP_DEFLET()
|
||||
attrs |= JSPROP_READONLY;
|
||||
MOZ_ASSERT(attrs <= UINT32_MAX);
|
||||
|
||||
masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg());
|
||||
|
||||
prepareVMCall();
|
||||
|
||||
pushArg(R0.scratchReg());
|
||||
pushArg(Imm32(attrs));
|
||||
pushArg(ImmGCPtr(script->getName(pc)));
|
||||
|
||||
|
@ -7617,7 +7617,12 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_
|
||||
obj->as<ScopeObject>().setAliasedVar(cx, ScopeCoordinate(pc), name, rhs);
|
||||
} else if (op == JSOP_INITGLEXICAL) {
|
||||
RootedValue v(cx, rhs);
|
||||
InitGlobalLexicalOperation(cx, script, pc, v);
|
||||
ClonedBlockObject* lexicalScope;
|
||||
if (script->hasNonSyntacticScope())
|
||||
lexicalScope = &NearestEnclosingExtensibleLexicalScope(frame->scopeChain());
|
||||
else
|
||||
lexicalScope = &cx->global()->lexicalScope();
|
||||
InitGlobalLexicalOperation(cx, lexicalScope, script, pc, v);
|
||||
} else {
|
||||
MOZ_ASSERT(op == JSOP_SETPROP || op == JSOP_STRICTSETPROP);
|
||||
|
||||
|
@ -3729,7 +3729,7 @@ CodeGenerator::visitDefVar(LDefVar* lir)
|
||||
}
|
||||
|
||||
typedef bool (*DefLexicalFn)(JSContext*, HandlePropertyName, unsigned);
|
||||
static const VMFunction DefLexicalInfo = FunctionInfo<DefLexicalFn>(DefLexicalOperation);
|
||||
static const VMFunction DefLexicalInfo = FunctionInfo<DefLexicalFn>(DefGlobalLexical);
|
||||
|
||||
void
|
||||
CodeGenerator::visitDefLexical(LDefLexical* lir)
|
||||
|
@ -1768,6 +1768,7 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
return true;
|
||||
|
||||
case JSOP_INITGLEXICAL: {
|
||||
MOZ_ASSERT(!script()->hasNonSyntacticScope());
|
||||
MDefinition* value = current->pop();
|
||||
current->push(constant(ObjectValue(script()->global().lexicalScope())));
|
||||
current->push(value);
|
||||
@ -12661,6 +12662,7 @@ IonBuilder::jsop_defvar(uint32_t index)
|
||||
bool
|
||||
IonBuilder::jsop_deflexical(uint32_t index)
|
||||
{
|
||||
MOZ_ASSERT(!script()->hasNonSyntacticScope());
|
||||
MOZ_ASSERT(JSOp(*pc) == JSOP_DEFLET || JSOp(*pc) == JSOP_DEFCONST);
|
||||
|
||||
PropertyName* name = script()->getName(index);
|
||||
|
@ -3341,7 +3341,8 @@ SetPropertyIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex
|
||||
RootedScript script(cx);
|
||||
jsbytecode* pc;
|
||||
cache.getScriptedLocation(&script, &pc);
|
||||
InitGlobalLexicalOperation(cx, script, pc, value);
|
||||
MOZ_ASSERT(!script->hasNonSyntacticScope());
|
||||
InitGlobalLexicalOperation(cx, &cx->global()->lexicalScope(), script, pc, value);
|
||||
} else {
|
||||
if (!SetProperty(cx, obj, name, value, cache.strict(), cache.pc()))
|
||||
return false;
|
||||
|
@ -177,6 +177,27 @@ DefVar(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeC
|
||||
return DefVarOperation(cx, obj, dn, attrs);
|
||||
}
|
||||
|
||||
bool
|
||||
DefLexical(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain)
|
||||
{
|
||||
// Find the extensible lexical scope.
|
||||
Rooted<ClonedBlockObject*> lexical(cx, &NearestEnclosingExtensibleLexicalScope(scopeChain));
|
||||
|
||||
// Find the variables object.
|
||||
RootedObject varObj(cx, scopeChain);
|
||||
while (!varObj->isQualifiedVarObj())
|
||||
varObj = varObj->enclosingScope();
|
||||
|
||||
return DefLexicalOperation(cx, lexical, varObj, dn, attrs);
|
||||
}
|
||||
|
||||
bool
|
||||
DefGlobalLexical(JSContext* cx, HandlePropertyName dn, unsigned attrs)
|
||||
{
|
||||
Rooted<ClonedBlockObject*> globalLexical(cx, &cx->global()->lexicalScope());
|
||||
return DefLexicalOperation(cx, globalLexical, cx->global(), dn, attrs);
|
||||
}
|
||||
|
||||
bool
|
||||
MutatePrototype(JSContext* cx, HandlePlainObject obj, HandleValue value)
|
||||
{
|
||||
|
@ -589,6 +589,8 @@ bool CheckOverRecursedWithExtra(JSContext* cx, BaselineFrame* frame,
|
||||
uint32_t extra, uint32_t earlyCheck);
|
||||
|
||||
bool DefVar(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain);
|
||||
bool DefLexical(JSContext* cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain);
|
||||
bool DefGlobalLexical(JSContext* cx, HandlePropertyName dn, unsigned attrs);
|
||||
bool MutatePrototype(JSContext* cx, HandlePlainObject obj, HandleValue value);
|
||||
bool InitProp(JSContext* cx, HandleObject obj, HandlePropertyName name, HandleValue value,
|
||||
jsbytecode* pc);
|
||||
|
@ -1458,6 +1458,30 @@ JS_IsGlobalObject(JSObject* obj)
|
||||
return obj->is<GlobalObject>();
|
||||
}
|
||||
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
JS_GlobalLexicalScope(JSObject* obj)
|
||||
{
|
||||
return &obj->as<GlobalObject>().lexicalScope();
|
||||
}
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_HasExtensibleLexicalScope(JSObject* obj)
|
||||
{
|
||||
return obj->is<GlobalObject>() || obj->compartment()->getNonSyntacticLexicalScope(obj);
|
||||
}
|
||||
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
JS_ExtensibleLexicalScope(JSObject* obj)
|
||||
{
|
||||
JSObject* lexical = nullptr;
|
||||
if (obj->is<GlobalObject>())
|
||||
lexical = JS_GlobalLexicalScope(obj);
|
||||
else
|
||||
lexical = obj->compartment()->getNonSyntacticLexicalScope(obj);
|
||||
MOZ_ASSERT(lexical);
|
||||
return lexical;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
JS_GetGlobalForCompartmentOrNull(JSContext* cx, JSCompartment* c)
|
||||
{
|
||||
@ -3456,6 +3480,19 @@ CreateNonSyntacticScopeChain(JSContext* cx, AutoObjectVector& scopeChain,
|
||||
// See JSObject::isQualifiedVarObj.
|
||||
if (!dynamicScopeObj->setQualifiedVarObj(cx))
|
||||
return false;
|
||||
|
||||
// Also get a non-syntactic lexical scope to capture 'let' and 'const'
|
||||
// bindings. To persist lexical bindings, we have a 1-1 mapping with
|
||||
// the final unwrapped dynamic scope object (the scope that stores the
|
||||
// 'var' bindings) and the lexical scope.
|
||||
//
|
||||
// TODOshu: disallow the subscript loader from using non-distinguished
|
||||
// objects as dynamic scopes.
|
||||
dynamicScopeObj.set(
|
||||
cx->compartment()->getOrCreateNonSyntacticLexicalScope(cx, staticScopeObj,
|
||||
dynamicScopeObj));
|
||||
if (!dynamicScopeObj)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1572,6 +1572,15 @@ JS_GetGlobalForObject(JSContext* cx, JSObject* obj);
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_IsGlobalObject(JSObject* obj);
|
||||
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
JS_GlobalLexicalScope(JSObject* obj);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_HasExtensibleLexicalScope(JSObject* obj);
|
||||
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
JS_ExtensibleLexicalScope(JSObject* obj);
|
||||
|
||||
/*
|
||||
* May return nullptr, if |c| never had a global (e.g. the atoms compartment),
|
||||
* or if |c|'s global has been collected.
|
||||
|
@ -66,6 +66,7 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options =
|
||||
selfHostingScriptSource(nullptr),
|
||||
objectMetadataTable(nullptr),
|
||||
lazyArrayBuffers(nullptr),
|
||||
nonSyntacticLexicalScopes_(nullptr),
|
||||
gcIncomingGrayPointers(nullptr),
|
||||
gcPreserveJitCode(options.preserveJitCode()),
|
||||
debugModeBits(0),
|
||||
@ -104,6 +105,7 @@ JSCompartment::~JSCompartment()
|
||||
js_delete(debugScopes);
|
||||
js_delete(objectMetadataTable);
|
||||
js_delete(lazyArrayBuffers);
|
||||
js_delete(nonSyntacticLexicalScopes_),
|
||||
js_free(enumerators);
|
||||
|
||||
runtime_->numCompartments--;
|
||||
@ -494,6 +496,48 @@ JSCompartment::wrap(JSContext* cx, MutableHandle<PropertyDescriptor> desc)
|
||||
return wrap(cx, desc.value());
|
||||
}
|
||||
|
||||
ClonedBlockObject*
|
||||
JSCompartment::getOrCreateNonSyntacticLexicalScope(JSContext* cx,
|
||||
HandleObject enclosingStatic,
|
||||
HandleObject enclosingScope)
|
||||
{
|
||||
if (!nonSyntacticLexicalScopes_) {
|
||||
nonSyntacticLexicalScopes_ = cx->new_<ObjectWeakMap>(cx);
|
||||
if (!nonSyntacticLexicalScopes_ || !nonSyntacticLexicalScopes_->init())
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The key is the unwrapped dynamic scope, as we may be creating different
|
||||
// DynamicWithObject wrappers each time.
|
||||
MOZ_ASSERT(!enclosingScope->as<DynamicWithObject>().isSyntactic());
|
||||
RootedObject key(cx, &enclosingScope->as<DynamicWithObject>().object());
|
||||
RootedObject lexicalScope(cx, nonSyntacticLexicalScopes_->lookup(key));
|
||||
|
||||
if (!lexicalScope) {
|
||||
lexicalScope = ClonedBlockObject::createNonSyntactic(cx, enclosingStatic, enclosingScope);
|
||||
if (!lexicalScope)
|
||||
return nullptr;
|
||||
if (!nonSyntacticLexicalScopes_->add(cx, key, lexicalScope))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &lexicalScope->as<ClonedBlockObject>();
|
||||
}
|
||||
|
||||
ClonedBlockObject*
|
||||
JSCompartment::getNonSyntacticLexicalScope(JSObject* enclosingScope) const
|
||||
{
|
||||
if (!nonSyntacticLexicalScopes_)
|
||||
return nullptr;
|
||||
if (!enclosingScope->is<DynamicWithObject>())
|
||||
return nullptr;
|
||||
JSObject* key = &enclosingScope->as<DynamicWithObject>().object();
|
||||
JSObject* lexicalScope = nonSyntacticLexicalScopes_->lookup(key);
|
||||
if (!lexicalScope)
|
||||
return nullptr;
|
||||
return &lexicalScope->as<ClonedBlockObject>();
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::traceOutgoingCrossCompartmentWrappers(JSTracer* trc)
|
||||
{
|
||||
@ -599,6 +643,9 @@ JSCompartment::traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime t
|
||||
MOZ_ASSERT(script == r.front().key(), "const_cast is only a work-around");
|
||||
}
|
||||
}
|
||||
|
||||
if (nonSyntacticLexicalScopes_)
|
||||
nonSyntacticLexicalScopes_->trace(trc);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1052,7 +1099,8 @@ JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
||||
size_t* objectMetadataTablesArg,
|
||||
size_t* crossCompartmentWrappersArg,
|
||||
size_t* regexpCompartment,
|
||||
size_t* savedStacksSet)
|
||||
size_t* savedStacksSet,
|
||||
size_t* nonSyntacticLexicalScopesArg)
|
||||
{
|
||||
*compartmentObject += mallocSizeOf(this);
|
||||
objectGroups.addSizeOfExcludingThis(mallocSizeOf, tiAllocationSiteTables,
|
||||
@ -1068,6 +1116,8 @@ JSCompartment::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
||||
*crossCompartmentWrappersArg += crossCompartmentWrappers.sizeOfExcludingThis(mallocSizeOf);
|
||||
*regexpCompartment += regExps.sizeOfExcludingThis(mallocSizeOf);
|
||||
*savedStacksSet += savedStacks_.sizeOfExcludingThis(mallocSizeOf);
|
||||
if (nonSyntacticLexicalScopes_)
|
||||
*nonSyntacticLexicalScopesArg += nonSyntacticLexicalScopes_->sizeOfIncludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -29,6 +29,7 @@ template<class Node> class ComponentFinder;
|
||||
} // namespace gc
|
||||
|
||||
struct NativeIterator;
|
||||
class ClonedBlockObject;
|
||||
|
||||
/*
|
||||
* A single-entry cache for some base-10 double-to-string conversions. This
|
||||
@ -397,7 +398,8 @@ struct JSCompartment
|
||||
size_t* objectMetadataTables,
|
||||
size_t* crossCompartmentWrappers,
|
||||
size_t* regexpCompartment,
|
||||
size_t* savedStacksSet);
|
||||
size_t* savedStacksSet,
|
||||
size_t* nonSyntacticLexicalScopes);
|
||||
|
||||
/*
|
||||
* Shared scope property tree, and arena-pool for allocating its nodes.
|
||||
@ -442,6 +444,13 @@ struct JSCompartment
|
||||
// All unboxed layouts in the compartment.
|
||||
mozilla::LinkedList<js::UnboxedLayout> unboxedLayouts;
|
||||
|
||||
private:
|
||||
// All non-syntactic lexical scopes in the compartment. These are kept in
|
||||
// a map because when loading scripts into a non-syntactic scope, we need
|
||||
// to use the same lexical scope to persist lexical bindings.
|
||||
js::ObjectWeakMap* nonSyntacticLexicalScopes_;
|
||||
|
||||
public:
|
||||
/* During GC, stores the index of this compartment in rt->compartments. */
|
||||
unsigned gcIndex;
|
||||
|
||||
@ -511,6 +520,11 @@ struct JSCompartment
|
||||
explicit WrapperEnum(JSCompartment* c) : js::WrapperMap::Enum(c->crossCompartmentWrappers) {}
|
||||
};
|
||||
|
||||
js::ClonedBlockObject* getOrCreateNonSyntacticLexicalScope(JSContext* cx,
|
||||
js::HandleObject enclosingStatic,
|
||||
js::HandleObject enclosingScope);
|
||||
js::ClonedBlockObject* getNonSyntacticLexicalScope(JSObject* enclosingScope) const;
|
||||
|
||||
/*
|
||||
* This method traces data that is live iff we know that this compartment's
|
||||
* global is still live.
|
||||
|
@ -2795,13 +2795,12 @@ SetJitExceptionHandler(JitExceptionHandler handler);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get the object underlying the object environment (in the ES
|
||||
* NewObjectEnvironment) sense for a given function. If the function is not
|
||||
* scripted or does not have an object environment, just returns the function's
|
||||
* parent.
|
||||
* Get the nearest enclosing with scope object for a given function. If the
|
||||
* function is not scripted or is not enclosed by a with scope, returns the
|
||||
* global.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSObject*)
|
||||
GetObjectEnvironmentObjectForFunction(JSFunction* fun);
|
||||
GetNearestEnclosingWithScopeObjectForFunction(JSFunction* fun);
|
||||
|
||||
/*
|
||||
* Get the first SavedFrame object in this SavedFrame stack whose principals are
|
||||
|
@ -6525,7 +6525,12 @@ EvaluateInEnv(JSContext* cx, Handle<Env*> env, HandleValue thisv, AbstractFrameP
|
||||
*/
|
||||
Rooted<ScopeObject*> enclosingStaticScope(cx);
|
||||
if (!IsGlobalLexicalScope(env)) {
|
||||
enclosingStaticScope = StaticNonSyntacticScopeObjects::create(cx, nullptr);
|
||||
// If we are doing a global evalWithBindings, we will still need to
|
||||
// link the static global lexical scope to the static non-syntactic
|
||||
// scope.
|
||||
if (IsGlobalLexicalScope(env->enclosingScope()))
|
||||
enclosingStaticScope = &cx->global()->lexicalScope().staticBlock();
|
||||
enclosingStaticScope = StaticNonSyntacticScopeObjects::create(cx, enclosingStaticScope);
|
||||
if (!enclosingStaticScope)
|
||||
return false;
|
||||
} else {
|
||||
@ -6675,9 +6680,9 @@ DebuggerGenericEval(JSContext* cx, const char* fullMethodName, const Value& code
|
||||
return false;
|
||||
} else {
|
||||
/*
|
||||
* Use the global as 'this'. If the global is an inner object, it
|
||||
* should have a thisObject hook that returns the appropriate outer
|
||||
* object.
|
||||
* Use the global lexical scope as 'this'. If the global is an inner
|
||||
* object, it should have a thisObject hook that returns the
|
||||
* appropriate outer object.
|
||||
*/
|
||||
JSObject* thisObj = GetThisObject(cx, scope);
|
||||
if (!thisObj)
|
||||
|
@ -300,19 +300,18 @@ SetNameOperation(JSContext* cx, JSScript* script, jsbytecode* pc, HandleObject s
|
||||
}
|
||||
|
||||
inline bool
|
||||
DefLexicalOperation(JSContext* cx, HandlePropertyName name, unsigned attrs)
|
||||
DefLexicalOperation(JSContext* cx, Handle<ClonedBlockObject*> lexicalScope,
|
||||
HandleObject varObj, HandlePropertyName name, unsigned attrs)
|
||||
{
|
||||
Rooted<ClonedBlockObject*> globalLexical(cx, &cx->global()->lexicalScope());
|
||||
|
||||
// Due to the extensibility of the global lexical scope, we must check for
|
||||
// redeclaring a binding.
|
||||
mozilla::Maybe<frontend::Definition::Kind> redeclKind;
|
||||
RootedId id(cx, NameToId(name));
|
||||
RootedShape shape(cx);
|
||||
if ((shape = globalLexical->lookup(cx, name))) {
|
||||
if ((shape = lexicalScope->lookup(cx, name))) {
|
||||
redeclKind = mozilla::Some(shape->writable() ? frontend::Definition::LET
|
||||
: frontend::Definition::CONST);
|
||||
} else if ((shape = cx->global()->lookup(cx, name))) {
|
||||
} else if (varObj->isNative() && (shape = varObj->as<NativeObject>().lookup(cx, name))) {
|
||||
if (!shape->configurable())
|
||||
redeclKind = mozilla::Some(frontend::Definition::VAR);
|
||||
} else {
|
||||
@ -332,7 +331,8 @@ DefLexicalOperation(JSContext* cx, HandlePropertyName name, unsigned attrs)
|
||||
}
|
||||
|
||||
inline bool
|
||||
DefLexicalOperation(JSContext* cx, JSScript* script, jsbytecode* pc)
|
||||
DefLexicalOperation(JSContext* cx, ClonedBlockObject* lexicalScopeArg,
|
||||
JSObject* varObjArg, JSScript* script, jsbytecode* pc)
|
||||
{
|
||||
MOZ_ASSERT(*pc == JSOP_DEFLET || *pc == JSOP_DEFCONST);
|
||||
RootedPropertyName name(cx, script->getName(pc));
|
||||
@ -341,17 +341,25 @@ DefLexicalOperation(JSContext* cx, JSScript* script, jsbytecode* pc)
|
||||
if (*pc == JSOP_DEFCONST)
|
||||
attrs |= JSPROP_READONLY;
|
||||
|
||||
return DefLexicalOperation(cx, name, attrs);
|
||||
Rooted<ClonedBlockObject*> lexicalScope(cx, lexicalScopeArg);
|
||||
RootedObject varObj(cx, varObjArg);
|
||||
MOZ_ASSERT_IF(!script->hasNonSyntacticScope(),
|
||||
lexicalScope == &cx->global()->lexicalScope() && varObj == cx->global());
|
||||
|
||||
return DefLexicalOperation(cx, lexicalScope, varObj, name, attrs);
|
||||
}
|
||||
|
||||
inline void
|
||||
InitGlobalLexicalOperation(JSContext* cx, JSScript* script, jsbytecode* pc, HandleValue value)
|
||||
InitGlobalLexicalOperation(JSContext* cx, ClonedBlockObject* lexicalScopeArg,
|
||||
JSScript* script, jsbytecode* pc, HandleValue value)
|
||||
{
|
||||
MOZ_ASSERT_IF(!script->hasNonSyntacticScope(),
|
||||
lexicalScopeArg == &cx->global()->lexicalScope());
|
||||
MOZ_ASSERT(*pc == JSOP_INITGLEXICAL);
|
||||
Rooted<ClonedBlockObject*> globalLexical(cx, &cx->global()->lexicalScope());
|
||||
RootedShape shape(cx, globalLexical->lookup(cx, script->getName(pc)));
|
||||
Rooted<ClonedBlockObject*> lexicalScope(cx, lexicalScopeArg);
|
||||
RootedShape shape(cx, lexicalScope->lookup(cx, script->getName(pc)));
|
||||
MOZ_ASSERT(shape);
|
||||
globalLexical->setSlot(shape->slot(), value);
|
||||
lexicalScope->setSlot(shape->slot(), value);
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
@ -3429,8 +3429,13 @@ END_CASE(JSOP_INITALIASEDLEXICAL)
|
||||
|
||||
CASE(JSOP_INITGLEXICAL)
|
||||
{
|
||||
ClonedBlockObject* lexicalScope;
|
||||
if (script->hasNonSyntacticScope())
|
||||
lexicalScope = ®S.fp()->extensibleLexicalScope();
|
||||
else
|
||||
lexicalScope = &cx->global()->lexicalScope();
|
||||
HandleValue value = REGS.stackHandleAt(-1);
|
||||
InitGlobalLexicalOperation(cx, script, REGS.pc, value);
|
||||
InitGlobalLexicalOperation(cx, lexicalScope, script, REGS.pc, value);
|
||||
}
|
||||
END_CASE(JSOP_INITGLEXICAL)
|
||||
|
||||
@ -3502,7 +3507,16 @@ END_CASE(JSOP_DEFVAR)
|
||||
CASE(JSOP_DEFCONST)
|
||||
CASE(JSOP_DEFLET)
|
||||
{
|
||||
if (!DefLexicalOperation(cx, script, REGS.pc))
|
||||
ClonedBlockObject* lexicalScope;
|
||||
JSObject* varObj;
|
||||
if (script->hasNonSyntacticScope()) {
|
||||
lexicalScope = ®S.fp()->extensibleLexicalScope();
|
||||
varObj = ®S.fp()->varObj();
|
||||
} else {
|
||||
lexicalScope = &cx->global()->lexicalScope();
|
||||
varObj = cx->global();
|
||||
}
|
||||
if (!DefLexicalOperation(cx, lexicalScope, varObj, script, REGS.pc))
|
||||
goto error;
|
||||
}
|
||||
END_CASE(JSOP_DEFLET)
|
||||
|
@ -342,7 +342,8 @@ StatsCompartmentCallback(JSRuntime* rt, void* data, JSCompartment* compartment)
|
||||
&cStats.objectMetadataTable,
|
||||
&cStats.crossCompartmentWrappersTable,
|
||||
&cStats.regexpCompartment,
|
||||
&cStats.savedStacksSet);
|
||||
&cStats.savedStacksSet,
|
||||
&cStats.nonSyntacticLexicalScopesTable);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -16,6 +16,14 @@
|
||||
|
||||
namespace js {
|
||||
|
||||
inline ClonedBlockObject&
|
||||
NearestEnclosingExtensibleLexicalScope(JSObject* scope)
|
||||
{
|
||||
while (!IsExtensibleLexicalScope(scope))
|
||||
scope = scope->enclosingScope();
|
||||
return scope->as<ClonedBlockObject>();
|
||||
}
|
||||
|
||||
inline void
|
||||
ScopeObject::setAliasedVar(JSContext* cx, ScopeCoordinate sc, PropertyName* name, const Value& v)
|
||||
{
|
||||
|
@ -782,8 +782,10 @@ const Class StaticNonSyntacticScopeObjects::class_ = {
|
||||
};
|
||||
|
||||
/* static */ NonSyntacticVariablesObject*
|
||||
NonSyntacticVariablesObject::create(JSContext* cx, Handle<GlobalObject*> global)
|
||||
NonSyntacticVariablesObject::create(JSContext* cx, Handle<ClonedBlockObject*> globalLexical)
|
||||
{
|
||||
MOZ_ASSERT(globalLexical->isGlobal());
|
||||
|
||||
Rooted<NonSyntacticVariablesObject*> obj(cx,
|
||||
NewObjectWithNullTaggedProto<NonSyntacticVariablesObject>(cx, TenuredObject,
|
||||
BaseShape::DELEGATE));
|
||||
@ -794,7 +796,7 @@ NonSyntacticVariablesObject::create(JSContext* cx, Handle<GlobalObject*> global)
|
||||
if (!obj->setQualifiedVarObj(cx))
|
||||
return nullptr;
|
||||
|
||||
obj->setEnclosingScope(global);
|
||||
obj->setEnclosingScope(globalLexical);
|
||||
return obj;
|
||||
}
|
||||
|
||||
@ -869,6 +871,26 @@ ClonedBlockObject::createGlobal(JSContext* cx, Handle<GlobalObject*> global)
|
||||
return lexical;
|
||||
}
|
||||
|
||||
/* static */ ClonedBlockObject*
|
||||
ClonedBlockObject::createNonSyntactic(JSContext* cx, HandleObject enclosingStatic,
|
||||
HandleObject enclosingScope)
|
||||
{
|
||||
MOZ_ASSERT(enclosingStatic->is<StaticNonSyntacticScopeObjects>());
|
||||
MOZ_ASSERT(!IsSyntacticScope(enclosingScope));
|
||||
|
||||
Rooted<StaticBlockObject*> staticLexical(cx, StaticBlockObject::create(cx));
|
||||
if (!staticLexical)
|
||||
return nullptr;
|
||||
|
||||
staticLexical->setLocalOffset(UINT32_MAX);
|
||||
staticLexical->initEnclosingScope(enclosingStatic);
|
||||
Rooted<ClonedBlockObject*> lexical(cx, ClonedBlockObject::create(cx, staticLexical,
|
||||
enclosingScope));
|
||||
if (!lexical)
|
||||
return nullptr;
|
||||
return lexical;
|
||||
}
|
||||
|
||||
/* static */ ClonedBlockObject*
|
||||
ClonedBlockObject::createHollowForDebug(JSContext* cx, Handle<StaticBlockObject*> block)
|
||||
{
|
||||
@ -987,9 +1009,11 @@ static JSObject*
|
||||
block_ThisObject(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
// No other block objects should ever get passed to the 'this' object
|
||||
// hook.
|
||||
MOZ_ASSERT(obj->as<ClonedBlockObject>().isGlobal());
|
||||
MOZ_ASSERT(&obj->as<ClonedBlockObject>().enclosingScope() == cx->global());
|
||||
// hook except the global lexical scope and non-syntactic ones.
|
||||
MOZ_ASSERT(obj->as<ClonedBlockObject>().isGlobal() ||
|
||||
!obj->as<ClonedBlockObject>().isSyntactic());
|
||||
MOZ_ASSERT_IF(obj->as<ClonedBlockObject>().isGlobal(),
|
||||
obj->enclosingScope() == cx->global());
|
||||
RootedObject enclosing(cx, obj->enclosingScope());
|
||||
return GetThisObject(cx, enclosing);
|
||||
}
|
||||
@ -1666,9 +1690,12 @@ class DebugScopeProxy : public BaseProxyHandler
|
||||
if (!shape)
|
||||
return true;
|
||||
|
||||
// Currently consider all global lexical bindings to be aliased.
|
||||
if (IsGlobalLexicalScope(block))
|
||||
// Currently consider all global and non-syntactic top-level lexical
|
||||
// bindings to be aliased.
|
||||
if (block->isExtensible()) {
|
||||
MOZ_ASSERT(IsGlobalLexicalScope(block) || !IsSyntacticScope(block));
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned i = block->staticBlock().shapeToIndex(*shape);
|
||||
if (block->staticBlock().isAliased(i))
|
||||
@ -2833,13 +2860,16 @@ js::GetDebugScopeForFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc)
|
||||
|
||||
// See declaration and documentation in jsfriendapi.h
|
||||
JS_FRIEND_API(JSObject*)
|
||||
js::GetObjectEnvironmentObjectForFunction(JSFunction* fun)
|
||||
js::GetNearestEnclosingWithScopeObjectForFunction(JSFunction* fun)
|
||||
{
|
||||
if (!fun->isInterpreted())
|
||||
return &fun->global();
|
||||
|
||||
JSObject* env = fun->environment();
|
||||
if (!env || !env->is<DynamicWithObject>())
|
||||
while (env && !env->is<DynamicWithObject>())
|
||||
env = env->enclosingScope();
|
||||
|
||||
if (!env)
|
||||
return &fun->global();
|
||||
|
||||
return &env->as<DynamicWithObject>().object();
|
||||
|
@ -215,7 +215,7 @@ ScopeCoordinateFunctionScript(JSScript* script, jsbytecode* pc);
|
||||
* |
|
||||
* ScopeObject---+---+ Engine-internal scope
|
||||
* | | | | |
|
||||
* | | | | StaticNonSyntacticScopeObjects See NB2
|
||||
* | | | | StaticNonSyntacticScopeObjects See "Non-syntactic scope objects"
|
||||
* | | | |
|
||||
* | | | StaticEvalObject Placeholder so eval scopes may be iterated through
|
||||
* | | |
|
||||
@ -247,9 +247,6 @@ ScopeCoordinateFunctionScript(JSScript* script, jsbytecode* pc);
|
||||
* are cloned at runtime. These objects should never escape into the wild and
|
||||
* support a restricted set of ScopeObject operations.
|
||||
*
|
||||
* NB2: StaticNonSyntacticScopeObjects notify either of 0+ non-syntactic
|
||||
* DynamicWithObjects on the dynamic scope chain or a NonSyntacticScopeObject.
|
||||
*
|
||||
* See also "Debug scope objects" below.
|
||||
*/
|
||||
|
||||
@ -459,13 +456,113 @@ class StaticEvalObject : public ScopeObject
|
||||
inline bool isNonGlobal() const;
|
||||
};
|
||||
|
||||
// Static scope objects that stand in for one or more "polluting global"
|
||||
// scopes on the dynamic scope chain.
|
||||
//
|
||||
// There are two flavors of polluting global scopes on the dynamic scope
|
||||
// chain: either 0+ non-syntactic DynamicWithObjects, or 1
|
||||
// NonSyntacticVariablesObject, created exclusively in
|
||||
// js::ExecuteInGlobalAndReturnScope.
|
||||
/*
|
||||
* Non-syntactic scope objects
|
||||
*
|
||||
* A non-syntactic scope is one that was not created due to source code. On
|
||||
* the static scope chain, a single StaticNonSyntacticScopeObjects maps to 0+
|
||||
* non-syntactic dynamic scope objects. This is contrasted with syntactic
|
||||
* scopes, where each syntactic static scope corresponds to 0 or 1 dynamic
|
||||
* scope objects.
|
||||
*
|
||||
* There are 3 kinds of dynamic non-syntactic scopes:
|
||||
*
|
||||
* 1. DynamicWithObject
|
||||
*
|
||||
* When the embedding compiles or executes a script, it has the option to
|
||||
* pass in a vector of objects to be used as the initial scope chain. Each
|
||||
* of those objects is wrapped by a DynamicWithObject.
|
||||
*
|
||||
* The innermost scope passed in by the embedding becomes a qualified
|
||||
* variables object that captures 'var' bindings. That is, it wraps the
|
||||
* holder object of 'var' bindings.
|
||||
*
|
||||
* Does not hold 'let' or 'const' bindings.
|
||||
*
|
||||
* 2. NonSyntacticVariablesObject
|
||||
*
|
||||
* When the embedding wants qualified 'var' bindings and unqualified
|
||||
* bareword assignments to go on a different object than the global
|
||||
* object. While any object can be made into a qualified variables object,
|
||||
* only the GlobalObject and NonSyntacticVariablesObject are considered
|
||||
* unqualified variables objects.
|
||||
*
|
||||
* Unlike DynamicWithObjects, this object is itself the holder of 'var'
|
||||
* bindings.
|
||||
*
|
||||
* Does not hold 'let' or 'const' bindings.
|
||||
*
|
||||
* 3. ClonedBlockObject
|
||||
*
|
||||
* Each non-syntactic object used as a qualified variables object needs to
|
||||
* enclose a non-syntactic ClonedBlockObject to hold 'let' and 'const'
|
||||
* bindings. There is a bijection per compartment between the non-syntactic
|
||||
* variables objects and their non-syntactic ClonedBlockObjects.
|
||||
*
|
||||
* Does not hold 'var' bindings.
|
||||
*
|
||||
* The embedding (Gecko) uses non-syntactic scopes for various things, some of
|
||||
* which are detailed below. All scope chain listings below are, from top to
|
||||
* bottom, outermost to innermost.
|
||||
*
|
||||
* A. Component loading
|
||||
*
|
||||
* Components may be loaded in "reuse loader global" mode, where to save on
|
||||
* memory, all JSMs and JS-implemented XPCOM modules are loaded into a single
|
||||
* global. Each individual JSMs are compiled as functions with their own
|
||||
* FakeBackstagePass. They have the following dynamic scope chain:
|
||||
*
|
||||
* BackstagePass global
|
||||
* |
|
||||
* Global lexical scope
|
||||
* |
|
||||
* DynamicWithObject wrapping FakeBackstagePass
|
||||
* |
|
||||
* Non-syntactic lexical scope
|
||||
*
|
||||
* B. Subscript loading
|
||||
*
|
||||
* Subscripts may be loaded into a target object. They have the following
|
||||
* dynamic scope chain:
|
||||
*
|
||||
* Loader global
|
||||
* |
|
||||
* Global lexical scope
|
||||
* |
|
||||
* DynamicWithObject wrapping target
|
||||
* |
|
||||
* ClonedBlockObject
|
||||
*
|
||||
* C. Frame scripts
|
||||
*
|
||||
* XUL frame scripts are always loaded with a NonSyntacticVariablesObject as a
|
||||
* "polluting global". This is done exclusively in
|
||||
* js::ExecuteInGlobalAndReturnScope.
|
||||
*
|
||||
* Loader global
|
||||
* |
|
||||
* Global lexical scope
|
||||
* |
|
||||
* NonSyntacticVariablesObject
|
||||
* |
|
||||
* ClonedBlockObject
|
||||
*
|
||||
* D. XBL
|
||||
*
|
||||
* XBL methods are compiled as functions with XUL elements on the scope chain.
|
||||
* For a chain of elements e0,...,eN:
|
||||
*
|
||||
* ...
|
||||
* |
|
||||
* DynamicWithObject wrapping eN
|
||||
* |
|
||||
* ...
|
||||
* |
|
||||
* DynamicWithObject wrapping e0
|
||||
* |
|
||||
* ClonedBlockObject
|
||||
*
|
||||
*/
|
||||
class StaticNonSyntacticScopeObjects : public ScopeObject
|
||||
{
|
||||
public:
|
||||
@ -482,7 +579,7 @@ class StaticNonSyntacticScopeObjects : public ScopeObject
|
||||
// A non-syntactic dynamic scope object that captures non-lexical
|
||||
// bindings. That is, a scope object that captures both qualified var
|
||||
// assignments and unqualified bareword assignments. Its parent is always the
|
||||
// real global.
|
||||
// global lexical scope.
|
||||
//
|
||||
// This is used in ExecuteInGlobalAndReturnScope and sits in front of the
|
||||
// global scope to capture 'var' and bareword asignments.
|
||||
@ -492,7 +589,8 @@ class NonSyntacticVariablesObject : public ScopeObject
|
||||
static const unsigned RESERVED_SLOTS = 1;
|
||||
static const Class class_;
|
||||
|
||||
static NonSyntacticVariablesObject* create(JSContext* cx, Handle<GlobalObject*> global);
|
||||
static NonSyntacticVariablesObject* create(JSContext* cx,
|
||||
Handle<ClonedBlockObject*> globalLexical);
|
||||
};
|
||||
|
||||
class NestedScopeObject : public ScopeObject
|
||||
@ -703,10 +801,14 @@ class StaticBlockObject : public BlockObject
|
||||
}
|
||||
|
||||
// Is this the static global lexical scope?
|
||||
bool isGlobal() {
|
||||
bool isGlobal() const {
|
||||
return !enclosingStaticScope();
|
||||
}
|
||||
|
||||
bool isSyntactic() const {
|
||||
return !isExtensible() || isGlobal();
|
||||
}
|
||||
|
||||
/* Frontend-only functions ***********************************************/
|
||||
|
||||
/* Initialization functions for above fields. */
|
||||
@ -765,6 +867,9 @@ class ClonedBlockObject : public BlockObject
|
||||
|
||||
static ClonedBlockObject* createGlobal(JSContext* cx, Handle<GlobalObject*> global);
|
||||
|
||||
static ClonedBlockObject* createNonSyntactic(JSContext* cx, HandleObject enclosingStatic,
|
||||
HandleObject enclosingScope);
|
||||
|
||||
static ClonedBlockObject* createHollowForDebug(JSContext* cx,
|
||||
Handle<StaticBlockObject*> block);
|
||||
|
||||
@ -795,6 +900,10 @@ class ClonedBlockObject : public BlockObject
|
||||
return enclosingScope().as<GlobalObject>();
|
||||
}
|
||||
|
||||
bool isSyntactic() const {
|
||||
return !isExtensible() || isGlobal();
|
||||
}
|
||||
|
||||
/* Copy in all the unaliased formals and locals. */
|
||||
void copyUnaliasedValues(AbstractFramePtr frame);
|
||||
|
||||
@ -1179,9 +1288,25 @@ namespace js {
|
||||
inline bool
|
||||
IsSyntacticScope(JSObject* scope)
|
||||
{
|
||||
return scope->is<ScopeObject>() &&
|
||||
(!scope->is<DynamicWithObject>() || scope->as<DynamicWithObject>().isSyntactic()) &&
|
||||
!scope->is<NonSyntacticVariablesObject>();
|
||||
if (!scope->is<ScopeObject>())
|
||||
return false;
|
||||
|
||||
if (scope->is<DynamicWithObject>())
|
||||
return scope->as<DynamicWithObject>().isSyntactic();
|
||||
|
||||
if (scope->is<ClonedBlockObject>())
|
||||
return scope->as<ClonedBlockObject>().isSyntactic();
|
||||
|
||||
if (scope->is<NonSyntacticVariablesObject>())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsExtensibleLexicalScope(JSObject* scope)
|
||||
{
|
||||
return scope->is<ClonedBlockObject>() && scope->as<ClonedBlockObject>().isExtensible();
|
||||
}
|
||||
|
||||
inline bool
|
||||
@ -1234,13 +1359,12 @@ inline bool
|
||||
ScopeIter::hasNonSyntacticScopeObject() const
|
||||
{
|
||||
// The case we're worrying about here is a NonSyntactic static scope which
|
||||
// has 0+ corresponding non-syntactic DynamicWithObject scopes or a
|
||||
// NonSyntacticVariablesObject.
|
||||
// has 0+ corresponding non-syntactic DynamicWithObject scopes, a
|
||||
// NonSyntacticVariablesObject, or a non-syntactic ClonedBlockObject.
|
||||
if (ssi_.type() == StaticScopeIter<CanGC>::NonSyntactic) {
|
||||
MOZ_ASSERT_IF(scope_->is<DynamicWithObject>(),
|
||||
!scope_->as<DynamicWithObject>().isSyntactic());
|
||||
return scope_->is<DynamicWithObject>() ||
|
||||
scope_->is<NonSyntacticVariablesObject>();
|
||||
return scope_->is<ScopeObject>() && !IsSyntacticScope(scope_);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ InterpreterFrame::global() const
|
||||
}
|
||||
|
||||
inline JSObject&
|
||||
InterpreterFrame::varObj()
|
||||
InterpreterFrame::varObj() const
|
||||
{
|
||||
JSObject* obj = scopeChain();
|
||||
while (!obj->isQualifiedVarObj())
|
||||
@ -70,6 +70,12 @@ InterpreterFrame::varObj()
|
||||
return *obj;
|
||||
}
|
||||
|
||||
inline ClonedBlockObject&
|
||||
InterpreterFrame::extensibleLexicalScope() const
|
||||
{
|
||||
return NearestEnclosingExtensibleLexicalScope(scopeChain());
|
||||
}
|
||||
|
||||
inline JSCompartment*
|
||||
InterpreterFrame::compartment() const
|
||||
{
|
||||
|
@ -144,7 +144,11 @@ AssertDynamicScopeMatchesStaticScope(JSContext* cx, JSScript* script, JSObject*
|
||||
RootedObject enclosingScope(cx, script->enclosingStaticScope());
|
||||
for (StaticScopeIter<NoGC> i(enclosingScope); !i.done(); i++) {
|
||||
if (i.type() == StaticScopeIter<NoGC>::NonSyntactic) {
|
||||
while (scope->is<DynamicWithObject>() || scope->is<NonSyntacticVariablesObject>()) {
|
||||
while (scope->is<DynamicWithObject>() ||
|
||||
scope->is<NonSyntacticVariablesObject>() ||
|
||||
(scope->is<ClonedBlockObject>() &&
|
||||
!scope->as<ClonedBlockObject>().isSyntactic()))
|
||||
{
|
||||
MOZ_ASSERT(!IsSyntacticScope(scope));
|
||||
scope = &scope->as<ScopeObject>().enclosingScope();
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ class ScriptFrameIter;
|
||||
class SPSProfiler;
|
||||
class InterpreterFrame;
|
||||
class StaticBlockObject;
|
||||
class ClonedBlockObject;
|
||||
|
||||
class ScopeCoordinate;
|
||||
|
||||
@ -616,7 +617,8 @@ class InterpreterFrame
|
||||
inline ScopeObject& aliasedVarScope(ScopeCoordinate sc) const;
|
||||
inline GlobalObject& global() const;
|
||||
inline CallObject& callObj() const;
|
||||
inline JSObject& varObj();
|
||||
inline JSObject& varObj() const;
|
||||
inline ClonedBlockObject& extensibleLexicalScope() const;
|
||||
|
||||
inline void pushOnScopeChain(ScopeObject& scope);
|
||||
inline void popOffScopeChain();
|
||||
|
@ -2566,9 +2566,11 @@ UpdatePropertyType(ExclusiveContext* cx, HeapTypeSet* types, NativeObject* obj,
|
||||
* comment).
|
||||
*
|
||||
* Also don't add untracked values (initial uninitialized lexical
|
||||
* magic values and optimized out values) as appearing in CallObjects.
|
||||
* magic values and optimized out values) as appearing in CallObjects
|
||||
* and the global lexical scope.
|
||||
*/
|
||||
MOZ_ASSERT_IF(TypeSet::IsUntrackedValue(value), obj->is<CallObject>());
|
||||
MOZ_ASSERT_IF(TypeSet::IsUntrackedValue(value),
|
||||
obj->is<CallObject>() || IsExtensibleLexicalScope(obj));
|
||||
if ((indexed || !value.isUndefined() || !CanHaveEmptyPropertyTypesForOwnProperty(obj)) &&
|
||||
!TypeSet::IsUntrackedValue(value))
|
||||
{
|
||||
|
@ -325,6 +325,25 @@ mozJSComponentLoader::ReallyInit()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// For terrible compatibility reasons, we need to consider both the global
|
||||
// lexical scope and the global of modules when searching for exported
|
||||
// symbols.
|
||||
static JSObject*
|
||||
ResolveModuleObjectProperty(JSContext* aCx, HandleObject aModObj, const char* name)
|
||||
{
|
||||
if (JS_HasExtensibleLexicalScope(aModObj)) {
|
||||
RootedObject lexical(aCx, JS_ExtensibleLexicalScope(aModObj));
|
||||
bool found;
|
||||
if (!JS_HasOwnProperty(aCx, lexical, name, &found)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (found) {
|
||||
return lexical;
|
||||
}
|
||||
}
|
||||
return aModObj;
|
||||
}
|
||||
|
||||
const mozilla::Module*
|
||||
mozJSComponentLoader::LoadModule(FileLocation& aFile)
|
||||
{
|
||||
@ -372,9 +391,12 @@ mozJSComponentLoader::LoadModule(FileLocation& aFile)
|
||||
JSAutoCompartment ac(cx, entry->obj);
|
||||
RootedObject entryObj(cx, entry->obj);
|
||||
|
||||
RootedObject NSGetFactoryHolder(cx, ResolveModuleObjectProperty(cx, entryObj, "NSGetFactory"));
|
||||
RootedValue NSGetFactory_val(cx);
|
||||
if (!JS_GetProperty(cx, entryObj, "NSGetFactory", &NSGetFactory_val) ||
|
||||
NSGetFactory_val.isUndefined()) {
|
||||
if (!NSGetFactoryHolder ||
|
||||
!JS_GetProperty(cx, NSGetFactoryHolder, "NSGetFactory", &NSGetFactory_val) ||
|
||||
NSGetFactory_val.isUndefined())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -424,7 +446,7 @@ mozJSComponentLoader::FindTargetObject(JSContext* aCx,
|
||||
if (mReuseLoaderGlobal) {
|
||||
JSFunction* fun = js::GetOutermostEnclosingFunctionOfScriptedCaller(aCx);
|
||||
if (fun) {
|
||||
JSObject* funParent = js::GetObjectEnvironmentObjectForFunction(fun);
|
||||
JSObject* funParent = js::GetNearestEnclosingWithScopeObjectForFunction(fun);
|
||||
if (JS_GetClass(funParent) == &kFakeBackstagePassJSClass)
|
||||
targetObject = funParent;
|
||||
}
|
||||
@ -964,6 +986,9 @@ mozJSComponentLoader::UnloadModules()
|
||||
RootedObject global(cx, mLoaderGlobal->GetJSObject());
|
||||
if (global) {
|
||||
JSAutoCompartment ac(cx, global);
|
||||
if (JS_HasExtensibleLexicalScope(global)) {
|
||||
JS_SetAllNonReservedSlotsToUndefined(cx, JS_ExtensibleLexicalScope(global));
|
||||
}
|
||||
JS_SetAllNonReservedSlotsToUndefined(cx, global);
|
||||
} else {
|
||||
NS_WARNING("Going to leak!");
|
||||
@ -1074,6 +1099,22 @@ mozJSComponentLoader::IsModuleLoaded(const nsACString& aLocation,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
ResolveModuleObjectPropertyById(JSContext* aCx, HandleObject aModObj, HandleId id)
|
||||
{
|
||||
if (JS_HasExtensibleLexicalScope(aModObj)) {
|
||||
RootedObject lexical(aCx, JS_ExtensibleLexicalScope(aModObj));
|
||||
bool found;
|
||||
if (!JS_HasOwnPropertyById(aCx, lexical, id, &found)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (found) {
|
||||
return lexical;
|
||||
}
|
||||
}
|
||||
return aModObj;
|
||||
}
|
||||
|
||||
nsresult
|
||||
mozJSComponentLoader::ImportInto(const nsACString& aLocation,
|
||||
HandleObject targetObj,
|
||||
@ -1178,8 +1219,10 @@ mozJSComponentLoader::ImportInto(const nsACString& aLocation,
|
||||
JSAutoCompartment ac(cx, mod->obj);
|
||||
|
||||
RootedValue symbols(cx);
|
||||
RootedObject modObj(cx, mod->obj);
|
||||
if (!JS_GetProperty(cx, modObj,
|
||||
RootedObject exportedSymbolsHolder(cx, ResolveModuleObjectProperty(cx, mod->obj,
|
||||
"EXPORTED_SYMBOLS"));
|
||||
if (!exportedSymbolsHolder ||
|
||||
!JS_GetProperty(cx, exportedSymbolsHolder,
|
||||
"EXPORTED_SYMBOLS", &symbols)) {
|
||||
return ReportOnCaller(cxhelper, ERROR_NOT_PRESENT,
|
||||
PromiseFlatCString(aLocation).get());
|
||||
@ -1210,6 +1253,7 @@ mozJSComponentLoader::ImportInto(const nsACString& aLocation,
|
||||
|
||||
RootedValue value(cx);
|
||||
RootedId symbolId(cx);
|
||||
RootedObject symbolHolder(cx);
|
||||
for (uint32_t i = 0; i < symbolCount; ++i) {
|
||||
if (!JS_GetElement(cx, symbolsObj, i, &value) ||
|
||||
!value.isString() ||
|
||||
@ -1218,8 +1262,9 @@ mozJSComponentLoader::ImportInto(const nsACString& aLocation,
|
||||
PromiseFlatCString(aLocation).get(), i);
|
||||
}
|
||||
|
||||
RootedObject modObj(cx, mod->obj);
|
||||
if (!JS_GetPropertyById(cx, modObj, symbolId, &value)) {
|
||||
symbolHolder = ResolveModuleObjectPropertyById(cx, mod->obj, symbolId);
|
||||
if (!symbolHolder ||
|
||||
!JS_GetPropertyById(cx, symbolHolder, symbolId, &value)) {
|
||||
JSAutoByteString bytes(cx, JSID_TO_STRING(symbolId));
|
||||
if (!bytes)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -112,6 +112,9 @@ class mozJSComponentLoader : public mozilla::ModuleLoader,
|
||||
mozilla::AutoJSContext cx;
|
||||
JSAutoCompartment ac(cx, obj);
|
||||
|
||||
if (JS_HasExtensibleLexicalScope(obj)) {
|
||||
JS_SetAllNonReservedSlotsToUndefined(cx, JS_ExtensibleLexicalScope(obj));
|
||||
}
|
||||
JS_SetAllNonReservedSlotsToUndefined(cx, obj);
|
||||
obj = nullptr;
|
||||
thisObjectKey = nullptr;
|
||||
|
@ -1556,6 +1556,7 @@ XRE_XPCShellMain(int argc, char** argv, char** envp)
|
||||
|
||||
JS_DropPrincipals(rt, gJSPrincipals);
|
||||
JS_SetAllNonReservedSlotsToUndefined(cx, glob);
|
||||
JS_SetAllNonReservedSlotsToUndefined(cx, JS_GlobalLexicalScope(glob));
|
||||
JS_GC(rt);
|
||||
}
|
||||
JS_GC(rt);
|
||||
|
@ -333,7 +333,7 @@ function _register_protocol_handlers() {
|
||||
}
|
||||
|
||||
function _register_modules_protocol_handler() {
|
||||
if (!this._TESTING_MODULES_DIR) {
|
||||
if (!_TESTING_MODULES_DIR) {
|
||||
throw new Error("Please define a path where the testing modules can be " +
|
||||
"found in a variable called '_TESTING_MODULES_DIR' before " +
|
||||
"head.js is included.");
|
||||
@ -1227,7 +1227,7 @@ function do_load_child_test_harness()
|
||||
+ "const _JSDEBUGGER_PORT=0; "
|
||||
+ "const _XPCSHELL_PROCESS='child';";
|
||||
|
||||
if (this._TESTING_MODULES_DIR) {
|
||||
if (_TESTING_MODULES_DIR) {
|
||||
command += " const _TESTING_MODULES_DIR=" + uneval(_TESTING_MODULES_DIR) + ";";
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user