Source/JavaScriptCore/ChangeLog

 12020-10-23 Saam Barati <sbarati@apple.com>
 2
 3 Better cache our serialization of the outer TDZ environment when creating FunctionExecutables during bytecode generation
 4 https://bugs.webkit.org/show_bug.cgi?id=199866
 5 <rdar://problem/53333108>
 6
 7 Reviewed by NOBODY (OOPS!).
 8
 9 This patch removes performance pathologies regarding programs with
 10 many variables under TDZ (let/const). We had an algorithm for caching
 11 the results of gathering all variables under TDZ, but that algorithm
 12 wasn't nearly aggressive enough in its caching. This lead us to worst
 13 case quadratic runtime, which could happens in practice for large functions.
 14
 15 There are a few fixes here:
 16 - Instead of flattening the entire TDZ stack, and caching that result,
 17 we now cache each stack entry individually. So as you push/pop to the
 18 TDZ environment stack, we no longer invalidate everything. Instead, we
 19 will just need to cache the newly pushed entry. We also no longer invalidate
 20 the cache for lifting a TDZ check. The compromise here is we may emit
 21 more runtime TDZ checks for closure variables. This is better than N^2
 22 bytecode compile time perf, since a well predicted branch for a TDZ
 23 check is essentially free.
 24 - We no longer transform the CompactTDZEnvironment (formerly CompactVariableEnvironment)
 25 from a Vector into a HashSet each time we generate code for an inner function. Instead,
 26 CompactTDZEnvironment can be in two modes: compact and inflated. It starts life off in
 27 compact mode (a vector), and will turn into an inflated mode if it's ever needed. Once
 28 inflated, it'll stay this way until it's destructed. This improves our algorithm from being
 29 O(EnvSize * NumFunctions) to O(EnvSize) at the cost of using more space in a HashTable versus a
 30 Vector. In the future, we could consider just binary searching through this Vector, and never using
 31 a hash table.
 32
 33 * bytecode/UnlinkedFunctionExecutable.cpp:
 34 (JSC::generateUnlinkedFunctionCodeBlock):
 35 (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
 36 * bytecode/UnlinkedFunctionExecutable.h:
 37 * bytecompiler/BytecodeGenerator.cpp:
 38 (JSC::BytecodeGenerator::BytecodeGenerator):
 39 (JSC::BytecodeGenerator::popLexicalScopeInternal):
 40 (JSC::BytecodeGenerator::needsTDZCheck):
 41 (JSC::BytecodeGenerator::liftTDZCheckIfPossible):
 42 (JSC::BytecodeGenerator::pushTDZVariables):
 43 (JSC::BytecodeGenerator::getVariablesUnderTDZ):
 44 (JSC::BytecodeGenerator::preserveTDZStack):
 45 (JSC::BytecodeGenerator::restoreTDZStack):
 46 (JSC::BytecodeGenerator::emitNewInstanceFieldInitializerFunction):
 47 * bytecompiler/BytecodeGenerator.h:
 48 (JSC::BytecodeGenerator::generate):
 49 (JSC::BytecodeGenerator::makeFunction):
 50 * debugger/DebuggerCallFrame.cpp:
 51 (JSC::DebuggerCallFrame::evaluateWithScopeExtension):
 52 * interpreter/Interpreter.cpp:
 53 (JSC::eval):
 54 * parser/Parser.h:
 55 (JSC::Parser<LexerType>::parse):
 56 (JSC::parse):
 57 * parser/VariableEnvironment.cpp:
 58 (JSC::CompactTDZEnvironment::sortCompact):
 59 (JSC::CompactTDZEnvironment::CompactTDZEnvironment):
 60 (JSC::CompactTDZEnvironment::operator== const):
 61 (JSC::CompactTDZEnvironment::toTDZEnvironmentSlow const):
 62 (JSC::CompactTDZEnvironmentMap::get):
 63 (JSC::CompactTDZEnvironmentMap::Handle::~Handle):
 64 (JSC::CompactTDZEnvironmentMap::Handle::Handle):
 65 (JSC::CompactVariableEnvironment::CompactVariableEnvironment): Deleted.
 66 (JSC::CompactVariableEnvironment::operator== const): Deleted.
 67 (JSC::CompactVariableEnvironment::toVariableEnvironment const): Deleted.
 68 (JSC::CompactVariableMap::get): Deleted.
 69 (JSC::CompactVariableMap::Handle::~Handle): Deleted.
 70 (JSC::CompactVariableMap::Handle::Handle): Deleted.
 71 * parser/VariableEnvironment.h:
 72 (JSC::CompactTDZEnvironment::toTDZEnvironment const):
 73 (JSC::CompactTDZEnvironmentKey::CompactTDZEnvironmentKey):
 74 (JSC::CompactTDZEnvironmentKey::hash):
 75 (JSC::CompactTDZEnvironmentKey::equal):
 76 (JSC::CompactTDZEnvironmentKey::makeDeletedValue):
 77 (JSC::CompactTDZEnvironmentKey::isHashTableDeletedValue const):
 78 (JSC::CompactTDZEnvironmentKey::environment):
 79 (WTF::HashTraits<JSC::CompactTDZEnvironmentKey>::emptyValue):
 80 (WTF::HashTraits<JSC::CompactTDZEnvironmentKey>::isEmptyValue):
 81 (WTF::HashTraits<JSC::CompactTDZEnvironmentKey>::constructDeletedValue):
 82 (WTF::HashTraits<JSC::CompactTDZEnvironmentKey>::isDeletedValue):
 83 (JSC::CompactTDZEnvironmentMap::Handle::environment const):
 84 (JSC::CompactVariableEnvironment::hash const): Deleted.
 85 (JSC::CompactVariableMapKey::CompactVariableMapKey): Deleted.
 86 (JSC::CompactVariableMapKey::hash): Deleted.
 87 (JSC::CompactVariableMapKey::equal): Deleted.
 88 (JSC::CompactVariableMapKey::makeDeletedValue): Deleted.
 89 (JSC::CompactVariableMapKey::isHashTableDeletedValue const): Deleted.
 90 (JSC::CompactVariableMapKey::isHashTableEmptyValue const): Deleted.
 91 (JSC::CompactVariableMapKey::environment): Deleted.
 92 (WTF::HashTraits<JSC::CompactVariableMapKey>::emptyValue): Deleted.
 93 (WTF::HashTraits<JSC::CompactVariableMapKey>::isEmptyValue): Deleted.
 94 (WTF::HashTraits<JSC::CompactVariableMapKey>::constructDeletedValue): Deleted.
 95 (WTF::HashTraits<JSC::CompactVariableMapKey>::isDeletedValue): Deleted.
 96 (JSC::CompactVariableMap::Handle::Handle): Deleted.
 97 (JSC::CompactVariableMap::Handle::operator=): Deleted.
 98 (JSC::CompactVariableMap::Handle::operator bool const): Deleted.
 99 (JSC::CompactVariableMap::Handle::environment const): Deleted.
 100 (JSC::CompactVariableMap::Handle::swap): Deleted.
 101 * runtime/CachedTypes.cpp:
 102 (JSC::Decoder::handleForTDZEnvironment const):
 103 (JSC::Decoder::setHandleForTDZEnvironment):
 104 (JSC::CachedCompactTDZEnvironment::encode):
 105 (JSC::CachedCompactTDZEnvironment::decode const):
 106 (JSC::CachedCompactTDZEnvironmentMapHandle::encode):
 107 (JSC::CachedCompactTDZEnvironmentMapHandle::decode const):
 108 (JSC::CachedFunctionExecutableRareData::decode const):
 109 (JSC::Decoder::handleForEnvironment const): Deleted.
 110 (JSC::Decoder::setHandleForEnvironment): Deleted.
 111 (JSC::CachedCompactVariableEnvironment::encode): Deleted.
 112 (JSC::CachedCompactVariableEnvironment::decode const): Deleted.
 113 (JSC::CachedCompactVariableMapHandle::encode): Deleted.
 114 (JSC::CachedCompactVariableMapHandle::decode const): Deleted.
 115 * runtime/CachedTypes.h:
 116 * runtime/CodeCache.cpp:
 117 (JSC::generateUnlinkedCodeBlockImpl):
 118 (JSC::generateUnlinkedCodeBlock):
 119 (JSC::generateUnlinkedCodeBlockForDirectEval):
 120 (JSC::recursivelyGenerateUnlinkedCodeBlockForProgram):
 121 (JSC::recursivelyGenerateUnlinkedCodeBlockForModuleProgram):
 122 (JSC::CodeCache::getUnlinkedGlobalCodeBlock):
 123 * runtime/CodeCache.h:
 124 * runtime/Completion.cpp:
 125 (JSC::generateProgramBytecode):
 126 (JSC::generateModuleBytecode):
 127 * runtime/DirectEvalExecutable.cpp:
 128 (JSC::DirectEvalExecutable::create):
 129 * runtime/DirectEvalExecutable.h:
 130 * runtime/JSScope.cpp:
 131 (JSC::JSScope::collectClosureVariablesUnderTDZ):
 132 * runtime/JSScope.h:
 133 * runtime/VM.cpp:
 134 (JSC::VM::VM):
 135 * runtime/VM.h:
 136
11372020-10-21 Caitlin Potter <caitp@igalia.com>
2138
3139 [JSC] support op_get_private_name in DFG and FTL
268822

Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp

@@static UnlinkedFunctionCodeBlock* genera
7272
7373 UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(vm, FunctionCode, ExecutableInfo(function->usesEval(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKind(), scriptMode, executable->superBinding(), parseMode, executable->derivedContextType(), executable->needsClassFieldInitializer(), false, isClassContext, EvalContextType::FunctionEvalContext), codeGenerationMode);
7474
75  VariableEnvironment parentScopeTDZVariables = executable->parentScopeTDZVariables();
 75 auto parentScopeTDZVariables = executable->parentScopeTDZVariables();
7676 ECMAMode ecmaMode = executable->isInStrictContext() ? ECMAMode::strict() : ECMAMode::sloppy();
77  error = BytecodeGenerator::generate(vm, function.get(), source, result, codeGenerationMode, &parentScopeTDZVariables, ecmaMode);
 77 error = BytecodeGenerator::generate(vm, function.get(), source, result, codeGenerationMode, parentScopeTDZVariables, ecmaMode);
7878
7979 if (error.isValid())
8080 return nullptr;

@@static UnlinkedFunctionCodeBlock* genera
8282 return result;
8383}
8484
85 UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM& vm, Structure* structure, const SourceCode& parentSource, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, Optional<CompactVariableMap::Handle> parentScopeTDZVariables, DerivedContextType derivedContextType, NeedsClassFieldInitializer needsClassFieldInitializer, bool isBuiltinDefaultClassConstructor)
 85UnlinkedFunctionExecutable::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)
