[JSC] We should consider moving UnlinkedFunctionExecutable::m_parentScopeTDZVariables...
authorticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 4 Apr 2019 17:21:15 +0000 (17:21 +0000)
committerticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 4 Apr 2019 17:21:15 +0000 (17:21 +0000)
https://bugs.webkit.org/show_bug.cgi?id=194944

Reviewed by Keith Miller.

JSTests:

* stress/verify-bytecode-generator-cached-variables-under-tdz.js: Added.

Source/JavaScriptCore:

Based on profile data collected on JetStream2, Speedometer 2 and
other benchmarks, it is very rare having non-empty
UnlinkedFunctionExecutable::m_parentScopeTDZVariables.

- Data collected from Speedometer2
    Total number of UnlinkedFunctionExecutable: 39463
    Total number of non-empty parentScopeTDZVars: 428 (~1%)

- Data collected from JetStream2
    Total number of UnlinkedFunctionExecutable: 83715
    Total number of non-empty parentScopeTDZVars: 5285 (~6%)

We also collected numbers on 6 of top 10 Alexia sites.

- Data collected from youtube.com
    Total number of UnlinkedFunctionExecutable: 29599
    Total number of non-empty parentScopeTDZVars: 97 (~0.3%)

- Data collected from twitter.com
    Total number of UnlinkedFunctionExecutable: 23774
    Total number of non-empty parentScopeTDZVars: 172 (~0.7%)

- Data collected from google.com
    Total number of UnlinkedFunctionExecutable: 33209
    Total number of non-empty parentScopeTDZVars: 174 (~0.5%)

- Data collected from amazon.com:
    Total number of UnlinkedFunctionExecutable: 15182
    Total number of non-empty parentScopeTDZVars: 166 (~1%)

- Data collected from facebook.com:
    Total number of UnlinkedFunctionExecutable: 54443
    Total number of non-empty parentScopeTDZVars: 269 (~0.4%)

- Data collected from netflix.com:
    Total number of UnlinkedFunctionExecutable: 39266
    Total number of non-empty parentScopeTDZVars: 97 (~0.2%)

Considering such numbers, this patch is moving `m_parentScopeTDZVariables`
to RareData. This decreases sizeof(UnlinkedFunctionExecutable) by
16 bytes. With this change, now UnlinkedFunctionExecutable constructors
receives an `Optional<VariableEnvironmentMap::Handle>` and only stores
it when `value != WTF::nullopt`. We also changed
UnlinkedFunctionExecutable::parentScopeTDZVariables() and it returns
`VariableEnvironment()` whenever the Executable doesn't have RareData,
or VariableEnvironmentMap::Handle is unitialized. This is required
because RareData is instantiated when any of its field is stored and
we can have an unitialized `Handle` even on cases when parentScopeTDZVariables
is `WTF::nullopt`.

Results on memory usage on JetStrem2 is neutral.

    Mean of memory peak on ToT: 4258633728 bytes (confidence interval: 249720072.95)
    Mean of memory peak on Changes: 4367325184 bytes (confidence interval: 321285583.61)

* builtins/BuiltinExecutables.cpp:
(JSC::BuiltinExecutables::createExecutable):
* bytecode/UnlinkedFunctionExecutable.cpp:
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
* bytecode/UnlinkedFunctionExecutable.h:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::getVariablesUnderTDZ):

BytecodeGenerator::getVariablesUnderTDZ now also caches if m_cachedVariablesUnderTDZ
is empty, so we can properly return `WTF::nullopt` without the
reconstruction of a VariableEnvironment to check if it is empty.

* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::makeFunction):
* parser/VariableEnvironment.h:
(JSC::VariableEnvironment::isEmpty const):
* runtime/CachedTypes.cpp:
(JSC::CachedCompactVariableMapHandle::decode const):

It returns an unitialized Handle when there is no
CompactVariableEnvironment. This can happen when RareData is ensured
because of another field.

(JSC::CachedFunctionExecutableRareData::encode):
(JSC::CachedFunctionExecutableRareData::decode const):
(JSC::CachedFunctionExecutable::encode):
(JSC::CachedFunctionExecutable::decode const):
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
* runtime/CodeCache.cpp:

Instead of creating a dummyVariablesUnderTDZ, we simply pass
WTF::nullopt.

