author | Jeff Walden <jwalden@mit.edu> |
Wed, 16 May 2018 10:34:55 -0700 (2018-05-16) | |
changeset 418608 | 73c36389c5f77846d89754386ef6f2d319aea86c |
parent 418607 | ead72cce7f0e2d2723e3a407db4e250d904d8722 |
child 418609 | 2ddbcf79bc48390a605ffe053b21a834521e6cb6 |
push id | 103351 |
push user | jwalden@mit.edu |
push date | Thu, 17 May 2018 07:17:38 +0000 (2018-05-17) |
treeherder | mozilla-inbound@e016aa76775e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jandem |
bugs | 1461821 |
milestone | 62.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -332,17 +332,17 @@ class TryFinallyControl : public Bytecod bool emittingSubroutine() const { return emittingSubroutine_; } }; static inline void MarkAllBindingsClosedOver(LexicalScope::Data& data) { - BindingName* names = data.names; + TrailingNamesArray& names = data.trailingNames; for (uint32_t i = 0; i < data.length; i++) names[i] = BindingName(names[i].name(), true); } // A scope that introduces bindings. class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterScope> { // The cache of bound names that may be looked up in the @@ -9255,17 +9255,18 @@ BytecodeEmitter::isRestParameter(ParseNo JSAtom* name = pn->name(); Maybe<NameLocation> paramLoc = locationOfNameBoundInFunctionScope(name); if (paramLoc && lookupName(name) == *paramLoc) { FunctionScope::Data* bindings = funbox->functionScopeBindings(); if (bindings->nonPositionalFormalStart > 0) { // |paramName| can be nullptr when the rest destructuring syntax is // used: `function f(...[]) {}`. - JSAtom* paramName = bindings->names[bindings->nonPositionalFormalStart - 1].name(); + JSAtom* paramName = + bindings->trailingNames[bindings->nonPositionalFormalStart - 1].name(); return paramName && name == paramName; } } return false; } bool
--- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -329,17 +329,17 @@ void LexicalScopeNode::dump(GenericPrinter& out, int indent) { const char* name = parseNodeNames[size_t(getKind())]; out.printf("(%s [", name); int nameIndent = indent + strlen(name) + 3; if (!isEmptyScope()) { LexicalScope::Data* bindings = scopeBindings(); for (uint32_t i = 0; i < bindings->length; i++) { - JSAtom* name = bindings->names[i].name(); + JSAtom* name = bindings->trailingNames[i].name(); JS::AutoCheckCannotGC nogc; if (name->hasLatin1Chars()) DumpName(out, name->latin1Chars(nogc), name->length()); else DumpName(out, name->twoByteChars(nogc), name->length()); if (i < bindings->length - 1) IndentNewLine(out, nameIndent); }
--- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -18,16 +18,18 @@ */ #include "frontend/Parser.h" #include "mozilla/Range.h" #include "mozilla/Sprintf.h" #include "mozilla/TypeTraits.h" +#include <new> + #include "jsapi.h" #include "jstypes.h" #include "builtin/ModuleObject.h" #include "builtin/SelfHostingDefines.h" #include "frontend/BytecodeCompiler.h" #include "frontend/FoldConstants.h" #include "frontend/TokenStream.h" @@ -1756,25 +1758,37 @@ Parser<FullParseHandler, CharT>::checkSt return true; } template <typename Scope> typename Scope::Data* NewEmptyBindingData(JSContext* cx, LifoAlloc& alloc, uint32_t numBindings) { size_t allocSize = Scope::sizeOfData(numBindings); - typename Scope::Data* bindings = static_cast<typename Scope::Data*>(alloc.alloc(allocSize)); + auto* bindings = static_cast<typename Scope::Data*>(alloc.alloc(allocSize)); if (!bindings) { ReportOutOfMemory(cx); return nullptr; } PodZero(bindings); return bindings; } +/** + * Copy-construct |BindingName|s from |bindings| into |cursor|, then return + * the location one past the newly-constructed |BindingName|s. + */ +static MOZ_MUST_USE BindingName* +FreshlyInitializeBindings(BindingName* cursor, const Vector<BindingName>& bindings) +{ + for (const BindingName& binding : bindings) + new (cursor++) BindingName(binding); + return cursor; +} + Maybe<GlobalScope::Data*> NewGlobalScopeData(JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc, ParseContext* pc) { Vector<BindingName> funs(context); Vector<BindingName> vars(context); Vector<BindingName> lets(context); Vector<BindingName> consts(context); @@ -1809,32 +1823,30 @@ NewGlobalScopeData(JSContext* context, P uint32_t numBindings = funs.length() + vars.length() + lets.length() + consts.length(); if (numBindings > 0) { bindings = NewEmptyBindingData<GlobalScope>(context, alloc, numBindings); if (!bindings) return Nothing(); // The ordering here is important. See comments in GlobalScope. - BindingName* start = bindings->names; + BindingName* start = bindings->trailingNames.start(); BindingName* cursor = start; - PodCopy(cursor, funs.begin(), funs.length()); - cursor += funs.length(); + cursor = FreshlyInitializeBindings(cursor, funs); bindings->varStart = cursor - start; - PodCopy(cursor, vars.begin(), vars.length()); - cursor += vars.length(); + cursor = FreshlyInitializeBindings(cursor, vars); bindings->letStart = cursor - start; - PodCopy(cursor, lets.begin(), lets.length()); - cursor += lets.length(); + cursor = FreshlyInitializeBindings(cursor, lets); bindings->constStart = cursor - start; - PodCopy(cursor, consts.begin(), consts.length()); + cursor = FreshlyInitializeBindings(cursor, consts); + bindings->length = numBindings; } return Some(bindings); } Maybe<GlobalScope::Data*> ParserBase::newGlobalScopeData(ParseContext::Scope& scope) @@ -1881,32 +1893,30 @@ NewModuleScopeData(JSContext* context, P uint32_t numBindings = imports.length() + vars.length() + lets.length() + consts.length(); if (numBindings > 0) { bindings = NewEmptyBindingData<ModuleScope>(context, alloc, numBindings); if (!bindings) return Nothing(); // The ordering here is important. See comments in ModuleScope. - BindingName* start = bindings->names; + BindingName* start = bindings->trailingNames.start(); BindingName* cursor = start; - PodCopy(cursor, imports.begin(), imports.length()); - cursor += imports.length(); + cursor = FreshlyInitializeBindings(cursor, imports); bindings->varStart = cursor - start; - PodCopy(cursor, vars.begin(), vars.length()); - cursor += vars.length(); + cursor = FreshlyInitializeBindings(cursor, vars); bindings->letStart = cursor - start; - PodCopy(cursor, lets.begin(), lets.length()); - cursor += lets.length(); + cursor = FreshlyInitializeBindings(cursor, lets); bindings->constStart = cursor - start; - PodCopy(cursor, consts.begin(), consts.length()); + cursor = FreshlyInitializeBindings(cursor, consts); + bindings->length = numBindings; } return Some(bindings); } Maybe<ModuleScope::Data*> ParserBase::newModuleScopeData(ParseContext::Scope& scope) @@ -1937,26 +1947,26 @@ NewEvalScopeData(JSContext* context, Par EvalScope::Data* bindings = nullptr; uint32_t numBindings = funs.length() + vars.length(); if (numBindings > 0) { bindings = NewEmptyBindingData<EvalScope>(context, alloc, numBindings); if (!bindings) return Nothing(); - BindingName* start = bindings->names; + BindingName* start = bindings->trailingNames.start(); BindingName* cursor = start; // Keep track of what vars are functions. This is only used in BCE to omit // superfluous DEFVARs. - PodCopy(cursor, funs.begin(), funs.length()); - cursor += funs.length(); + cursor = FreshlyInitializeBindings(cursor, funs); bindings->varStart = cursor - start; - PodCopy(cursor, vars.begin(), vars.length()); + cursor = FreshlyInitializeBindings(cursor, vars); + bindings->length = numBindings; } return Some(bindings); } Maybe<EvalScope::Data*> ParserBase::newEvalScopeData(ParseContext::Scope& scope) @@ -2035,28 +2045,27 @@ NewFunctionScopeData(JSContext* context, uint32_t numBindings = positionalFormals.length() + formals.length() + vars.length(); if (numBindings > 0) { bindings = NewEmptyBindingData<FunctionScope>(context, alloc, numBindings); if (!bindings) return Nothing(); // The ordering here is important. See comments in FunctionScope. - BindingName* start = bindings->names; + BindingName* start = bindings->trailingNames.start(); BindingName* cursor = start; - PodCopy(cursor, positionalFormals.begin(), positionalFormals.length()); - cursor += positionalFormals.length(); + cursor = FreshlyInitializeBindings(cursor, positionalFormals); bindings->nonPositionalFormalStart = cursor - start; - PodCopy(cursor, formals.begin(), formals.length()); - cursor += formals.length(); + cursor = FreshlyInitializeBindings(cursor, formals); bindings->varStart = cursor - start; - PodCopy(cursor, vars.begin(), vars.length()); + cursor = FreshlyInitializeBindings(cursor, vars); + bindings->length = numBindings; } return Some(bindings); } Maybe<FunctionScope::Data*> ParserBase::newFunctionScopeData(ParseContext::Scope& scope, bool hasParameterExprs) @@ -2083,20 +2092,21 @@ NewVarScopeData(JSContext* context, Pars uint32_t numBindings = vars.length(); if (numBindings > 0) { bindings = NewEmptyBindingData<VarScope>(context, alloc, numBindings); if (!bindings) return Nothing(); // The ordering here is important. See comments in FunctionScope. - BindingName* start = bindings->names; + BindingName* start = bindings->trailingNames.start(); BindingName* cursor = start; - PodCopy(cursor, vars.begin(), vars.length()); + cursor = FreshlyInitializeBindings(cursor, vars); + bindings->length = numBindings; } return Some(bindings); } Maybe<VarScope::Data*> ParserBase::newVarScopeData(ParseContext::Scope& scope) @@ -2136,24 +2146,24 @@ NewLexicalScopeData(JSContext* context, uint32_t numBindings = lets.length() + consts.length(); if (numBindings > 0) { bindings = NewEmptyBindingData<LexicalScope>(context, alloc, numBindings); if (!bindings) return Nothing(); // The ordering here is important. See comments in LexicalScope. - BindingName* cursor = bindings->names; + BindingName* cursor = bindings->trailingNames.start(); BindingName* start = cursor; - PodCopy(cursor, lets.begin(), lets.length()); - cursor += lets.length(); + cursor = FreshlyInitializeBindings(cursor, lets); bindings->constStart = cursor - start; - PodCopy(cursor, consts.begin(), consts.length()); + cursor = FreshlyInitializeBindings(cursor, consts); + bindings->length = numBindings; } return Some(bindings); } Maybe<LexicalScope::Data*> ParserBase::newLexicalScopeData(ParseContext::Scope& scope)
--- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -1290,55 +1290,55 @@ BindingName::trace(JSTracer* trc) void BindingIter::trace(JSTracer* trc) { TraceNullableBindingNames(trc, names_, length_); } void LexicalScope::Data::trace(JSTracer* trc) { - TraceBindingNames(trc, names, length); + TraceBindingNames(trc, trailingNames.start(), length); } void FunctionScope::Data::trace(JSTracer* trc) { TraceNullableEdge(trc, &canonicalFunction, "scope canonical function"); - TraceNullableBindingNames(trc, names, length); + TraceNullableBindingNames(trc, trailingNames.start(), length); } void VarScope::Data::trace(JSTracer* trc) { - TraceBindingNames(trc, names, length); + TraceBindingNames(trc, trailingNames.start(), length); } void GlobalScope::Data::trace(JSTracer* trc) { - TraceBindingNames(trc, names, length); + TraceBindingNames(trc, trailingNames.start(), length); } void EvalScope::Data::trace(JSTracer* trc) { - TraceBindingNames(trc, names, length); + TraceBindingNames(trc, trailingNames.start(), length); } void ModuleScope::Data::trace(JSTracer* trc) { TraceNullableEdge(trc, &module, "scope module"); - TraceBindingNames(trc, names, length); + TraceBindingNames(trc, trailingNames.start(), length); } void WasmInstanceScope::Data::trace(JSTracer* trc) { TraceNullableEdge(trc, &instance, "wasm instance"); - TraceBindingNames(trc, names, length); + TraceBindingNames(trc, trailingNames.start(), length); } void WasmFunctionScope::Data::trace(JSTracer* trc) { - TraceBindingNames(trc, names, length); + TraceBindingNames(trc, trailingNames.start(), length); } void Scope::traceChildren(JSTracer* trc) { TraceNullableEdge(trc, &enclosing_, "scope enclosing"); TraceNullableEdge(trc, &environmentShape_, "scope env shape"); switch (kind_) { case ScopeKind::Function: @@ -1378,96 +1378,96 @@ Scope::traceChildren(JSTracer* trc) } inline void js::GCMarker::eagerlyMarkChildren(Scope* scope) { if (scope->enclosing_) traverseEdge(scope, static_cast<Scope*>(scope->enclosing_)); if (scope->environmentShape_) traverseEdge(scope, static_cast<Shape*>(scope->environmentShape_)); - BindingName* names = nullptr; + TrailingNamesArray* names = nullptr; uint32_t length = 0; switch (scope->kind_) { case ScopeKind::Function: { FunctionScope::Data* data = reinterpret_cast<FunctionScope::Data*>(scope->data_); traverseEdge(scope, static_cast<JSObject*>(data->canonicalFunction)); - names = data->names; + names = &data->trailingNames; length = data->length; break; } case ScopeKind::FunctionBodyVar: case ScopeKind::ParameterExpressionVar: { VarScope::Data* data = reinterpret_cast<VarScope::Data*>(scope->data_); - names = data->names; + names = &data->trailingNames; length = data->length; break; } case ScopeKind::Lexical: case ScopeKind::SimpleCatch: case ScopeKind::Catch: case ScopeKind::NamedLambda: case ScopeKind::StrictNamedLambda: { LexicalScope::Data* data = reinterpret_cast<LexicalScope::Data*>(scope->data_); - names = data->names; + names = &data->trailingNames; length = data->length; break; } case ScopeKind::Global: case ScopeKind::NonSyntactic: { GlobalScope::Data* data = reinterpret_cast<GlobalScope::Data*>(scope->data_); - names = data->names; + names = &data->trailingNames; length = data->length; break; } case ScopeKind::Eval: case ScopeKind::StrictEval: { EvalScope::Data* data = reinterpret_cast<EvalScope::Data*>(scope->data_); - names = data->names; + names = &data->trailingNames; length = data->length; break; } case ScopeKind::Module: { ModuleScope::Data* data = reinterpret_cast<ModuleScope::Data*>(scope->data_); traverseEdge(scope, static_cast<JSObject*>(data->module)); - names = data->names; + names = &data->trailingNames; length = data->length; break; } case ScopeKind::With: break; case ScopeKind::WasmInstance: { WasmInstanceScope::Data* data = reinterpret_cast<WasmInstanceScope::Data*>(scope->data_); traverseEdge(scope, static_cast<JSObject*>(data->instance)); - names = data->names; + names = &data->trailingNames; length = data->length; break; } case ScopeKind::WasmFunction: { WasmFunctionScope::Data* data = reinterpret_cast<WasmFunctionScope::Data*>(scope->data_); - names = data->names; + names = &data->trailingNames; length = data->length; break; } } if (scope->kind_ == ScopeKind::Function) { for (uint32_t i = 0; i < length; i++) { - if (JSAtom* name = names[i].name()) + if (JSAtom* name = names->operator[](i).name()) traverseEdge(scope, static_cast<JSString*>(name)); } } else { for (uint32_t i = 0; i < length; i++) - traverseEdge(scope, static_cast<JSString*>(names[i].name())); + traverseEdge(scope, static_cast<JSString*>(names->operator[](i).name())); } } void js::ObjectGroup::traceChildren(JSTracer* trc) { AutoSweepObjectGroup sweep(this);
--- a/js/src/vm/Scope.cpp +++ b/js/src/vm/Scope.cpp @@ -285,17 +285,17 @@ Scope::XDRSizedBindingNames(XDRState<mod auto dataGuard = mozilla::MakeScopeExit([&] () { if (mode == XDR_DECODE) { DeleteScopeData(data.get()); data.set(nullptr); } }); for (uint32_t i = 0; i < length; i++) - MOZ_TRY(XDRBindingName(xdr, &data->names[i])); + MOZ_TRY(XDRBindingName(xdr, &data->trailingNames[i])); dataGuard.release(); return Ok(); } /* static */ Scope* Scope::create(JSContext* cx, ScopeKind kind, HandleScope enclosing, HandleShape envShape) { @@ -1248,28 +1248,29 @@ WasmInstanceScope::create(JSContext* cx, size_t globalsCount = instance->instance().metadata().globals.length(); namesCount += globalsCount; Rooted<UniquePtr<Data>> data(cx, NewEmptyScopeData<WasmInstanceScope>(cx, namesCount)); if (!data) return nullptr; size_t nameIndex = 0; + RootedAtom name(cx); if (instance->instance().memory()) { - RootedAtom name(cx, GenerateWasmName(cx, "memory", /* index = */ 0)); + name = GenerateWasmName(cx, "memory", /* index = */ 0); if (!name) return nullptr; - data->names[nameIndex] = BindingName(name, false); + new (&data->trailingNames[nameIndex]) BindingName(name, false); nameIndex++; } for (size_t i = 0; i < globalsCount; i++) { - RootedAtom name(cx, GenerateWasmName(cx, "global", i)); + name = GenerateWasmName(cx, "global", i); if (!name) return nullptr; - data->names[nameIndex] = BindingName(name, false); + new (&data->trailingNames[nameIndex]) BindingName(name, false); nameIndex++; } MOZ_ASSERT(nameIndex == namesCount); data->instance.init(instance); data->memoriesStart = 0; data->globalsStart = globalsStart; data->length = namesCount; @@ -1316,21 +1317,22 @@ WasmFunctionScope::create(JSContext* cx, uint32_t namesCount = locals.length(); Rooted<UniquePtr<Data>> data(cx, NewEmptyScopeData<WasmFunctionScope>(cx, namesCount)); if (!data) return nullptr; data->funcIndex = funcIndex; data->length = namesCount; + RootedAtom name(cx); for (size_t i = 0; i < namesCount; i++) { - RootedAtom name(cx, GenerateWasmName(cx, "var", i)); + name = GenerateWasmName(cx, "var", i); if (!name) return nullptr; - data->names[i] = BindingName(name, false); + new (&data->trailingNames[i]) BindingName(name, false); } Scope* scope = Scope::create(cx, ScopeKind::WasmFunction, enclosing, /* envShape = */ nullptr); if (!scope) return nullptr; wasmFunctionScope = &scope->as<WasmFunctionScope>(); wasmFunctionScope->initData(Move(data.get())); @@ -1415,29 +1417,29 @@ BindingIter::init(LexicalScope::Data& da // Named lambda scopes can only have environment slots. If the callee // isn't closed over, it is accessed via JSOP_CALLEE. if (flags & IsNamedLambda) { // Named lambda binding is weird. Normal BindingKind ordering rules // don't apply. init(0, 0, 0, 0, 0, 0, CanHaveEnvironmentSlots | flags, firstFrameSlot, JSSLOT_FREE(&LexicalEnvironmentObject::class_), - data.names, data.length); + data.trailingNames.start(), data.length); } else { // imports - [0, 0) // positional formals - [0, 0) // other formals - [0, 0) // top-level funcs - [0, 0) // vars - [0, 0) // lets - [0, data.constStart) // consts - [data.constStart, data.length) init(0, 0, 0, 0, 0, data.constStart, CanHaveFrameSlots | CanHaveEnvironmentSlots | flags, firstFrameSlot, JSSLOT_FREE(&LexicalEnvironmentObject::class_), - data.names, data.length); + data.trailingNames.start(), data.length); } } void BindingIter::init(FunctionScope::Data& data, uint8_t flags) { flags = CanHaveFrameSlots | CanHaveEnvironmentSlots | flags; if (!(flags & HasFormalParameterExprs)) @@ -1448,49 +1450,49 @@ BindingIter::init(FunctionScope::Data& d // other formals - [data.nonPositionalParamStart, data.varStart) // top-level funcs - [data.varStart, data.varStart) // vars - [data.varStart, data.length) // lets - [data.length, data.length) // consts - [data.length, data.length) init(0, data.nonPositionalFormalStart, data.varStart, data.varStart, data.length, data.length, flags, 0, JSSLOT_FREE(&CallObject::class_), - data.names, data.length); + data.trailingNames.start(), data.length); } void BindingIter::init(VarScope::Data& data, uint32_t firstFrameSlot) { // imports - [0, 0) // positional formals - [0, 0) // other formals - [0, 0) // top-level funcs - [0, 0) // vars - [0, data.length) // lets - [data.length, data.length) // consts - [data.length, data.length) init(0, 0, 0, 0, data.length, data.length, CanHaveFrameSlots | CanHaveEnvironmentSlots, firstFrameSlot, JSSLOT_FREE(&VarEnvironmentObject::class_), - data.names, data.length); + data.trailingNames.start(), data.length); } void BindingIter::init(GlobalScope::Data& data) { // imports - [0, 0) // positional formals - [0, 0) // other formals - [0, 0) // top-level funcs - [0, data.varStart) // vars - [data.varStart, data.letStart) // lets - [data.letStart, data.constStart) // consts - [data.constStart, data.length) init(0, 0, 0, data.varStart, data.letStart, data.constStart, CannotHaveSlots, UINT32_MAX, UINT32_MAX, - data.names, data.length); + data.trailingNames.start(), data.length); } void BindingIter::init(EvalScope::Data& data, bool strict) { uint32_t flags; uint32_t firstFrameSlot; uint32_t firstEnvironmentSlot; @@ -1508,65 +1510,65 @@ BindingIter::init(EvalScope::Data& data, // positional formals - [0, 0) // other formals - [0, 0) // top-level funcs - [0, data.varStart) // vars - [data.varStart, data.length) // lets - [data.length, data.length) // consts - [data.length, data.length) init(0, 0, 0, data.varStart, data.length, data.length, flags, firstFrameSlot, firstEnvironmentSlot, - data.names, data.length); + data.trailingNames.start(), data.length); } void BindingIter::init(ModuleScope::Data& data) { // imports - [0, data.varStart) // positional formals - [data.varStart, data.varStart) // other formals - [data.varStart, data.varStart) // top-level funcs - [data.varStart, data.varStart) // vars - [data.varStart, data.letStart) // lets - [data.letStart, data.constStart) // consts - [data.constStart, data.length) init(data.varStart, data.varStart, data.varStart, data.varStart, data.letStart, data.constStart, CanHaveFrameSlots | CanHaveEnvironmentSlots, 0, JSSLOT_FREE(&ModuleEnvironmentObject::class_), - data.names, data.length); + data.trailingNames.start(), data.length); } void BindingIter::init(WasmInstanceScope::Data& data) { // imports - [0, 0) // positional formals - [0, 0) // other formals - [0, 0) // top-level funcs - [0, 0) // vars - [0, data.length) // lets - [data.length, data.length) // consts - [data.length, data.length) init(0, 0, 0, 0, data.length, data.length, CanHaveFrameSlots | CanHaveEnvironmentSlots, UINT32_MAX, UINT32_MAX, - data.names, data.length); + data.trailingNames.start(), data.length); } void BindingIter::init(WasmFunctionScope::Data& data) { // imports - [0, 0) // positional formals - [0, 0) // other formals - [0, 0) // top-level funcs - [0, 0) // vars - [0, data.length) // lets - [data.length, data.length) // consts - [data.length, data.length) init(0, 0, 0, 0, data.length, data.length, CanHaveFrameSlots | CanHaveEnvironmentSlots, UINT32_MAX, UINT32_MAX, - data.names, data.length); + data.trailingNames.start(), data.length); } PositionalFormalParameterIter::PositionalFormalParameterIter(JSScript* script) : BindingIter(script) { // Reinit with flags = 0, i.e., iterate over all positional parameters. if (script->bodyScope()->is<FunctionScope>()) init(script->bodyScope()->as<FunctionScope>().data(), /* flags = */ 0);
--- a/js/src/vm/Scope.h +++ b/js/src/vm/Scope.h @@ -124,16 +124,49 @@ class BindingName bool closedOver() const { return bits_ & ClosedOverFlag; } void trace(JSTracer* trc); }; +/** + * The various {Global,Module,...}Scope::Data classes consist of always-present + * bits, then a trailing array of BindingNames. The various Data classes all + * end in a TrailingNamesArray that contains sized/aligned space for *one* + * BindingName. Data instances that contain N BindingNames, are then allocated + * in sizeof(Data) + (space for (N - 1) BindingNames). Because this class's + * |data_| field is properly sized/aligned, the N-BindingName array can start + * at |data_|. + * + * This is concededly a very low-level representation, but we want to only + * allocate once for data+bindings both, and this does so approximately as + * elegantly as C++ allows. + */ +class TrailingNamesArray +{ + private: + alignas(BindingName) unsigned char data_[sizeof(BindingName)]; + + private: + // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a + // -Werror compile error) to reinterpret_cast<> |data_| to |T*|, even + // through |void*|. Placing the latter cast in these separate functions + // breaks the chain such that affected GCC versions no longer warn/error. + void* ptr() { + return data_; + } + + public: + BindingName* start() { return reinterpret_cast<BindingName*>(ptr()); } + + BindingName& operator[](size_t i) { return start()[i]; } +}; + class BindingLocation { public: enum class Kind { Global, Argument, Frame, Environment, @@ -383,27 +416,27 @@ class LexicalScope : public Scope uint32_t length; // Frame slots [0, nextFrameSlot) are live when this is the innermost // scope. uint32_t nextFrameSlot; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; void trace(JSTracer* trc); }; static size_t sizeOfData(uint32_t length) { return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName); } static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) { - *names = data->names; + *names = data->trailingNames.start(); *length = data->length; } static LexicalScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data, uint32_t firstFrameSlot, HandleScope enclosing); template <XDRMode mode> static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing, @@ -505,28 +538,28 @@ class FunctionScope : public Scope uint32_t length; // Frame slots [0, nextFrameSlot) are live when this is the innermost // scope. uint32_t nextFrameSlot; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; void trace(JSTracer* trc); Zone* zone() const; }; static size_t sizeOfData(uint32_t length) { return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName); } static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) { - *names = data->names; + *names = data->trailingNames.start(); *length = data->length; } static FunctionScope* create(JSContext* cx, Handle<Data*> data, bool hasParameterExprs, bool needsEnvironment, HandleFunction fun, HandleScope enclosing); static FunctionScope* clone(JSContext* cx, Handle<FunctionScope*> scope, HandleFunction fun, @@ -607,27 +640,27 @@ class VarScope : public Scope uint32_t length; // Frame slots [firstFrameSlot(), nextFrameSlot) are live when this is // the innermost scope. uint32_t nextFrameSlot; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; void trace(JSTracer* trc); }; static size_t sizeOfData(uint32_t length) { return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName); } static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) { - *names = data->names; + *names = data->trailingNames.start(); *length = data->length; } static VarScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data, uint32_t firstFrameSlot, bool needsEnvironment, HandleScope enclosing); template <XDRMode mode> @@ -701,27 +734,27 @@ class GlobalScope : public Scope // consts - [constStart, length) uint32_t varStart; uint32_t letStart; uint32_t constStart; uint32_t length; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; void trace(JSTracer* trc); }; static size_t sizeOfData(uint32_t length) { return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName); } static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) { - *names = data->names; + *names = data->trailingNames.start(); *length = data->length; } static GlobalScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data); static GlobalScope* createEmpty(JSContext* cx, ScopeKind kind) { return create(cx, kind, nullptr); } @@ -806,27 +839,27 @@ class EvalScope : public Scope uint32_t length; // Frame slots [0, nextFrameSlot) are live when this is the innermost // scope. uint32_t nextFrameSlot; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; void trace(JSTracer* trc); }; static size_t sizeOfData(uint32_t length) { return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName); } static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) { - *names = data->names; + *names = data->trailingNames.start(); *length = data->length; } static EvalScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data, HandleScope enclosing); template <XDRMode mode> static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing, @@ -912,28 +945,28 @@ class ModuleScope : public Scope uint32_t length; // Frame slots [0, nextFrameSlot) are live when this is the innermost // scope. uint32_t nextFrameSlot; // The array of tagged JSAtom* names, allocated beyond the end of the // struct. - BindingName names[1]; + TrailingNamesArray trailingNames; void trace(JSTracer* trc); Zone* zone() const; }; static size_t sizeOfData(uint32_t length) { return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName); } static void getDataNamesAndLength(Data* data, BindingName** names, uint32_t* length) { - *names = data->names; + *names = data->trailingNames.start(); *length = data->length; } static ModuleScope* create(JSContext* cx, Handle<Data*> data, Handle<ModuleObject*> module, HandleScope enclosing); private: static ModuleScope* createWithData(JSContext* cx, MutableHandle<UniquePtr<Data>> data, @@ -973,17 +1006,17 @@ class WasmInstanceScope : public Scope uint32_t memoriesStart; uint32_t globalsStart; uint32_t length; uint32_t nextFrameSlot; // The wasm instance of the scope. GCPtr<WasmInstanceObject*> instance; - BindingName names[1]; + TrailingNamesArray trailingNames; void trace(JSTracer* trc); }; static WasmInstanceScope* create(JSContext* cx, WasmInstanceObject* instance); static size_t sizeOfData(uint32_t length) { return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName); @@ -1029,17 +1062,17 @@ class WasmFunctionScope : public Scope public: struct Data { uint32_t length; uint32_t nextFrameSlot; uint32_t funcIndex; - BindingName names[1]; + TrailingNamesArray trailingNames; void trace(JSTracer* trc); }; static WasmFunctionScope* create(JSContext* cx, HandleScope enclosing, uint32_t funcIndex); static size_t sizeOfData(uint32_t length) { return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);