Changeset 269115 in webkit


Ignore:
Timestamp:
Oct 28, 2020 12:25:14 PM (3 years ago)
Author:
sbarati@apple.com
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
Files:
1 added
24 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r269107 r269115  
     12020-10-28  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 Tadeu Zagallo.
     8
     9        * microbenchmarks/let-const-tdz-environment-parsing-and-hash-consing-speed.js: Added.
     10
    1112020-10-28  Robin Morisset  <rmorisset@apple.com>
    212
  • trunk/Source/JavaScriptCore/ChangeLog

    r269107 r269115  
     12020-10-28  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 Tadeu Zagallo.
     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-28  Robin Morisset  <rmorisset@apple.com>
    2138
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp

    r262613 r269115  
    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())
     
    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())
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h

    r260415 r269115  
    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))
     
    169169    }
    170170
    171     VariableEnvironment parentScopeTDZVariables() const
    172     {
    173         if (!m_rareData || !m_rareData->m_parentScopeTDZVariables)
    174             return VariableEnvironment();
    175         return m_rareData->m_parentScopeTDZVariables.environment().toVariableEnvironment();
     171    Vector<CompactTDZEnvironmentMap::Handle> parentScopeTDZVariables() const
     172    {
     173        if (!m_rareData || m_rareData->m_parentScopeTDZVariables.isEmpty())
     174            return { };
     175        return m_rareData->m_parentScopeTDZVariables;
    176176    }
    177177   
     
    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    };
     
    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
  • 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 {
  • trunk/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp

    r266534 r269115  
    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();
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r268004 r269115  
    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)
  • trunk/Source/JavaScriptCore/parser/Parser.h

    r267306 r269115  
    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;
     
    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
     
    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)
     
    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();
     
    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();
  • trunk/Source/JavaScriptCore/parser/VariableEnvironment.cpp

    r262613 r269115  
    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 });
    114 
    115     std::sort(sortedEntries.begin(), sortedEntries.end(), [] (const auto& a, const auto& b) {
    116         return a.first < b.first;
     107
     108void CompactTDZEnvironment::sortCompact(Compact& compact)
     109{
     110    std::sort(compact.begin(), compact.end(), [] (auto& a, auto& b) {
     111        return a.get() < b.get();
    117112    });
    118 
    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();
    127     }
    128 
    129     if (m_isEverythingCaptured)
    130         m_hash *= 2;
    131 }
    132 
    133 bool CompactVariableEnvironment::operator==(const CompactVariableEnvironment& other) const
     113}
     114
     115CompactTDZEnvironment::CompactTDZEnvironment(const TDZEnvironment& env)
     116{
     117    Compact compactVariables;
     118    compactVariables.reserveCapacity(env.size());
     119
     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();
     124    }
     125
     126    sortCompact(compactVariables);
     127    m_variables = WTFMove(compactVariables);
     128}
     129
     130bool CompactTDZEnvironment::operator==(const CompactTDZEnvironment& other) const
    134131{
    135132    if (this == &other)
    136133        return true;
    137     if (m_isEverythingCaptured != other.m_isEverythingCaptured)
     134
     135    if (m_hash != other.m_hash)
    138136        return false;
    139     if (m_variables != other.m_variables)
    140         return false;
    141     if (m_variableMetadata != other.m_variableMetadata)
    142         return false;
    143     return true;
    144 }
    145 
    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     }
    155 
    156     if (m_isEverythingCaptured)
    157         result.markAllVariablesAsCaptured();
     137
     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    };
     147
     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)
    163 {
    164     auto* environment = new CompactVariableEnvironment(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)
     187{
     188    auto* environment = new CompactTDZEnvironment(env);
    165189    bool isNewEntry;
    166190    auto handle = get(environment, isNewEntry);
     
    170194}
    171195
    172 CompactVariableMap::Handle CompactVariableMap::get(CompactVariableEnvironment* environment, bool& isNewEntry)
    173 {
    174     CompactVariableMapKey key { *environment };
     196CompactTDZEnvironmentMap::Handle CompactTDZEnvironmentMap::get(CompactTDZEnvironment* environment, bool& isNewEntry)
     197{
     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);
    182 }
    183 
    184 CompactVariableMap::Handle::~Handle()
     205    return CompactTDZEnvironmentMap::Handle(addResult.iterator->key.environment(), *this);
     206}
     207
     208CompactTDZEnvironmentMap::Handle::~Handle()
    185209{
    186210    if (!m_map) {
     
    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;
     
    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;
     
    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)
  • trunk/Source/JavaScriptCore/parser/VariableEnvironment.h

    r264488 r269115  
    3030#include <wtf/HashSet.h>
    3131#include <wtf/IteratorRange.h>
     32#include <wtf/Variant.h>
    3233
    3334namespace JSC {
     
    120121
    121122class VariableEnvironment {
     123    WTF_MAKE_FAST_ALLOCATED;
    122124private:
    123125    typedef HashMap<PackedRefPtr<UniquedStringImpl>, VariableEnvironmentEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, VariableEnvironmentEntryHashTraits> Map;
     
    263265};
    264266
    265 class CompactVariableEnvironment {
     267using TDZEnvironment = HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash>;
     268
     269class CompactTDZEnvironment {
    266270    WTF_MAKE_FAST_ALLOCATED;
    267     WTF_MAKE_NONCOPYABLE(CompactVariableEnvironment);
    268 
    269     friend class CachedCompactVariableEnvironment;
     271    WTF_MAKE_NONCOPYABLE(CompactTDZEnvironment);
     272
     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;
    274 
    275     bool operator==(const CompactVariableEnvironment&) const;
     280    CompactTDZEnvironment(const TDZEnvironment&);
     281
     282    bool operator==(const CompactTDZEnvironment&) const;
    276283    unsigned hash() const { return m_hash; }
    277284
    278 private:
    279     CompactVariableEnvironment() = default;
    280 
    281     Vector<PackedRefPtr<UniquedStringImpl>> m_variables;
    282     Vector<VariableEnvironmentEntry> m_variableMetadata;
     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
     294private:
     295    CompactTDZEnvironment() = default;
     296    TDZEnvironment& toTDZEnvironmentSlow() const;
     297
     298    mutable Variables m_variables;
    283299    unsigned m_hash;
    284     bool m_isEverythingCaptured;
    285 };
    286 
    287 struct CompactVariableMapKey {
    288     CompactVariableMapKey()
     300};
     301
     302struct CompactTDZEnvironmentKey {
     303    CompactTDZEnvironmentKey()
    289304        : m_environment(nullptr)
    290305    {
     
    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)
    302     {
    303         key.m_environment = reinterpret_cast<CompactVariableEnvironment*>(1);
     316    static void makeDeletedValue(CompactTDZEnvironmentKey& key)
     317    {
     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
     
    312327    }
    313328
    314     CompactVariableEnvironment& environment()
     329    CompactTDZEnvironment& environment()
    315330    {
    316331        RELEASE_ASSERT(!isHashTableDeletedValue());
     
    320335
    321336private:
    322     CompactVariableEnvironment* m_environment;
     337    CompactTDZEnvironment* m_environment;
    323338};
    324339
     
    328343
    329344template<typename T> struct DefaultHash;
    330 template<> struct DefaultHash<JSC::CompactVariableMapKey> : JSC::CompactVariableMapKey { };
    331 
    332 template<> struct HashTraits<JSC::CompactVariableMapKey> : GenericHashTraits<JSC::CompactVariableMapKey> {
     345template<> struct DefaultHash<JSC::CompactTDZEnvironmentKey> : JSC::CompactTDZEnvironmentKey { };
     346
     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(); }
    338 
    339     static void constructDeletedValue(JSC::CompactVariableMapKey& key) { JSC::CompactVariableMapKey::makeDeletedValue(key); }
    340     static bool isDeletedValue(JSC::CompactVariableMapKey key) { return key.isHashTableDeletedValue(); }
     352    static bool isEmptyValue(JSC::CompactTDZEnvironmentKey key) { return key.isHashTableEmptyValue(); }
     353
     354    static void constructDeletedValue(JSC::CompactTDZEnvironmentKey& key) { JSC::CompactTDZEnvironmentKey::makeDeletedValue(key); }
     355    static bool isDeletedValue(JSC::CompactTDZEnvironmentKey key) { return key.isHashTableDeletedValue(); }
    341356};
    342357
     
    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)
     
    378393        explicit operator bool() const { return !!m_map; }
    379394
    380         const CompactVariableEnvironment& environment() const
     395        const CompactTDZEnvironment& environment() const
    381396        {
    382397            return *m_environment;
     
    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;
    401 
    402     Handle get(CompactVariableEnvironment*, bool& isNewEntry);
    403 
    404     HashMap<CompactVariableMapKey, unsigned> m_map;
     415    friend class CachedCompactTDZEnvironmentMapHandle;
     416
     417    Handle get(CompactTDZEnvironment*, bool& isNewEntry);
     418
     419    HashMap<CompactTDZEnvironmentKey, unsigned> m_map;
    405420};
    406421
  • trunk/Source/JavaScriptCore/runtime/CachedTypes.cpp

    r268993 r269115  
    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);
     
    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);
     
    10511051};
    10521052
    1053 class CachedCompactVariableEnvironment : public CachedObject<CompactVariableEnvironment> {
    1054 public:
    1055     void encode(Encoder& encoder, const CompactVariableEnvironment& env)
    1056     {
    1057         m_variables.encode(encoder, env.m_variables);
    1058         m_variableMetadata.encode(encoder, env.m_variableMetadata);
     1053class CachedCompactTDZEnvironment : public CachedObject<CompactTDZEnvironment> {
     1054public:
     1055    void encode(Encoder& encoder, const CompactTDZEnvironment& env)
     1056    {
     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;
    1061     }
    1062 
    1063     void decode(Decoder& decoder, CompactVariableEnvironment& env) const
    1064     {
    1065         m_variables.decode(decoder, env.m_variables);
    1066         m_variableMetadata.decode(decoder, env.m_variableMetadata);
     1066    }
     1067
     1068    void decode(Decoder& decoder, CompactTDZEnvironment& env) const
     1069    {
     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;
    1069     }
    1070 
    1071     CompactVariableEnvironment* decode(Decoder& decoder) const
    1072     {
    1073         CompactVariableEnvironment* env = new CompactVariableEnvironment;
     1077    }
     1078
     1079    CompactTDZEnvironment* decode(Decoder& decoder) const
     1080    {
     1081        CompactTDZEnvironment* env = new CompactTDZEnvironment;
    10741082        decode(decoder, *env);
    10751083        return env;
     
    10781086private:
    10791087    CachedVector<CachedRefPtr<CachedUniquedStringImpl, UniquedStringImpl, WTF::PackedPtrTraits<UniquedStringImpl>>> m_variables;
    1080     CachedVector<VariableEnvironmentEntry> m_variableMetadata;
    10811088    unsigned m_hash;
    1082     bool m_isEverythingCaptured;
    1083 };
    1084 
    1085 class CachedCompactVariableMapHandle : public CachedObject<CompactVariableMap::Handle> {
    1086 public:
    1087     void encode(Encoder& encoder, const CompactVariableMap::Handle& handle)
     1089};
     1090
     1091class CachedCompactTDZEnvironmentMapHandle : public CachedObject<CompactTDZEnvironmentMap::Handle> {
     1092public:
     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([=] {
     
    11081114            });
    11091115        }
    1110         decoder.setHandleForEnvironment(environment, handle);
     1116        decoder.setHandleForTDZEnvironment(environment, handle);
    11111117        return handle;
    11121118    }
    11131119
    1114 private:
    1115     CachedPtr<CachedCompactVariableEnvironment> m_environment;
     1120    void decode(Decoder& decoder, CompactTDZEnvironmentMap::Handle& handle) const
     1121    {
     1122        handle = decode(decoder);
     1123    }
     1124
     1125private:
     1126    CachedPtr<CachedCompactTDZEnvironment> m_environment;
    11161127};
    11171128
     
    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    }
     
    17591769private:
    17601770    CachedSourceCodeWithoutProvider m_classSource;
    1761     CachedCompactVariableMapHandle m_parentScopeTDZVariables;
     1771    CachedVector<CachedCompactTDZEnvironmentMapHandle> m_parentScopeTDZVariables;
    17621772};
    17631773
  • trunk/Source/JavaScriptCore/runtime/CachedTypes.h

    r247705 r269115  
    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;
     
    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};
  • trunk/Source/JavaScriptCore/runtime/CodeCache.cpp

    r262613 r269115  
    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;
     
    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())
     
    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)
    116 {
    117     return generateUnlinkedCodeBlockImpl<UnlinkedCodeBlockType, ExecutableType>(vm, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType, executable->derivedContextType(), executable->isArrowFunctionContext(), variablesUnderTDZ, executable);
    118 }
    119 
    120 UnlinkedEvalCodeBlock* generateUnlinkedCodeBlockForDirectEval(VM& vm, DirectEvalExecutable* executable, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
    121 {
    122     return generateUnlinkedCodeBlock<UnlinkedEvalCodeBlock>(vm, executable, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType, 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)
     121{
     122    return generateUnlinkedCodeBlockImpl<UnlinkedCodeBlockType, ExecutableType>(vm, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType, executable->derivedContextType(), executable->isArrowFunctionContext(), variablesUnderTDZ, parentScopePrivateNames, executable);
     123}
     124
     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)
     126{
     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;
     
    136141}
    137142
    138 UnlinkedProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForProgram(VM& vm, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
    139 {
    140     return recursivelyGenerateUnlinkedCodeBlock<UnlinkedProgramCodeBlock>(vm, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType, variablesUnderTDZ);
    141 }
    142 
    143 UnlinkedModuleProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForModuleProgram(VM& vm, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
    144 {
    145     return recursivelyGenerateUnlinkedCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType, variablesUnderTDZ);
     143UnlinkedProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForProgram(VM& vm, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType)
     144{
     145    return recursivelyGenerateUnlinkedCodeBlock<UnlinkedProgramCodeBlock>(vm, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType);
     146}
     147
     148UnlinkedModuleProgramCodeBlock* recursivelyGenerateUnlinkedCodeBlockForModuleProgram(VM& vm, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType)
     149{
     150    return recursivelyGenerateUnlinkedCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, source, strictMode, scriptMode, codeGenerationMode, error, evalContextType);
    146151}
    147152
     
    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()) {
  • trunk/Source/JavaScriptCore/runtime/CodeCache.h

    r255321 r269115  
    5151class SourceCode;
    5252class VM;
    53 class VariableEnvironment;
     53
     54using TDZEnvironment = HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash>;
    5455
    5556namespace CodeCacheInternal {
     
    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&);
  • trunk/Source/JavaScriptCore/runtime/Completion.cpp

    r261755 r269115  
    9292    RELEASE_ASSERT(vm.atomStringTable() == Thread::current().atomStringTable());
    9393
    94     VariableEnvironment variablesUnderTDZ;
    9594    JSParserStrictMode strictMode = JSParserStrictMode::NotStrict;
    9695    JSParserScriptMode scriptMode = JSParserScriptMode::Classic;
     
    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;
     
    112111    RELEASE_ASSERT(vm.atomStringTable() == Thread::current().atomStringTable());
    113112
    114     VariableEnvironment variablesUnderTDZ;
    115113    JSParserStrictMode strictMode = JSParserStrictMode::Strict;
    116114    JSParserScriptMode scriptMode = JSParserScriptMode::Module;
     
    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;
  • trunk/Source/JavaScriptCore/runtime/DirectEvalExecutable.cpp

    r261755 r269115  
    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();
     
    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())
  • trunk/Source/JavaScriptCore/runtime/DirectEvalExecutable.h

    r259676 r269115  
    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);
  • trunk/Source/JavaScriptCore/runtime/JSScope.cpp

    r264736 r269115  
    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()) {
     
    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    }
  • trunk/Source/JavaScriptCore/runtime/JSScope.h

    r261464 r269115  
    3636class WatchpointSet;
    3737
     38using TDZEnvironment = HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash>;
     39
    3840class JSScope : public JSNonFinalObject {
    3941public:
     
    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&);
  • trunk/Source/JavaScriptCore/runtime/VM.cpp

    r268956 r269115  
    393393    , entryScope(nullptr)
    394394    , m_regExpCache(new RegExpCache(this))
    395     , m_compactVariableMap(adoptRef(*(new CompactVariableMap)))
     395    , m_compactVariableMap(adoptRef(*(new CompactTDZEnvironmentMap)))
    396396#if ENABLE(REGEXP_TRACING)
    397397    , m_rtTraceList(new RTTraceList())
  • trunk/Source/JavaScriptCore/runtime/VM.h

    r268956 r269115  
    109109class CodeCache;
    110110class CommonIdentifiers;
    111 class CompactVariableMap;
     111class CompactTDZEnvironmentMap;
    112112class ConservativeRoots;
    113113class ControlFlowProfiler;
     
    10081008#endif
    10091009
    1010     Ref<CompactVariableMap> m_compactVariableMap;
     1010    Ref<CompactTDZEnvironmentMap> m_compactVariableMap;
    10111011
    10121012    std::unique_ptr<HasOwnPropertyCache> m_hasOwnPropertyCache;
  • trunk/Source/WTF/ChangeLog

    r269111 r269115  
     12020-10-28  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 Tadeu Zagallo.
     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-28  Sam Weinig  <weinig@apple.com>
    215
  • trunk/Source/WTF/wtf/RefPtr.h

    r268993 r269115  
    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, RawPtrTraits<T>>::value || !std::is_same<Y, RawPtrTraits<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)
Note: See TracChangeset for help on using the changeset viewer.