8686 : Base(vm, structure)
8787 , m_firstLineOffset(node->firstLine() - parentSource.firstLine().oneBasedInt())
8888 , m_isInStrictContext(node->isInStrictContext())
268822

Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h

@@public:
7070 return &vm.unlinkedFunctionExecutableSpace.space;
7171 }
7272
73  static UnlinkedFunctionExecutable* create(VM& vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, Optional<CompactVariableMap::Handle> parentScopeTDZVariables, DerivedContextType derivedContextType, NeedsClassFieldInitializer needsClassFieldInitializer, bool isBuiltinDefaultClassConstructor = false)
 73 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)
7474 {
7575 UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(vm.heap))
7676 UnlinkedFunctionExecutable(vm, vm.unlinkedFunctionExecutableStructure.get(), source, node, unlinkedFunctionKind, constructAbility, scriptMode, WTFMove(parentScopeTDZVariables), derivedContextType, needsClassFieldInitializer, isBuiltinDefaultClassConstructor);

@@public:
168168 return !m_rareData->m_classSource.isNull();
169169 }
170170
171  VariableEnvironment parentScopeTDZVariables() const
 171 Vector<CompactTDZEnvironmentMap::Handle> parentScopeTDZVariables() const
172172 {
173  if (!m_rareData || !m_rareData->m_parentScopeTDZVariables)
174  return VariableEnvironment();
175  return m_rareData->m_parentScopeTDZVariables.environment().toVariableEnvironment();
 173 if (!m_rareData || m_rareData->m_parentScopeTDZVariables.isEmpty())
 174 return { };
 175 return m_rareData->m_parentScopeTDZVariables;
176176 }
177177
178178 bool isArrowFunction() const { return isArrowFunctionParseMode(parseMode()); }

@@public:
208208 SourceCode m_classSource;
209209 String m_sourceURLDirective;
210210 String m_sourceMappingURLDirective;
211  CompactVariableMap::Handle m_parentScopeTDZVariables;
 211 Vector<CompactTDZEnvironmentMap::Handle> m_parentScopeTDZVariables;
212212 Vector<JSTextPosition> m_instanceFieldLocations;
213213 };
214214

@@public:
229229 }
230230
231231private:
232  UnlinkedFunctionExecutable(VM&, Structure*, const SourceCode&, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, JSParserScriptMode, Optional<CompactVariableMap::Handle>, JSC::DerivedContextType, JSC::NeedsClassFieldInitializer, bool isBuiltinDefaultClassConstructor);
 232 UnlinkedFunctionExecutable(VM&, Structure*, const SourceCode&, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, JSParserScriptMode, Optional<Vector<CompactTDZEnvironmentMap::Handle>>, JSC::DerivedContextType, JSC::NeedsClassFieldInitializer, bool isBuiltinDefaultClassConstructor);
233233 UnlinkedFunctionExecutable(Decoder&, const CachedFunctionExecutable&);
234234
235235 static void visitChildren(JSCell*, SlotVisitor&);
268822

Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

4848#include "Options.h"
4949#include "PrivateFieldPutKind.h"
5050#include "StrongInlines.h"
 51#include "SuperSampler.h"
5152#include "UnlinkedCodeBlock.h"
5253#include "UnlinkedEvalCodeBlock.h"
5354#include "UnlinkedFunctionCodeBlock.h"

@@ParserError BytecodeGenerator::generate(
288289 return ParserError(ParserError::ErrorNone);
289290}
290291
291 BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const VariableEnvironment* parentScopeTDZVariables, ECMAMode ecmaMode)
 292BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const CachedTDZStack& parentScopeTDZVariables, ECMAMode ecmaMode)
292293 : BytecodeGeneratorBase(makeUnique<UnlinkedCodeBlockGenerator>(vm, codeBlock), CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters())
293294 , m_codeGenerationMode(codeGenerationMode)
294295 , m_scopeNode(programNode)

@@BytecodeGenerator::BytecodeGenerator(VM&
300301 , m_isBuiltinFunction(false)
301302 , m_usesNonStrictEval(false)
302303 , m_inTailPosition(false)
303  , m_hasCachedVariablesUnderTDZ(false)
304304 , m_needsToUpdateArrowFunctionContext(programNode->usesArrowFunction() || programNode->usesEval())
305305 , m_ecmaMode(ecmaMode)
306306{
307  ASSERT_UNUSED(parentScopeTDZVariables, !parentScopeTDZVariables->size());
 307 ASSERT_UNUSED(parentScopeTDZVariables, !parentScopeTDZVariables.size());
308308
309309 m_codeBlock->setNumParameters(1); // Allocate space for "this"
310310

@@BytecodeGenerator::BytecodeGenerator(VM&
336336 }
337337}
338338
339 BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, UnlinkedFunctionCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const VariableEnvironment* parentScopeTDZVariables, ECMAMode ecmaMode)
 339BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, UnlinkedFunctionCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const CachedTDZStack& parentScopeTDZVariables, ECMAMode ecmaMode)
340340 : BytecodeGeneratorBase(makeUnique<UnlinkedCodeBlockGenerator>(vm, codeBlock), CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters())
341341 , m_codeGenerationMode(codeGenerationMode)
342342 , m_scopeNode(functionNode)