(JSC::CodeCache::getUnlinkedGlobalFunctionExecutable):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@243875 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JSTests/ChangeLog
JSTests/stress/verify-bytecode-generator-cached-variables-under-tdz.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/builtins/BuiltinExecutables.cpp
Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp
Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/parser/VariableEnvironment.h
Source/JavaScriptCore/runtime/CachedTypes.cpp
Source/JavaScriptCore/runtime/CodeCache.cpp

index f8f912a..b240f6f 100644 (file)
@@ -1,3 +1,12 @@
+2019-04-04  Caio Lima  <ticaiolima@gmail.com>
+
+        [JSC] We should consider moving UnlinkedFunctionExecutable::m_parentScopeTDZVariables to RareData
+        https://bugs.webkit.org/show_bug.cgi?id=194944
+
+        Reviewed by Keith Miller.
+
+        * stress/verify-bytecode-generator-cached-variables-under-tdz.js: Added.
+
 2019-04-04  Tadeu Zagallo  <tzagallo@apple.com>
 
         Cache bytecode for jsc.cpp helpers and fix CachedStringImpl
diff --git a/JSTests/stress/verify-bytecode-generator-cached-variables-under-tdz.js b/JSTests/stress/verify-bytecode-generator-cached-variables-under-tdz.js
new file mode 100644 (file)
index 0000000..4387c09
--- /dev/null
@@ -0,0 +1,36 @@
+function assert(a, e) {
+    if (a !== e)
+        throw new Error("Expected: " + e + " Actual: " + a);
+}
+
+function a(i) {
+    "use strict";
+
+    var foo;
+    if (i) {
+        var b = 3;
+        foo = function () {
+            return b;
+        }
+    } else {
+        // Test if cachedVariablesUnderTDZIsEmpty is consistent with
+        // cachedVariablesUnderTDZ
+        foo = function () {
+            return b;
+        }
+
+        function bar() {
+            return b;
+        }
+
+        let b = 4;
+        assert(bar(), 4);
+    }
+
+    return foo();
+}
+
+var b = 10;
+assert(a(true), 3);
+assert(a(false), 4);
+
index e733b05..33fc8d6 100644 (file)
@@ -1,3 +1,100 @@
+2019-04-04  Caio Lima  <ticaiolima@gmail.com>
+
+        [JSC] We should consider moving UnlinkedFunctionExecutable::m_parentScopeTDZVariables to RareData
+        https://bugs.webkit.org/show_bug.cgi?id=194944
+
+        Reviewed by Keith Miller.
+
+        Based on profile data collected on JetStream2, Speedometer 2 and
+        other benchmarks, it is very rare having non-empty
+        UnlinkedFunctionExecutable::m_parentScopeTDZVariables.
+
+        - Data collected from Speedometer2
+            Total number of UnlinkedFunctionExecutable: 39463
+            Total number of non-empty parentScopeTDZVars: 428 (~1%)
+
+        - Data collected from JetStream2
+            Total number of UnlinkedFunctionExecutable: 83715
+            Total number of non-empty parentScopeTDZVars: 5285 (~6%)
+
+        We also collected numbers on 6 of top 10 Alexia sites.
+
+        - Data collected from youtube.com
+            Total number of UnlinkedFunctionExecutable: 29599
+            Total number of non-empty parentScopeTDZVars: 97 (~0.3%)
+
+        - Data collected from twitter.com
+            Total number of UnlinkedFunctionExecutable: 23774
+            Total number of non-empty parentScopeTDZVars: 172 (~0.7%)
+
+        - Data collected from google.com
+            Total number of UnlinkedFunctionExecutable: 33209
+            Total number of non-empty parentScopeTDZVars: 174 (~0.5%)
+
+        - Data collected from amazon.com:
+            Total number of UnlinkedFunctionExecutable: 15182
+            Total number of non-empty parentScopeTDZVars: 166 (~1%)
+
+        - Data collected from facebook.com:
+            Total number of UnlinkedFunctionExecutable: 54443
+            Total number of non-empty parentScopeTDZVars: 269 (~0.4%)
+
+        - Data collected from netflix.com:
+            Total number of UnlinkedFunctionExecutable: 39266
+            Total number of non-empty parentScopeTDZVars: 97 (~0.2%)
+
+        Considering such numbers, this patch is moving `m_parentScopeTDZVariables`
+        to RareData. This decreases sizeof(UnlinkedFunctionExecutable) by
+        16 bytes. With this change, now UnlinkedFunctionExecutable constructors
+        receives an `Optional<VariableEnvironmentMap::Handle>` and only stores
+        it when `value != WTF::nullopt`. We also changed
+        UnlinkedFunctionExecutable::parentScopeTDZVariables() and it returns
+        `VariableEnvironment()` whenever the Executable doesn't have RareData,
+        or VariableEnvironmentMap::Handle is unitialized. This is required
+        because RareData is instantiated when any of its field is stored and
+        we can have an unitialized `Handle` even on cases when parentScopeTDZVariables
+        is `WTF::nullopt`.
+
+        Results on memory usage on JetStrem2 is neutral.
+
+            Mean of memory peak on ToT: 4258633728 bytes (confidence interval: 249720072.95)
+            Mean of memory peak on Changes: 4367325184 bytes (confidence interval: 321285583.61)
+
+        * builtins/BuiltinExecutables.cpp:
+        (JSC::BuiltinExecutables::createExecutable):
+        * bytecode/UnlinkedFunctionExecutable.cpp:
+        (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
+        * bytecode/UnlinkedFunctionExecutable.h:
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::getVariablesUnderTDZ):
+
+        BytecodeGenerator::getVariablesUnderTDZ now also caches if m_cachedVariablesUnderTDZ
+        is empty, so we can properly return `WTF::nullopt` without the
+        reconstruction of a VariableEnvironment to check if it is empty.
+
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::makeFunction):
+        * parser/VariableEnvironment.h:
+        (JSC::VariableEnvironment::isEmpty const):
+        * runtime/CachedTypes.cpp:
+        (JSC::CachedCompactVariableMapHandle::decode const):
+
+        It returns an unitialized Handle when there is no
+        CompactVariableEnvironment. This can happen when RareData is ensured
+        because of another field.
+
+        (JSC::CachedFunctionExecutableRareData::encode):
+        (JSC::CachedFunctionExecutableRareData::decode const):
+        (JSC::CachedFunctionExecutable::encode):
+        (JSC::CachedFunctionExecutable::decode const):
+        (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
+        * runtime/CodeCache.cpp:
+
+        Instead of creating a dummyVariablesUnderTDZ, we simply pass
+        WTF::nullopt.
+
+        (JSC::CodeCache::getUnlinkedGlobalFunctionExecutable):
+
 2019-04-04  Tadeu Zagallo  <tzagallo@apple.com>
 
         Cache bytecode for jsc.cpp helpers and fix CachedStringImpl
index 4830a56..fef4122 100644 (file)
@@ -254,8 +254,7 @@ UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const S
         }
     }
 
