Ignore:
Timestamp:
Oct 28, 2020, 12:25:14 PM (5 years ago)
Author:
[email protected]
Message:

Better cache our serialization of the outer TDZ environment when creating FunctionExecutables during bytecode generation
https://bugs.webkit.org/show_bug.cgi?id=199866
<rdar://problem/53333108>

Reviewed by Tadeu Zagallo.

JSTests:

  • microbenchmarks/let-const-tdz-environment-parsing-and-hash-consing-speed.js: Added.

Source/JavaScriptCore:

This patch removes performance pathologies regarding programs with
many variables under TDZ (let/const). We had an algorithm for caching
the results of gathering all variables under TDZ, but that algorithm
wasn't nearly aggressive enough in its caching. This lead us to worst
case quadratic runtime, which could happens in practice for large functions.

There are a few fixes here:

  • Instead of flattening the entire TDZ stack, and caching that result,

we now cache each stack entry individually. So as you push/pop to the
TDZ environment stack, we no longer invalidate everything. Instead, we
will just need to cache the newly pushed entry. We also no longer invalidate
the cache for lifting a TDZ check. The compromise here is we may emit
more runtime TDZ checks for closure variables. This is better than N2
bytecode compile time perf, since a well predicted branch for a TDZ
check is essentially free.

  • We no longer transform the CompactTDZEnvironment (formerly CompactVariableEnvironment)

from a Vector into a HashSet each time we generate code for an inner function. Instead,
CompactTDZEnvironment can be in two modes: compact and inflated. It starts life off in
compact mode (a vector), and will turn into an inflated mode if it's ever needed. Once
inflated, it'll stay this way until it's destructed. This improves our algorithm from being
O(EnvSize * NumFunctions) to O(EnvSize) at the cost of using more space in a HashTable versus a
Vector. In the future, we could consider just binary searching through this Vector, and never using
a hash table.

  • bytecode/UnlinkedFunctionExecutable.cpp:

(JSC::generateUnlinkedFunctionCodeBlock):
(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):
(JSC::BytecodeGenerator::emitNewInstanceFieldInitializerFunction):

  • bytecompiler/BytecodeGenerator.h:

(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::makeFunction):

  • debugger/DebuggerCallFrame.cpp:

(JSC::DebuggerCallFrame::evaluateWithScopeExtension):

  • interpreter/Interpreter.cpp:

(JSC::eval):

  • parser/Parser.h:

(JSC::Parser<LexerType>::parse):
(JSC::parse):

  • parser/VariableEnvironment.cpp:

(JSC::CompactTDZEnvironment::sortCompact):
(JSC::CompactTDZEnvironment::CompactTDZEnvironment):
(JSC::CompactTDZEnvironment::operator== const):
(JSC::CompactTDZEnvironment::toTDZEnvironmentSlow const):
(JSC::CompactTDZEnvironmentMap::get):
(JSC::CompactTDZEnvironmentMap::Handle::~Handle):
(JSC::CompactTDZEnvironmentMap::Handle::Handle):
(JSC::CompactVariableEnvironment::CompactVariableEnvironment): Deleted.
(JSC::CompactVariableEnvironment::operator== const): Deleted.
(JSC::CompactVariableEnvironment::toVariableEnvironment const): Deleted.
(JSC::CompactVariableMap::get): Deleted.
(JSC::CompactVariableMap::Handle::~Handle): Deleted.
(JSC::CompactVariableMap::Handle::Handle): Deleted.

  • parser/VariableEnvironment.h:

