Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (270869 => 270870)
--- trunk/Source/_javascript_Core/ChangeLog 2020-12-15 23:09:07 UTC (rev 270869)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-12-15 23:18:33 UTC (rev 270870)
@@ -1,3 +1,52 @@
+2020-12-15 Saam Barati <sbar...@apple.com>
+
+ Switch to using a linked list for the TDZ environment instead of a Vector
+ https://bugs.webkit.org/show_bug.cgi?id=219909
+ <rdar://71441753>
+
+ Reviewed by Tadeu Zagallo.
+
+ Before, we'd represent the TDZ stack in terms of a Vector. While the entries
+ in the Vector were reference counted, the spine of the Vector itself would
+ match the length of the TDZ scope stack. It turns out this spine itself can
+ use non-trivial amounts of memory. We are seeing about a 0.5% regression from
+ this inside RAMification. This change makes it so that we now use a tree-like
+ data structure for scope stack entries. The data structure is a tree with only
+ parent pointers. Any field that used to be a vector of entries is now a
+ pointer to a node in this tree. So any pointer into this tree will have a
+ linked-list window into the tree, where the linked-list represents the same
+ data as the previous vector-as-stack data structure.
+
+ Initial testing shows this might be up to a 0.5% progression on RAMification.
+
+ * builtins/BuiltinExecutables.cpp:
+ (JSC::BuiltinExecutables::createExecutable):
+ * bytecode/UnlinkedFunctionExecutable.cpp:
+ (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
+ * bytecode/UnlinkedFunctionExecutable.h:
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::BytecodeGenerator):
+ (JSC::BytecodeGenerator::popLexicalScopeInternal):
+ (JSC::BytecodeGenerator::needsTDZCheck):
+ (JSC::BytecodeGenerator::liftTDZCheckIfPossible):
+ (JSC::BytecodeGenerator::pushTDZVariables):
+ (JSC::BytecodeGenerator::getVariablesUnderTDZ):
+ (JSC::BytecodeGenerator::preserveTDZStack):
+ (JSC::BytecodeGenerator::restoreTDZStack):
+ * bytecompiler/BytecodeGenerator.h:
+ (JSC::BytecodeGenerator::generate):
+ * parser/VariableEnvironment.h:
+ (JSC::TDZEnvironmentLink::TDZEnvironmentLink):
+ (JSC::TDZEnvironmentLink::create):
+ (JSC::TDZEnvironmentLink::contains const):
+ (JSC::TDZEnvironmentLink::parent):
+ * runtime/CachedTypes.cpp:
+ (JSC::CachedTDZEnvironmentLink::encode):
+ (JSC::CachedTDZEnvironmentLink::decode const):
+ * runtime/CodeCache.cpp:
+ (JSC::generateUnlinkedCodeBlockImpl):
+ (JSC::CodeCache::getUnlinkedGlobalFunctionExecutable):
+
2020-12-15 Commit Queue <commit-qu...@webkit.org>
Unreviewed, reverting r270860.
Modified: trunk/Source/_javascript_Core/builtins/BuiltinExecutables.cpp (270869 => 270870)
--- trunk/Source/_javascript_Core/builtins/BuiltinExecutables.cpp 2020-12-15 23:09:07 UTC (rev 270869)
+++ trunk/Source/_javascript_Core/builtins/BuiltinExecutables.cpp 2020-12-15 23:18:33 UTC (rev 270870)
@@ -251,7 +251,7 @@
}
}
- UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(vm, source, &metadata, kind, constructAbility, JSParserScriptMode::Classic, WTF::nullopt, DerivedContextType::None, needsClassFieldInitializer, isBuiltinDefaultClassConstructor);
+ UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(vm, source, &metadata, kind, constructAbility, JSParserScriptMode::Classic, nullptr, DerivedContextType::None, needsClassFieldInitializer, isBuiltinDefaultClassConstructor);
return functionExecutable;
}
Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.cpp (270869 => 270870)
--- trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.cpp 2020-12-15 23:09:07 UTC (rev 270869)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.cpp 2020-12-15 23:18:33 UTC (rev 270870)
@@ -82,7 +82,7 @@
return result;
}
-UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM& vm, Structure* structure, const SourceCode& parentSource, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, Optional<Vector<CompactTDZEnvironmentMap::Handle>> parentScopeTDZVariables, DerivedContextType derivedContextType, NeedsClassFieldInitializer needsClassFieldInitializer, bool isBuiltinDefaultClassConstructor)
+UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM& vm, Structure* structure, const SourceCode& parentSource, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, RefPtr<TDZEnvironmentLink> parentScopeTDZVariables, DerivedContextType derivedContextType, NeedsClassFieldInitializer needsClassFieldInitializer, bool isBuiltinDefaultClassConstructor)
: Base(vm, structure)
, m_firstLineOffset(node->firstLine() - parentSource.firstLine().oneBasedInt())
, m_isInStrictContext(node->isInStrictContext())
@@ -127,7 +127,7 @@
if (!node->classSource().isNull())
setClassSource(node->classSource());
if (parentScopeTDZVariables)
- ensureRareData().m_parentScopeTDZVariables = WTFMove(*parentScopeTDZVariables);
+ ensureRareData().m_parentScopeTDZVariables = WTFMove(parentScopeTDZVariables);
}
UnlinkedFunctionExecutable::~UnlinkedFunctionExecutable()
Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.h (270869 => 270870)
--- trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.h 2020-12-15 23:09:07 UTC (rev 270869)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.h 2020-12-15 23:18:33 UTC (rev 270870)
@@ -70,7 +70,7 @@
return &vm.unlinkedFunctionExecutableSpace.space;
}
- static UnlinkedFunctionExecutable* create(VM& vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, Optional<Vector<CompactTDZEnvironmentMap::Handle>> parentScopeTDZVariables, DerivedContextType derivedContextType, NeedsClassFieldInitializer needsClassFieldInitializer, bool isBuiltinDefaultClassConstructor = false)
+ static UnlinkedFunctionExecutable* create(VM& vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, RefPtr<TDZEnvironmentLink> parentScopeTDZVariables, DerivedContextType derivedContextType, NeedsClassFieldInitializer needsClassFieldInitializer, bool isBuiltinDefaultClassConstructor = false)
{
UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(vm.heap))
UnlinkedFunctionExecutable(vm, vm.unlinkedFunctionExecutableStructure.get(), source, node, unlinkedFunctionKind, constructAbility, scriptMode, WTFMove(parentScopeTDZVariables), derivedContextType, needsClassFieldInitializer, isBuiltinDefaultClassConstructor);
@@ -168,10 +168,10 @@
return !m_rareData->m_classSource.isNull();
}
- Vector<CompactTDZEnvironmentMap::Handle> parentScopeTDZVariables() const
+ RefPtr<TDZEnvironmentLink> parentScopeTDZVariables() const
{
- if (!m_rareData || m_rareData->m_parentScopeTDZVariables.isEmpty())
- return { };
+ if (!m_rareData)
+ return nullptr;
return m_rareData->m_parentScopeTDZVariables;
}
@@ -208,7 +208,7 @@
SourceCode m_classSource;
String m_sourceURLDirective;
String m_sourceMappingURLDirective;
- Vector<CompactTDZEnvironmentMap::Handle> m_parentScopeTDZVariables;
+ RefPtr<TDZEnvironmentLink> m_parentScopeTDZVariables;
Vector<JSTextPosition> m_classFieldLocations;
};
@@ -229,7 +229,7 @@
}
private:
- UnlinkedFunctionExecutable(VM&, Structure*, const SourceCode&, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, JSParserScriptMode, Optional<Vector<CompactTDZEnvironmentMap::Handle>>, JSC::DerivedContextType, JSC::NeedsClassFieldInitializer, bool isBuiltinDefaultClassConstructor);
+ UnlinkedFunctionExecutable(VM&, Structure*, const SourceCode&, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, JSParserScriptMode, RefPtr<TDZEnvironmentLink>, JSC::DerivedContextType, JSC::NeedsClassFieldInitializer, bool isBuiltinDefaultClassConstructor);
UnlinkedFunctionExecutable(Decoder&, const CachedFunctionExecutable&);
static void visitChildren(JSCell*, SlotVisitor&);
Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (270869 => 270870)
--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2020-12-15 23:09:07 UTC (rev 270869)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2020-12-15 23:18:33 UTC (rev 270870)
@@ -289,7 +289,7 @@
return ParserError(ParserError::ErrorNone);
}
-BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const CachedTDZStack& parentScopeTDZVariables, ECMAMode ecmaMode)
+BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const RefPtr<TDZEnvironmentLink>& parentScopeTDZVariables, ECMAMode ecmaMode)
: BytecodeGeneratorBase(makeUnique<UnlinkedCodeBlockGenerator>(vm, codeBlock), CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters())
, m_codeGenerationMode(codeGenerationMode)
, m_scopeNode(programNode)
@@ -304,7 +304,7 @@
, m_needsToUpdateArrowFunctionContext(programNode->usesArrowFunction() || programNode->usesEval())
, m_ecmaMode(ecmaMode)
{
- ASSERT_UNUSED(parentScopeTDZVariables, !parentScopeTDZVariables.size());
+ ASSERT_UNUSED(parentScopeTDZVariables, !parentScopeTDZVariables);
m_codeBlock->setNumParameters(1); // Allocate space for "this"
@@ -336,7 +336,7 @@
}
}
-BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, UnlinkedFunctionCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const CachedTDZStack& parentScopeTDZVariables, ECMAMode ecmaMode)
+BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, UnlinkedFunctionCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const RefPtr<TDZEnvironmentLink>& parentScopeTDZVariables, ECMAMode ecmaMode)
: BytecodeGeneratorBase(makeUnique<UnlinkedCodeBlockGenerator>(vm, codeBlock), CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters())
, m_codeGenerationMode(codeGenerationMode)
, m_scopeNode(functionNode)
@@ -363,8 +363,7 @@
functionSymbolTable->setUsesNonStrictEval(m_usesNonStrictEval);
int symbolTableConstantIndex = 0;
- m_parentScopeTDZStackSize = parentScopeTDZVariables.size();
- m_cachedVariablesUnderTDZ = parentScopeTDZVariables;
+ m_cachedParentTDZ = parentScopeTDZVariables;
FunctionParameters& parameters = *functionNode->parameters();
// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-functiondeclarationinstantiation
@@ -839,7 +838,7 @@
pushLexicalScope(m_scopeNode, TDZCheckOptimization::Optimize, NestedScopeType::IsNotNested, nullptr, shouldInitializeBlockScopedFunctions);
}
-BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const CachedTDZStack& parentScopeTDZVariables, ECMAMode ecmaMode)
+BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const RefPtr<TDZEnvironmentLink>& parentScopeTDZVariables, ECMAMode ecmaMode)
: BytecodeGeneratorBase(makeUnique<UnlinkedCodeBlockGenerator>(vm, codeBlock), CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters())
, m_codeGenerationMode(codeGenerationMode)
, m_scopeNode(evalNode)
@@ -857,8 +856,7 @@
{
m_codeBlock->setNumParameters(1);
- m_parentScopeTDZStackSize = parentScopeTDZVariables.size();
- m_cachedVariablesUnderTDZ = parentScopeTDZVariables;
+ m_cachedParentTDZ = parentScopeTDZVariables;
emitEnter();
@@ -903,7 +901,7 @@
pushLexicalScope(m_scopeNode, TDZCheckOptimization::Optimize, NestedScopeType::IsNotNested, nullptr, shouldInitializeBlockScopedFunctions);
}
-BytecodeGenerator::BytecodeGenerator(VM& vm, ModuleProgramNode* moduleProgramNode, UnlinkedModuleProgramCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const CachedTDZStack& parentScopeTDZVariables, ECMAMode ecmaMode)
+BytecodeGenerator::BytecodeGenerator(VM& vm, ModuleProgramNode* moduleProgramNode, UnlinkedModuleProgramCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const RefPtr<TDZEnvironmentLink>& parentScopeTDZVariables, ECMAMode ecmaMode)
: BytecodeGeneratorBase(makeUnique<UnlinkedCodeBlockGenerator>(vm, codeBlock), CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters())
, m_codeGenerationMode(codeGenerationMode)
, m_scopeNode(moduleProgramNode)
@@ -918,7 +916,7 @@
, m_needsToUpdateArrowFunctionContext(moduleProgramNode->usesArrowFunction() || moduleProgramNode->usesEval())
, m_ecmaMode(ecmaMode)
{
- ASSERT_UNUSED(parentScopeTDZVariables, !parentScopeTDZVariables.size());
+ ASSERT_UNUSED(parentScopeTDZVariables, !parentScopeTDZVariables);
SymbolTable* moduleEnvironmentSymbolTable = SymbolTable::create(m_vm);
moduleEnvironmentSymbolTable->setUsesNonStrictEval(m_usesNonStrictEval);
@@ -2168,7 +2166,6 @@
}
m_TDZStack.removeLast();
- m_cachedVariablesUnderTDZ.removeLast();
}
void BytecodeGenerator::prepareLexicalScopeForNextForLoopIteration(VariableEnvironmentNode* node, RegisterID* loopSymbolTable)
@@ -2850,17 +2847,20 @@
bool BytecodeGenerator::needsTDZCheck(const Variable& variable)
{
for (unsigned i = m_TDZStack.size(); i--;) {
- auto iter = m_TDZStack[i].find(variable.ident().impl());
- if (iter == m_TDZStack[i].end())
+ auto iter = m_TDZStack[i].first.find(variable.ident().impl());
+ if (iter == m_TDZStack[i].first.end())
continue;
return iter->value != TDZNecessityLevel::NotNeeded;
}
- for (unsigned i = m_parentScopeTDZStackSize; i--;) {
- if (m_cachedVariablesUnderTDZ[i].environment().toTDZEnvironment().contains(variable.ident().impl()))
- return true;
+ {
+ TDZEnvironmentLink* environment = m_cachedParentTDZ.get();
+ while (environment) {
+ if (environment->contains(variable.ident().impl()))
+ return true;
+ environment = environment->parent();
+ }
}
-
return false;
}
@@ -2881,8 +2881,8 @@
{
RefPtr<UniquedStringImpl> identifier(variable.ident().impl());
for (unsigned i = m_TDZStack.size(); i--;) {
- auto iter = m_TDZStack[i].find(identifier);
- if (iter != m_TDZStack[i].end()) {
+ auto iter = m_TDZStack[i].first.find(identifier);
+ if (iter != m_TDZStack[i].first.end()) {
if (iter->value == TDZNecessityLevel::Optimize)
iter->value = TDZNecessityLevel::NotNeeded;
break;
@@ -2908,56 +2908,57 @@
for (const auto& entry : environment)
map.add(entry.key, entry.value.isFunction() ? TDZNecessityLevel::NotNeeded : level);
- m_TDZStack.append(WTFMove(map));
- m_cachedVariablesUnderTDZ.append({ });
+ m_TDZStack.append(TDZStackEntry { WTFMove(map), nullptr });
}
-Optional<BytecodeGenerator::CachedTDZStack> BytecodeGenerator::getVariablesUnderTDZ()
+RefPtr<TDZEnvironmentLink> BytecodeGenerator::getVariablesUnderTDZ()
{
+ RefPtr<TDZEnvironmentLink> parent = m_cachedParentTDZ;
+ if (!m_TDZStack.size())
+ return parent;
+
auto assertCacheIsCoherent = [&] {
#if ASSERT_ENABLED
- for (size_t i = 0; i < m_cachedVariablesUnderTDZ.size(); ++i)
- ASSERT(!!m_cachedVariablesUnderTDZ[i]);
+ TDZEnvironmentLink* parent = m_cachedParentTDZ.get();
+ for (auto& entry : m_TDZStack) {
+ ASSERT(entry.second);
+ ASSERT(entry.second->parent() == parent);
+ parent = entry.second.get();
+ }
#endif
};
- RELEASE_ASSERT(m_TDZStack.size() + m_parentScopeTDZStackSize == m_cachedVariablesUnderTDZ.size());
-
- if (m_cachedVariablesUnderTDZ.isEmpty())
- return WTF::nullopt;
-
- if (m_cachedVariablesUnderTDZ.last()) {
+ if (m_TDZStack.last().second) {
assertCacheIsCoherent();
- return m_cachedVariablesUnderTDZ;
+ return m_TDZStack.last().second;
}
- for (size_t i = m_TDZStack.size(); i--;) {
- if (m_cachedVariablesUnderTDZ[i + m_parentScopeTDZStackSize])
- break;
-
- auto& map = m_TDZStack[i];
- TDZEnvironment environment;
- for (auto& entry : map) {
- if (entry.value != TDZNecessityLevel::NotNeeded)
- environment.add(entry.key.get());
+ for (auto& entry : m_TDZStack) {
+ if (!entry.second) {
+ auto& map = entry.first;
+ TDZEnvironment environment;
+ for (auto& entry : map) {
+ if (entry.value != TDZNecessityLevel::NotNeeded)
+ environment.add(entry.key.get());
+ }
+ entry.second = TDZEnvironmentLink::create(m_vm.m_compactVariableMap->get(environment), parent);
}
- m_cachedVariablesUnderTDZ[i + m_parentScopeTDZStackSize] = m_vm.m_compactVariableMap->get(environment);
+ parent = entry.second;
}
assertCacheIsCoherent();
- return m_cachedVariablesUnderTDZ;
+
+ return parent;
}
void BytecodeGenerator::preserveTDZStack(BytecodeGenerator::PreservedTDZStack& preservedStack)
{
preservedStack.m_preservedTDZStack = m_TDZStack;
- preservedStack.m_cachedTDZStack = m_cachedVariablesUnderTDZ;
}
void BytecodeGenerator::restoreTDZStack(const BytecodeGenerator::PreservedTDZStack& preservedStack)
{
m_TDZStack = preservedStack.m_preservedTDZStack;
- m_cachedVariablesUnderTDZ = preservedStack.m_cachedTDZStack;
}
RegisterID* BytecodeGenerator::emitNewObject(RegisterID* dst)
Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (270869 => 270870)
--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h 2020-12-15 23:09:07 UTC (rev 270869)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h 2020-12-15 23:18:33 UTC (rev 270870)
@@ -407,12 +407,11 @@
public:
typedef DeclarationStacks::FunctionStack FunctionStack;
- using CachedTDZStack = Vector<CompactTDZEnvironmentMap::Handle>;
- BytecodeGenerator(VM&, ProgramNode*, UnlinkedProgramCodeBlock*, OptionSet<CodeGenerationMode>, const CachedTDZStack&, ECMAMode);
- BytecodeGenerator(VM&, FunctionNode*, UnlinkedFunctionCodeBlock*, OptionSet<CodeGenerationMode>, const CachedTDZStack&, ECMAMode);
- BytecodeGenerator(VM&, EvalNode*, UnlinkedEvalCodeBlock*, OptionSet<CodeGenerationMode>, const CachedTDZStack&, ECMAMode);
- BytecodeGenerator(VM&, ModuleProgramNode*, UnlinkedModuleProgramCodeBlock*, OptionSet<CodeGenerationMode>, const CachedTDZStack&, ECMAMode);
+ BytecodeGenerator(VM&, ProgramNode*, UnlinkedProgramCodeBlock*, OptionSet<CodeGenerationMode>, const RefPtr<TDZEnvironmentLink>&, ECMAMode);
+ BytecodeGenerator(VM&, FunctionNode*, UnlinkedFunctionCodeBlock*, OptionSet<CodeGenerationMode>, const RefPtr<TDZEnvironmentLink>&, ECMAMode);
+ BytecodeGenerator(VM&, EvalNode*, UnlinkedEvalCodeBlock*, OptionSet<CodeGenerationMode>, const RefPtr<TDZEnvironmentLink>&, ECMAMode);
+ BytecodeGenerator(VM&, ModuleProgramNode*, UnlinkedModuleProgramCodeBlock*, OptionSet<CodeGenerationMode>, const RefPtr<TDZEnvironmentLink>&, ECMAMode);
~BytecodeGenerator();
@@ -432,7 +431,7 @@
NeedsClassFieldInitializer needsClassFieldInitializer() const { return m_codeBlock->needsClassFieldInitializer(); }
template<typename Node, typename UnlinkedCodeBlock>
- static ParserError generate(VM& vm, Node* node, const SourceCode& sourceCode, UnlinkedCodeBlock* unlinkedCodeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const CachedTDZStack& parentScopeTDZVariables, ECMAMode ecmaMode)
+ static ParserError generate(VM& vm, Node* node, const SourceCode& sourceCode, UnlinkedCodeBlock* unlinkedCodeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const RefPtr<TDZEnvironmentLink>& parentScopeTDZVariables, ECMAMode ecmaMode)
{
MonotonicTime before;
if (UNLIKELY(Options::reportBytecodeCompileTimes()))
@@ -1198,7 +1197,7 @@
return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, scriptMode(), WTFMove(optionalVariablesUnderTDZ), newDerivedContextType, needsClassFieldInitializer);
}
- Optional<CachedTDZStack> getVariablesUnderTDZ();
+ RefPtr<TDZEnvironmentLink> getVariablesUnderTDZ();
RegisterID* emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, DebuggableCall);
template<typename CallOp>
@@ -1229,10 +1228,11 @@
RegisterID* emitThrowExpressionTooDeepException();
+ using TDZStackEntry = std::pair<TDZMap, RefPtr<TDZEnvironmentLink>>;
+
class PreservedTDZStack {
private:
- Vector<TDZMap> m_preservedTDZStack;
- CachedTDZStack m_cachedTDZStack;
+ Vector<TDZStackEntry> m_preservedTDZStack;
friend class BytecodeGenerator;
};
@@ -1264,9 +1264,8 @@
};
Vector<LexicalScopeStackEntry> m_lexicalScopeStack;
- size_t m_parentScopeTDZStackSize { 0 };
- Vector<TDZMap> m_TDZStack;
- CachedTDZStack m_cachedVariablesUnderTDZ;
+ RefPtr<TDZEnvironmentLink> m_cachedParentTDZ;
+ Vector<TDZStackEntry> m_TDZStack;
Optional<size_t> m_varScopeLexicalScopeStackIndex;
void pushTDZVariables(const VariableEnvironment&, TDZCheckOptimization, TDZRequirement);
Modified: trunk/Source/_javascript_Core/parser/VariableEnvironment.h (270869 => 270870)
--- trunk/Source/_javascript_Core/parser/VariableEnvironment.h 2020-12-15 23:09:07 UTC (rev 270869)
+++ trunk/Source/_javascript_Core/parser/VariableEnvironment.h 2020-12-15 23:18:33 UTC (rev 270870)
@@ -419,4 +419,26 @@
HashMap<CompactTDZEnvironmentKey, unsigned> m_map;
};
+class TDZEnvironmentLink : public RefCounted<TDZEnvironmentLink> {
+ TDZEnvironmentLink(CompactTDZEnvironmentMap::Handle handle, RefPtr<TDZEnvironmentLink> parent)
+ : m_handle(WTFMove(handle))
+ , m_parent(WTFMove(parent))
+ { }
+
+public:
+ static RefPtr<TDZEnvironmentLink> create(CompactTDZEnvironmentMap::Handle handle, RefPtr<TDZEnvironmentLink> parent)
+ {
+ return adoptRef(new TDZEnvironmentLink(WTFMove(handle), WTFMove(parent)));
+ }
+
+ bool contains(UniquedStringImpl* impl) const { return m_handle.environment().toTDZEnvironment().contains(impl); }
+ TDZEnvironmentLink* parent() { return m_parent.get(); }
+
+private:
+ friend class CachedTDZEnvironmentLink;
+
+ CompactTDZEnvironmentMap::Handle m_handle;
+ RefPtr<TDZEnvironmentLink> m_parent;
+};
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/CachedTypes.cpp (270869 => 270870)
--- trunk/Source/_javascript_Core/runtime/CachedTypes.cpp 2020-12-15 23:09:07 UTC (rev 270869)
+++ trunk/Source/_javascript_Core/runtime/CachedTypes.cpp 2020-12-15 23:18:33 UTC (rev 270870)
@@ -1763,6 +1763,26 @@
int m_startColumn;
};
+class CachedTDZEnvironmentLink : public CachedObject<TDZEnvironmentLink> {
+public:
+ void encode(Encoder& encoder, const TDZEnvironmentLink& environment)
+ {
+ m_handle.encode(encoder, environment.m_handle);
+ m_parent.encode(encoder, environment.m_parent);
+ }
+
+ TDZEnvironmentLink* decode(Decoder& decoder) const
+ {
+ CompactTDZEnvironmentMap::Handle handle = m_handle.decode(decoder);
+ RefPtr<TDZEnvironmentLink> parent = m_parent.decode(decoder);
+ return new TDZEnvironmentLink(WTFMove(handle), WTFMove(parent));
+ }
+
+private:
+ CachedCompactTDZEnvironmentMapHandle m_handle;
+ CachedRefPtr<CachedTDZEnvironmentLink> m_parent;
+};
+
class CachedFunctionExecutableRareData : public CachedObject<UnlinkedFunctionExecutable::RareData> {
public:
void encode(Encoder& encoder, const UnlinkedFunctionExecutable::RareData& rareData)
@@ -1781,7 +1801,7 @@
private:
CachedSourceCodeWithoutProvider m_classSource;
- CachedVector<CachedCompactTDZEnvironmentMapHandle> m_parentScopeTDZVariables;
+ CachedRefPtr<CachedTDZEnvironmentLink> m_parentScopeTDZVariables;
};
class CachedFunctionExecutable : public CachedObject<UnlinkedFunctionExecutable> {
Modified: trunk/Source/_javascript_Core/runtime/CodeCache.cpp (270869 => 270870)
--- trunk/Source/_javascript_Core/runtime/CodeCache.cpp 2020-12-15 23:09:07 UTC (rev 270869)
+++ trunk/Source/_javascript_Core/runtime/CodeCache.cpp 2020-12-15 23:18:33 UTC (rev 270870)
@@ -105,9 +105,9 @@
if (!source.provider()->sourceMappingURLDirective().isNull())
unlinkedCodeBlock->setSourceMappingURLDirective(source.provider()->sourceMappingURLDirective());
- Vector<CompactTDZEnvironmentMap::Handle> parentVariablesUnderTDZ;
+ RefPtr<TDZEnvironmentLink> parentVariablesUnderTDZ;
if (variablesUnderTDZ)
- parentVariablesUnderTDZ.append(vm.m_compactVariableMap->get(*variablesUnderTDZ));
+ parentVariablesUnderTDZ = TDZEnvironmentLink::create(vm.m_compactVariableMap->get(*variablesUnderTDZ), nullptr);
error = BytecodeGenerator::generate(vm, rootNode.get(), source, unlinkedCodeBlock, codeGenerationMode, parentVariablesUnderTDZ, ecmaMode);
if (error.isValid())
@@ -248,7 +248,7 @@
// The Function constructor only has access to global variables, so no variables will be under TDZ unless they're
// in the global lexical environment, which we always TDZ check accesses from.
ConstructAbility constructAbility = constructAbilityForParseMode(metadata->parseMode());
- UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(vm, source, metadata, UnlinkedNormalFunction, constructAbility, JSParserScriptMode::Classic, WTF::nullopt, DerivedContextType::None, NeedsClassFieldInitializer::No);
+ UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(vm, source, metadata, UnlinkedNormalFunction, constructAbility, JSParserScriptMode::Classic, nullptr, DerivedContextType::None, NeedsClassFieldInitializer::No);
if (!source.provider()->sourceURLDirective().isNull())
functionExecutable->setSourceURLDirective(source.provider()->sourceURLDirective());