-    VariableEnvironment dummyTDZVariables;
-    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, &metadata, kind, constructAbility, JSParserScriptMode::Classic, vm.m_compactVariableMap->get(dummyTDZVariables), DerivedContextType::None, isBuiltinDefaultClassConstructor);
+    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, &metadata, kind, constructAbility, JSParserScriptMode::Classic, WTF::nullopt, DerivedContextType::None, isBuiltinDefaultClassConstructor);
     return functionExecutable;
 }
 
index 58ae6c5..7997e66 100644 (file)
@@ -40,6 +40,7 @@
 #include "SourceProvider.h"
 #include "Structure.h"
 #include "UnlinkedFunctionCodeBlock.h"
+#include <wtf/Optional.h>
 
 namespace JSC {
 
@@ -79,7 +80,7 @@ static UnlinkedFunctionCodeBlock* generateUnlinkedFunctionCodeBlock(
     return result;
 }
 
-UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& parentSource, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, CompactVariableMap::Handle parentScopeTDZVariables, DerivedContextType derivedContextType, bool isBuiltinDefaultClassConstructor)
+UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& parentSource, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, Optional<CompactVariableMap::Handle> parentScopeTDZVariables, DerivedContextType derivedContextType, bool isBuiltinDefaultClassConstructor)
     : Base(*vm, structure)
     , m_firstLineOffset(node->firstLine() - parentSource.firstLine().oneBasedInt())
     , m_lineCount(node->lastLine() - node->firstLine())
@@ -110,7 +111,6 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct
     , m_name(node->ident())
     , m_ecmaName(node->ecmaName())
     , m_inferredName(node->inferredName())