(JSC::CompactTDZEnvironment::toTDZEnvironment const):
(JSC::CompactTDZEnvironmentKey::CompactTDZEnvironmentKey):
(JSC::CompactTDZEnvironmentKey::hash):
(JSC::CompactTDZEnvironmentKey::equal):
(JSC::CompactTDZEnvironmentKey::makeDeletedValue):
(JSC::CompactTDZEnvironmentKey::isHashTableDeletedValue const):
(JSC::CompactTDZEnvironmentKey::environment):
(WTF::HashTraits<JSC::CompactTDZEnvironmentKey>::emptyValue):
(WTF::HashTraits<JSC::CompactTDZEnvironmentKey>::isEmptyValue):
(WTF::HashTraits<JSC::CompactTDZEnvironmentKey>::constructDeletedValue):
(WTF::HashTraits<JSC::CompactTDZEnvironmentKey>::isDeletedValue):
(JSC::CompactTDZEnvironmentMap::Handle::environment const):
(JSC::CompactVariableEnvironment::hash const): Deleted.
(JSC::CompactVariableMapKey::CompactVariableMapKey): Deleted.
(JSC::CompactVariableMapKey::hash): Deleted.
(JSC::CompactVariableMapKey::equal): Deleted.
(JSC::CompactVariableMapKey::makeDeletedValue): Deleted.
(JSC::CompactVariableMapKey::isHashTableDeletedValue const): Deleted.
(JSC::CompactVariableMapKey::isHashTableEmptyValue const): Deleted.
(JSC::CompactVariableMapKey::environment): Deleted.
(WTF::HashTraits<JSC::CompactVariableMapKey>::emptyValue): Deleted.
(WTF::HashTraits<JSC::CompactVariableMapKey>::isEmptyValue): Deleted.
(WTF::HashTraits<JSC::CompactVariableMapKey>::constructDeletedValue): Deleted.
(WTF::HashTraits<JSC::CompactVariableMapKey>::isDeletedValue): Deleted.
(JSC::CompactVariableMap::Handle::Handle): Deleted.
(JSC::CompactVariableMap::Handle::operator=): Deleted.
(JSC::CompactVariableMap::Handle::operator bool const): Deleted.
(JSC::CompactVariableMap::Handle::environment const): Deleted.
(JSC::CompactVariableMap::Handle::swap): Deleted.

  • runtime/CachedTypes.cpp:

(JSC::Decoder::handleForTDZEnvironment const):
(JSC::Decoder::setHandleForTDZEnvironment):
(JSC::CachedCompactTDZEnvironment::encode):
(JSC::CachedCompactTDZEnvironment::decode const):
(JSC::CachedCompactTDZEnvironmentMapHandle::encode):
(JSC::CachedCompactTDZEnvironmentMapHandle::decode const):
(JSC::CachedFunctionExecutableRareData::decode const):
(JSC::Decoder::handleForEnvironment const): Deleted.
(JSC::Decoder::setHandleForEnvironment): Deleted.
(JSC::CachedCompactVariableEnvironment::encode): Deleted.
(JSC::CachedCompactVariableEnvironment::decode const): Deleted.
(JSC::CachedCompactVariableMapHandle::encode): Deleted.
(JSC::CachedCompactVariableMapHandle::decode const): Deleted.

  • runtime/CachedTypes.h:
  • runtime/CodeCache.cpp:

(JSC::generateUnlinkedCodeBlockImpl):
(JSC::generateUnlinkedCodeBlock):
(JSC::generateUnlinkedCodeBlockForDirectEval):
(JSC::recursivelyGenerateUnlinkedCodeBlockForProgram):
(JSC::recursivelyGenerateUnlinkedCodeBlockForModuleProgram):
(JSC::CodeCache::getUnlinkedGlobalCodeBlock):

  • runtime/CodeCache.h:
  • runtime/Completion.cpp:

(JSC::generateProgramBytecode):
(JSC::generateModuleBytecode):

  • runtime/DirectEvalExecutable.cpp:

(JSC::DirectEvalExecutable::create):

  • runtime/DirectEvalExecutable.h:
  • runtime/JSScope.cpp:

(JSC::JSScope::collectClosureVariablesUnderTDZ):

  • runtime/JSScope.h:
  • runtime/VM.cpp:

(JSC::VM::VM):

  • runtime/VM.h:

Source/WTF:

  • wtf/RefPtr.h:

(WTF::swap): Deleted.
This function is no longer necessary, and causes ADL (https://en.cppreference.com/w/cpp/language/adl)
compile errors when not using DumbPtrTraits and calling sort on a vector of that type.

Location:
trunk/Source/JavaScriptCore/bytecompiler
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r268593 r269115  
    4949#include "PrivateFieldPutKind.h"
    5050#include "StrongInlines.h"
     51#include "SuperSampler.h"
    5152#include "UnlinkedCodeBlock.h"
    5253#include "UnlinkedEvalCodeBlock.h"
     
    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)
     
    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"
     
    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)
     
    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)
     
    364363    functionSymbolTable->setUsesNonStrictEval(m_usesNonStrictEval);
    365364    int symbolTableConstantIndex = 0;
     365
     366    m_parentScopeTDZStackSize = parentScopeTDZVariables.size();
     367    m_cachedVariablesUnderTDZ = parentScopeTDZVariables;
    366368
    367369    FunctionParameters& parameters = *functionNode->parameters();
     
    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;
     
    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
     
    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)
     
    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)
     
    860859    m_codeBlock->setNumParameters(1);
    861860
    862     pushTDZVariables(*parentScopeTDZVariables, TDZCheckOptimization::DoNotOptimize, TDZRequirement::UnderTDZ);
     861    m_parentScopeTDZStackSize = parentScopeTDZVariables.size();
     862    m_cachedVariablesUnderTDZ = parentScopeTDZVariables;
    863863
    864864    emitEnter();
     
    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)
     
    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);
     
    21712170
    21722171    m_TDZStack.removeLast();
    2173     m_cachedVariablesUnderTDZ = { };
     2172    m_cachedVariablesUnderTDZ.removeLast();
    21742173}
    21752174
     
    28592858    }
    28602859
     2860    for (unsigned i = m_parentScopeTDZStackSize; i--;) {
     2861        if (m_cachedVariablesUnderTDZ[i].environment().toTDZEnvironment().contains(variable.ident().impl()))
     2862            return true;
     2863    }
     2864
    28612865    return false;
    28622866}
     
    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        }
     
    29092911
    29102912    m_TDZStack.append(WTFMove(map));
    2911     m_cachedVariablesUnderTDZ = { };
    2912 }
    2913 
    2914 Optional<CompactVariableMap::Handle> BytecodeGenerator::getVariablesUnderTDZ()
    2915 {
    2916     if (m_cachedVariablesUnderTDZ) {
    2917         if (!m_hasCachedVariablesUnderTDZ) {
    2918             ASSERT(m_cachedVariablesUnderTDZ.environment().toVariableEnvironment().isEmpty());
    2919             return WTF::nullopt;
    2920         }
     2913    m_cachedVariablesUnderTDZ.append({ });
     2914}
     2915
     2916Optional<BytecodeGenerator::CachedTDZStack> BytecodeGenerator::getVariablesUnderTDZ()
     2917{
     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_parentScopeTDZStackSize == 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_parentScopeTDZStackSize])
     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());
    2944         }
    2945     }
    2946 
    2947     m_cachedVariablesUnderTDZ = m_vm.m_compactVariableMap->get(environment);
    2948     m_hasCachedVariablesUnderTDZ = !environment.isEmpty();
    2949     if (!m_hasCachedVariablesUnderTDZ)
    2950         return WTF::nullopt;
    2951 
     2940        TDZEnvironment environment;
     2941        for (auto& entry : map) {
     2942            if (entry.value != TDZNecessityLevel::NotNeeded)
     2943                environment.add(entry.key.get());
     2944        }
     2945        m_cachedVariablesUnderTDZ[i + m_parentScopeTDZStackSize] = m_vm.m_compactVariableMap->get(environment);
     2946    }
     2947
     2948    assertCacheIsCoherent();
    29522949    return m_cachedVariablesUnderTDZ;
    29532950}
     
    29562953{
    29572954    preservedStack.m_preservedTDZStack = m_TDZStack;
     2955    preservedStack.m_cachedTDZStack = m_cachedVariablesUnderTDZ;
    29582956}
    29592957
     
    29612959{
    29622960    m_TDZStack = preservedStack.m_preservedTDZStack;
    2963     m_cachedVariablesUnderTDZ = { };
     2961    m_cachedVariablesUnderTDZ = preservedStack.m_cachedTDZStack;
    29642962}
    29652963
     
    31483146    }
    31493147
    3150     Optional<CompactVariableMap::Handle> variablesUnderTDZ = getVariablesUnderTDZ();
     3148    auto variablesUnderTDZ = getVariablesUnderTDZ();
    31513149    SourceParseMode parseMode = SourceParseMode::InstanceFieldInitializerMode;
    31523150    ConstructAbility constructAbility = ConstructAbility::CannotConstruct;
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r266264 r269115  
    408408    public:
    409409        typedef DeclarationStacks::FunctionStack FunctionStack;
    410 
    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);
     410        using CachedTDZStack = Vector<CompactTDZEnvironmentMap::Handle>;
     411
     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();
     
    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;
     
    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
     
    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.
     
    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);
     
    12321233        private:
    12331234            Vector<TDZMap> m_preservedTDZStack;
     1235            CachedTDZStack m_cachedTDZStack;
    12341236            friend class BytecodeGenerator;
    12351237        };
     
    12631265        Vector<LexicalScopeStackEntry> m_lexicalScopeStack;
    12641266
     1267        size_t m_parentScopeTDZStackSize { 0 };
    12651268        Vector<TDZMap> m_TDZStack;
     1269        CachedTDZStack m_cachedVariablesUnderTDZ;
    12661270        Optional<size_t> m_varScopeLexicalScopeStackIndex;
    12671271        void pushTDZVariables(const VariableEnvironment&, TDZCheckOptimization, TDZRequirement);
     
    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 };
    1351 
    1352         CompactVariableMap::Handle m_cachedVariablesUnderTDZ;
    13531354
    13541355        struct CatchEntry {
Note: See TracChangeset for help on using the changeset viewer.