@@BytecodeGenerator::BytecodeGenerator(VM&
355355 //
356356 // Note that we intentionally enable tail call for naked constructors since it does not have special code for "return".
357357 , m_inTailPosition(Options::useTailCalls() && !isConstructor() && constructorKind() == ConstructorKind::None && ecmaMode.isStrict())
358  , m_hasCachedVariablesUnderTDZ(false)
359358 , m_needsToUpdateArrowFunctionContext(functionNode->usesArrowFunction() || functionNode->usesEval())
360359 , m_ecmaMode(ecmaMode)
361360 , m_derivedContextType(codeBlock->derivedContextType())

@@BytecodeGenerator::BytecodeGenerator(VM&
364363 functionSymbolTable->setUsesNonStrictEval(m_usesNonStrictEval);
365364 int symbolTableConstantIndex = 0;
366365
 366 m_parentScopeTDZVariables = parentScopeTDZVariables;
 367 m_cachedVariablesUnderTDZ = m_parentScopeTDZVariables;
 368
367369 FunctionParameters& parameters = *functionNode->parameters();
368370 // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-functiondeclarationinstantiation
369371 // This implements IsSimpleParameterList in the Ecma 2015 spec.

@@BytecodeGenerator::BytecodeGenerator(VM&
770772 emitPutDerivedConstructorToArrowFunctionContextScope();
771773 }
772774
773  // All "addVar()"s needs to happen before "initializeDefaultParameterValuesAndSetupFunctionScopeStack()" is called
774  // because a function's default parameter ExpressionNodes will use temporary registers.
775  pushTDZVariables(*parentScopeTDZVariables, TDZCheckOptimization::DoNotOptimize, TDZRequirement::UnderTDZ);
776 
777775 Ref<Label> catchLabel = newLabel();
778776 TryData* tryFormalParametersData = nullptr;
779777 bool needTryCatch = isAsyncFunctionWrapperParseMode(parseMode) && !isSimpleParameterList;

@@BytecodeGenerator::BytecodeGenerator(VM&
782780 tryFormalParametersData = pushTry(tryFormalParametersStart.get(), catchLabel.get(), HandlerType::SynthesizedCatch);
783781 }
784782
 783 // All "addVar()"s needs to happen before "initializeDefaultParameterValuesAndSetupFunctionScopeStack()" is called
 784 // because a function's default parameter ExpressionNodes will use temporary registers.
785785 initializeDefaultParameterValuesAndSetupFunctionScopeStack(parameters, isSimpleParameterList, functionNode, functionSymbolTable, symbolTableConstantIndex, captures, shouldCreateArgumentsVariableInParameterScope);
786786
787787 if (needTryCatch) {

@@BytecodeGenerator::BytecodeGenerator(VM&
840840 pushLexicalScope(m_scopeNode, TDZCheckOptimization::Optimize, NestedScopeType::IsNotNested, nullptr, shouldInitializeBlockScopedFunctions);
841841}
842842
843 BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const VariableEnvironment* parentScopeTDZVariables, ECMAMode ecmaMode)
 843BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const CachedTDZStack& parentScopeTDZVariables, ECMAMode ecmaMode)
844844 : BytecodeGeneratorBase(makeUnique<UnlinkedCodeBlockGenerator>(vm, codeBlock), CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters())
845845 , m_codeGenerationMode(codeGenerationMode)
846846 , m_scopeNode(evalNode)

@@BytecodeGenerator::BytecodeGenerator(VM&
852852 , m_isBuiltinFunction(false)
853853 , m_usesNonStrictEval(codeBlock->usesEval() && !ecmaMode.isStrict())
854854 , m_inTailPosition(false)
855  , m_hasCachedVariablesUnderTDZ(false)
856855 , m_needsToUpdateArrowFunctionContext(evalNode->usesArrowFunction() || evalNode->usesEval())
857856 , m_ecmaMode(ecmaMode)
858857 , m_derivedContextType(codeBlock->derivedContextType())
859858{
860859 m_codeBlock->setNumParameters(1);
861860
862  pushTDZVariables(*parentScopeTDZVariables, TDZCheckOptimization::DoNotOptimize, TDZRequirement::UnderTDZ);
 861 m_parentScopeTDZVariables = parentScopeTDZVariables;
 862 m_cachedVariablesUnderTDZ = m_parentScopeTDZVariables;
863863
864864 emitEnter();
865865

@@BytecodeGenerator::BytecodeGenerator(VM&
904904 pushLexicalScope(m_scopeNode, TDZCheckOptimization::Optimize, NestedScopeType::IsNotNested, nullptr, shouldInitializeBlockScopedFunctions);
905905}
906906
907 BytecodeGenerator::BytecodeGenerator(VM& vm, ModuleProgramNode* moduleProgramNode, UnlinkedModuleProgramCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const VariableEnvironment* parentScopeTDZVariables, ECMAMode ecmaMode)
 907BytecodeGenerator::BytecodeGenerator(VM& vm, ModuleProgramNode* moduleProgramNode, UnlinkedModuleProgramCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const CachedTDZStack& parentScopeTDZVariables, ECMAMode ecmaMode)
908908 : BytecodeGeneratorBase(makeUnique<UnlinkedCodeBlockGenerator>(vm, codeBlock), CodeBlock::llintBaselineCalleeSaveSpaceAsVirtualRegisters())
909909 , m_codeGenerationMode(codeGenerationMode)
910910 , m_scopeNode(moduleProgramNode)

@@BytecodeGenerator::BytecodeGenerator(VM&
916916 , m_isBuiltinFunction(false)
917917 , m_usesNonStrictEval(false)
918918 , m_inTailPosition(false)
919  , m_hasCachedVariablesUnderTDZ(false)
920919 , m_needsToUpdateArrowFunctionContext(moduleProgramNode->usesArrowFunction() || moduleProgramNode->usesEval())
921920 , m_ecmaMode(ecmaMode)
922921{
923  ASSERT_UNUSED(parentScopeTDZVariables, !parentScopeTDZVariables->size());
 922 ASSERT_UNUSED(parentScopeTDZVariables, !parentScopeTDZVariables.size());
924923
925924 SymbolTable* moduleEnvironmentSymbolTable = SymbolTable::create(m_vm);
926925 moduleEnvironmentSymbolTable->setUsesNonStrictEval(m_usesNonStrictEval);

@@void BytecodeGenerator::popLexicalScopeI
21702169 }
21712170
21722171 m_TDZStack.removeLast();
2173  m_cachedVariablesUnderTDZ = { };
 2172 m_cachedVariablesUnderTDZ.removeLast();
21742173}
21752174
21762175void BytecodeGenerator::prepareLexicalScopeForNextForLoopIteration(VariableEnvironmentNode* node, RegisterID* loopSymbolTable)

@@bool BytecodeGenerator::needsTDZCheck(co
28582857 return iter->value != TDZNecessityLevel::NotNeeded;
28592858 }
28602859
 2860 for (unsigned i = m_parentScopeTDZVariables.size(); i--;) {
 2861 if (m_parentScopeTDZVariables[i].environment().toTDZEnvironment().contains(variable.ident().impl()))
 2862 return true;
 2863 }
 2864
28612865 return false;
28622866}
28632867

@@void BytecodeGenerator::liftTDZCheckIfPo
28802884 for (unsigned i = m_TDZStack.size(); i--;) {
28812885 auto iter = m_TDZStack[i].find(identifier);
28822886 if (iter != m_TDZStack[i].end()) {
2883  if (iter->value == TDZNecessityLevel::Optimize) {
2884  m_cachedVariablesUnderTDZ = { };
 2887 if (iter->value == TDZNecessityLevel::Optimize)
28852888 iter->value = TDZNecessityLevel::NotNeeded;
2886  }
28872889 break;
28882890 }
28892891 }

@@void BytecodeGenerator::pushTDZVariables
29082910 map.add(entry.key, entry.value.isFunction() ? TDZNecessityLevel::NotNeeded : level);
29092911
29102912 m_TDZStack.append(WTFMove(map));
2911  m_cachedVariablesUnderTDZ = { };
 2913 m_cachedVariablesUnderTDZ.append({ });
29122914}
29132915
2914 Optional<CompactVariableMap::Handle> BytecodeGenerator::getVariablesUnderTDZ()
 2916Optional<BytecodeGenerator::CachedTDZStack> BytecodeGenerator::getVariablesUnderTDZ()
29152917{
2916  if (m_cachedVariablesUnderTDZ) {
2917  if (!m_hasCachedVariablesUnderTDZ) {
2918  ASSERT(m_cachedVariablesUnderTDZ.environment().toVariableEnvironment().isEmpty());
2919  return WTF::nullopt;
2920  }
 2918 auto assertCacheIsCoherent = [&] {
 2919#if ASSERT_ENABLED
 2920 for (size_t i = 0; i < m_cachedVariablesUnderTDZ.size(); ++i)
 2921 ASSERT(!!m_cachedVariablesUnderTDZ[i]);
 2922#endif
 2923 };
 2924
 2925 RELEASE_ASSERT(m_TDZStack.size() + m_parentScopeTDZVariables.size() == m_cachedVariablesUnderTDZ.size());
 2926
 2927 if (m_cachedVariablesUnderTDZ.isEmpty())
 2928 return WTF::nullopt;
 2929
 2930 if (m_cachedVariablesUnderTDZ.last()) {
 2931 assertCacheIsCoherent();
29212932 return m_cachedVariablesUnderTDZ;
29222933 }
29232934
2924  // We keep track of variablesThatDontNeedTDZ in this algorithm to prevent
2925  // reporting that "x" is under TDZ if this function is called at "...".
2926  //
2927  // {
2928  // {
2929  // let x;
2930  // ...
2931  // }
2932  // let x;
2933  // }
2934  SmallPtrSet<UniquedStringImpl*, 16> variablesThatDontNeedTDZ;
2935  VariableEnvironment environment;
2936  for (unsigned i = m_TDZStack.size(); i--; ) {
 2935 for (size_t i = m_TDZStack.size(); i--;) {
 2936 if (m_cachedVariablesUnderTDZ[i + m_parentScopeTDZVariables.size()])
 2937 break;
 2938
29372939 auto& map = m_TDZStack[i];
2938  for (auto& entry : map) {
2939  if (entry.value != TDZNecessityLevel::NotNeeded) {
2940  if (!variablesThatDontNeedTDZ.contains(entry.key.get()))
2941  environment.add(entry.key.get());
2942  } else
2943  variablesThatDontNeedTDZ.add(entry.key.get());
 2940 TDZEnvironment environment;
 2941 for (auto& entry : map) {
 2942 if (entry.value != TDZNecessityLevel::NotNeeded)
 2943 environment.add(entry.key.get());
29442944 }
 2945 m_cachedVariablesUnderTDZ[i + m_parentScopeTDZVariables.size()] = m_vm.m_compactVariableMap->get(environment);
29452946 }
29462947
2947  m_cachedVariablesUnderTDZ = m_vm.m_compactVariableMap->get(environment);
2948  m_hasCachedVariablesUnderTDZ = !environment.isEmpty();
2949  if (!m_hasCachedVariablesUnderTDZ)
2950  return WTF::nullopt;
2951 
 2948 assertCacheIsCoherent();
29522949 return m_cachedVariablesUnderTDZ;
29532950}
29542951
29552952void BytecodeGenerator::preserveTDZStack(BytecodeGenerator::PreservedTDZStack& preservedStack)
29562953{
29572954 preservedStack.m_preservedTDZStack = m_TDZStack;
 2955 preservedStack.m_cachedTDZStack = m_cachedVariablesUnderTDZ;
29582956}
29592957
29602958void BytecodeGenerator::restoreTDZStack(const BytecodeGenerator::PreservedTDZStack& preservedStack)
29612959{
29622960 m_TDZStack = preservedStack.m_preservedTDZStack;
2963  m_cachedVariablesUnderTDZ = { };
 2961 m_cachedVariablesUnderTDZ = preservedStack.m_cachedTDZStack;
29642962}
29652963
29662964RegisterID* BytecodeGenerator::emitNewObject(RegisterID* dst)

@@RegisterID* BytecodeGenerator::emitNewIn
31473145 superBinding = SuperBinding::Needed;
31483146 }
31493147
3150  Optional<CompactVariableMap::Handle> variablesUnderTDZ = getVariablesUnderTDZ();
 3148 auto variablesUnderTDZ = getVariablesUnderTDZ();
31513149 SourceParseMode parseMode = SourceParseMode::InstanceFieldInitializerMode;
31523150 ConstructAbility constructAbility = ConstructAbility::CannotConstruct;
31533151
268822

Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

@@namespace JSC {
407407
408408 public:
409409 typedef DeclarationStacks::FunctionStack FunctionStack;
 410 using CachedTDZStack = Vector<CompactTDZEnvironmentMap::Handle>;
410411
411  BytecodeGenerator(VM&, ProgramNode*, UnlinkedProgramCodeBlock*, OptionSet<CodeGenerationMode>, const VariableEnvironment*, ECMAMode);
412  BytecodeGenerator(VM&, FunctionNode*, UnlinkedFunctionCodeBlock*, OptionSet<CodeGenerationMode>, const VariableEnvironment*, ECMAMode);
413  BytecodeGenerator(VM&, EvalNode*, UnlinkedEvalCodeBlock*, OptionSet<CodeGenerationMode>, const VariableEnvironment*, ECMAMode);
414  BytecodeGenerator(VM&, ModuleProgramNode*, UnlinkedModuleProgramCodeBlock*, OptionSet<CodeGenerationMode>, const VariableEnvironment*, ECMAMode);
 412 BytecodeGenerator(VM&, ProgramNode*, UnlinkedProgramCodeBlock*, OptionSet<CodeGenerationMode>, const CachedTDZStack&, ECMAMode);
 413 BytecodeGenerator(VM&, FunctionNode*, UnlinkedFunctionCodeBlock*, OptionSet<CodeGenerationMode>, const CachedTDZStack&, ECMAMode);
 414 BytecodeGenerator(VM&, EvalNode*, UnlinkedEvalCodeBlock*, OptionSet<CodeGenerationMode>, const CachedTDZStack&, ECMAMode);
 415 BytecodeGenerator(VM&, ModuleProgramNode*, UnlinkedModuleProgramCodeBlock*, OptionSet<CodeGenerationMode>, const CachedTDZStack&, ECMAMode);
415416
416417 ~BytecodeGenerator();
417418

@@namespace JSC {
431432 NeedsClassFieldInitializer needsClassFieldInitializer() const { return m_codeBlock->needsClassFieldInitializer(); }
432433
433434 template<typename Node, typename UnlinkedCodeBlock>
434  static ParserError generate(VM& vm, Node* node, const SourceCode& sourceCode, UnlinkedCodeBlock* unlinkedCodeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const VariableEnvironment* environment, ECMAMode ecmaMode)
 435 static ParserError generate(VM& vm, Node* node, const SourceCode& sourceCode, UnlinkedCodeBlock* unlinkedCodeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const CachedTDZStack& parentScopeTDZVariables, ECMAMode ecmaMode)
435436 {
436437 MonotonicTime before;
437438 if (UNLIKELY(Options::reportBytecodeCompileTimes()))
438439 before = MonotonicTime::now();
439440
440441 DeferGC deferGC(vm.heap);
441  auto bytecodeGenerator = makeUnique<BytecodeGenerator>(vm, node, unlinkedCodeBlock, codeGenerationMode, environment, ecmaMode);
 442 auto bytecodeGenerator = makeUnique<BytecodeGenerator>(vm, node, unlinkedCodeBlock, codeGenerationMode, parentScopeTDZVariables, ecmaMode);
442443 auto result = bytecodeGenerator->generate();
443444
444445 if (UNLIKELY(Options::reportBytecodeCompileTimes())) {

@@namespace JSC {
11851186 newDerivedContextType = DerivedContextType::DerivedMethodContext;
11861187 }
11871188
1188  Optional<CompactVariableMap::Handle> optionalVariablesUnderTDZ = getVariablesUnderTDZ();
 1189 auto optionalVariablesUnderTDZ = getVariablesUnderTDZ();
11891190
11901191 // FIXME: These flags, ParserModes and propagation to XXXCodeBlocks should be reorganized.
11911192 // https://bugs.webkit.org/show_bug.cgi?id=151547

@@namespace JSC {
11971198 return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, scriptMode(), WTFMove(optionalVariablesUnderTDZ), newDerivedContextType, needsClassFieldInitializer);
11981199 }
11991200
1200  Optional<CompactVariableMap::Handle> getVariablesUnderTDZ();
 1201 Optional<CachedTDZStack> getVariablesUnderTDZ();
12011202
12021203 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);
12031204 template<typename CallOp>

@@namespace JSC {
12311232 class PreservedTDZStack {
12321233 private:
12331234 Vector<TDZMap> m_preservedTDZStack;
 1235 CachedTDZStack m_cachedTDZStack;
12341236 friend class BytecodeGenerator;
12351237 };
12361238

@@namespace JSC {
12621264 };
12631265 Vector<LexicalScopeStackEntry> m_lexicalScopeStack;
12641266
 1267 CachedTDZStack m_parentScopeTDZVariables;
12651268 Vector<TDZMap> m_TDZStack;
 1269 CachedTDZStack m_cachedVariablesUnderTDZ;
12661270 Optional<size_t> m_varScopeLexicalScopeStackIndex;
12671271 void pushTDZVariables(const VariableEnvironment&, TDZCheckOptimization, TDZRequirement);
12681272

@@namespace JSC {
13441348 bool m_isBuiltinFunction { false };
13451349 bool m_usesNonStrictEval { false };
13461350 bool m_inTailPosition { false };
1347  bool m_hasCachedVariablesUnderTDZ { false };
13481351 bool m_needsToUpdateArrowFunctionContext : 1;
13491352 ECMAMode m_ecmaMode;
13501353 DerivedContextType m_derivedContextType { DerivedContextType::None };
13511354
1352  CompactVariableMap::Handle m_cachedVariablesUnderTDZ;
1353 
13541355 struct CatchEntry {
13551356 TryData* tryData;
13561357 VirtualRegister exceptionRegister;
268822

Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp

@@JSValue DebuggerCallFrame::evaluateWithS
258258 else
259259 evalContextType = EvalContextType::None;
260260
261  VariableEnvironment variablesUnderTDZ;
262  JSScope::collectClosureVariablesUnderTDZ(scope()->jsScope(), variablesUnderTDZ);
 261 TDZEnvironment variablesUnderTDZ;
 262 VariableEnvironment privateNames;
 263 JSScope::collectClosureVariablesUnderTDZ(scope()->jsScope(), variablesUnderTDZ, privateNames);
263264
264265 ECMAMode ecmaMode = codeBlock->ownerExecutable()->isInStrictContext() ? ECMAMode::strict() : ECMAMode::sloppy();
265  auto* eval = DirectEvalExecutable::create(globalObject, makeSource(script, callFrame->callerSourceOrigin(vm)), codeBlock->unlinkedCodeBlock()->derivedContextType(), codeBlock->unlinkedCodeBlock()->needsClassFieldInitializer(), codeBlock->unlinkedCodeBlock()->isArrowFunction(), codeBlock->ownerExecutable()->isInsideOrdinaryFunction(), evalContextType, &variablesUnderTDZ, ecmaMode);
 266 auto* eval = DirectEvalExecutable::create(globalObject, makeSource(script, callFrame->callerSourceOrigin(vm)), codeBlock->unlinkedCodeBlock()->derivedContextType(), codeBlock->unlinkedCodeBlock()->needsClassFieldInitializer(), codeBlock->unlinkedCodeBlock()->isArrowFunction(), codeBlock->ownerExecutable()->isInsideOrdinaryFunction(), evalContextType, &variablesUnderTDZ, &privateNames, ecmaMode);
266267 if (UNLIKELY(catchScope.exception())) {
267268 exception = catchScope.exception();
268269 catchScope.clearException();
268822

Source/JavaScriptCore/interpreter/Interpreter.cpp

@@JSValue eval(JSGlobalObject* globalObjec
143143 RETURN_IF_EXCEPTION(scope, JSValue());
144144 }
145145
146  VariableEnvironment variablesUnderTDZ;
147  JSScope::collectClosureVariablesUnderTDZ(callerScopeChain, variablesUnderTDZ);
148  eval = DirectEvalExecutable::create(globalObject, makeSource(programSource, callerCodeBlock->source().provider()->sourceOrigin()), derivedContextType, callerUnlinkedCodeBlock->needsClassFieldInitializer(), isArrowFunctionContext, callerCodeBlock->ownerExecutable()->isInsideOrdinaryFunction(), evalContextType, &variablesUnderTDZ, ecmaMode);
 146 TDZEnvironment variablesUnderTDZ;
 147 VariableEnvironment privateNames;
 148 JSScope::collectClosureVariablesUnderTDZ(callerScopeChain, variablesUnderTDZ, privateNames);
 149 eval = DirectEvalExecutable::create(globalObject, makeSource(programSource, callerCodeBlock->source().provider()->sourceOrigin()), derivedContextType, callerUnlinkedCodeBlock->needsClassFieldInitializer(), isArrowFunctionContext, callerCodeBlock->ownerExecutable()->isInsideOrdinaryFunction(), evalContextType, &variablesUnderTDZ, &privateNames, ecmaMode);
149150 EXCEPTION_ASSERT(!!scope.exception() == !eval);
150151 if (!eval)
151152 return jsUndefined();
268822

Source/JavaScriptCore/parser/Parser.h

@@private:
20532053
20542054template <typename LexerType>
20552055template <class ParsedNode>
2056 std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, Optional<int> functionConstructorParametersEndPosition, const VariableEnvironment* variablesUnderTDZ, const Vector<JSTextPosition>* instanceFieldLocations)
 2056std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, Optional<int> functionConstructorParametersEndPosition, const VariableEnvironment* parentScopePrivateNames, const Vector<JSTextPosition>* instanceFieldLocations)
20572057{
20582058 int errLine;
20592059 String errMsg;

@@std::unique_ptr<ParsedNode> Parser<Lexer
20682068 ASSERT(m_source->startColumn() > OrdinalNumber::beforeFirst());
20692069 unsigned startColumn = m_source->startColumn().zeroBasedInt();
20702070
2071  if (isEvalNode<ParsedNode>() && variablesUnderTDZ && variablesUnderTDZ->privateNamesSize()) {
 2071 if (isEvalNode<ParsedNode>() && parentScopePrivateNames && parentScopePrivateNames->privateNamesSize()) {
20722072 currentScope()->setIsPrivateNameScope();
2073  variablesUnderTDZ->copyPrivateNamesTo(currentScope()->lexicalVariables());
 2073 parentScopePrivateNames->copyPrivateNamesTo(currentScope()->lexicalVariables());
20742074 }
20752075
20762076 auto parseResult = parseInner(calleeName, parseMode, parsingContext, functionConstructorParametersEndPosition, instanceFieldLocations);

@@std::unique_ptr<ParsedNode> parse(
21572157 DerivedContextType derivedContextType = DerivedContextType::None,
21582158 EvalContextType evalContextType = EvalContextType::None,
21592159 DebuggerParseData* debuggerParseData = nullptr,
2160  const VariableEnvironment* variablesUnderTDZ = nullptr,
 2160 const VariableEnvironment* parentScopePrivateNames = nullptr,
21612161 const Vector<JSTextPosition>* instanceFieldLocations = nullptr,
21622162 bool isInsideOrdinaryFunction = false)
21632163{

@@std::unique_ptr<ParsedNode> parse(
21702170 std::unique_ptr<ParsedNode> result;
21712171 if (source.provider()->source().is8Bit()) {
21722172 Parser<Lexer<LChar>> parser(vm, source, builtinMode, strictMode, scriptMode, parseMode, superBinding, defaultConstructorKindForTopLevelFunction, derivedContextType, isEvalNode<ParsedNode>(), evalContextType, debuggerParseData, isInsideOrdinaryFunction);
2173  result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, variablesUnderTDZ, instanceFieldLocations);
 2173 result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, parentScopePrivateNames, instanceFieldLocations);
21742174 if (positionBeforeLastNewline)
21752175 *positionBeforeLastNewline = parser.positionBeforeLastNewline();
21762176 if (builtinMode == JSParserBuiltinMode::Builtin) {

@@std::unique_ptr<ParsedNode> parse(
21832183 } else {
21842184 ASSERT_WITH_MESSAGE(defaultConstructorKindForTopLevelFunction == ConstructorKind::None, "BuiltinExecutables's special constructors should always use a 8-bit string");
21852185 Parser<Lexer<UChar>> parser(vm, source, builtinMode, strictMode, scriptMode, parseMode, superBinding, defaultConstructorKindForTopLevelFunction, derivedContextType, isEvalNode<ParsedNode>(), evalContextType, debuggerParseData, isInsideOrdinaryFunction);
2186  result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, variablesUnderTDZ, instanceFieldLocations);
 2186 result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, parentScopePrivateNames, instanceFieldLocations);
21872187 if (positionBeforeLastNewline)
21882188 *positionBeforeLastNewline = parser.positionBeforeLastNewline();
21892189 }
268822

Source/JavaScriptCore/parser/VariableEnvironment.cpp

@@void VariableEnvironment::markVariableAs
104104 findResult->value.setIsExported();
105105}
106106
107 CompactVariableEnvironment::CompactVariableEnvironment(const VariableEnvironment& env)
108  : m_isEverythingCaptured(env.isEverythingCaptured())
109 {
110  Vector<std::pair<UniquedStringImpl*, VariableEnvironmentEntry>, 32> sortedEntries;
111  sortedEntries.reserveInitialCapacity(env.mapSize());
112  for (auto& pair : env)
113  sortedEntries.append({ pair.key.get(), pair.value });
114107
115  std::sort(sortedEntries.begin(), sortedEntries.end(), [] (const auto& a, const auto& b) {
116  return a.first < b.first;
 108void CompactTDZEnvironment::sortCompact(Compact& compact)
 109{
 110 std::sort(compact.begin(), compact.end(), [] (auto& a, auto& b) {
 111 return a.get() < b.get();
117112 });
 113}
 114
 115CompactTDZEnvironment::CompactTDZEnvironment(const TDZEnvironment& env)
 116{
 117 Compact compactVariables;
 118 compactVariables.reserveCapacity(env.size());
118119
119  m_hash = 0;
120  m_variables.reserveInitialCapacity(sortedEntries.size());
121  m_variableMetadata.reserveInitialCapacity(sortedEntries.size());
122  for (const auto& pair : sortedEntries) {
123  m_variables.append(pair.first);
124  m_variableMetadata.append(pair.second);
125  m_hash ^= pair.first->hash();
126  m_hash += pair.second.bits();
 120 m_hash = 0; // Note: XOR is commutative so order doesn't matter here.
 121 for (auto& key : env) {
 122 compactVariables.append(key.get());
 123 m_hash ^= key->hash();
127124 }
128125
129  if (m_isEverythingCaptured)
130  m_hash *= 2;
 126 sortCompact(compactVariables);
 127 m_variables = WTFMove(compactVariables);
131128}
132129
133 bool CompactVariableEnvironment::operator==(const CompactVariableEnvironment& other) const
 130bool CompactTDZEnvironment::operator==(const CompactTDZEnvironment& other) const
134131{
135132 if (this == &other)
136133 return true;
137  if (m_isEverythingCaptured != other.m_isEverythingCaptured)
138  return false;
139  if (m_variables != other.m_variables)
140  return false;
141  if (m_variableMetadata != other.m_variableMetadata)
 134
 135 if (m_hash != other.m_hash)
142136 return false;
143  return true;
144 }
145137
146 VariableEnvironment CompactVariableEnvironment::toVariableEnvironment() const
147 {
148  VariableEnvironment result;
149  ASSERT(m_variables.size() == m_variableMetadata.size());
150  for (size_t i = 0; i < m_variables.size(); ++i) {
151  auto addResult = result.add(m_variables[i]);
152  ASSERT(addResult.isNewEntry);
153  addResult.iterator->value = m_variableMetadata[i];
154  }
 138 auto equal = [&] (const Compact& compact, const Inflated& inflated) {
 139 if (compact.size() != inflated.size())
 140 return false;
 141 for (auto& ident : compact) {
 142 if (!inflated.contains(ident))
 143 return false;
 144 }
 145 return true;
 146 };
155147
156  if (m_isEverythingCaptured)
157  result.markAllVariablesAsCaptured();
 148 bool result;
 149 WTF::switchOn(m_variables,
 150 [&] (const Compact& compact) {
 151 WTF::switchOn(other.m_variables,
 152 [&] (const Compact& otherCompact) {
 153 result = compact == otherCompact;
 154 },
 155 [&] (const Inflated& otherInflated) {
 156 result = equal(compact, otherInflated);
 157 });
 158 },
 159 [&] (const Inflated& inflated) {
 160 WTF::switchOn(other.m_variables,
 161 [&] (const Compact& otherCompact) {
 162 result = equal(otherCompact, inflated);
 163 },
 164 [&] (const Inflated& otherInflated) {
 165 result = inflated == otherInflated;
 166 });
 167 });
158168
159169 return result;
160170}
161171
162 CompactVariableMap::Handle CompactVariableMap::get(const VariableEnvironment& env)
 172TDZEnvironment& CompactTDZEnvironment::toTDZEnvironmentSlow() const
 173{
 174 Inflated inflated;
 175 {
 176 auto& compact = WTF::get<Compact>(m_variables);
 177 for (size_t i = 0; i < compact.size(); ++i) {
 178 auto addResult = inflated.add(compact[i]);
 179 ASSERT_UNUSED(addResult, addResult.isNewEntry);
 180 }
 181 }
 182 m_variables = Variables(WTFMove(inflated));
 183 return const_cast<Inflated&>(WTF::get<Inflated>(m_variables));
 184}
 185
 186CompactTDZEnvironmentMap::Handle CompactTDZEnvironmentMap::get(const TDZEnvironment& env)
163187{
164  auto* environment = new CompactVariableEnvironment(env);
 188 auto* environment = new CompactTDZEnvironment(env);
165189 bool isNewEntry;
166190 auto handle = get(environment, isNewEntry);
167191 if (!isNewEntry)

@@CompactVariableMap::Handle CompactVariab
169193 return handle;
170194}
171195
172 CompactVariableMap::Handle CompactVariableMap::get(CompactVariableEnvironment* environment, bool& isNewEntry)
 196CompactTDZEnvironmentMap::Handle CompactTDZEnvironmentMap::get(CompactTDZEnvironment* environment, bool& isNewEntry)
173197{
174  CompactVariableMapKey key { *environment };
 198 CompactTDZEnvironmentKey key { *environment };
175199 auto addResult = m_map.add(key, 1);
176200 isNewEntry = addResult.isNewEntry;
177201 if (addResult.isNewEntry)
178  return CompactVariableMap::Handle(*environment, *this);
 202 return CompactTDZEnvironmentMap::Handle(*environment, *this);
179203
180204 ++addResult.iterator->value;
181  return CompactVariableMap::Handle(addResult.iterator->key.environment(), *this);
 205 return CompactTDZEnvironmentMap::Handle(addResult.iterator->key.environment(), *this);
182206}
183207
184 CompactVariableMap::Handle::~Handle()
 208CompactTDZEnvironmentMap::Handle::~Handle()
185209{
186210 if (!m_map) {
187211 ASSERT(!m_environment);

@@CompactVariableMap::Handle::~Handle()
190214 }
191215
192216 RELEASE_ASSERT(m_environment);
193  auto iter = m_map->m_map.find(CompactVariableMapKey { *m_environment });
 217 auto iter = m_map->m_map.find(CompactTDZEnvironmentKey { *m_environment });
194218 RELEASE_ASSERT(iter != m_map->m_map.end());
195219 --iter->value;
196220 if (!iter->value) {

@@CompactVariableMap::Handle::~Handle()
200224 }
201225}
202226
203 CompactVariableMap::Handle::Handle(const CompactVariableMap::Handle& other)
 227CompactTDZEnvironmentMap::Handle::Handle(const CompactTDZEnvironmentMap::Handle& other)
204228 : m_environment(other.m_environment)
205229 , m_map(other.m_map)
206230{
207231 if (m_map) {
208  auto iter = m_map->m_map.find(CompactVariableMapKey { *m_environment });
 232 auto iter = m_map->m_map.find(CompactTDZEnvironmentKey { *m_environment });
209233 RELEASE_ASSERT(iter != m_map->m_map.end());
210234 ++iter->value;
211235 }
212236}
213237
214 CompactVariableMap::Handle::Handle(CompactVariableEnvironment& environment, CompactVariableMap& map)
 238CompactTDZEnvironmentMap::Handle::Handle(CompactTDZEnvironment& environment, CompactTDZEnvironmentMap& map)
215239 : m_environment(&environment)
216240 , m_map(&map)
217241{
268822

Source/JavaScriptCore/parser/VariableEnvironment.h

2929#include <wtf/HashMap.h>
3030#include <wtf/HashSet.h>
3131#include <wtf/IteratorRange.h>
 32#include <wtf/Variant.h>
3233
3334namespace JSC {
3435

@@struct PrivateNameEntryHashTraits : Hash
119120};
120121
121122class VariableEnvironment {
 123 WTF_MAKE_FAST_ALLOCATED;
122124private:
123125 typedef HashMap<PackedRefPtr<UniquedStringImpl>, VariableEnvironmentEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, VariableEnvironmentEntryHashTraits> Map;
124126 typedef HashMap<PackedRefPtr<UniquedStringImpl>, PrivateNameEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, PrivateNameEntryHashTraits> PrivateNames;

@@private:
262264 std::unique_ptr<VariableEnvironment::RareData> m_rareData;
263265};
264266
265 class CompactVariableEnvironment {
 267using TDZEnvironment = HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash>;
 268
 269class CompactTDZEnvironment {
266270 WTF_MAKE_FAST_ALLOCATED;
267  WTF_MAKE_NONCOPYABLE(CompactVariableEnvironment);
 271 WTF_MAKE_NONCOPYABLE(CompactTDZEnvironment);
268272
269  friend class CachedCompactVariableEnvironment;
 273 friend class CachedCompactTDZEnvironment;
 274
 275 using Compact = Vector<PackedRefPtr<UniquedStringImpl>>;
 276 using Inflated = TDZEnvironment;
 277 using Variables = Variant<Compact, Inflated>;
270278
271279public:
272  CompactVariableEnvironment(const VariableEnvironment&);
273  VariableEnvironment toVariableEnvironment() const;
 280 CompactTDZEnvironment(const TDZEnvironment&);
274281
275  bool operator==(const CompactVariableEnvironment&) const;
 282 bool operator==(const CompactTDZEnvironment&) const;
276283 unsigned hash() const { return m_hash; }
277284
 285 static void sortCompact(Compact&);
 286
 287 TDZEnvironment& toTDZEnvironment() const
 288 {
 289 if (WTF::holds_alternative<Inflated>(m_variables))
 290 return const_cast<TDZEnvironment&>(WTF::get<Inflated>(m_variables));
 291 return toTDZEnvironmentSlow();
 292 }
 293
278294private:
279  CompactVariableEnvironment() = default;
 295 CompactTDZEnvironment() = default;
 296 TDZEnvironment& toTDZEnvironmentSlow() const;
280297
281  Vector<PackedRefPtr<UniquedStringImpl>> m_variables;
282  Vector<VariableEnvironmentEntry> m_variableMetadata;
 298 mutable Variables m_variables;
283299 unsigned m_hash;
284  bool m_isEverythingCaptured;
285300};
286301
287 struct CompactVariableMapKey {
288  CompactVariableMapKey()
 302struct CompactTDZEnvironmentKey {
 303 CompactTDZEnvironmentKey()
289304 : m_environment(nullptr)
290305 {
291306 ASSERT(isHashTableEmptyValue());
292307 }
293308
294  CompactVariableMapKey(CompactVariableEnvironment& environment)
 309 CompactTDZEnvironmentKey(CompactTDZEnvironment& environment)
295310 : m_environment(&environment)
296311 { }
297312
298  static unsigned hash(const CompactVariableMapKey& key) { return key.m_environment->hash(); }
299  static bool equal(const CompactVariableMapKey& a, const CompactVariableMapKey& b) { return *a.m_environment == *b.m_environment; }
 313 static unsigned hash(const CompactTDZEnvironmentKey& key) { return key.m_environment->hash(); }
 314 static bool equal(const CompactTDZEnvironmentKey& a, const CompactTDZEnvironmentKey& b) { return *a.m_environment == *b.m_environment; }
300315 static constexpr bool safeToCompareToEmptyOrDeleted = false;
301  static void makeDeletedValue(CompactVariableMapKey& key)
 316 static void makeDeletedValue(CompactTDZEnvironmentKey& key)
302317 {
303  key.m_environment = reinterpret_cast<CompactVariableEnvironment*>(1);
 318 key.m_environment = reinterpret_cast<CompactTDZEnvironment*>(1);
304319 }
305320 bool isHashTableDeletedValue() const
306321 {
307  return m_environment == reinterpret_cast<CompactVariableEnvironment*>(1);
 322 return m_environment == reinterpret_cast<CompactTDZEnvironment*>(1);
308323 }
309324 bool isHashTableEmptyValue() const
310325 {
311326 return !m_environment;
312327 }
313328
314  CompactVariableEnvironment& environment()
 329 CompactTDZEnvironment& environment()
315330 {
316331 RELEASE_ASSERT(!isHashTableDeletedValue());
317332 RELEASE_ASSERT(!isHashTableEmptyValue());

@@struct CompactVariableMapKey {
319334 }
320335
321336private:
322  CompactVariableEnvironment* m_environment;
 337 CompactTDZEnvironment* m_environment;
323338};
324339
325340} // namespace JSC

@@private:
327342namespace WTF {
328343
329344template<typename T> struct DefaultHash;
330 template<> struct DefaultHash<JSC::CompactVariableMapKey> : JSC::CompactVariableMapKey { };
 345template<> struct DefaultHash<JSC::CompactTDZEnvironmentKey> : JSC::CompactTDZEnvironmentKey { };
331346
332 template<> struct HashTraits<JSC::CompactVariableMapKey> : GenericHashTraits<JSC::CompactVariableMapKey> {
 347template<> struct HashTraits<JSC::CompactTDZEnvironmentKey> : GenericHashTraits<JSC::CompactTDZEnvironmentKey> {
333348 static constexpr bool emptyValueIsZero = true;
334  static JSC::CompactVariableMapKey emptyValue() { return JSC::CompactVariableMapKey(); }
 349 static JSC::CompactTDZEnvironmentKey emptyValue() { return JSC::CompactTDZEnvironmentKey(); }
335350
336351 static constexpr bool hasIsEmptyValueFunction = true;
337  static bool isEmptyValue(JSC::CompactVariableMapKey key) { return key.isHashTableEmptyValue(); }
 352 static bool isEmptyValue(JSC::CompactTDZEnvironmentKey key) { return key.isHashTableEmptyValue(); }
338353
339  static void constructDeletedValue(JSC::CompactVariableMapKey& key) { JSC::CompactVariableMapKey::makeDeletedValue(key); }
340  static bool isDeletedValue(JSC::CompactVariableMapKey key) { return key.isHashTableDeletedValue(); }
 354 static void constructDeletedValue(JSC::CompactTDZEnvironmentKey& key) { JSC::CompactTDZEnvironmentKey::makeDeletedValue(key); }
 355 static bool isDeletedValue(JSC::CompactTDZEnvironmentKey key) { return key.isHashTableDeletedValue(); }
341356};
342357
343358} // namespace WTF
344359
345360namespace JSC {
346361
347 class CompactVariableMap : public RefCounted<CompactVariableMap> {
 362class CompactTDZEnvironmentMap : public RefCounted<CompactTDZEnvironmentMap> {
348363public:
349364 class Handle {
350  friend class CachedCompactVariableMapHandle;
 365 friend class CachedCompactTDZEnvironmentMapHandle;
351366
352367 public:
353368 Handle() = default;
354369
355  Handle(CompactVariableEnvironment&, CompactVariableMap&);
 370 Handle(CompactTDZEnvironment&, CompactTDZEnvironmentMap&);
356371
357372 Handle(Handle&& other)
358373 {

@@public:
377392
378393 explicit operator bool() const { return !!m_map; }
379394
380  const CompactVariableEnvironment& environment() const
 395 const CompactTDZEnvironment& environment() const
381396 {
382397 return *m_environment;
383398 }

@@public:
389404 std::swap(other.m_map, m_map);
390405 }
391406
392  CompactVariableEnvironment* m_environment { nullptr };
393  RefPtr<CompactVariableMap> m_map;
 407 CompactTDZEnvironment* m_environment { nullptr };
 408 RefPtr<CompactTDZEnvironmentMap> m_map;
394409 };
395410
396  Handle get(const VariableEnvironment&);
 411 Handle get(const TDZEnvironment&);
397412
398413private:
399414 friend class Handle;
400  friend class CachedCompactVariableMapHandle;
 415 friend class CachedCompactTDZEnvironmentMapHandle;
401416
402  Handle get(CompactVariableEnvironment*, bool& isNewEntry);
 417 Handle get(CompactTDZEnvironment*, bool& isNewEntry);
403418
404  HashMap<CompactVariableMapKey, unsigned> m_map;
 419 HashMap<CompactTDZEnvironmentKey, unsigned> m_map;
405420};
406421
407422} // namespace JSC
268822

Source/JavaScriptCore/runtime/CachedTypes.cpp

@@const void* Decoder::ptrForOffsetFromBas
327327 return m_cachedBytecode->data() + offset;
328328}
329329
330 CompactVariableMap::Handle Decoder::handleForEnvironment(CompactVariableEnvironment* environment) const
 330CompactTDZEnvironmentMap::Handle Decoder::handleForTDZEnvironment(CompactTDZEnvironment* environment) const
331331{
332332 auto it = m_environmentToHandleMap.find(environment);
333333 RELEASE_ASSERT(it != m_environmentToHandleMap.end());
334334 return it->value;
335335}
336336
337 void Decoder::setHandleForEnvironment(CompactVariableEnvironment* environment, const CompactVariableMap::Handle& handle)
 337void Decoder::setHandleForTDZEnvironment(CompactTDZEnvironment* environment, const CompactTDZEnvironmentMap::Handle& handle)
338338{
339339 auto addResult = m_environmentToHandleMap.add(environment, handle);
340340 RELEASE_ASSERT(addResult.isNewEntry);

@@private:
10501050 CachedPtr<CachedVariableEnvironmentRareData> m_rareData;
10511051};
10521052
1053 class CachedCompactVariableEnvironment : public CachedObject<CompactVariableEnvironment> {
 1053class CachedCompactTDZEnvironment : public CachedObject<CompactTDZEnvironment> {
10541054public:
1055  void encode(Encoder& encoder, const CompactVariableEnvironment& env)
 1055 void encode(Encoder& encoder, const CompactTDZEnvironment& env)
10561056 {
1057  m_variables.encode(encoder, env.m_variables);
1058  m_variableMetadata.encode(encoder, env.m_variableMetadata);
 1057 if (WTF::holds_alternative<CompactTDZEnvironment::Compact>(env.m_variables))
 1058 m_variables.encode(encoder, WTF::get<CompactTDZEnvironment::Compact>(env.m_variables));
 1059 else {
 1060 CompactTDZEnvironment::Compact compact;
 1061 for (auto& key : WTF::get<CompactTDZEnvironment::Inflated>(env.m_variables))
 1062 compact.append(key);
 1063 m_variables.encode(encoder, compact);
 1064 }
10591065 m_hash = env.m_hash;
1060  m_isEverythingCaptured = env.m_isEverythingCaptured;
10611066 }
10621067
1063  void decode(Decoder& decoder, CompactVariableEnvironment& env) const
 1068 void decode(Decoder& decoder, CompactTDZEnvironment& env) const
10641069 {
1065  m_variables.decode(decoder, env.m_variables);
1066  m_variableMetadata.decode(decoder, env.m_variableMetadata);
 1070 {
 1071 CompactTDZEnvironment::Compact compact;
 1072 m_variables.decode(decoder, compact);
 1073 CompactTDZEnvironment::sortCompact(compact);
 1074 env.m_variables = CompactTDZEnvironment::Variables(WTFMove(compact));
 1075 }
10671076 env.m_hash = m_hash;
1068  env.m_isEverythingCaptured = m_isEverythingCaptured;
10691077 }
10701078
1071  CompactVariableEnvironment* decode(Decoder& decoder) const
 1079 CompactTDZEnvironment* decode(Decoder& decoder) const
10721080 {
1073  CompactVariableEnvironment* env = new CompactVariableEnvironment;
 1081 CompactTDZEnvironment* env = new CompactTDZEnvironment;
10741082 decode(decoder, *env);
10751083 return env;
10761084 }
10771085
10781086private:
10791087 CachedVector<CachedRefPtr<CachedUniquedStringImpl, UniquedStringImpl, WTF::PackedPtrTraits<UniquedStringImpl>>> m_variables;
1080  CachedVector<VariableEnvironmentEntry> m_variableMetadata;
10811088 unsigned m_hash;
1082  bool m_isEverythingCaptured;
10831089};
10841090
1085 class CachedCompactVariableMapHandle : public CachedObject<CompactVariableMap::Handle> {
 1091class CachedCompactTDZEnvironmentMapHandle : public CachedObject<CompactTDZEnvironmentMap::Handle> {
10861092public:
1087  void encode(Encoder& encoder, const CompactVariableMap::Handle& handle)
 1093 void encode(Encoder& encoder, const CompactTDZEnvironmentMap::Handle& handle)
10881094 {
10891095 m_environment.encode(encoder, handle.m_environment);
10901096 }
10911097
1092  CompactVariableMap::Handle decode(Decoder& decoder) const
 1098 CompactTDZEnvironmentMap::Handle decode(Decoder& decoder) const
10931099 {
10941100 bool isNewAllocation;
1095  CompactVariableEnvironment* environment = m_environment.decode(decoder, isNewAllocation);
 1101 CompactTDZEnvironment* environment = m_environment.decode(decoder, isNewAllocation);
10961102 if (!environment) {
10971103 ASSERT(!isNewAllocation);
1098  return CompactVariableMap::Handle();
 1104 return CompactTDZEnvironmentMap::Handle();
10991105 }
11001106
11011107 if (!isNewAllocation)
1102  return decoder.handleForEnvironment(environment);
 1108 return decoder.handleForTDZEnvironment(environment);
11031109 bool isNewEntry;
1104  CompactVariableMap::Handle handle = decoder.vm().m_compactVariableMap->get(environment, isNewEntry);
 1110 CompactTDZEnvironmentMap::Handle handle = decoder.vm().m_compactVariableMap->get(environment, isNewEntry);
11051111 if (!isNewEntry) {
11061112 decoder.addFinalizer([=] {
11071113 delete environment;
11081114 });
11091115 }
1110  decoder.setHandleForEnvironment(environment, handle);
 1116 decoder.setHandleForTDZEnvironment(environment, handle);
11111117 return handle;
11121118 }
11131119
 1120 void decode(Decoder& decoder, CompactTDZEnvironmentMap::Handle& handle) const
 1121 {
 1122 handle = decode(decoder);
 1123 }
 1124
11141125private:
1115  CachedPtr<CachedCompactVariableEnvironment> m_environment;
 1126 CachedPtr<CachedCompactTDZEnvironment> m_environment;
11161127};
11171128
11181129template<typename T, typename Source = SourceType<T>>

@@public:
17511762 {
17521763 UnlinkedFunctionExecutable::RareData* rareData = new UnlinkedFunctionExecutable::RareData { };
17531764 m_classSource.decode(decoder, rareData->m_classSource);
1754  auto parentScopeTDZVariables = m_parentScopeTDZVariables.decode(decoder);
1755  rareData->m_parentScopeTDZVariables = WTFMove(parentScopeTDZVariables);
 1765 m_parentScopeTDZVariables.decode(decoder, rareData->m_parentScopeTDZVariables);
17561766 return rareData;
17571767 }
17581768
17591769private:
17601770 CachedSourceCodeWithoutProvider m_classSource;
1761  CachedCompactVariableMapHandle m_parentScopeTDZVariables;
 1771 CachedVector<CachedCompactTDZEnvironmentMapHandle> m_parentScopeTDZVariables;
17621772};
17631773
17641774class CachedFunctionExecutable : public CachedObject<UnlinkedFunctionExecutable> {
268822

Source/JavaScriptCore/runtime/CachedTypes.h

@@public:
9090 void cacheOffset(ptrdiff_t, void*);
9191 WTF::Optional<void*> cachedPtrForOffset(ptrdiff_t);
9292 const void* ptrForOffsetFromBase(ptrdiff_t);
93  CompactVariableMap::Handle handleForEnvironment(CompactVariableEnvironment*) const;
94  void setHandleForEnvironment(CompactVariableEnvironment*, const CompactVariableMap::Handle&);
 93 CompactTDZEnvironmentMap::Handle handleForTDZEnvironment(CompactTDZEnvironment*) const;
 94 void setHandleForTDZEnvironment(CompactTDZEnvironment*, const CompactTDZEnvironmentMap::Handle&);
9595 void addLeafExecutable(const UnlinkedFunctionExecutable*, ptrdiff_t);
9696 RefPtr<SourceProvider> provider() const;
9797

@@private:
105105 Ref<CachedBytecode> m_cachedBytecode;
106106 HashMap<ptrdiff_t, void*> m_offsetToPtrMap;
107107 Vector<std::function<void()>> m_finalizers;
108  HashMap<CompactVariableEnvironment*, CompactVariableMap::Handle> m_environmentToHandleMap;
 108 HashMap<CompactTDZEnvironment*, CompactTDZEnvironmentMap::Handle> m_environmentToHandleMap;
109109 RefPtr<SourceProvider> m_provider;
110110};
111111
268822

Source/JavaScriptCore/runtime/CodeCache.cpp

@@static void generateUnlinkedCodeBlockFor
7171}
7272
7373template <class UnlinkedCodeBlockType, class ExecutableType = ScriptExecutable>
74 UnlinkedCodeBlockType* generateUnlinkedCodeBlockImpl(VM& vm, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType, DerivedContextType derivedContextType, bool isArrowFunctionContext, const VariableEnvironment* variablesUnderTDZ, ExecutableType* executable = nullptr)
 74UnlinkedCodeBlockType* generateUnlinkedCodeBlockImpl(VM& vm, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType, DerivedContextType derivedContextType, bool isArrowFunctionContext, const TDZEnvironment* variablesUnderTDZ = nullptr, const VariableEnvironment* parentScopePrivateNames = nullptr, ExecutableType* executable = nullptr)
7575{
7676 typedef typename CacheTypes<UnlinkedCodeBlockType>::RootNode RootNode;
7777 bool isInsideOrdinaryFunction = executable && executable->isInsideOrdinaryFunction();
 78
7879 std::unique_ptr<RootNode> rootNode = parse<RootNode>(
79  vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin, strictMode, scriptMode, CacheTypes<UnlinkedCodeBlockType>::parseMode, SuperBinding::NotNeeded, error, nullptr, ConstructorKind::None, derivedContextType, evalContextType, nullptr, variablesUnderTDZ, nullptr, isInsideOrdinaryFunction);
 80 vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin, strictMode, scriptMode, CacheTypes<UnlinkedCodeBlockType>::parseMode, SuperBinding::NotNeeded, error, nullptr, ConstructorKind::None, derivedContextType, evalContextType, nullptr, parentScopePrivateNames, nullptr, isInsideOrdinaryFunction);
 81
8082 if (!rootNode)
8183 return nullptr;
8284

@@UnlinkedCodeBlockType* generateUnlinkedC
103105 if (!source.provider()->sourceMappingURLDirective().isNull())
104106 unlinkedCodeBlock->setSourceMappingURLDirective(source.provider()->sourceMappingURLDirective());
105107
106  error = BytecodeGenerator::generate(vm, rootNode.get(), source, unlinkedCodeBlock, codeGenerationMode, variablesUnderTDZ, ecmaMode);
 108 Vector<CompactTDZEnvironmentMap::Handle> parentVariablesUnderTDZ;
 109 if (variablesUnderTDZ)
 110 parentVariablesUnderTDZ.append(vm.m_compactVariableMap->get(*variablesUnderTDZ));
 111 error = BytecodeGenerator::generate(vm, rootNode.get(), source, unlinkedCodeBlock, codeGenerationMode, parentVariablesUnderTDZ, ecmaMode);
107112
108113 if (error.isValid())
109114 return nullptr;

@@UnlinkedCodeBlockType* generateUnlinkedC
112117}
113118
114119template <class UnlinkedCodeBlockType, class ExecutableType>
115 UnlinkedCodeBlockType* generateUnlinkedCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
 120UnlinkedCodeBlockType* generateUnlinkedCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType, const TDZEnvironment* variablesUnderTDZ = nullptr, const VariableEnvironment* parentScopePrivateNames = nullptr)
116121{
117  return generateUnlinkedCodeBlockImpl<UnlinkedCodeBlockType, ExecutableType>(vm, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType, executable->derivedContextType(), executable->isArrowFunctionContext(), variablesUnderTDZ, executable);
 122 return generateUnlinkedCodeBlockImpl<UnlinkedCodeBlockType, ExecutableType>(vm, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType, executable->derivedContextType(), executable->isArrowFunctionContext(), variablesUnderTDZ, parentScopePrivateNames, executable);
118123}
119124
120 UnlinkedEvalCodeBlock* generateUnlinkedCodeBlockForDirectEval(VM& vm, DirectEvalExecutable* executable, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
 125UnlinkedEvalCodeBlock* generateUnlinkedCodeBlockForDirectEval(VM& vm, DirectEvalExecutable* executable, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType, const TDZEnvironment* variablesUnderTDZ, const VariableEnvironment* parentScopePrivateNames)
121126{
122  return generateUnlinkedCodeBlock<UnlinkedEvalCodeBlock>(vm, executable, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType, variablesUnderTDZ);
 127 return generateUnlinkedCodeBlock<UnlinkedEvalCodeBlock>(vm, executable, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType, variablesUnderTDZ, parentScopePrivateNames);
123128}
124129
125130template <class UnlinkedCodeBlockType>
126131std::enable_if_t<!std::is_same<UnlinkedCodeBlockType, UnlinkedEvalCodeBlock>::value, UnlinkedCodeBlockType*>
127 recursivelyGenerateUnlinkedCodeBlock(VM& vm, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
 132recursivelyGenerateUnlinkedCodeBlock(VM& vm, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType)
128133{
129134 bool isArrowFunctionContext = false;
130  UnlinkedCodeBlockType* unlinkedCodeBlock = generateUnlinkedCodeBlockImpl<UnlinkedCodeBlockType>(vm, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType, DerivedContextType::None, isArrowFunctionContext, variablesUnderTDZ);
 135 UnlinkedCodeBlockType* unlinkedCodeBlock = generateUnlinkedCodeBlockImpl<UnlinkedCodeBlockType>(vm, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType, DerivedContextType::None, isArrowFunctionContext);
131136 if (!unlinkedCodeBlock)
132137 return nullptr;
133138

@@recursivelyGenerateUnlinkedCodeBlock(VM&
135140 return unlinkedCodeBlock;
136141}
137142
138 UnlinkedProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForProgram(VM& vm, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
 143UnlinkedProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForProgram(VM& vm, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType)
139144{
140  return recursivelyGenerateUnlinkedCodeBlock<UnlinkedProgramCodeBlock>(vm, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType, variablesUnderTDZ);
 145 return recursivelyGenerateUnlinkedCodeBlock<UnlinkedProgramCodeBlock>(vm, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType);
141146}
142147
143 UnlinkedModuleProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForModuleProgram(VM& vm, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
 148UnlinkedModuleProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForModuleProgram(VM& vm, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType)
144149{
145  return recursivelyGenerateUnlinkedCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType, variablesUnderTDZ);
 150 return recursivelyGenerateUnlinkedCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType);
146151}
147152
148153template <class UnlinkedCodeBlockType, class ExecutableType>

@@UnlinkedCodeBlockType* CodeCache::getUnl
168173 return unlinkedCodeBlock;
169174 }
170175
171  VariableEnvironment variablesUnderTDZ;
172  unlinkedCodeBlock = generateUnlinkedCodeBlock<UnlinkedCodeBlockType, ExecutableType>(vm, executable, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType, &variablesUnderTDZ);
 176 unlinkedCodeBlock = generateUnlinkedCodeBlock<UnlinkedCodeBlockType, ExecutableType>(vm, executable, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType);
173177
174178 if (unlinkedCodeBlock && Options::useCodeCache()) {
175179 m_sourceCode.addCache(key, SourceCodeValue(vm, unlinkedCodeBlock, m_sourceCode.age()));
268822

Source/JavaScriptCore/runtime/CodeCache.h

@@class ParserError;
5050class ProgramExecutable;
5151class SourceCode;
5252class VM;
53 class VariableEnvironment;
 53
 54using TDZEnvironment = HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash>;
5455
5556namespace CodeCacheInternal {
5657static constexpr bool verbose = false;

@@template <> struct CacheTypes<UnlinkedMo
253254 static constexpr SourceParseMode parseMode = SourceParseMode::ModuleEvaluateMode;
254255};
255256
256 UnlinkedEvalCodeBlock* generateUnlinkedCodeBlockForDirectEval(VM&, DirectEvalExecutable*, const SourceCode&, JSParserStrictMode, JSParserScriptMode, OptionSet<CodeGenerationMode>, ParserError&, EvalContextType, const VariableEnvironment* variablesUnderTDZ);
257 UnlinkedProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForProgram(VM&, const SourceCode&, JSParserStrictMode, JSParserScriptMode, OptionSet<CodeGenerationMode>, ParserError&, EvalContextType, const VariableEnvironment* variablesUnderTDZ);
258 UnlinkedModuleProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForModuleProgram(VM&, const SourceCode&, JSParserStrictMode, JSParserScriptMode, OptionSet<CodeGenerationMode>, ParserError&, EvalContextType, const VariableEnvironment* variablesUnderTDZ);
 257UnlinkedEvalCodeBlock* generateUnlinkedCodeBlockForDirectEval(VM&, DirectEvalExecutable*, const SourceCode&, JSParserStrictMode, JSParserScriptMode, OptionSet<CodeGenerationMode>, ParserError&, EvalContextType, const TDZEnvironment* variablesUnderTDZ, const VariableEnvironment* parentScopePrivateNames);
 258UnlinkedProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForProgram(VM&, const SourceCode&, JSParserStrictMode, JSParserScriptMode, OptionSet<CodeGenerationMode>, ParserError&, EvalContextType);
 259UnlinkedModuleProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForModuleProgram(VM&, const SourceCode&, JSParserStrictMode, JSParserScriptMode, OptionSet<CodeGenerationMode>, ParserError&, EvalContextType);
259260
260261void writeCodeBlock(VM&, const SourceCodeKey&, const SourceCodeValue&);
261262RefPtr<CachedBytecode> serializeBytecode(VM&, UnlinkedCodeBlock*, const SourceCode&, SourceCodeType, JSParserStrictMode, JSParserScriptMode, FileSystem::PlatformFileHandle fd, BytecodeCacheError&, OptionSet<CodeGenerationMode>);
268822

Source/JavaScriptCore/runtime/Completion.cpp

@@RefPtr<CachedBytecode> generateProgramBy
9191 JSLockHolder lock(vm);
9292 RELEASE_ASSERT(vm.atomStringTable() == Thread::current().atomStringTable());
9393
94  VariableEnvironment variablesUnderTDZ;
9594 JSParserStrictMode strictMode = JSParserStrictMode::NotStrict;
9695 JSParserScriptMode scriptMode = JSParserScriptMode::Classic;
9796 EvalContextType evalContextType = EvalContextType::None;
9897
9998 ParserError parserError;
100  UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlockForProgram(vm, source, strictMode, scriptMode, { }, parserError, evalContextType, &variablesUnderTDZ);
 99 UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlockForProgram(vm, source, strictMode, scriptMode, { }, parserError, evalContextType);
101100 if (parserError.isValid())
102101 error = parserError;
103102 if (!unlinkedCodeBlock)

@@RefPtr<CachedBytecode> generateModuleByt
111110 JSLockHolder lock(vm);
112111 RELEASE_ASSERT(vm.atomStringTable() == Thread::current().atomStringTable());
113112
114  VariableEnvironment variablesUnderTDZ;
115113 JSParserStrictMode strictMode = JSParserStrictMode::Strict;
116114 JSParserScriptMode scriptMode = JSParserScriptMode::Module;
117115 EvalContextType evalContextType = EvalContextType::None;
118116
119117 ParserError parserError;
120  UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlockForModuleProgram(vm, source, strictMode, scriptMode, { }, parserError, evalContextType, &variablesUnderTDZ);
 118 UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlockForModuleProgram(vm, source, strictMode, scriptMode, { }, parserError, evalContextType);
121119 if (parserError.isValid())
122120 error = parserError;
123121 if (!unlinkedCodeBlock)
268822

Source/JavaScriptCore/runtime/DirectEvalExecutable.cpp

3434
3535namespace JSC {
3636
37 DirectEvalExecutable* DirectEvalExecutable::create(JSGlobalObject* globalObject, const SourceCode& source, DerivedContextType derivedContextType, NeedsClassFieldInitializer needsClassFieldInitializer, bool isArrowFunctionContext, bool isInsideOrdinaryFunction, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ, ECMAMode ecmaMode)
 37DirectEvalExecutable* DirectEvalExecutable::create(JSGlobalObject* globalObject, const SourceCode& source, DerivedContextType derivedContextType, NeedsClassFieldInitializer needsClassFieldInitializer, bool isArrowFunctionContext, bool isInsideOrdinaryFunction, EvalContextType evalContextType, const TDZEnvironment* variablesUnderTDZ, const VariableEnvironment* privateNames, ECMAMode ecmaMode)
3838{
3939 VM& vm = globalObject->vm();
4040 auto scope = DECLARE_THROW_SCOPE(vm);

@@DirectEvalExecutable* DirectEvalExecutab
5252 OptionSet<CodeGenerationMode> codeGenerationMode = globalObject->defaultCodeGenerationMode();
5353
5454 // We don't bother with CodeCache here because direct eval uses a specialized DirectEvalCodeCache.
55  UnlinkedEvalCodeBlock* unlinkedEvalCode = generateUnlinkedCodeBlockForDirectEval(vm, executable, executable->source(), strictMode, JSParserScriptMode::Classic, codeGenerationMode, error, evalContextType, variablesUnderTDZ);
 55 UnlinkedEvalCodeBlock* unlinkedEvalCode = generateUnlinkedCodeBlockForDirectEval(vm, executable, executable->source(), strictMode, JSParserScriptMode::Classic, codeGenerationMode, error, evalContextType, variablesUnderTDZ, privateNames);
5656
5757 if (globalObject->hasDebugger())
5858 globalObject->debugger()->sourceParsed(globalObject, executable->source().provider(), error.line(), error.message());
268822

Source/JavaScriptCore/runtime/DirectEvalExecutable.h

@@namespace JSC {
3131
3232class DirectEvalExecutable final : public EvalExecutable {
3333public:
34  static DirectEvalExecutable* create(JSGlobalObject*, const SourceCode&, DerivedContextType, NeedsClassFieldInitializer, bool isArrowFunctionContext, bool isInsideOrdinaryFunction, EvalContextType, const VariableEnvironment*, ECMAMode);
 34 static DirectEvalExecutable* create(JSGlobalObject*, const SourceCode&, DerivedContextType, NeedsClassFieldInitializer, bool isArrowFunctionContext, bool isInsideOrdinaryFunction, EvalContextType, const TDZEnvironment* parentScopeTDZVariables, const VariableEnvironment* privateNames, ECMAMode);
3535private:
3636 DirectEvalExecutable(JSGlobalObject*, const SourceCode&, bool inStrictContext, DerivedContextType, NeedsClassFieldInitializer, bool isArrowFunctionContext, bool isInsideOrdinaryFunction, EvalContextType);
3737};
268822

Source/JavaScriptCore/runtime/JSScope.cpp

@@ResolveOp JSScope::abstractResolve(JSGlo
321321 return op;
322322}
323323
324 void JSScope::collectClosureVariablesUnderTDZ(JSScope* scope, VariableEnvironment& result)
 324void JSScope::collectClosureVariablesUnderTDZ(JSScope* scope, TDZEnvironment& result, VariableEnvironment& privateNames)
325325{
326326 for (; scope; scope = scope->next()) {
327327 if (!scope->isLexicalScope() && !scope->isCatchScope())

@@void JSScope::collectClosureVariablesUnd
338338 ConcurrentJSLocker locker(symbolTable->m_lock);
339339 for (auto end = symbolTable->end(locker), iter = symbolTable->begin(locker); iter != end; ++iter)
340340 result.add(iter->key);
 341
341342 if (symbolTable->hasPrivateNames()) {
342343 for (auto name : symbolTable->privateNames())
343  result.usePrivateName(name);
 344 privateNames.usePrivateName(name);
344345 }
345346 }
346347}
268822

Source/JavaScriptCore/runtime/JSScope.h

@@class SymbolTable;
3535class VariableEnvironment;
3636class WatchpointSet;
3737
 38using TDZEnvironment = HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash>;
 39
3840class JSScope : public JSNonFinalObject {
3941public:
4042 using Base = JSNonFinalObject;

@@public:
6062 static bool hasConstantScope(ResolveType);
6163 static JSScope* constantScopeForCodeBlock(ResolveType, CodeBlock*);
6264
63  static void collectClosureVariablesUnderTDZ(JSScope*, VariableEnvironment& result);
 65 static void collectClosureVariablesUnderTDZ(JSScope*, TDZEnvironment& result, VariableEnvironment& privateNames);
6466
6567 static void visitChildren(JSCell*, SlotVisitor&);
6668
268822

Source/JavaScriptCore/runtime/VM.cpp

@@VM::VM(VMType vmType, HeapType heapType,
390390 , interpreter(nullptr)
391391 , entryScope(nullptr)
392392 , m_regExpCache(new RegExpCache(this))
393  , m_compactVariableMap(adoptRef(*(new CompactVariableMap)))
 393 , m_compactVariableMap(adoptRef(*(new CompactTDZEnvironmentMap)))
394394#if ENABLE(REGEXP_TRACING)
395395 , m_rtTraceList(new RTTraceList())
396396#endif
268822

Source/JavaScriptCore/runtime/VM.h

@@struct CheckpointOSRExitSideState;
108108class CodeBlock;
109109class CodeCache;
110110class CommonIdentifiers;
111 class CompactVariableMap;
 111class CompactTDZEnvironmentMap;
112112class ConservativeRoots;
113113class ControlFlowProfiler;
114114class CustomGetterSetter;

@@public:
10041004 static constexpr size_t patternContextBufferSize = 0; // Space allocated to save nested parenthesis context
10051005#endif
10061006
1007  Ref<CompactVariableMap> m_compactVariableMap;
 1007 Ref<CompactTDZEnvironmentMap> m_compactVariableMap;
10081008
10091009 std::unique_ptr<HasOwnPropertyCache> m_hasOwnPropertyCache;
10101010 ALWAYS_INLINE HasOwnPropertyCache* hasOwnPropertyCache() { return m_hasOwnPropertyCache.get(); }
268822

Source/WTF/ChangeLog

 12020-10-23 Saam Barati <sbarati@apple.com>
 2
 3 Better cache our serialization of the outer TDZ environment when creating FunctionExecutables during bytecode generation
 4 https://bugs.webkit.org/show_bug.cgi?id=199866
 5 <rdar://problem/53333108>
 6
 7 Reviewed by NOBODY (OOPS!).
 8
 9 * wtf/RefPtr.h:
 10 (WTF::swap): Deleted.
 11 This function is no longer necessary, and causes ADL (https://en.cppreference.com/w/cpp/language/adl)
 12 compile errors when not using DumbPtrTraits and calling sort on a vector of that type.
 13
1142020-10-20 Sihui Liu <sihui_liu@apple.com>
215
316 Add stubs for SpeechRecognition
268822

Source/WTF/wtf/RefPtr.h

@@inline void RefPtr<T, U, V>::swap(RefPtr
193193 U::swap(m_ptr, o.m_ptr);
194194}
195195
196 template<typename T, typename U, typename V, typename X, typename Y, typename Z, typename = std::enable_if_t<!std::is_same<U, DumbPtrTraits<T>>::value || !std::is_same<Y, DumbPtrTraits<X>>::value>>
197 inline void swap(RefPtr<T, U, V>& a, RefPtr<X, Y, Z>& b)
198 {
199  a.swap(b);
200 }
201 
202196template<typename T, typename U, typename V, typename X, typename Y, typename Z>
203197inline bool operator==(const RefPtr<T, U, V>& a, const RefPtr<X, Y, Z>& b)
204198{
268822