-    , m_parentScopeTDZVariables(WTFMove(parentScopeTDZVariables))
 {
     // Make sure these bitfields are adequately wide.
     ASSERT(m_constructAbility == static_cast<unsigned>(constructAbility));
@@ -122,6 +122,8 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct
     ASSERT(!(m_isBuiltinDefaultClassConstructor && constructorKind() == ConstructorKind::None));
     if (!node->classSource().isNull())
         setClassSource(node->classSource());
+    if (parentScopeTDZVariables)
+        ensureRareData().m_parentScopeTDZVariables = WTFMove(*parentScopeTDZVariables);
 }
 
 UnlinkedFunctionExecutable::~UnlinkedFunctionExecutable()
index 39a73f2..3d3956c 100644 (file)
@@ -36,6 +36,7 @@
 #include "RegExp.h"
 #include "SourceCode.h"
 #include "VariableEnvironment.h"
+#include <wtf/Optional.h>
 
 namespace JSC {
 
@@ -67,10 +68,10 @@ public:
         return &vm.unlinkedFunctionExecutableSpace.space;
     }
 
-    static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, CompactVariableMap::Handle parentScopeTDZVariables, DerivedContextType derivedContextType, bool isBuiltinDefaultClassConstructor = false)
+    static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, Optional<CompactVariableMap::Handle> parentScopeTDZVariables, DerivedContextType derivedContextType, bool isBuiltinDefaultClassConstructor = false)
     {
         UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(vm->heap))
-            UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, node, unlinkedFunctionKind, constructAbility, scriptMode, parentScopeTDZVariables, derivedContextType, isBuiltinDefaultClassConstructor);
+            UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, node, unlinkedFunctionKind, constructAbility, scriptMode, WTFMove(parentScopeTDZVariables), derivedContextType, isBuiltinDefaultClassConstructor);
         instance->finishCreation(*vm);
         return instance;
     }
@@ -156,7 +157,13 @@ public:
             return false;
         return !m_rareData->m_classSource.isNull();
     }
-    VariableEnvironment parentScopeTDZVariables() const { return m_parentScopeTDZVariables.environment().toVariableEnvironment(); }
+
+    VariableEnvironment parentScopeTDZVariables() const
+    {
+        if (!m_rareData || !m_rareData->m_parentScopeTDZVariables)
+            return VariableEnvironment();
+        return m_rareData->m_parentScopeTDZVariables.environment().toVariableEnvironment();
+    }
     
     bool isArrowFunction() const { return isArrowFunctionParseMode(parseMode()); }
 
@@ -189,11 +196,12 @@ public:
         SourceCode m_classSource;
         String m_sourceURLDirective;
         String m_sourceMappingURLDirective;
+        CompactVariableMap::Handle m_parentScopeTDZVariables;
     };
 
 private:
-    UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, JSParserScriptMode, CompactVariableMap::Handle,  JSC::DerivedContextType, bool isBuiltinDefaultClassConstructor);
-    UnlinkedFunctionExecutable(Decoder&, CompactVariableMap::Handle, const CachedFunctionExecutable&);
+    UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, JSParserScriptMode, Optional<CompactVariableMap::Handle>,  JSC::DerivedContextType, bool isBuiltinDefaultClassConstructor);
+    UnlinkedFunctionExecutable(Decoder&, const CachedFunctionExecutable&);
 
     void decodeCachedCodeBlocks();
 
@@ -247,7 +255,6 @@ private:
     }
     RareData& ensureRareDataSlow();
 
-    CompactVariableMap::Handle m_parentScopeTDZVariables;
     std::unique_ptr<RareData> m_rareData;
 
 protected:
index 5bf75f7..dc7ec64 100644 (file)
@@ -64,6 +64,7 @@
 #include "UnlinkedProgramCodeBlock.h"
 #include <wtf/BitVector.h>
 #include <wtf/CommaPrinter.h>
+#include <wtf/Optional.h>
 #include <wtf/SmallPtrSet.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/text/WTFString.h>
@@ -2869,10 +2870,15 @@ void BytecodeGenerator::pushTDZVariables(const VariableEnvironment& environment,
     m_cachedVariablesUnderTDZ = { };
 }
 
