author | Tooru Fujisawa <arai_a@mac.com> |
Wed, 22 Sep 2021 04:29:41 +0000 (2021-09-22) | |
changeset 592899 | 8bbbcc59e36b5fc47081de3d545fcb66b56479ab |
parent 592898 | 78c378e9d9d2f13a645b1fa1d036d3915f0ca437 |
child 592900 | 114dc6e441534b3982494e4fc012318ed5e07c92 |
push id | 150167 |
push user | arai_a@mac.com |
push date | Wed, 22 Sep 2021 04:32:48 +0000 (2021-09-22) |
treeherder | autoland@ba3814055b37 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | tcampbell |
bugs | 1721413 |
milestone | 94.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/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -8,16 +8,17 @@ #include "mozilla/DebugOnly.h" #include "mozilla/EnumSet.h" #include "mozilla/ScopeExit.h" #include "builtin/Promise.h" #include "builtin/SelfHostingDefines.h" #include "frontend/ParseNode.h" +#include "frontend/ParserAtom.h" // TaggedParserAtomIndex, ParserAtomsTable, ParserAtom #include "frontend/SharedContext.h" #include "gc/FreeOp.h" #include "gc/Policy.h" #include "gc/Tracer.h" #include "js/friend/ErrorMessages.h" // JSMSG_* #include "js/Modules.h" // JS::GetModulePrivate, JS::ModuleDynamicImportHook #include "js/PropertySpec.h" #include "vm/AsyncFunction.h" @@ -2008,17 +2009,19 @@ bool ModuleBuilder::maybeAppendRequested js::ReportOutOfMemory(cx_); return false; } return requestedModuleSpecifiers_.put(specifier); } void ModuleBuilder::markUsedByStencil(frontend::TaggedParserAtomIndex name) { - eitherParser_.parserAtoms().markUsedByStencil(name); + // Imported/exported identifiers must be atomized. + eitherParser_.parserAtoms().markUsedByStencil( + name, frontend::ParserAtom::Atomize::Yes); } template <typename T> ArrayObject* js::CreateArray(JSContext* cx, const JS::Rooted<GCVector<T>>& vector) { uint32_t length = vector.length(); RootedArrayObject array(cx, NewDenseFullyAllocatedArray(cx, length)); if (!array) {
--- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -45,17 +45,17 @@ #include "frontend/ModuleSharedContext.h" // ModuleSharedContext #include "frontend/NameAnalysisTypes.h" // PrivateNameKind #include "frontend/NameFunctions.h" // NameFunctions #include "frontend/NameOpEmitter.h" // NameOpEmitter #include "frontend/ObjectEmitter.h" // PropertyEmitter, ObjectEmitter, ClassEmitter #include "frontend/OptionalEmitter.h" // OptionalEmitter #include "frontend/ParseNode.h" // ParseNodeKind, ParseNode and subclasses #include "frontend/Parser.h" // Parser -#include "frontend/ParserAtom.h" // ParserAtomsTable +#include "frontend/ParserAtom.h" // ParserAtomsTable, ParserAtom #include "frontend/PrivateOpEmitter.h" // PrivateOpEmitter #include "frontend/PropOpEmitter.h" // PropOpEmitter #include "frontend/SourceNotes.h" // SrcNote, SrcNoteType, SrcNoteWriter #include "frontend/SwitchEmitter.h" // SwitchEmitter #include "frontend/TaggedParserAtomIndexHasher.h" // TaggedParserAtomIndexHasher #include "frontend/TDZCheckCache.h" // TDZCheckCache #include "frontend/TryEmitter.h" // TryEmitter #include "frontend/WhileEmitter.h" // WhileEmitter @@ -932,25 +932,44 @@ bool BytecodeEmitter::emitAtomOp(JSOp op // .generator lookups should be emitted as JSOp::GetAliasedVar instead of // JSOp::GetName etc, to bypass |with| objects on the scope chain. // It's safe to emit .this lookups though because |with| objects skip // those. MOZ_ASSERT_IF(op == JSOp::GetName || op == JSOp::GetGName, atom != TaggedParserAtomIndex::WellKnown::dotGenerator()); GCThingIndex index; - if (!makeAtomIndex(atom, &index)) { + if (!makeAtomIndex(atom, ParserAtom::Atomize::Yes, &index)) { return false; } return emitAtomOp(op, index); } bool BytecodeEmitter::emitAtomOp(JSOp op, GCThingIndex atomIndex) { MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ATOM); +#ifdef DEBUG + auto atom = perScriptData().gcThingList().getAtom(atomIndex); + MOZ_ASSERT(compilationState.parserAtoms.isInstantiatedAsJSAtom(atom)); +#endif + return emitGCIndexOp(op, atomIndex); +} + +bool BytecodeEmitter::emitStringOp(JSOp op, TaggedParserAtomIndex atom) { + MOZ_ASSERT(atom); + GCThingIndex index; + if (!makeAtomIndex(atom, ParserAtom::Atomize::No, &index)) { + return false; + } + + return emitStringOp(op, index); +} + +bool BytecodeEmitter::emitStringOp(JSOp op, GCThingIndex atomIndex) { + MOZ_ASSERT(JOF_OPTYPE(op) == JOF_ATOM); return emitGCIndexOp(op, atomIndex); } bool BytecodeEmitter::emitInternedScopeOp(GCThingIndex index, JSOp op) { MOZ_ASSERT(JOF_OPTYPE(op) == JOF_SCOPE); MOZ_ASSERT(index < perScriptData().gcThingList().length()); return emitGCIndexOp(op, index); } @@ -4141,17 +4160,18 @@ bool BytecodeEmitter::emitTemplateString } else { pushedString = true; } } if (!pushedString) { // All strings were empty, this can happen for something like `${""}`. // Just push an empty string. - if (!emitAtomOp(JSOp::String, TaggedParserAtomIndex::WellKnown::empty())) { + if (!emitStringOp(JSOp::String, + TaggedParserAtomIndex::WellKnown::empty())) { return false; } } return true; } bool BytecodeEmitter::emitDeclarationList(ListNode* declList) { @@ -7717,17 +7737,19 @@ bool BytecodeEmitter::emitSelfHostedSetC if (!checkSelfHostedExpectedTopLevel(callNode, argsList->head())) { return false; } #endif ParseNode* nameNode = argsList->last(); MOZ_ASSERT(nameNode->isKind(ParseNodeKind::StringExpr)); TaggedParserAtomIndex specName = nameNode->as<NameNode>().atom(); - compilationState.parserAtoms.markUsedByStencil(specName); + // Canonical name must be atomized. + compilationState.parserAtoms.markUsedByStencil(specName, + ParserAtom::Atomize::Yes); // Store the canonical name for instantiation. prevSelfHostedTopLevelFunction->functionStencil().setSelfHostedCanonicalName( specName); return emit1(JSOp::Undefined); } @@ -11492,17 +11514,17 @@ bool BytecodeEmitter::emitTree( case ParseNodeKind::TemplateStringListExpr: if (!emitTemplateString(&pn->as<ListNode>())) { return false; } break; case ParseNodeKind::TemplateStringExpr: case ParseNodeKind::StringExpr: - if (!emitAtomOp(JSOp::String, pn->as<NameNode>().atom())) { + if (!emitStringOp(JSOp::String, pn->as<NameNode>().atom())) { return false; } break; case ParseNodeKind::NumberExpr: if (!emitNumberOp(pn->as<NumericLiteral>().value())) { return false; }
--- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -29,17 +29,17 @@ #include "frontend/ErrorReporter.h" // ErrorReporter #include "frontend/FullParseHandler.h" // FullParseHandler #include "frontend/IteratorKind.h" // IteratorKind #include "frontend/JumpList.h" // JumpList, JumpTarget #include "frontend/NameAnalysisTypes.h" // NameLocation #include "frontend/NameCollections.h" // AtomIndexMap #include "frontend/ParseNode.h" // ParseNode and subclasses #include "frontend/Parser.h" // Parser, PropListType -#include "frontend/ParserAtom.h" // TaggedParserAtomIndex +#include "frontend/ParserAtom.h" // TaggedParserAtomIndex, ParserAtom #include "frontend/PrivateOpEmitter.h" // PrivateOpEmitter #include "frontend/ScriptIndex.h" // ScriptIndex #include "frontend/SharedContext.h" // SharedContext, TopLevelFunction #include "frontend/SourceNotes.h" // SrcNoteType #include "frontend/TokenStream.h" // TokenPos #include "frontend/ValueUsage.h" // ValueUsage #include "js/RootingAPI.h" // JS::Rooted, JS::Handle #include "js/TypeDecls.h" // jsbytecode @@ -390,27 +390,29 @@ struct MOZ_STACK_CLASS BytecodeEmitter { } AbstractScopePtr outermostScope() const { return perScriptData().gcThingList().firstScope(); } AbstractScopePtr innermostScope() const; ScopeIndex innermostScopeIndex() const; - [[nodiscard]] MOZ_ALWAYS_INLINE bool makeAtomIndex(TaggedParserAtomIndex atom, - GCThingIndex* indexp) { + [[nodiscard]] MOZ_ALWAYS_INLINE bool makeAtomIndex( + TaggedParserAtomIndex atom, ParserAtom::Atomize atomize, + GCThingIndex* indexp) { MOZ_ASSERT(perScriptData().atomIndices()); AtomIndexMap::AddPtr p = perScriptData().atomIndices()->lookupForAdd(atom); if (p) { + compilationState.parserAtoms.markAtomize(atom, atomize); *indexp = GCThingIndex(p->value()); return true; } GCThingIndex index; - if (!perScriptData().gcThingList().append(atom, &index)) { + if (!perScriptData().gcThingList().append(atom, atomize, &index)) { return false; } // `atomIndices()` uses uint32_t instead of GCThingIndex, because // GCThingIndex isn't trivial type. if (!perScriptData().atomIndices()->add(p, atom, index.index)) { ReportOutOfMemory(cx); return false; @@ -603,16 +605,19 @@ struct MOZ_STACK_CLASS BytecodeEmitter { [[nodiscard]] bool emitGoto(NestableControl* target, JumpList* jumplist, GotoKind kind); [[nodiscard]] bool emitGCIndexOp(JSOp op, GCThingIndex index); [[nodiscard]] bool emitAtomOp(JSOp op, TaggedParserAtomIndex atom); [[nodiscard]] bool emitAtomOp(JSOp op, GCThingIndex atomIndex); + [[nodiscard]] bool emitStringOp(JSOp op, TaggedParserAtomIndex atom); + [[nodiscard]] bool emitStringOp(JSOp op, GCThingIndex atomIndex); + [[nodiscard]] bool emitArrayLiteral(ListNode* array); [[nodiscard]] bool emitArray(ParseNode* arrayHead, uint32_t count); [[nodiscard]] bool emitInternedScopeOp(GCThingIndex index, JSOp op); [[nodiscard]] bool emitInternedObjectOp(GCThingIndex index, JSOp op); [[nodiscard]] bool emitObjectPairOp(GCThingIndex index1, GCThingIndex index2, JSOp op); [[nodiscard]] bool emitRegExp(GCThingIndex index);
--- a/js/src/frontend/BytecodeSection.cpp +++ b/js/src/frontend/BytecodeSection.cpp @@ -44,16 +44,21 @@ AbstractScopePtr GCThingList::getScope(s mozilla::Maybe<ScopeIndex> GCThingList::getScopeIndex(size_t index) const { const TaggedScriptThingIndex& elem = vector[index]; if (elem.isEmptyGlobalScope()) { return mozilla::Nothing(); } return mozilla::Some(vector[index].toScope()); } +TaggedParserAtomIndex GCThingList::getAtom(size_t index) const { + const TaggedScriptThingIndex& elem = vector[index]; + return elem.toAtom(); +} + bool js::frontend::EmitScriptThingsVector( JSContext* cx, const CompilationAtomCache& atomCache, const CompilationStencil& stencil, CompilationGCOutput& gcOutput, mozilla::Span<const TaggedScriptThingIndex> things, mozilla::Span<JS::GCCellPtr> output) { MOZ_ASSERT(things.size() <= INDEX_LIMIT); MOZ_ASSERT(things.size() == output.size());
--- a/js/src/frontend/BytecodeSection.h +++ b/js/src/frontend/BytecodeSection.h @@ -19,17 +19,17 @@ #include "frontend/AbstractScopePtr.h" // AbstractScopePtr, ScopeIndex #include "frontend/BytecodeOffset.h" // BytecodeOffset #include "frontend/CompilationStencil.h" // CompilationStencil, CompilationGCOutput, CompilationAtomCache #include "frontend/JumpList.h" // JumpTarget #include "frontend/NameCollections.h" // AtomIndexMap, PooledMapPtr #include "frontend/ObjLiteral.h" // ObjLiteralStencil #include "frontend/ParseNode.h" // BigIntLiteral -#include "frontend/ParserAtom.h" // ParserAtomsTable, TaggedParserAtomIndex +#include "frontend/ParserAtom.h" // ParserAtomsTable, TaggedParserAtomIndex, ParserAtom #include "frontend/SourceNotes.h" // SrcNote #include "frontend/Stencil.h" // Stencils #include "gc/Rooting.h" // JS::Rooted #include "js/GCVariant.h" // GCPolicy<mozilla::Variant> #include "js/GCVector.h" // GCVector #include "js/TypeDecls.h" // jsbytecode, JSContext #include "js/Value.h" // JS::Vector #include "js/Vector.h" // Vector @@ -54,19 +54,20 @@ struct MOZ_STACK_CLASS GCThingList { ScriptThingsStackVector vector; // Index of the first scope in the vector. mozilla::Maybe<GCThingIndex> firstScopeIndex; explicit GCThingList(JSContext* cx, CompilationState& compilationState) : compilationState(compilationState), vector(cx) {} - [[nodiscard]] bool append(TaggedParserAtomIndex atom, GCThingIndex* index) { + [[nodiscard]] bool append(TaggedParserAtomIndex atom, + ParserAtom::Atomize atomize, GCThingIndex* index) { *index = GCThingIndex(vector.length()); - compilationState.parserAtoms.markUsedByStencil(atom); + compilationState.parserAtoms.markUsedByStencil(atom, atomize); if (!vector.emplaceBack(atom)) { return false; } return true; } [[nodiscard]] bool append(ScopeIndex scope, GCThingIndex* index) { *index = GCThingIndex(vector.length()); if (!vector.emplaceBack(scope)) { @@ -117,16 +118,18 @@ struct MOZ_STACK_CLASS GCThingList { const ScriptThingsStackVector& objects() { return vector; } AbstractScopePtr getScope(size_t index) const; // Index of scope within CompilationStencil or Nothing is the scope is // EmptyGlobalScopeType. mozilla::Maybe<ScopeIndex> getScopeIndex(size_t index) const; + TaggedParserAtomIndex getAtom(size_t index) const; + AbstractScopePtr firstScope() const { MOZ_ASSERT(firstScopeIndex.isSome()); return getScope(*firstScopeIndex); } }; [[nodiscard]] bool EmitScriptThingsVector( JSContext* cx, const CompilationAtomCache& atomCache,
--- a/js/src/frontend/Frontend2.cpp +++ b/js/src/frontend/Frontend2.cpp @@ -65,17 +65,20 @@ bool ConvertAtoms(JSContext* cx, const S for (size_t i = 0; i < numAtoms; i++) { auto s = reinterpret_cast<const mozilla::Utf8Unit*>( smoosh_get_atom_at(result, i)); auto len = smoosh_get_atom_len_at(result, i); auto atom = compilationState.parserAtoms.internUtf8(cx, s, len); if (!atom) { return false; } - compilationState.parserAtoms.markUsedByStencil(atom); + // We don't collect atomization information in smoosh yet. + // Assume it needs to be atomized. + compilationState.parserAtoms.markUsedByStencil(atom, + ParserAtom::Atomize::Yes); allAtoms.infallibleAppend(atom); } return true; } void CopyBindingNames(JSContext* cx, CVec<SmooshBindingName>& from, Vector<TaggedParserAtomIndex>& allAtoms, @@ -323,17 +326,19 @@ bool ConvertRegExpData(JSContext* cx, co const mozilla::Utf8Unit* sUtf8 = reinterpret_cast<const mozilla::Utf8Unit*>(s); auto atom = compilationState.parserAtoms.internUtf8(cx, sUtf8, len); if (!atom) { return false; } - compilationState.parserAtoms.markUsedByStencil(atom); + // RegExp patterm must be atomized. + compilationState.parserAtoms.markUsedByStencil(atom, + ParserAtom::Atomize::Yes); compilationState.regExpData.infallibleEmplaceBack(atom, JS::RegExpFlags(flags)); } return true; } // Convert SmooshImmutableScriptData into ImmutableScriptData.
--- a/js/src/frontend/NameOpEmitter.cpp +++ b/js/src/frontend/NameOpEmitter.cpp @@ -3,16 +3,17 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "frontend/NameOpEmitter.h" #include "frontend/AbstractScopePtr.h" #include "frontend/BytecodeEmitter.h" +#include "frontend/ParserAtom.h" // ParserAtom #include "frontend/SharedContext.h" #include "frontend/TDZCheckCache.h" #include "vm/Opcodes.h" #include "vm/Scope.h" #include "vm/StringType.h" using namespace js; using namespace js::frontend; @@ -148,17 +149,17 @@ bool NameOpEmitter::emitGet() { bool NameOpEmitter::prepareForRhs() { MOZ_ASSERT(state_ == State::Start); switch (loc_.kind()) { case NameLocation::Kind::Dynamic: case NameLocation::Kind::Import: case NameLocation::Kind::DynamicAnnexBVar: - if (!bce_->makeAtomIndex(name_, &atomIndex_)) { + if (!bce_->makeAtomIndex(name_, ParserAtom::Atomize::Yes, &atomIndex_)) { return false; } if (loc_.kind() == NameLocation::Kind::DynamicAnnexBVar) { // Annex B vars always go on the nearest variable environment, // even if lexical environments in between contain same-named // bindings. if (!bce_->emit1(JSOp::BindVar)) { // [stack] ENV @@ -168,17 +169,17 @@ bool NameOpEmitter::prepareForRhs() { if (!bce_->emitAtomOp(JSOp::BindName, atomIndex_)) { // [stack] ENV return false; } } emittedBindOp_ = true; break; case NameLocation::Kind::Global: - if (!bce_->makeAtomIndex(name_, &atomIndex_)) { + if (!bce_->makeAtomIndex(name_, ParserAtom::Atomize::Yes, &atomIndex_)) { return false; } if (loc_.isLexical() && isInitialize()) { // InitGLexical always gets the global lexical scope. It doesn't // need a BindGName. MOZ_ASSERT(bce_->innermostScope().is<GlobalScope>()); } else { if (!bce_->emitAtomOp(JSOp::BindGName, atomIndex_)) {
--- a/js/src/frontend/ObjLiteral.h +++ b/js/src/frontend/ObjLiteral.h @@ -7,17 +7,17 @@ #ifndef frontend_ObjLiteral_h #define frontend_ObjLiteral_h #include "mozilla/BloomFilter.h" // mozilla::BitBloomFilter #include "mozilla/EnumSet.h" #include "mozilla/Span.h" -#include "frontend/ParserAtom.h" // ParserAtomsTable, TaggedParserAtomIndex +#include "frontend/ParserAtom.h" // ParserAtomsTable, TaggedParserAtomIndex, ParserAtom #include "js/AllocPolicy.h" #include "js/GCPolicyAPI.h" #include "js/Value.h" #include "js/Vector.h" #include "util/EnumFlags.h" #include "vm/BytecodeUtil.h" #include "vm/Opcodes.h" @@ -376,17 +376,17 @@ struct ObjLiteralWriter : private ObjLit } return true; } void setPropNameNoDuplicateCheck( frontend::ParserAtomsTable& parserAtoms, const frontend::TaggedParserAtomIndex propName) { MOZ_ASSERT(kind_ == ObjLiteralKind::Object || kind_ == ObjLiteralKind::Shape); - parserAtoms.markUsedByStencil(propName); + parserAtoms.markUsedByStencil(propName, frontend::ParserAtom::Atomize::Yes); nextKey_ = ObjLiteralKey::fromPropName(propName); } void setPropIndex(uint32_t propIndex) { MOZ_ASSERT(kind_ == ObjLiteralKind::Object); MOZ_ASSERT(propIndex <= ATOM_INDEX_MASK); nextKey_ = ObjLiteralKey::fromArrayIndex(propIndex); flags_.setFlag(ObjLiteralFlag::HasIndexOrDuplicatePropName); } @@ -405,17 +405,17 @@ struct ObjLiteralWriter : private ObjLit return pushOpAndName(cx, ObjLiteralOpcode::ConstValue, nextKey_) && pushValueArg(cx, value); } [[nodiscard]] bool propWithAtomValue( JSContext* cx, frontend::ParserAtomsTable& parserAtoms, const frontend::TaggedParserAtomIndex value) { MOZ_ASSERT(kind_ != ObjLiteralKind::Shape); propertyCount_++; - parserAtoms.markUsedByStencil(value); + parserAtoms.markUsedByStencil(value, frontend::ParserAtom::Atomize::No); return pushOpAndName(cx, ObjLiteralOpcode::ConstAtom, nextKey_) && pushAtomArg(cx, value); } [[nodiscard]] bool propWithNullValue(JSContext* cx) { MOZ_ASSERT(kind_ != ObjLiteralKind::Shape); propertyCount_++; return pushOpAndName(cx, ObjLiteralOpcode::Null, nextKey_); }
--- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -38,16 +38,17 @@ #include "builtin/SelfHostingDefines.h" #include "frontend/BytecodeCompiler.h" #include "frontend/BytecodeSection.h" #include "frontend/FoldConstants.h" #include "frontend/FunctionSyntaxKind.h" // FunctionSyntaxKind #include "frontend/ModuleSharedContext.h" #include "frontend/ParseNode.h" #include "frontend/ParseNodeVerify.h" +#include "frontend/ParserAtom.h" // TaggedParserAtomIndex, ParserAtomsTable, ParserAtom #include "frontend/ScriptIndex.h" // ScriptIndex #include "frontend/TokenStream.h" #include "irregexp/RegExpAPI.h" #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_* #include "js/RegExpFlags.h" // JS::RegExpFlags #include "util/StringBuffer.h" // StringBuffer #include "vm/BigIntType.h" #include "vm/BytecodeUtil.h" @@ -2203,17 +2204,17 @@ bool PerHandlerParser<SyntaxParseHandler // FullParseHandler::nextLazyClosedOverBinding() for (const ScriptIndex& index : pc_->innerFunctionIndexesForLazy) { void* raw = &(*cursor++); new (raw) TaggedScriptThingIndex(index); } for (auto binding : pc_->closedOverBindingsForLazy()) { void* raw = &(*cursor++); if (binding) { - this->parserAtoms().markUsedByStencil(binding); + this->parserAtoms().markUsedByStencil(binding, ParserAtom::Atomize::Yes); new (raw) TaggedScriptThingIndex(binding); } else { new (raw) TaggedScriptThingIndex(); } } return true; } @@ -10910,17 +10911,18 @@ RegExpLiteral* Parser<FullParseHandler, } } auto atom = this->parserAtoms().internChar16(cx_, chars.begin(), chars.length()); if (!atom) { return nullptr; } - this->parserAtoms().markUsedByStencil(atom); + // RegExp patterm must be atomized. + this->parserAtoms().markUsedByStencil(atom, ParserAtom::Atomize::Yes); RegExpIndex index(this->compilationState_.regExpData.length()); if (uint32_t(index) >= TaggedScriptThingIndex::IndexLimit) { ReportAllocationOverflow(cx_); return nullptr; } if (!this->compilationState_.regExpData.emplaceBack(atom, flags)) { js::ReportOutOfMemory(cx_);
--- a/js/src/frontend/ParserAtom.cpp +++ b/js/src/frontend/ParserAtom.cpp @@ -310,21 +310,36 @@ TaggedParserAtomIndex ParserAtomsTable:: JSContext* cx, const ParserAtom* atom) { InflatedChar16Sequence<AtomCharT> seq(atom->chars<AtomCharT>(), atom->length()); SpecificParserAtomLookup<AtomCharT> lookup(seq, atom->hash()); // Check for existing atom. auto addPtr = entryMap_.lookupForAdd(lookup); if (addPtr) { - return addPtr->value(); + auto index = addPtr->value(); + + // Copy UsedByStencilFlag and AtomizeFlag. + MOZ_ASSERT(entries_[index.toParserAtomIndex()]->hasTwoByteChars() == + atom->hasTwoByteChars()); + entries_[index.toParserAtomIndex()]->flags_ |= atom->flags_; + return index; } - return internChar16Seq<AtomCharT>(cx, addPtr, atom->hash(), seq, - atom->length()); + auto index = + internChar16Seq<AtomCharT>(cx, addPtr, atom->hash(), seq, atom->length()); + if (!index) { + return TaggedParserAtomIndex::null(); + } + + // Copy UsedByStencilFlag and AtomizeFlag. + MOZ_ASSERT(entries_[index.toParserAtomIndex()]->hasTwoByteChars() == + atom->hasTwoByteChars()); + entries_[index.toParserAtomIndex()]->flags_ |= atom->flags_; + return index; } TaggedParserAtomIndex ParserAtomsTable::internExternalParserAtom( JSContext* cx, const ParserAtom* atom) { if (atom->hasLatin1Chars()) { return internExternalParserAtomImpl<JS::Latin1Char>(cx, atom); } return internExternalParserAtomImpl<char16_t>(cx, atom); @@ -467,22 +482,32 @@ TaggedParserAtomIndex ParserAtomsTable:: return parserAtom; } ParserAtom* ParserAtomsTable::getParserAtom(ParserAtomIndex index) const { return entries_[index]; } -void ParserAtomsTable::markUsedByStencil(TaggedParserAtomIndex index) const { +void ParserAtomsTable::markUsedByStencil(TaggedParserAtomIndex index, + ParserAtom::Atomize atomize) const { if (!index.isParserAtomIndex()) { return; } - getParserAtom(index.toParserAtomIndex())->markUsedByStencil(); + getParserAtom(index.toParserAtomIndex())->markUsedByStencil(atomize); +} + +void ParserAtomsTable::markAtomize(TaggedParserAtomIndex index, + ParserAtom::Atomize atomize) const { + if (!index.isParserAtomIndex()) { + return; + } + + getParserAtom(index.toParserAtomIndex())->markAtomize(atomize); } bool ParserAtomsTable::isIdentifier(TaggedParserAtomIndex index) const { if (index.isParserAtomIndex()) { const auto* atom = getParserAtom(index.toParserAtomIndex()); return atom->hasLatin1Chars() ? IsIdentifier(atom->latin1Chars(), atom->length()) : IsIdentifier(atom->twoByteChars(), atom->length()); @@ -642,16 +667,27 @@ bool ParserAtomsTable::isIndex(TaggedPar mozilla::IsAsciiDigit(content[1])) { *indexp = AsciiDigitToNumber(content[0]) * 10 + AsciiDigitToNumber(content[1]); return true; } return false; } +bool ParserAtomsTable::isInstantiatedAsJSAtom( + TaggedParserAtomIndex index) const { + if (index.isParserAtomIndex()) { + const auto* atom = getParserAtom(index.toParserAtomIndex()); + return atom->isMarkedAtomize(); + } + + // Everything else are always JSAtom. + return true; +} + uint32_t ParserAtomsTable::length(TaggedParserAtomIndex index) const { if (index.isParserAtomIndex()) { return getParserAtom(index.toParserAtomIndex())->length(); } if (index.isWellKnownAtomId()) { const auto& info = GetWellKnownAtomInfo(index.toWellKnownAtomId()); return info.length;
--- a/js/src/frontend/ParserAtom.h +++ b/js/src/frontend/ParserAtom.h @@ -331,17 +331,31 @@ class alignas(alignof(uint32_t)) ParserA friend class ParserAtomsTable; friend class WellKnownParserAtoms; static const uint16_t MAX_LATIN1_CHAR = 0xff; // Bit flags inside flags_. static constexpr uint32_t HasTwoByteCharsFlag = 1 << 0; static constexpr uint32_t UsedByStencilFlag = 1 << 1; + static constexpr uint32_t AtomizeFlag = 1 << 2; + public: + // Whether to atomize the ParserAtom during instantiation. + // + // If this ParserAtom is used by opcode with JOF_ATOM, or used as a binding + // in scope, it needs to be instantiated as JSAtom. + // Otherwise, it needs to be instantiated as LinearString, to reduce the + // cost of atomization. + enum class Atomize : uint32_t { + No = 0, + Yes = AtomizeFlag, + }; + + private: // Helper routine to read some sequence of two-byte chars, and write them // into a target buffer of a particular character width. // // The characters in the sequence must have been verified prior template <typename CharT, typename SeqCharT> static void drainChar16Seq(CharT* buf, InflatedChar16Sequence<SeqCharT> seq, uint32_t length) { static_assert( @@ -406,25 +420,30 @@ class alignas(alignof(uint32_t)) ParserA return true; } HashNumber hash() const { return hash_; } uint32_t length() const { return length_; } bool isUsedByStencil() const { return flags_ & UsedByStencilFlag; } + bool isMarkedAtomize() const { return flags_ & AtomizeFlag; } + template <typename CharT> bool equalsSeq(HashNumber hash, InflatedChar16Sequence<CharT> seq) const; // Convert NotInstantiated and usedByStencil entry to a js-atom. JSAtom* instantiate(JSContext* cx, ParserAtomIndex index, CompilationAtomCache& atomCache) const; private: - void markUsedByStencil() { flags_ |= UsedByStencilFlag; } + void markUsedByStencil(Atomize atomize) { + flags_ |= UsedByStencilFlag | uint32_t(atomize); + } + void markAtomize(Atomize atomize) { flags_ |= uint32_t(atomize); } constexpr void setHashAndLength(HashNumber hash, uint32_t length) { hash_ = hash; length_ = length; } template <typename CharT> const CharT* chars() const { @@ -636,16 +655,18 @@ class ParserAtomsTable { TaggedParserAtomIndex internChar16(JSContext* cx, const char16_t* char16Ptr, uint32_t length); TaggedParserAtomIndex internJSAtom(JSContext* cx, CompilationAtomCache& atomCache, JSAtom* atom); + // Intern ParserAtom data from other ParserAtomTable. + // This copies flags as well. TaggedParserAtomIndex internExternalParserAtom(JSContext* cx, const ParserAtom* atom); bool addPlaceholder(JSContext* cx); private: const ParserAtom* getWellKnown(WellKnownAtomId atomId) const; ParserAtom* getParserAtom(ParserAtomIndex index) const; @@ -655,20 +676,24 @@ class ParserAtomsTable { // Accessors for querying atom properties. bool isIdentifier(TaggedParserAtomIndex index) const; bool isPrivateName(TaggedParserAtomIndex index) const; bool isExtendedUnclonedSelfHostedFunctionName( TaggedParserAtomIndex index) const; bool isModuleExportName(TaggedParserAtomIndex index) const; bool isIndex(TaggedParserAtomIndex index, uint32_t* indexp) const; + bool isInstantiatedAsJSAtom(TaggedParserAtomIndex index) const; uint32_t length(TaggedParserAtomIndex index) const; // Methods for atom. - void markUsedByStencil(TaggedParserAtomIndex index) const; + void markUsedByStencil(TaggedParserAtomIndex index, + ParserAtom::Atomize atomize) const; + void markAtomize(TaggedParserAtomIndex index, + ParserAtom::Atomize atomize) const; bool toNumber(JSContext* cx, TaggedParserAtomIndex index, double* result) const; UniqueChars toNewUTF8CharsZ(JSContext* cx, TaggedParserAtomIndex index) const; UniqueChars toPrintableString(JSContext* cx, TaggedParserAtomIndex index) const; UniqueChars toQuotedString(JSContext* cx, TaggedParserAtomIndex index) const; JSAtom* toJSAtom(JSContext* cx, TaggedParserAtomIndex index, CompilationAtomCache& atomCache) const;
--- a/js/src/frontend/PropOpEmitter.cpp +++ b/js/src/frontend/PropOpEmitter.cpp @@ -2,29 +2,30 @@ * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "frontend/PropOpEmitter.h" #include "frontend/BytecodeEmitter.h" +#include "frontend/ParserAtom.h" // ParserAtom #include "frontend/SharedContext.h" #include "vm/Opcodes.h" #include "vm/StringType.h" #include "vm/ThrowMsgKind.h" // ThrowMsgKind using namespace js; using namespace js::frontend; PropOpEmitter::PropOpEmitter(BytecodeEmitter* bce, Kind kind, ObjKind objKind) : bce_(bce), kind_(kind), objKind_(objKind) {} bool PropOpEmitter::prepareAtomIndex(TaggedParserAtomIndex prop) { - return bce_->makeAtomIndex(prop, &propAtomIndex_); + return bce_->makeAtomIndex(prop, ParserAtom::Atomize::Yes, &propAtomIndex_); } bool PropOpEmitter::prepareForObj() { MOZ_ASSERT(state_ == State::Start); #ifdef DEBUG state_ = State::Obj; #endif
--- a/js/src/frontend/SharedContext.cpp +++ b/js/src/frontend/SharedContext.cpp @@ -334,17 +334,18 @@ void FunctionBox::finishScriptFlags() { immutableFlags_.setFlag(ImmutableFlags::HasMappedArgsObj, hasMappedArgsObj()); } void FunctionBox::copyFunctionFields(ScriptStencil& script) { MOZ_ASSERT(&script == &functionStencil()); MOZ_ASSERT(!isFunctionFieldCopiedToStencil); if (atom_) { - compilationState_.parserAtoms.markUsedByStencil(atom_); + compilationState_.parserAtoms.markUsedByStencil(atom_, + ParserAtom::Atomize::Yes); script.functionAtom = atom_; } script.functionFlags = flags_; if (enclosingScopeIndex_) { script.setLazyFunctionEnclosingScopeIndex(*enclosingScopeIndex_); } if (wasEmittedByEnclosingScript_) { script.setWasEmittedByEnclosingScript(); @@ -389,17 +390,18 @@ void FunctionBox::copyUpdatedEnclosingSc if (enclosingScopeIndex_) { script.setLazyFunctionEnclosingScopeIndex(*enclosingScopeIndex_); } } void FunctionBox::copyUpdatedAtomAndFlags() { ScriptStencil& script = functionStencil(); if (atom_) { - compilationState_.parserAtoms.markUsedByStencil(atom_); + compilationState_.parserAtoms.markUsedByStencil(atom_, + ParserAtom::Atomize::Yes); script.functionAtom = atom_; } script.functionFlags = flags_; } void FunctionBox::copyUpdatedWasEmitted() { ScriptStencil& script = functionStencil(); if (wasEmittedByEnclosingScript_) {
--- a/js/src/frontend/Stencil.cpp +++ b/js/src/frontend/Stencil.cpp @@ -2399,19 +2399,16 @@ bool ExtensibleCompilationStencil::steal } continue; } auto index = parserAtoms.internExternalParserAtom(cx, entry); if (!index) { return false; } - if (entry->isUsedByStencil()) { - parserAtoms.markUsedByStencil(index); - } } sharedData = std::move(other.sharedData); moduleMetadata = std::move(other.moduleMetadata); asmJS = std::move(other.asmJS); @@ -3612,19 +3609,16 @@ bool CompilationStencilMerger::buildAtom ReportOutOfMemory(cx); return false; } for (const auto& atom : delazification.parserAtomData) { auto mappedIndex = initial_->parserAtoms.internExternalParserAtom(cx, atom); if (!mappedIndex) { return false; } - if (atom->isUsedByStencil()) { - initial_->parserAtoms.markUsedByStencil(mappedIndex); - } atomIndexMap.infallibleAppend(mappedIndex); } return true; } bool CompilationStencilMerger::setInitial( JSContext* cx, UniquePtr<ExtensibleCompilationStencil>&& initial) { MOZ_ASSERT(!initial_);
--- a/js/src/vm/Scope.cpp +++ b/js/src/vm/Scope.cpp @@ -10,17 +10,18 @@ #include "mozilla/ScopeExit.h" #include <memory> #include <new> #include "builtin/ModuleObject.h" #include "frontend/CompilationStencil.h" // CompilationState, CompilationAtomCache #include "frontend/Parser.h" // Copy*ScopeData -#include "frontend/ScriptIndex.h" // ScriptIndex +#include "frontend/ParserAtom.h" // frontend::ParserAtomsTable, frontend::ParserAtom +#include "frontend/ScriptIndex.h" // ScriptIndex #include "frontend/SharedContext.h" #include "frontend/Stencil.h" #include "gc/Allocator.h" #include "gc/MaybeRooted.h" #include "util/StringBuffer.h" #include "vm/EnvironmentObject.h" #include "vm/ErrorReporting.h" // MaybePrintAndClearPendingException #include "vm/JSScript.h" @@ -217,17 +218,18 @@ static void MarkParserScopeData(JSContex typename ConcreteScope::ParserData* data, frontend::CompilationState& compilationState) { auto names = GetScopeDataTrailingNames(data); for (auto& binding : names) { auto index = binding.name(); if (!index) { continue; } - compilationState.parserAtoms.markUsedByStencil(index); + compilationState.parserAtoms.markUsedByStencil( + index, frontend::ParserAtom::Atomize::Yes); } } static bool SetEnvironmentShape(JSContext* cx, BindingIter& freshBi, BindingIter& bi, const JSClass* cls, uint32_t firstFrameSlot, ObjectFlags objectFlags, MutableHandleShape envShape) {