-CompactVariableMap::Handle BytecodeGenerator::getVariablesUnderTDZ()
+Optional<CompactVariableMap::Handle> BytecodeGenerator::getVariablesUnderTDZ()
 {
-    if (m_cachedVariablesUnderTDZ)
+    if (m_cachedVariablesUnderTDZ) {
+        if (!m_hasCachedVariablesUnderTDZ) {
+            ASSERT(m_cachedVariablesUnderTDZ.environment().toVariableEnvironment().isEmpty());
+            return WTF::nullopt;
+        }
         return m_cachedVariablesUnderTDZ;
+    }
 
     // We keep track of variablesThatDontNeedTDZ in this algorithm to prevent
     // reporting that "x" is under TDZ if this function is called at "...".
@@ -2898,6 +2904,10 @@ CompactVariableMap::Handle BytecodeGenerator::getVariablesUnderTDZ()
     }
 
     m_cachedVariablesUnderTDZ = m_vm->m_compactVariableMap->get(environment);
+    m_hasCachedVariablesUnderTDZ = !environment.isEmpty();
+    if (!m_hasCachedVariablesUnderTDZ)
+        return WTF::nullopt;
+
     return m_cachedVariablesUnderTDZ;
 }
 
index 3885b2f..71e7254 100644 (file)
@@ -49,6 +49,7 @@
 #include <functional>
 #include <wtf/CheckedArithmetic.h>
 #include <wtf/HashFunctions.h>
+#include <wtf/Optional.h>
 #include <wtf/SegmentedVector.h>
 #include <wtf/SetForScope.h>
 #include <wtf/Vector.h>
@@ -1104,7 +1105,7 @@ namespace JSC {
                     newDerivedContextType = DerivedContextType::DerivedMethodContext;
             }
 
-            CompactVariableMap::Handle variablesUnderTDZ = getVariablesUnderTDZ();
+            Optional<CompactVariableMap::Handle> optionalVariablesUnderTDZ = getVariablesUnderTDZ();
 
             // FIXME: These flags, ParserModes and propagation to XXXCodeBlocks should be reorganized.
             // https://bugs.webkit.org/show_bug.cgi?id=151547
@@ -1113,10 +1114,10 @@ namespace JSC {
             if (parseMode == SourceParseMode::MethodMode && metadata->constructorKind() != ConstructorKind::None)
                 constructAbility = ConstructAbility::CanConstruct;
 
-            return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, scriptMode(), WTFMove(variablesUnderTDZ), newDerivedContextType);
+            return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, scriptMode(), WTFMove(optionalVariablesUnderTDZ), newDerivedContextType);
         }
 
-        CompactVariableMap::Handle getVariablesUnderTDZ();
+        Optional<CompactVariableMap::Handle> getVariablesUnderTDZ();
 
         RegisterID* emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, DebuggableCall);
         template<typename CallOp>
@@ -1274,6 +1275,7 @@ namespace JSC {
         bool m_usesNonStrictEval { false };
         bool m_inTailPosition { false };
         bool m_needsToUpdateArrowFunctionContext;
+        bool m_hasCachedVariablesUnderTDZ { false };
         DerivedContextType m_derivedContextType { DerivedContextType::None };
 
         CompactVariableMap::Handle m_cachedVariablesUnderTDZ;
index efaa5a7..96372c5 100644 (file)
@@ -114,6 +114,7 @@ public:
     void markVariableAsExported(const RefPtr<UniquedStringImpl>& identifier);
 
     bool isEverythingCaptured() const { return m_isEverythingCaptured; }
+    bool isEmpty() const { return !m_map.size(); }
 
 private:
     friend class CachedVariableEnvironment;
index 3fc6702..f811760 100644 (file)
@@ -937,6 +937,11 @@ public:
     {
         bool isNewAllocation;
         CompactVariableEnvironment* environment = m_environment.decode(decoder, isNewAllocation);
+        if (!environment) {
+            ASSERT(!isNewAllocation);
+            return CompactVariableMap::Handle();
+        }
+
         if (!isNewAllocation)
             return decoder.handleForEnvironment(environment);
         bool isNewEntry;
@@ -1512,17 +1517,21 @@ public:
     void encode(Encoder& encoder, const UnlinkedFunctionExecutable::RareData& rareData)
     {
         m_classSource.encode(encoder, rareData.m_classSource);
+        m_parentScopeTDZVariables.encode(encoder, rareData.m_parentScopeTDZVariables);
     }
 
     UnlinkedFunctionExecutable::RareData* decode(Decoder& decoder) const
     {
         UnlinkedFunctionExecutable::RareData* rareData = new UnlinkedFunctionExecutable::RareData { };
         m_classSource.decode(decoder, rareData->m_classSource);
+        auto parentScopeTDZVariables = m_parentScopeTDZVariables.decode(decoder);
+        rareData->m_parentScopeTDZVariables = WTFMove(parentScopeTDZVariables);
         return rareData;
     }
 
 private:
     CachedSourceCode m_classSource;
+    CachedCompactVariableMapHandle m_parentScopeTDZVariables;
 };
 
 class CachedFunctionExecutable : public CachedObject<UnlinkedFunctionExecutable> {
@@ -1596,8 +1605,6 @@ private:
     CachedIdentifier m_ecmaName;
     CachedIdentifier m_inferredName;
 
-    CachedCompactVariableMapHandle m_parentScopeTDZVariables;
-
     CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForCall;
     CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForConstruct;
 };
@@ -1949,22 +1956,19 @@ ALWAYS_INLINE void CachedFunctionExecutable::encode(Encoder& encoder, const Unli
     m_ecmaName.encode(encoder, executable.ecmaName());
     m_inferredName.encode(encoder, executable.inferredName());
 
-    m_parentScopeTDZVariables.encode(encoder, executable.m_parentScopeTDZVariables);
-
     m_unlinkedCodeBlockForCall.encode(encoder, executable.m_unlinkedCodeBlockForCall);
     m_unlinkedCodeBlockForConstruct.encode(encoder, executable.m_unlinkedCodeBlockForConstruct);
 }
 
 ALWAYS_INLINE UnlinkedFunctionExecutable* CachedFunctionExecutable::decode(Decoder& decoder) const
 {
-    CompactVariableMap::Handle env = m_parentScopeTDZVariables.decode(decoder);
-    UnlinkedFunctionExecutable* executable = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(decoder.vm().heap)) UnlinkedFunctionExecutable(decoder, WTFMove(env), *this);
+    UnlinkedFunctionExecutable* executable = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(decoder.vm().heap)) UnlinkedFunctionExecutable(decoder, *this);
     executable->finishCreation(decoder.vm());
 
     return executable;
 }
 
-ALWAYS_INLINE UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(Decoder& decoder, CompactVariableMap::Handle parentScopeTDZVariables, const CachedFunctionExecutable& cachedExecutable)
+ALWAYS_INLINE UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(Decoder& decoder, const CachedFunctionExecutable& cachedExecutable)
     : Base(decoder.vm(), decoder.vm().unlinkedFunctionExecutableStructure.get())
     , m_firstLineOffset(cachedExecutable.firstLineOffset())
     , m_lineCount(cachedExecutable.lineCount())
@@ -1997,8 +2001,6 @@ ALWAYS_INLINE UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(Decoder& de
     , m_ecmaName(cachedExecutable.ecmaName(decoder))
     , m_inferredName(cachedExecutable.inferredName(decoder))
 
-    , m_parentScopeTDZVariables(WTFMove(parentScopeTDZVariables))
-
     , m_rareData(cachedExecutable.rareData(decoder))
 {
 
index d6ea8e3..3e424df 100644 (file)
@@ -149,9 +149,8 @@ UnlinkedFunctionExecutable* CodeCache::getUnlinkedGlobalFunctionExecutable(VM& v
     metadata->setEndPosition(positionBeforeLastNewline);
     // The Function constructor only has access to global variables, so no variables will be under TDZ unless they're
     // in the global lexical environment, which we always TDZ check accesses from.
-    VariableEnvironment emptyTDZVariables;
     ConstructAbility constructAbility = constructAbilityForParseMode(metadata->parseMode());
-    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, constructAbility, JSParserScriptMode::Classic, vm.m_compactVariableMap->get(emptyTDZVariables), DerivedContextType::None);
+    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, constructAbility, JSParserScriptMode::Classic, WTF::nullopt, DerivedContextType::None);
 
     if (!source.provider()->sourceURLDirective().isNull())
         functionExecutable->setSourceURLDirective(source.provider()->sourceURLDirective());