Title: [292191] trunk/Source/_javascript_Core
Revision
292191
Author
ysuz...@apple.com
Date
2022-03-31 17:33:33 -0700 (Thu, 31 Mar 2022)

Log Message

[JSC] Remove ExecutableToCodeBlockEdge
https://bugs.webkit.org/show_bug.cgi?id=238485

Reviewed by Keith Miller.

It turned out that getting CodeBlock from JSFunction is critical. As we start using unlinked Baseline, we are loading
CodeBlock from JSFunction instead of embedding it, and it roughly contributes to 0.5% regression in Speedometer2.
It is also crucial to some other places: bound function thunk, remote function thunk, and virtual function calls.
While the subsequent patch will embed CodeBlock into CallLinkInfo to make it fast, we also would like to keep loading
CodeBlock from JSFunction faster since this is still used in bound function thunk etc.

In this patch, we remove ExecutableToCodeBlockEdge to remove one-level indirection between Executable to CodeBlock.
We can delegate ExecutableToCodeBlockEdge's job to existing Executables so that we can keep the current weak-edge
feature without introducing ExecutableToCodeBlockEdge. It also removes ExecutableToCodeBlockEdge allocations and
shrinks sizeof(CodeBlock) by 8 byte.

We move key functions from ExecutableToCodeBlockEdge to ScriptExecutable, and we maintain Executable-to-CodeBlock edge
in Executable side.

Local testing showed that 0.3% progression in Speedometer2.

* CMakeLists.txt:
* _javascript_Core.xcodeproj/project.pbxproj:
* Sources.txt:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::finishCreation):
(JSC::CodeBlock::visitChildrenImpl):
(JSC::CodeBlock::visitChildren):
(JSC::CodeBlock::finalizeUnconditionally):
(JSC::CodeBlock::stronglyVisitStrongReferences):
(JSC::CodeBlock::finishCreationCommon): Deleted.
* bytecode/CodeBlock.h:
(JSC::CodeBlock::ownerEdge const): Deleted.
* bytecode/ExecutableToCodeBlockEdge.cpp: Removed.
* bytecode/ExecutableToCodeBlockEdge.h: Removed.
* heap/Heap.cpp:
(JSC::Heap::Heap):
(JSC::Heap::finalizeUnconditionalFinalizers):
(JSC::Heap::deleteAllCodeBlocks):
(JSC::Heap::addCoreConstraints):
* heap/Heap.h:
(JSC::Heap::ScriptExecutableSpaceAndSet::ScriptExecutableSpaceAndSet):
(JSC::Heap::ScriptExecutableSpaceAndSet::setAndSpaceFor):
(JSC::Heap::ScriptExecutableSpaceAndSet::clearableCodeSetFor):
(JSC::Heap::ScriptExecutableSpaceAndSet::outputConstraintsSetFor):
(JSC::Heap::ScriptExecutableSpaceAndSet::finalizerSetFor):
* heap/IsoCellSet.h:
* jit/JIT.cpp:
(JSC::JIT::emitPutCodeBlockToFrameInPrologue):
* llint/LowLevelInterpreter.asm:
* runtime/DirectEvalExecutable.cpp:
(JSC::DirectEvalExecutable::create):
* runtime/EvalExecutable.cpp:
(JSC::EvalExecutable::visitChildrenImpl):
* runtime/EvalExecutable.h:
(JSC::EvalExecutable::codeBlock const):
(JSC::EvalExecutable::unlinkedCodeBlock const):
(JSC::EvalExecutable::numVariables):
(JSC::EvalExecutable::numFunctionHoistingCandidates):
(JSC::EvalExecutable::numTopLevelFunctionDecls):
(JSC::EvalExecutable::allowDirectEvalCache const):
(JSC::EvalExecutable::codeBlock): Deleted.
* runtime/FunctionExecutable.cpp:
(JSC::FunctionExecutable::baselineCodeBlockFor):
(JSC::shouldKeepInConstraintSet):
(JSC::FunctionExecutable::visitChildrenImpl):
(JSC::FunctionExecutable::visitOutputConstraintsImpl):
* runtime/FunctionExecutable.h:
* runtime/FunctionExecutableInlines.h:
(JSC::FunctionExecutable::finalizeUnconditionally):
(JSC::FunctionExecutable::replaceCodeBlockWith):
(JSC::FunctionExecutable::toString):
* runtime/GlobalExecutable.cpp:
(JSC::GlobalExecutable::visitChildrenImpl):
(JSC::GlobalExecutable::visitOutputConstraintsImpl):
(JSC::GlobalExecutable::replaceCodeBlockWith):
(JSC::GlobalExecutable::finalizeUnconditionally):
* runtime/GlobalExecutable.h:
(JSC::GlobalExecutable::codeBlock const):
(JSC::GlobalExecutable::unlinkedCodeBlock const):
* runtime/IndirectEvalExecutable.cpp:
(JSC::IndirectEvalExecutable::createImpl):
* runtime/JSFunction.cpp:
* runtime/JSModuleRecord.cpp:
(JSC::JSModuleRecord::link):
(JSC::JSModuleRecord::instantiateDeclarations):
* runtime/ModuleProgramExecutable.cpp:
(JSC::ModuleProgramExecutable::create):
(JSC::ModuleProgramExecutable::visitChildrenImpl):
* runtime/ModuleProgramExecutable.h:
* runtime/ProgramExecutable.cpp:
(JSC::ProgramExecutable::initializeGlobalProperties):
(JSC::ProgramExecutable::visitChildrenImpl):
* runtime/ProgramExecutable.h:
* runtime/ScriptExecutable.cpp:
(JSC::ScriptExecutable::clearCode):
(JSC::ScriptExecutable::installCode):
(JSC::ScriptExecutable::hasClearableCode const):
(JSC::ScriptExecutable::newCodeBlockFor):
(JSC::ScriptExecutable::runConstraint):
(JSC::ScriptExecutable::visitCodeBlockEdge):
* runtime/ScriptExecutable.h:
* runtime/ScriptExecutableInlines.h: Copied from Source/_javascript_Core/runtime/FunctionExecutableInlines.h.
(JSC::ScriptExecutable::finalizeCodeBlockEdge):
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:
(JSC::VM::executableToCodeBlockEdgesWithConstraints): Deleted.
(JSC::VM::executableToCodeBlockEdgesWithFinalizers): Deleted.

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (292190 => 292191)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2022-04-01 00:33:33 UTC (rev 292191)
@@ -627,7 +627,6 @@
     bytecode/DataFormat.h
     bytecode/DirectEvalCodeCache.h
     bytecode/ExecutableInfo.h
-    bytecode/ExecutableToCodeBlockEdge.h
     bytecode/ExecutionCounter.h
     bytecode/ExitKind.h
     bytecode/ExitingInlineKind.h
@@ -1153,6 +1152,7 @@
     runtime/ScopedArgumentsTable.h
     runtime/Scribble.h
     runtime/ScriptExecutable.h
+    runtime/ScriptExecutableInlines.h
     runtime/ScriptFetchParameters.h
     runtime/ScriptFetcher.h
     runtime/ShadowRealmObject.h

Modified: trunk/Source/_javascript_Core/ChangeLog (292190 => 292191)


--- trunk/Source/_javascript_Core/ChangeLog	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/ChangeLog	2022-04-01 00:33:33 UTC (rev 292191)
@@ -1,3 +1,115 @@
+2022-03-31  Yusuke Suzuki  <ysuz...@apple.com>
+
+        [JSC] Remove ExecutableToCodeBlockEdge
+        https://bugs.webkit.org/show_bug.cgi?id=238485
+
+        Reviewed by Keith Miller.
+
+        It turned out that getting CodeBlock from JSFunction is critical. As we start using unlinked Baseline, we are loading
+        CodeBlock from JSFunction instead of embedding it, and it roughly contributes to 0.5% regression in Speedometer2.
+        It is also crucial to some other places: bound function thunk, remote function thunk, and virtual function calls.
+        While the subsequent patch will embed CodeBlock into CallLinkInfo to make it fast, we also would like to keep loading
+        CodeBlock from JSFunction faster since this is still used in bound function thunk etc.
+
+        In this patch, we remove ExecutableToCodeBlockEdge to remove one-level indirection between Executable to CodeBlock.
+        We can delegate ExecutableToCodeBlockEdge's job to existing Executables so that we can keep the current weak-edge
+        feature without introducing ExecutableToCodeBlockEdge. It also removes ExecutableToCodeBlockEdge allocations and
+        shrinks sizeof(CodeBlock) by 8 byte.
+
+        We move key functions from ExecutableToCodeBlockEdge to ScriptExecutable, and we maintain Executable-to-CodeBlock edge
+        in Executable side.
+
+        Local testing showed that 0.3% progression in Speedometer2.
+
+        * CMakeLists.txt:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * Sources.txt:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::finishCreation):
+        (JSC::CodeBlock::visitChildrenImpl):
+        (JSC::CodeBlock::visitChildren):
+        (JSC::CodeBlock::finalizeUnconditionally):
+        (JSC::CodeBlock::stronglyVisitStrongReferences):
+        (JSC::CodeBlock::finishCreationCommon): Deleted.
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::ownerEdge const): Deleted.
+        * bytecode/ExecutableToCodeBlockEdge.cpp: Removed.
+        * bytecode/ExecutableToCodeBlockEdge.h: Removed.
+        * heap/Heap.cpp:
+        (JSC::Heap::Heap):
+        (JSC::Heap::finalizeUnconditionalFinalizers):
+        (JSC::Heap::deleteAllCodeBlocks):
+        (JSC::Heap::addCoreConstraints):
+        * heap/Heap.h:
+        (JSC::Heap::ScriptExecutableSpaceAndSet::ScriptExecutableSpaceAndSet):
+        (JSC::Heap::ScriptExecutableSpaceAndSet::setAndSpaceFor):
+        (JSC::Heap::ScriptExecutableSpaceAndSet::clearableCodeSetFor):
+        (JSC::Heap::ScriptExecutableSpaceAndSet::outputConstraintsSetFor):
+        (JSC::Heap::ScriptExecutableSpaceAndSet::finalizerSetFor):
+        * heap/IsoCellSet.h:
+        * jit/JIT.cpp:
+        (JSC::JIT::emitPutCodeBlockToFrameInPrologue):
+        * llint/LowLevelInterpreter.asm:
+        * runtime/DirectEvalExecutable.cpp:
+        (JSC::DirectEvalExecutable::create):
+        * runtime/EvalExecutable.cpp:
+        (JSC::EvalExecutable::visitChildrenImpl):
+        * runtime/EvalExecutable.h:
+        (JSC::EvalExecutable::codeBlock const):
+        (JSC::EvalExecutable::unlinkedCodeBlock const):
+        (JSC::EvalExecutable::numVariables):
+        (JSC::EvalExecutable::numFunctionHoistingCandidates):
+        (JSC::EvalExecutable::numTopLevelFunctionDecls):
+        (JSC::EvalExecutable::allowDirectEvalCache const):
+        (JSC::EvalExecutable::codeBlock): Deleted.
+        * runtime/FunctionExecutable.cpp:
+        (JSC::FunctionExecutable::baselineCodeBlockFor):
+        (JSC::shouldKeepInConstraintSet):
+        (JSC::FunctionExecutable::visitChildrenImpl):
+        (JSC::FunctionExecutable::visitOutputConstraintsImpl):
+        * runtime/FunctionExecutable.h:
+        * runtime/FunctionExecutableInlines.h:
+        (JSC::FunctionExecutable::finalizeUnconditionally):
+        (JSC::FunctionExecutable::replaceCodeBlockWith):
+        (JSC::FunctionExecutable::toString):
+        * runtime/GlobalExecutable.cpp:
+        (JSC::GlobalExecutable::visitChildrenImpl):
+        (JSC::GlobalExecutable::visitOutputConstraintsImpl):
+        (JSC::GlobalExecutable::replaceCodeBlockWith):
+        (JSC::GlobalExecutable::finalizeUnconditionally):
+        * runtime/GlobalExecutable.h:
+        (JSC::GlobalExecutable::codeBlock const):
+        (JSC::GlobalExecutable::unlinkedCodeBlock const):
+        * runtime/IndirectEvalExecutable.cpp:
+        (JSC::IndirectEvalExecutable::createImpl):
+        * runtime/JSFunction.cpp:
+        * runtime/JSModuleRecord.cpp:
+        (JSC::JSModuleRecord::link):
+        (JSC::JSModuleRecord::instantiateDeclarations):
+        * runtime/ModuleProgramExecutable.cpp:
+        (JSC::ModuleProgramExecutable::create):
+        (JSC::ModuleProgramExecutable::visitChildrenImpl):
+        * runtime/ModuleProgramExecutable.h:
+        * runtime/ProgramExecutable.cpp:
+        (JSC::ProgramExecutable::initializeGlobalProperties):
+        (JSC::ProgramExecutable::visitChildrenImpl):
+        * runtime/ProgramExecutable.h:
+        * runtime/ScriptExecutable.cpp:
+        (JSC::ScriptExecutable::clearCode):
+        (JSC::ScriptExecutable::installCode):
+        (JSC::ScriptExecutable::hasClearableCode const):
+        (JSC::ScriptExecutable::newCodeBlockFor):
+        (JSC::ScriptExecutable::runConstraint):
+        (JSC::ScriptExecutable::visitCodeBlockEdge):
+        * runtime/ScriptExecutable.h:
+        * runtime/ScriptExecutableInlines.h: Copied from Source/_javascript_Core/runtime/FunctionExecutableInlines.h.
+        (JSC::ScriptExecutable::finalizeCodeBlockEdge):
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+        * runtime/VM.h:
+        (JSC::VM::executableToCodeBlockEdgesWithConstraints): Deleted.
+        (JSC::VM::executableToCodeBlockEdgesWithFinalizers): Deleted.
+
 2022-03-31  Patrick Angle  <pan...@apple.com>
 
         Web Inspector: Support Container Queries in the Styles sidebar

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (292190 => 292191)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2022-04-01 00:33:33 UTC (rev 292191)
@@ -370,7 +370,6 @@
 		0F5E0FD8207C72730097F0DE /* DFGAbstractInterpreterClobberState.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5E0FD6207C72710097F0DE /* DFGAbstractInterpreterClobberState.h */; };
 		0F5E0FE72086AD480097F0DE /* IsoSubspacePerVM.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5E0FE52086AD460097F0DE /* IsoSubspacePerVM.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F5EF91F16878F7D003E5C25 /* JITThunks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5EF91C16878F78003E5C25 /* JITThunks.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		0F60FE901FFC37020003320A /* ExecutableToCodeBlockEdge.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F60FE8E1FFC36FD0003320A /* ExecutableToCodeBlockEdge.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F61832A1C45BF070072450B /* AirCCallingConvention.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6183211C45BF070072450B /* AirCCallingConvention.h */; };
 		0F61832D1C45BF070072450B /* AirEmitShuffle.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6183241C45BF070072450B /* AirEmitShuffle.h */; };
 		0F61832F1C45BF070072450B /* AirLowerAfterRegAlloc.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6183261C45BF070072450B /* AirLowerAfterRegAlloc.h */; };
@@ -1989,6 +1988,7 @@
 		E386FD7E26E867B800E4C28B /* TemporalPlainTime.h in Headers */ = {isa = PBXBuildFile; fileRef = E386FD7826E867B800E4C28B /* TemporalPlainTime.h */; };
 		E386FD7F26E867B800E4C28B /* TemporalPlainTimePrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = E386FD7926E867B800E4C28B /* TemporalPlainTimePrototype.h */; };
 		E3893A1D2203A7C600E79A74 /* AsyncFromSyncIteratorPrototype.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = E3893A1C2203A7C600E79A74 /* AsyncFromSyncIteratorPrototype.lut.h */; };
+		E38DB2E727F588F80027BD3F /* ScriptExecutableInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E38DB2E627F588F70027BD3F /* ScriptExecutableInlines.h */; };
 		E38E8790254B978400F6F9E4 /* JSDateMath.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9788FC221471AD0C0068CE2D /* JSDateMath.cpp */; };
 		E39006212208BFC4001019CF /* SubspaceAccess.h in Headers */ = {isa = PBXBuildFile; fileRef = E39006202208BFC3001019CF /* SubspaceAccess.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E392E6F824D25FA600B20767 /* B3BottomTupleValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E392E6F624D25FA600B20767 /* B3BottomTupleValue.cpp */; };
@@ -2897,8 +2897,6 @@
 		0F5E0FE62086AD470097F0DE /* IsoSubspacePerVM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IsoSubspacePerVM.cpp; sourceTree = "<group>"; };
 		0F5EF91B16878F78003E5C25 /* JITThunks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITThunks.cpp; sourceTree = "<group>"; };
 		0F5EF91C16878F78003E5C25 /* JITThunks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITThunks.h; sourceTree = "<group>"; };
-		0F60FE8D1FFC36FC0003320A /* ExecutableToCodeBlockEdge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExecutableToCodeBlockEdge.cpp; sourceTree = "<group>"; };
-		0F60FE8E1FFC36FD0003320A /* ExecutableToCodeBlockEdge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExecutableToCodeBlockEdge.h; sourceTree = "<group>"; };
 		0F6183201C45BF070072450B /* AirCCallingConvention.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirCCallingConvention.cpp; path = b3/air/AirCCallingConvention.cpp; sourceTree = "<group>"; };
 		0F6183211C45BF070072450B /* AirCCallingConvention.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirCCallingConvention.h; path = b3/air/AirCCallingConvention.h; sourceTree = "<group>"; };
 		0F6183221C45BF070072450B /* AirCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirCustom.cpp; path = b3/air/AirCustom.cpp; sourceTree = "<group>"; };
@@ -5479,6 +5477,7 @@
 		E38D060B1F8E814100649CF2 /* JSScriptFetchParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSScriptFetchParameters.h; sourceTree = "<group>"; };
 		E38D060C1F8E814100649CF2 /* ScriptFetchParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptFetchParameters.h; sourceTree = "<group>"; };
 		E38D060D1F8E814100649CF2 /* JSScriptFetchParameters.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSScriptFetchParameters.cpp; sourceTree = "<group>"; };
+		E38DB2E627F588F70027BD3F /* ScriptExecutableInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptExecutableInlines.h; sourceTree = "<group>"; };
 		E39006202208BFC3001019CF /* SubspaceAccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SubspaceAccess.h; sourceTree = "<group>"; };
 		E3915C062309682900CB2561 /* WasmContext.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WasmContext.cpp; sourceTree = "<group>"; };
 		E392E6F624D25FA600B20767 /* B3BottomTupleValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3BottomTupleValue.cpp; path = b3/B3BottomTupleValue.cpp; sourceTree = "<group>"; };
@@ -8224,6 +8223,7 @@
 				33111B8A2397256500AA34CE /* Scribble.h */,
 				147341E01DC2CE9600AA29BA /* ScriptExecutable.cpp */,
 				147341CD1DC02D7900AA29BA /* ScriptExecutable.h */,
+				E38DB2E627F588F70027BD3F /* ScriptExecutableInlines.h */,
 				8852151A9C3842389B3215B7 /* ScriptFetcher.h */,
 				E38D060C1F8E814100649CF2 /* ScriptFetchParameters.h */,
 				A7299DA317D12858005F5FF9 /* SetConstructor.cpp */,
@@ -8977,8 +8977,6 @@
 				14AD91121DCA97FD0014F9FE /* EvalCodeBlock.cpp */,
 				14AD91061DCA92940014F9FE /* EvalCodeBlock.h */,
 				14142E521B796EDD00F4BF4B /* ExecutableInfo.h */,
-				0F60FE8D1FFC36FC0003320A /* ExecutableToCodeBlockEdge.cpp */,
-				0F60FE8E1FFC36FD0003320A /* ExecutableToCodeBlockEdge.h */,
 				0F56A1D415001CF2002992B1 /* ExecutionCounter.cpp */,
 				0F56A1D115000F31002992B1 /* ExecutionCounter.h */,
 				0F44A7A920BF685E0022B171 /* ExitFlag.cpp */,
@@ -10273,7 +10271,6 @@
 				E35A0B9D220AD87A00AC4474 /* ExecutableBaseInlines.h in Headers */,
 				14142E531B796EDD00F4BF4B /* ExecutableInfo.h in Headers */,
 				0F5193F7266C432D00483A2C /* ExecutableMemoryHandle.h in Headers */,
-				0F60FE901FFC37020003320A /* ExecutableToCodeBlockEdge.h in Headers */,
 				0F56A1D315000F35002992B1 /* ExecutionCounter.h in Headers */,
 				0F44A7B020BF68620022B171 /* ExitFlag.h in Headers */,
 				0F44A7B120BF68C90022B171 /* ExitingInlineKind.h in Headers */,
@@ -11044,6 +11041,7 @@
 				A5FD0070189B00AA00633231 /* ScriptCallStack.h in Headers */,
 				A5FD007E189B0B4C00633231 /* ScriptCallStackFactory.h in Headers */,
 				147341CE1DC02D7900AA29BA /* ScriptExecutable.h in Headers */,
+				E38DB2E727F588F80027BD3F /* ScriptExecutableInlines.h in Headers */,
 				CEAE7D7B889B477BA93ABA6C /* ScriptFetcher.h in Headers */,
 				E3201C1E1F8E824C0076A032 /* ScriptFetchParameters.h in Headers */,
 				A55D93A6185012A800400DED /* ScriptFunctionCall.h in Headers */,

Modified: trunk/Source/_javascript_Core/Sources.txt (292190 => 292191)


--- trunk/Source/_javascript_Core/Sources.txt	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/Sources.txt	2022-04-01 00:33:33 UTC (rev 292191)
@@ -229,7 +229,6 @@
 bytecode/DeleteByVariant.cpp
 bytecode/DirectEvalCodeCache.cpp
 bytecode/EvalCodeBlock.cpp
-bytecode/ExecutableToCodeBlockEdge.cpp
 bytecode/ExecutionCounter.cpp
 bytecode/ExitFlag.cpp
 bytecode/ExitKind.cpp

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (292190 => 292191)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2022-04-01 00:33:33 UTC (rev 292191)
@@ -311,7 +311,6 @@
 void CodeBlock::finishCreation(VM& vm, CopyParsedBlockTag, CodeBlock& other)
 {
     Base::finishCreation(vm);
-    finishCreationCommon(vm);
 
     optimizeAfterWarmUp();
 
@@ -367,7 +366,6 @@
     JSScope* scope)
 {
     Base::finishCreation(vm);
-    finishCreationCommon(vm);
 
     ASSERT(vm.heap.isDeferred());
 
@@ -766,11 +764,6 @@
     return true;
 }
 
-void CodeBlock::finishCreationCommon(VM& vm)
-{
-    m_ownerEdge.set(vm, this, ExecutableToCodeBlockEdge::create(vm, this));
-}
-
 #if ENABLE(JIT)
 void CodeBlock::setupWithUnlinkedBaselineCode(Ref<BaselineJITCode> jitCode)
 {
@@ -1051,7 +1044,6 @@
     CodeBlock* thisObject = jsCast<CodeBlock*>(cell);
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
     Base::visitChildren(cell, visitor);
-    visitor.append(thisObject->m_ownerEdge);
     thisObject->visitChildren(visitor);
 }
 
@@ -1079,7 +1071,7 @@
     stronglyVisitStrongReferences(locker, visitor);
     stronglyVisitWeakReferences(locker, visitor);
     
-    Heap::SpaceAndSet::setFor(*subspace()).add(this);
+    Heap::CodeBlockSpaceAndSet::setFor(*subspace()).add(this);
 }
 
 template<typename Visitor>
@@ -1667,7 +1659,7 @@
     };
     updateActivity();
 
-    Heap::SpaceAndSet::setFor(*subspace()).remove(this);
+    Heap::CodeBlockSpaceAndSet::setFor(*subspace()).remove(this);
 
     // In CodeBlock::shouldVisitStrongly() we may have decided to skip visiting this
     // codeBlock. By the time we get here, we're done with the verifier GC. So, let's
@@ -1834,7 +1826,7 @@
     UNUSED_PARAM(locker);
     
     visitor.append(m_globalObject);
-    visitor.append(m_ownerExecutable); // This is extra important since it causes the ExecutableToCodeBlockEdge to be marked.
+    visitor.append(m_ownerExecutable); // This is extra important since it causes the Executable -> CodeBlock edge activated.
     visitor.append(m_unlinkedCode);
     if (m_rareData)
         m_rareData->m_directEvalCodeCache.visitAggregate(visitor);

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.h (292190 => 292191)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.h	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.h	2022-04-01 00:33:33 UTC (rev 292191)
@@ -87,12 +87,12 @@
 class BinaryArithProfile;
 class BytecodeLivenessAnalysis;
 class CodeBlockSet;
-class ExecutableToCodeBlockEdge;
 class JSModuleEnvironment;
 class LLIntOffsetsExtractor;
 class LLIntPrototypeLoadAdaptiveStructureWatchpoint;
 class MetadataTable;
 class RegisterAtOffsetList;
+class ScriptExecutable;
 class StructureStubInfo;
 class BaselineJITCode;
 class BaselineJITData;
@@ -134,8 +134,6 @@
 
     void finishCreation(VM&, CopyParsedBlockTag, CodeBlock& other);
     bool finishCreation(VM&, ScriptExecutable* ownerExecutable, UnlinkedCodeBlock*, JSScope*);
-    
-    void finishCreationCommon(VM&);
 
     WriteBarrier<JSGlobalObject> m_globalObject;
 
@@ -369,8 +367,6 @@
     
     ScriptExecutable* ownerExecutable() const { return m_ownerExecutable.get(); }
     
-    ExecutableToCodeBlockEdge* ownerEdge() const { return m_ownerEdge.get(); }
-
     VM& vm() const { return *m_vm; }
 
     VirtualRegister thisRegister() const { return m_unlinkedCode->thisRegister(); }
@@ -849,7 +845,8 @@
 
 private:
     friend class CodeBlockSet;
-    friend class ExecutableToCodeBlockEdge;
+    friend class FunctionExecutable;
+    friend class ScriptExecutable;
 
     template<typename Visitor> ALWAYS_INLINE void visitChildren(Visitor&);
 
@@ -923,7 +920,6 @@
 
     WriteBarrier<UnlinkedCodeBlock> m_unlinkedCode;
     WriteBarrier<ScriptExecutable> m_ownerExecutable;
-    WriteBarrier<ExecutableToCodeBlockEdge> m_ownerEdge;
     // m_vm must be a pointer (instead of a reference) because the JSCLLIntOffsetsExtractor
     // cannot handle it being a reference.
     VM* m_vm;
@@ -975,7 +971,7 @@
 #endif
 };
 #if !ASSERT_ENABLED && COMPILER(GCC_COMPATIBLE)
-static_assert(sizeof(CodeBlock) <= 256, "Keep it small for memory saving");
+static_assert(sizeof(CodeBlock) <= 240, "Keep it small for memory saving");
 #endif
 
 template <typename ExecutableType>

Deleted: trunk/Source/_javascript_Core/bytecode/ExecutableToCodeBlockEdge.cpp (292190 => 292191)


--- trunk/Source/_javascript_Core/bytecode/ExecutableToCodeBlockEdge.cpp	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/bytecode/ExecutableToCodeBlockEdge.cpp	2022-04-01 00:33:33 UTC (rev 292191)
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2018-2021 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
- */
-
-#include "config.h"
-#include "ExecutableToCodeBlockEdge.h"
-
-#include "CodeBlock.h"
-#include "IsoCellSetInlines.h"
-#include "JSObjectInlines.h"
-#include "StructureInlines.h"
-
-namespace JSC {
-
-const ClassInfo ExecutableToCodeBlockEdge::s_info = { "ExecutableToCodeBlockEdge"_s, nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(ExecutableToCodeBlockEdge) };
-
-Structure* ExecutableToCodeBlockEdge::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
-{
-    return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
-}
-
-ExecutableToCodeBlockEdge* ExecutableToCodeBlockEdge::create(VM& vm, CodeBlock* codeBlock)
-{
-    ExecutableToCodeBlockEdge* result = new (NotNull, allocateCell<ExecutableToCodeBlockEdge>(vm)) ExecutableToCodeBlockEdge(vm, codeBlock);
-    result->finishCreation(vm);
-    return result;
-}
-
-void ExecutableToCodeBlockEdge::finishCreation(VM& vm)
-{
-    Base::finishCreation(vm);
-    ASSERT(!isActive());
-}
-
-template<typename Visitor>
-void ExecutableToCodeBlockEdge::visitChildrenImpl(JSCell* cell, Visitor& visitor)
-{
-    VM& vm = visitor.vm();
-    ExecutableToCodeBlockEdge* edge = jsCast<ExecutableToCodeBlockEdge*>(cell);
-    ASSERT_GC_OBJECT_INHERITS(cell, info());
-    Base::visitChildren(cell, visitor);
-
-    CodeBlock* codeBlock = edge->m_codeBlock.get();
-
-    // It's possible for someone to hold a pointer to the edge after the edge has cleared its weak
-    // reference to the codeBlock. In a conservative GC like ours, that could happen at random for
-    // no good reason and it's Totally OK (TM). See finalizeUnconditionally() for where we clear
-    // m_codeBlock.
-    if (!codeBlock)
-        return;
-    
-    if (!edge->isActive()) {
-        visitor.appendUnbarriered(codeBlock);
-        return;
-    }
-    
-    ConcurrentJSLocker locker(codeBlock->m_lock);
-
-    if (codeBlock->shouldVisitStrongly(locker, visitor))
-        visitor.appendUnbarriered(codeBlock);
-    
-    if (!visitor.isMarked(codeBlock))
-        vm.executableToCodeBlockEdgesWithFinalizers().add(edge);
-    
-    if (JITCode::isOptimizingJIT(codeBlock->jitType())) {
-        // If we jettison ourselves we'll install our alternative, so make sure that it
-        // survives GC even if we don't.
-        visitor.append(codeBlock->m_alternative);
-    }
-    
-    // NOTE: There are two sides to this constraint, with different requirements for correctness.
-    // Because everything is ultimately protected with weak references and jettisoning, it's
-    // always "OK" to claim that something is dead prematurely and it's "OK" to keep things alive.
-    // But both choices could lead to bad perf - either recomp cycles or leaks.
-    //
-    // Determining CodeBlock liveness: This part is the most consequential. We want to keep the
-    // output constraint active so long as we think that we may yet prove that the CodeBlock is
-    // live but we haven't done it yet.
-    //
-    // Marking Structures if profitable: It's important that we do a pass of this. Logically, this
-    // seems like it is a constraint of CodeBlock. But we have always first run this as a result
-    // of the edge being marked even before we determine the liveness of the CodeBlock. This
-    // allows a CodeBlock to mark itself by first proving that all of the Structures it weakly
-    // depends on could be strongly marked. (This part is also called propagateTransitions.)
-    //
-    // As a weird caveat, we only fixpoint the constraints so long as the CodeBlock is not live.
-    // This means that we may overlook structure marking opportunities created by other marking
-    // that happens after the CodeBlock is marked. This was an accidental policy decision from a
-    // long time ago, but it is probably OK, since it's only worthwhile to keep fixpointing the
-    // structure marking if we still have unmarked structures after the first round. We almost
-    // never will because we will mark-if-profitable based on the owning global object being
-    // already marked. We mark it just in case that hadn't happened yet. And if the CodeBlock is
-    // not yet marked because it weakly depends on a structure that we did not yet mark, then we
-    // will keep fixpointing until the end.
-    visitor.appendUnbarriered(codeBlock->globalObject());
-    vm.executableToCodeBlockEdgesWithConstraints().add(edge);
-    edge->runConstraint(locker, vm, visitor);
-}
-
-DEFINE_VISIT_CHILDREN(ExecutableToCodeBlockEdge);
-
-template<typename Visitor>
-void ExecutableToCodeBlockEdge::visitOutputConstraintsImpl(JSCell* cell, Visitor& visitor)
-{
-    VM& vm = visitor.vm();
-    ExecutableToCodeBlockEdge* edge = jsCast<ExecutableToCodeBlockEdge*>(cell);
-    
-    edge->runConstraint(NoLockingNecessary, vm, visitor);
-}
-
-DEFINE_VISIT_OUTPUT_CONSTRAINTS(ExecutableToCodeBlockEdge);
-
-void ExecutableToCodeBlockEdge::finalizeUnconditionally(VM& vm)
-{
-    CodeBlock* codeBlock = m_codeBlock.get();
-    
-    if (!vm.heap.isMarked(codeBlock)) {
-        if (codeBlock->shouldJettisonDueToWeakReference(vm))
-            codeBlock->jettison(Profiler::JettisonDueToWeakReference);
-        else
-            codeBlock->jettison(Profiler::JettisonDueToOldAge);
-        m_codeBlock.clear();
-    }
-    
-    vm.executableToCodeBlockEdgesWithFinalizers().remove(this);
-    vm.executableToCodeBlockEdgesWithConstraints().remove(this);
-}
-
-inline void ExecutableToCodeBlockEdge::activate()
-{
-    setPerCellBit(true);
-}
-
-inline void ExecutableToCodeBlockEdge::deactivate()
-{
-    setPerCellBit(false);
-}
-
-inline bool ExecutableToCodeBlockEdge::isActive() const
-{
-    return perCellBit();
-}
-
-CodeBlock* ExecutableToCodeBlockEdge::deactivateAndUnwrap(ExecutableToCodeBlockEdge* edge)
-{
-    if (!edge)
-        return nullptr;
-    edge->deactivate();
-    return edge->codeBlock();
-}
-
-ExecutableToCodeBlockEdge* ExecutableToCodeBlockEdge::wrap(CodeBlock* codeBlock)
-{
-    if (!codeBlock)
-        return nullptr;
-    return codeBlock->ownerEdge();
-}
-    
-ExecutableToCodeBlockEdge* ExecutableToCodeBlockEdge::wrapAndActivate(CodeBlock* codeBlock)
-{
-    if (!codeBlock)
-        return nullptr;
-    ExecutableToCodeBlockEdge* result = codeBlock->ownerEdge();
-    result->activate();
-    return result;
-}
-
-ExecutableToCodeBlockEdge::ExecutableToCodeBlockEdge(VM& vm, CodeBlock* codeBlock)
-    : Base(vm, vm.executableToCodeBlockEdgeStructure.get())
-    , m_codeBlock(vm, this, codeBlock)
-{
-}
-
-template<typename Visitor>
-void ExecutableToCodeBlockEdge::runConstraint(const ConcurrentJSLocker& locker, VM& vm, Visitor& visitor)
-{
-    CodeBlock* codeBlock = m_codeBlock.get();
-    
-    codeBlock->propagateTransitions(locker, visitor);
-    codeBlock->determineLiveness(locker, visitor);
-
-    if (visitor.isMarked(codeBlock))
-        vm.executableToCodeBlockEdgesWithConstraints().remove(this);
-}
-
-template void ExecutableToCodeBlockEdge::runConstraint(const ConcurrentJSLocker&, VM&, AbstractSlotVisitor&);
-template void ExecutableToCodeBlockEdge::runConstraint(const ConcurrentJSLocker&, VM&, SlotVisitor&);
-
-
-} // namespace JSC
-

Deleted: trunk/Source/_javascript_Core/bytecode/ExecutableToCodeBlockEdge.h (292190 => 292191)


--- trunk/Source/_javascript_Core/bytecode/ExecutableToCodeBlockEdge.h	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/bytecode/ExecutableToCodeBlockEdge.h	2022-04-01 00:33:33 UTC (rev 292191)
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2018-2022 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
- */
-
-#pragma once
-
-#include "ConcurrentJSLock.h"
-#include "IsoSubspace.h"
-#include "JSCast.h"
-#include "VM.h"
-
-namespace JSC {
-
-class CodeBlock;
-class LLIntOffsetsExtractor;
-
-class ExecutableToCodeBlockEdge final : public JSCell {
-public:
-    typedef JSCell Base;
-    static constexpr unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
-
-    template<typename CellType, SubspaceAccess>
-    static GCClient::IsoSubspace* subspaceFor(VM& vm)
-    {
-        return &vm.executableToCodeBlockEdgeSpace();
-    }
-
-    static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
-
-    static ExecutableToCodeBlockEdge* create(VM&, CodeBlock*);
-    
-    DECLARE_INFO;
-
-    CodeBlock* codeBlock() const { return m_codeBlock.get(); }
-
-    DECLARE_VISIT_CHILDREN;
-    DECLARE_VISIT_OUTPUT_CONSTRAINTS;
-    void finalizeUnconditionally(VM&);
-    
-    static CodeBlock* unwrap(ExecutableToCodeBlockEdge* edge)
-    {
-        if (!edge)
-            return nullptr;
-        return edge->codeBlock();
-    }
-    
-    static CodeBlock* deactivateAndUnwrap(ExecutableToCodeBlockEdge* edge);
-    
-    static ExecutableToCodeBlockEdge* wrap(CodeBlock* codeBlock);
-    
-    static ExecutableToCodeBlockEdge* wrapAndActivate(CodeBlock* codeBlock);
-
-    static ptrdiff_t offsetOfCodeBlock() { return OBJECT_OFFSETOF(ExecutableToCodeBlockEdge, m_codeBlock); }
-    
-private:
-    friend class LLIntOffsetsExtractor;
-
-    ExecutableToCodeBlockEdge(VM&, CodeBlock*);
-
-    void finishCreation(VM&);
-
-    void activate();
-    void deactivate();
-    bool isActive() const;
-
-    template<typename Visitor> void runConstraint(const ConcurrentJSLocker&, VM&, Visitor&);
-
-    WriteBarrier<CodeBlock> m_codeBlock;
-};
-
-} // namespace JSC

Modified: trunk/Source/_javascript_Core/heap/Heap.cpp (292190 => 292191)


--- trunk/Source/_javascript_Core/heap/Heap.cpp	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/heap/Heap.cpp	2022-04-01 00:33:33 UTC (rev 292191)
@@ -368,8 +368,6 @@
     , destructibleObjectSpace("JSDestructibleObject", *this, destructibleObjectHeapCellType, fastMallocAllocator.get()) // Hash:0x4f5ed7a9
     FOR_EACH_JSC_COMMON_ISO_SUBSPACE(INIT_SERVER_ISO_SUBSPACE)
     FOR_EACH_JSC_STRUCTURE_ISO_SUBSPACE(INIT_SERVER_STRUCTURE_ISO_SUBSPACE)
-    , executableToCodeBlockEdgesWithConstraints(executableToCodeBlockEdgeSpace)
-    , executableToCodeBlockEdgesWithFinalizers(executableToCodeBlockEdgeSpace)
     , codeBlockSpaceAndSet ISO_SUBSPACE_INIT(*this, destructibleCellHeapCellType, CodeBlock) // Hash:0x77e66ec9
     , functionExecutableSpaceAndSet ISO_SUBSPACE_INIT(*this, destructibleCellHeapCellType, FunctionExecutable) // Hash:0x5d158f3
     , programExecutableSpaceAndSet ISO_SUBSPACE_INIT(*this, destructibleCellHeapCellType, ProgramExecutable) // Hash:0x527c77e7
@@ -674,9 +672,22 @@
 {
     VM& vm = this->vm();
     vm.builtinExecutables()->finalizeUnconditionally();
-    finalizeMarkedUnconditionalFinalizers<FunctionExecutable>(functionExecutableSpaceAndSet.space);
+
+    {
+        // We run this before CodeBlock's unconditional finalizer since CodeBlock looks at the owner executable's installed CodeBlock in its finalizeUnconditionally.
+
+        // FunctionExecutable requires all live instances to run finalizers. Thus, we do not use finalizer set.
+        finalizeMarkedUnconditionalFinalizers<FunctionExecutable>(functionExecutableSpaceAndSet.space);
+
+        finalizeMarkedUnconditionalFinalizers<ProgramExecutable>(programExecutableSpaceAndSet.finalizerSet);
+        if (m_evalExecutableSpace)
+            finalizeMarkedUnconditionalFinalizers<EvalExecutable>(m_evalExecutableSpace->finalizerSet);
+        if (m_moduleProgramExecutableSpace)
+            finalizeMarkedUnconditionalFinalizers<ModuleProgramExecutable>(m_moduleProgramExecutableSpace->finalizerSet);
+    }
+
     finalizeMarkedUnconditionalFinalizers<SymbolTable>(symbolTableSpace);
-    finalizeMarkedUnconditionalFinalizers<ExecutableToCodeBlockEdge>(executableToCodeBlockEdgesWithFinalizers); // We run this before CodeBlock's unconditional finalizer since CodeBlock looks at the owner executable's installed CodeBlock in its finalizeUnconditionally.
+
     forEachCodeBlockSpace(
         [&] (auto& space) {
             this->finalizeMarkedUnconditionalFinalizers<CodeBlock>(space.set);
@@ -1003,7 +1014,7 @@
     forEachScriptExecutableSpace(
         [&] (auto& spaceAndSet) {
             HeapIterationScope heapIterationScope(*this);
-            auto& set = spaceAndSet.set;
+            auto& set = spaceAndSet.clearableCodeSet;
             set.forEachLiveCell(
                 [&] (HeapCell* cell, HeapCell::Kind) {
                     ScriptExecutable* executable = static_cast<ScriptExecutable*>(cell);
@@ -2917,7 +2928,12 @@
 
             {
                 SetRootMarkReasonScope rootScope(visitor, RootMarkReason::ExecutableToCodeBlockEdges);
-                add(heap->executableToCodeBlockEdgesWithConstraints);
+                add(heap->functionExecutableSpaceAndSet.outputConstraintsSet);
+                add(heap->programExecutableSpaceAndSet.outputConstraintsSet);
+                if (heap->m_evalExecutableSpace)
+                    add(heap->m_evalExecutableSpace->outputConstraintsSet);
+                if (heap->m_moduleProgramExecutableSpace)
+                    add(heap->m_moduleProgramExecutableSpace->outputConstraintsSet);
             }
             if (heap->m_weakMapSpace) {
                 SetRootMarkReasonScope rootScope(visitor, RootMarkReason::WeakMapSpace);
@@ -3169,18 +3185,18 @@
 
 #undef DEFINE_DYNAMIC_ISO_SUBSPACE_MEMBER_SLOW
 
-#define DEFINE_DYNAMIC_SPACE_AND_SET_MEMBER_SLOW(name, heapCellType, type) \
+#define DEFINE_DYNAMIC_SPACE_AND_SET_MEMBER_SLOW(name, heapCellType, type, spaceType) \
     IsoSubspace* Heap::name##Slow() \
     { \
         ASSERT(!m_##name); \
-        auto space = makeUnique<SpaceAndSet> ISO_SUBSPACE_INIT(*this, heapCellType, type); \
+        auto space = makeUnique<spaceType> ISO_SUBSPACE_INIT(*this, heapCellType, type); \
         WTF::storeStoreFence(); \
         m_##name = WTFMove(space); \
         return &m_##name->space; \
     }
 
-DEFINE_DYNAMIC_SPACE_AND_SET_MEMBER_SLOW(evalExecutableSpace, destructibleCellHeapCellType, EvalExecutable) // Hash:0x958e3e9d
-DEFINE_DYNAMIC_SPACE_AND_SET_MEMBER_SLOW(moduleProgramExecutableSpace, destructibleCellHeapCellType, ModuleProgramExecutable) // Hash:0x6506fa3c
+DEFINE_DYNAMIC_SPACE_AND_SET_MEMBER_SLOW(evalExecutableSpace, destructibleCellHeapCellType, EvalExecutable, Heap::ScriptExecutableSpaceAndSets) // Hash:0x958e3e9d
+DEFINE_DYNAMIC_SPACE_AND_SET_MEMBER_SLOW(moduleProgramExecutableSpace, destructibleCellHeapCellType, ModuleProgramExecutable, Heap::ScriptExecutableSpaceAndSets) // Hash:0x6506fa3c
 
 #undef DEFINE_DYNAMIC_SPACE_AND_SET_MEMBER_SLOW
 

Modified: trunk/Source/_javascript_Core/heap/Heap.h (292190 => 292191)


--- trunk/Source/_javascript_Core/heap/Heap.h	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/heap/Heap.h	2022-04-01 00:33:33 UTC (rev 292191)
@@ -120,7 +120,6 @@
     v(dateInstanceSpace, dateInstanceHeapCellType, DateInstance) \
     v(domAttributeGetterSetterSpace, cellHeapCellType, DOMAttributeGetterSetter) \
     v(exceptionSpace, destructibleCellHeapCellType, Exception) \
-    v(executableToCodeBlockEdgeSpace, cellHeapCellType, ExecutableToCodeBlockEdge) \
     v(functionSpace, cellHeapCellType, JSFunction) \
     v(getterSetterSpace, cellHeapCellType, GetterSetter) \
     v(globalLexicalEnvironmentSpace, globalLexicalEnvironmentHeapCellType, JSGlobalLexicalEnvironment) \
@@ -1029,10 +1028,7 @@
     FOR_EACH_JSC_DYNAMIC_ISO_SUBSPACE(DEFINE_DYNAMIC_ISO_SUBSPACE_MEMBER)
 #undef DEFINE_DYNAMIC_ISO_SUBSPACE_MEMBER
     
-    IsoCellSet executableToCodeBlockEdgesWithConstraints;
-    IsoCellSet executableToCodeBlockEdgesWithFinalizers;
-
-#define DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(name) \
+#define DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(name, type) \
     template<SubspaceAccess mode> \
     IsoSubspace* name() \
     { \
@@ -1043,7 +1039,7 @@
         return name##Slow(); \
     } \
     IsoSubspace* name##Slow(); \
-    std::unique_ptr<SpaceAndSet> m_##name;
+    std::unique_ptr<type> m_##name;
     
     struct SpaceAndSet {
         WTF_MAKE_STRUCT_FAST_ALLOCATED;
@@ -1067,7 +1063,8 @@
         }
     };
 
-    SpaceAndSet codeBlockSpaceAndSet;
+    using CodeBlockSpaceAndSet = SpaceAndSet;
+    CodeBlockSpaceAndSet codeBlockSpaceAndSet;
 
     template<typename Func>
     void forEachCodeBlockSpace(const Func& func)
@@ -1075,11 +1072,40 @@
         func(codeBlockSpaceAndSet);
     }
 
-    DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(evalExecutableSpace)
-    DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(moduleProgramExecutableSpace)
-    SpaceAndSet functionExecutableSpaceAndSet;
-    SpaceAndSet programExecutableSpaceAndSet;
+    struct ScriptExecutableSpaceAndSets {
+        WTF_MAKE_STRUCT_FAST_ALLOCATED;
 
+        IsoSubspace space;
+        IsoCellSet clearableCodeSet;
+        IsoCellSet outputConstraintsSet;
+        IsoCellSet finalizerSet;
+
+        template<typename... Arguments>
+        ScriptExecutableSpaceAndSets(Arguments&&... arguments)
+            : space(std::forward<Arguments>(arguments)...)
+            , clearableCodeSet(space)
+            , outputConstraintsSet(space)
+            , finalizerSet(space)
+        {
+        }
+
+        static ScriptExecutableSpaceAndSets& setAndSpaceFor(Subspace& space)
+        {
+            return *bitwise_cast<ScriptExecutableSpaceAndSets*>(
+                bitwise_cast<char*>(&space) -
+                OBJECT_OFFSETOF(ScriptExecutableSpaceAndSets, space));
+        }
+
+        static IsoCellSet& clearableCodeSetFor(Subspace& space) { return setAndSpaceFor(space).clearableCodeSet; }
+        static IsoCellSet& outputConstraintsSetFor(Subspace& space) { return setAndSpaceFor(space).outputConstraintsSet; }
+        static IsoCellSet& finalizerSetFor(Subspace& space) { return setAndSpaceFor(space).finalizerSet; }
+    };
+
+    DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(evalExecutableSpace, ScriptExecutableSpaceAndSets)
+    DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(moduleProgramExecutableSpace, ScriptExecutableSpaceAndSets)
+    ScriptExecutableSpaceAndSets functionExecutableSpaceAndSet;
+    ScriptExecutableSpaceAndSets programExecutableSpaceAndSet;
+
     template<typename Func>
     void forEachScriptExecutableSpace(const Func& func)
     {
@@ -1091,7 +1117,8 @@
         func(programExecutableSpaceAndSet);
     }
 
-    SpaceAndSet unlinkedFunctionExecutableSpaceAndSet;
+    using UnlinkedFunctionExecutableSpaceAndSet = SpaceAndSet;
+    UnlinkedFunctionExecutableSpaceAndSet unlinkedFunctionExecutableSpaceAndSet;
 
     Vector<IsoSubspacePerVM*> perVMIsoSubspaces;
 #undef DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER

Modified: trunk/Source/_javascript_Core/heap/IsoCellSet.h (292190 => 292191)


--- trunk/Source/_javascript_Core/heap/IsoCellSet.h	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/heap/IsoCellSet.h	2022-04-01 00:33:33 UTC (rev 292191)
@@ -29,6 +29,8 @@
 #include <wtf/Bitmap.h>
 #include <wtf/ConcurrentVector.h>
 #include <wtf/FastBitVector.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Nonmovable.h>
 #include <wtf/SentinelLinkedList.h>
 #include <wtf/SharedTask.h>
 
@@ -40,7 +42,9 @@
 // Create a set of cells that are in an IsoSubspace. This allows concurrent O(1) set insertion and
 // removal. Each such set should be thought of as a 0.8% increase in object size for objects in that
 // IsoSubspace (it's like adding 1 bit every 16 bytes, or 1 bit every 128 bits).
-class IsoCellSet : public PackedRawSentinelNode<IsoCellSet> {
+class IsoCellSet final : public PackedRawSentinelNode<IsoCellSet> {
+    WTF_MAKE_NONCOPYABLE(IsoCellSet);
+    WTF_MAKE_NONMOVABLE(IsoCellSet);
 public:
     IsoCellSet(IsoSubspace& subspace);
     ~IsoCellSet();

Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (292190 => 292191)


--- trunk/Source/_javascript_Core/jit/JIT.cpp	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp	2022-04-01 00:33:33 UTC (rev 292191)
@@ -215,8 +215,6 @@
         loadPtr(Address(result, FunctionExecutable::offsetOfCodeBlockForConstruct()), result);
     else
         loadPtr(Address(result, FunctionExecutable::offsetOfCodeBlockForCall()), result);
-
-    loadPtr(Address(result, ExecutableToCodeBlockEdge::offsetOfCodeBlock()), result);
     emitPutToCallFrameHeader(result, CallFrameSlot::codeBlock);
 
 #if ASSERT_ENABLED

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm (292190 => 292191)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2022-04-01 00:33:33 UTC (rev 292191)
@@ -1493,7 +1493,6 @@
     loadp (FunctionRareData::m_executable - (constexpr JSFunction::rareDataTag))[targetRegister], targetRegister
 .isExecutable:
     loadp FunctionExecutable::m_codeBlockForCall[targetRegister], targetRegister
-    loadp ExecutableToCodeBlockEdge::m_codeBlock[targetRegister], targetRegister
 end
 
 macro functionForConstructCodeBlockGetter(targetRegister)
@@ -1507,7 +1506,6 @@
     loadp (FunctionRareData::m_executable - (constexpr JSFunction::rareDataTag))[targetRegister], targetRegister
 .isExecutable:
     loadp FunctionExecutable::m_codeBlockForConstruct[targetRegister], targetRegister
-    loadp ExecutableToCodeBlockEdge::m_codeBlock[targetRegister], targetRegister
 end
 
 macro notFunctionCodeBlockGetter(targetRegister)

Modified: trunk/Source/_javascript_Core/runtime/DirectEvalExecutable.cpp (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/DirectEvalExecutable.cpp	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/DirectEvalExecutable.cpp	2022-04-01 00:33:33 UTC (rev 292191)
@@ -63,7 +63,7 @@
         return nullptr;
     }
 
-    executable->m_unlinkedEvalCodeBlock.set(vm, executable, unlinkedEvalCode);
+    executable->m_unlinkedCodeBlock.set(vm, executable, unlinkedEvalCode);
 
     return executable;
 }

Modified: trunk/Source/_javascript_Core/runtime/EvalExecutable.cpp (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/EvalExecutable.cpp	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/EvalExecutable.cpp	2022-04-01 00:33:33 UTC (rev 292191)
@@ -56,8 +56,6 @@
     EvalExecutable* thisObject = jsCast<EvalExecutable*>(cell);
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
     Base::visitChildren(thisObject, visitor);
-    visitor.append(thisObject->m_unlinkedEvalCodeBlock);
-    visitor.append(thisObject->m_evalCodeBlock);
     if (TemplateObjectMap* map = thisObject->m_templateObjectMap.get()) {
         Locker locker { thisObject->cellLock() };
         for (auto& entry : *map)

Modified: trunk/Source/_javascript_Core/runtime/EvalExecutable.h (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/EvalExecutable.h	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/EvalExecutable.h	2022-04-01 00:33:33 UTC (rev 292191)
@@ -25,7 +25,6 @@
 
 #pragma once
 
-#include "ExecutableToCodeBlockEdge.h"
 #include "GlobalExecutable.h"
 #include "UnlinkedEvalCodeBlock.h"
 
@@ -39,11 +38,16 @@
 
     static void destroy(JSCell*);
     
-    EvalCodeBlock* codeBlock()
+    EvalCodeBlock* codeBlock() const
     {
-        return bitwise_cast<EvalCodeBlock*>(ExecutableToCodeBlockEdge::unwrap(m_evalCodeBlock.get()));
+        return bitwise_cast<EvalCodeBlock*>(Base::codeBlock());
     }
 
+    UnlinkedEvalCodeBlock* unlinkedCodeBlock() const
+    {
+        return bitwise_cast<UnlinkedEvalCodeBlock*>(Base::unlinkedCodeBlock());
+    }
+
     Ref<JITCode> generatedJITCode()
     {
         return generatedJITCodeForCall();
@@ -62,10 +66,10 @@
 
     DECLARE_INFO;
 
-    unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); }
-    unsigned numFunctionHoistingCandidates() { return m_unlinkedEvalCodeBlock->numFunctionHoistingCandidates(); }
-    unsigned numTopLevelFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); }
-    bool allowDirectEvalCache() const { return m_unlinkedEvalCodeBlock->allowDirectEvalCache(); }
+    unsigned numVariables() { return unlinkedCodeBlock()->numVariables(); }
+    unsigned numFunctionHoistingCandidates() { return unlinkedCodeBlock()->numFunctionHoistingCandidates(); }
+    unsigned numTopLevelFunctionDecls() { return unlinkedCodeBlock()->numberOfFunctionDecls(); }
+    bool allowDirectEvalCache() const { return unlinkedCodeBlock()->allowDirectEvalCache(); }
     NeedsClassFieldInitializer needsClassFieldInitializer() const { return static_cast<NeedsClassFieldInitializer>(m_needsClassFieldInitializer); }
     PrivateBrandRequirement privateBrandRequirement() const { return static_cast<PrivateBrandRequirement>(m_privateBrandRequirement); }
     TemplateObjectMap& ensureTemplateObjectMap(VM&);
@@ -82,8 +86,6 @@
     unsigned m_needsClassFieldInitializer : 1;
     unsigned m_privateBrandRequirement : 1;
 
-    WriteBarrier<ExecutableToCodeBlockEdge> m_evalCodeBlock;
-    WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock;
     std::unique_ptr<TemplateObjectMap> m_templateObjectMap;
 };
 

Modified: trunk/Source/_javascript_Core/runtime/FunctionExecutable.cpp (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/FunctionExecutable.cpp	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/FunctionExecutable.cpp	2022-04-01 00:33:33 UTC (rev 292191)
@@ -24,10 +24,13 @@
  */
 
 #include "config.h"
+#include "FunctionExecutable.h"
 
 #include "CodeBlock.h"
 #include "FunctionCodeBlock.h"
+#include "FunctionExecutableInlines.h"
 #include "FunctionOverrides.h"
+#include "IsoCellSetInlines.h"
 #include "JSCJSValueInlines.h"
 
 namespace JSC {
@@ -55,27 +58,33 @@
 
 FunctionCodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKind kind)
 {
-    ExecutableToCodeBlockEdge* edge;
+    CodeBlock* codeBlock = nullptr;
     if (kind == CodeForCall)
-        edge = m_codeBlockForCall.get();
+        codeBlock = codeBlockForCall();
     else {
         RELEASE_ASSERT(kind == CodeForConstruct);
-        edge = m_codeBlockForConstruct.get();
+        codeBlock = codeBlockForConstruct();
     }
-    if (!edge)
+    if (!codeBlock)
         return nullptr;
-    return static_cast<FunctionCodeBlock*>(edge->codeBlock()->baselineAlternative());
+    return static_cast<FunctionCodeBlock*>(codeBlock->baselineAlternative());
 }
 
 template<typename Visitor>
+static inline bool shouldKeepInConstraintSet(Visitor& visitor, CodeBlock* codeBlockForCall, CodeBlock* codeBlockForConstruct)
+{
+    // If either CodeBlock is not marked yet, we will run output-constraints.
+    return (codeBlockForCall && !visitor.isMarked(codeBlockForCall)) || (codeBlockForConstruct && !visitor.isMarked(codeBlockForConstruct));
+}
+
+template<typename Visitor>
 void FunctionExecutable::visitChildrenImpl(JSCell* cell, Visitor& visitor)
 {
+    VM& vm = visitor.vm();
     FunctionExecutable* thisObject = jsCast<FunctionExecutable*>(cell);
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
     Base::visitChildren(thisObject, visitor);
     visitor.append(thisObject->m_topLevelExecutable);
-    visitor.append(thisObject->m_codeBlockForCall);
-    visitor.append(thisObject->m_codeBlockForConstruct);
     visitor.append(thisObject->m_unlinkedExecutable);
     if (RareData* rareData = thisObject->m_rareData.get()) {
         visitor.append(rareData->m_cachedPolyProtoStructureID);
@@ -86,10 +95,43 @@
                 visitor.append(entry.value);
         }
     }
+
+    // Since FunctionExecutable's finalizer always needs to be run, we do not track FunctionExecutable via finalizerSet.
+    auto* codeBlockForCall = thisObject->m_codeBlockForCall.get();
+    if (codeBlockForCall)
+        visitCodeBlockEdge(visitor, codeBlockForCall);
+    auto* codeBlockForConstruct = thisObject->m_codeBlockForConstruct.get();
+    if (codeBlockForConstruct)
+        visitCodeBlockEdge(visitor, codeBlockForConstruct);
+
+    if (shouldKeepInConstraintSet(visitor, codeBlockForCall, codeBlockForConstruct))
+        vm.heap.functionExecutableSpaceAndSet.outputConstraintsSet.add(thisObject);
 }
 
 DEFINE_VISIT_CHILDREN(FunctionExecutable);
 
+template<typename Visitor>
+void FunctionExecutable::visitOutputConstraintsImpl(JSCell* cell, Visitor& visitor)
+{
+    VM& vm = visitor.vm();
+    auto* executable = jsCast<FunctionExecutable*>(cell);
+    auto* codeBlockForCall = executable->m_codeBlockForCall.get();
+    if (codeBlockForCall) {
+        if (!visitor.isMarked(codeBlockForCall))
+            runConstraint(NoLockingNecessary, visitor, codeBlockForCall);
+    }
+    auto* codeBlockForConstruct = executable->codeBlockForConstruct();
+    if (codeBlockForConstruct) {
+        if (!visitor.isMarked(codeBlockForConstruct))
+            runConstraint(NoLockingNecessary, visitor, codeBlockForConstruct);
+    }
+
+    if (!shouldKeepInConstraintSet(visitor, codeBlockForCall, codeBlockForConstruct))
+        vm.heap.functionExecutableSpaceAndSet.outputConstraintsSet.remove(executable);
+}
+
+DEFINE_VISIT_OUTPUT_CONSTRAINTS(FunctionExecutable);
+
 FunctionExecutable* FunctionExecutable::fromGlobalCode(
     const Identifier& name, JSGlobalObject* globalObject, const SourceCode& source, 
     JSObject*& exception, int overrideLineNumber, std::optional<int> functionConstructorParametersEndPosition)

Modified: trunk/Source/_javascript_Core/runtime/FunctionExecutable.h (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/FunctionExecutable.h	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/FunctionExecutable.h	2022-04-01 00:33:33 UTC (rev 292191)
@@ -25,7 +25,6 @@
 
 #pragma once
 
-#include "ExecutableToCodeBlockEdge.h"
 #include "JSFunction.h"
 #include "ScriptExecutable.h"
 #include "SourceCode.h"
@@ -69,34 +68,31 @@
     // Returns either call or construct bytecode. This can be appropriate
     // for answering questions that that don't vary between call and construct --
     // for example, argumentsRegister().
-    FunctionCodeBlock* eitherCodeBlock()
+    FunctionCodeBlock* eitherCodeBlock() const
     {
-        ExecutableToCodeBlockEdge* edge;
-        if (m_codeBlockForCall)
-            edge = m_codeBlockForCall.get();
-        else
-            edge = m_codeBlockForConstruct.get();
-        return bitwise_cast<FunctionCodeBlock*>(ExecutableToCodeBlockEdge::unwrap(edge));
+        if (auto* result = codeBlockForCall())
+            return result;
+        return codeBlockForConstruct();
     }
         
     bool isGeneratedForCall() const
     {
-        return !!m_codeBlockForCall;
+        return !!codeBlockForCall();
     }
 
-    FunctionCodeBlock* codeBlockForCall()
+    FunctionCodeBlock* codeBlockForCall() const
     {
-        return bitwise_cast<FunctionCodeBlock*>(ExecutableToCodeBlockEdge::unwrap(m_codeBlockForCall.get()));
+        return bitwise_cast<FunctionCodeBlock*>(m_codeBlockForCall.get());
     }
 
     bool isGeneratedForConstruct() const
     {
-        return !!m_codeBlockForConstruct;
+        return !!codeBlockForConstruct();
     }
 
-    FunctionCodeBlock* codeBlockForConstruct()
+    FunctionCodeBlock* codeBlockForConstruct() const
     {
-        return bitwise_cast<FunctionCodeBlock*>(ExecutableToCodeBlockEdge::unwrap(m_codeBlockForConstruct.get()));
+        return bitwise_cast<FunctionCodeBlock*>(m_codeBlockForConstruct.get());
     }
         
     bool isGeneratedFor(CodeSpecializationKind kind)
@@ -122,6 +118,8 @@
         return baselineCodeBlockFor(kind);
     }
 
+    FunctionCodeBlock* replaceCodeBlockWith(VM&, CodeSpecializationKind, CodeBlock*);
+
     RefPtr<TypeSet> returnStatementTypeSet() 
     {
         RareData& rareData = ensureRareData();
@@ -162,6 +160,7 @@
     SourceCode classSource() const { return m_unlinkedExecutable->classSource(); }
 
     DECLARE_VISIT_CHILDREN;
+    DECLARE_VISIT_OUTPUT_CONSTRAINTS;
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
     {
         return Structure::create(vm, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), info());
@@ -331,8 +330,8 @@
     std::unique_ptr<RareData> m_rareData;
     WriteBarrier<ScriptExecutable> m_topLevelExecutable;
     WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable;
-    WriteBarrier<ExecutableToCodeBlockEdge> m_codeBlockForCall;
-    WriteBarrier<ExecutableToCodeBlockEdge> m_codeBlockForConstruct;
+    WriteBarrier<CodeBlock> m_codeBlockForCall;
+    WriteBarrier<CodeBlock> m_codeBlockForConstruct;
     InferredValue<JSFunction> m_singleton;
     Box<InlineWatchpointSet> m_polyProtoWatchpoint;
 };

Modified: trunk/Source/_javascript_Core/runtime/FunctionExecutableInlines.h (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/FunctionExecutableInlines.h	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/FunctionExecutableInlines.h	2022-04-01 00:33:33 UTC (rev 292191)
@@ -27,6 +27,7 @@
 
 #include "FunctionExecutable.h"
 #include "InferredValueInlines.h"
+#include "ScriptExecutableInlines.h"
 
 namespace JSC {
 
@@ -33,10 +34,26 @@
 inline void FunctionExecutable::finalizeUnconditionally(VM& vm)
 {
     m_singleton.finalizeUnconditionally(vm);
+    finalizeCodeBlockEdge(vm, m_codeBlockForCall);
+    finalizeCodeBlockEdge(vm, m_codeBlockForConstruct);
+    vm.heap.functionExecutableSpaceAndSet.outputConstraintsSet.remove(this);
 }
 
-JSString* FunctionExecutable::toString(JSGlobalObject* globalObject)
+inline FunctionCodeBlock* FunctionExecutable::replaceCodeBlockWith(VM& vm, CodeSpecializationKind kind, CodeBlock* newCodeBlock)
 {
+    if (kind == CodeForCall) {
+        FunctionCodeBlock* oldCodeBlock = codeBlockForCall();
+        m_codeBlockForCall.setMayBeNull(vm, this, newCodeBlock);
+        return oldCodeBlock;
+    }
+    ASSERT(kind == CodeForConstruct);
+    FunctionCodeBlock* oldCodeBlock = codeBlockForConstruct();
+    m_codeBlockForConstruct.setMayBeNull(vm, this, newCodeBlock);
+    return oldCodeBlock;
+}
+
+inline JSString* FunctionExecutable::toString(JSGlobalObject* globalObject)
+{
     RareData& rareData = ensureRareData();
     if (!rareData.m_asString)
         return toStringSlow(globalObject);

Modified: trunk/Source/_javascript_Core/runtime/GlobalExecutable.cpp (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/GlobalExecutable.cpp	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/GlobalExecutable.cpp	2022-04-01 00:33:33 UTC (rev 292191)
@@ -26,10 +26,62 @@
 #include "config.h"
 #include "GlobalExecutable.h"
 
+#include "IsoCellSetInlines.h"
 #include "JSCellInlines.h"
+#include "ScriptExecutableInlines.h"
 
 namespace JSC {
 
 const ClassInfo GlobalExecutable::s_info = { "GlobalExecutable"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(GlobalExecutable) };
 
+template<typename Visitor>
+void GlobalExecutable::visitChildrenImpl(JSCell* cell, Visitor& visitor)
+{
+    auto* executable = jsCast<GlobalExecutable*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(executable, info());
+    Base::visitChildren(executable, visitor);
+    visitor.append(executable->m_unlinkedCodeBlock);
+
+    if (auto* codeBlock = executable->codeBlock()) {
+        // If CodeBlocks is not marked yet, we will run output-constraints.
+        // We maintain the invariant that, whenever we see unmarked CodeBlock, then we must run finalizer.
+        // And whenever we set a bit on outputConstraintsSet, we must already set a bit in finalizerSet.
+        visitCodeBlockEdge(visitor, codeBlock);
+        if (!visitor.isMarked(codeBlock)) {
+            Heap::ScriptExecutableSpaceAndSets::finalizerSetFor(*executable->subspace()).add(executable);
+            Heap::ScriptExecutableSpaceAndSets::outputConstraintsSetFor(*executable->subspace()).add(executable);
+        }
+    }
+}
+
+DEFINE_VISIT_CHILDREN(GlobalExecutable);
+
+template<typename Visitor>
+void GlobalExecutable::visitOutputConstraintsImpl(JSCell* cell, Visitor& visitor)
+{
+    auto* executable = jsCast<GlobalExecutable*>(cell);
+    if (CodeBlock* codeBlock = executable->codeBlock()) {
+        if (!visitor.isMarked(codeBlock))
+            runConstraint(NoLockingNecessary, visitor, codeBlock);
+        if (visitor.isMarked(codeBlock))
+            Heap::ScriptExecutableSpaceAndSets::outputConstraintsSetFor(*executable->subspace()).remove(executable);
+    }
+}
+
+DEFINE_VISIT_OUTPUT_CONSTRAINTS(GlobalExecutable);
+
+CodeBlock* GlobalExecutable::replaceCodeBlockWith(VM& vm, CodeBlock* newCodeBlock)
+{
+    CodeBlock* oldCodeBlock = codeBlock();
+    m_codeBlock.setMayBeNull(vm, this, newCodeBlock);
+    return oldCodeBlock;
+}
+
+void GlobalExecutable::finalizeUnconditionally(VM& vm)
+{
+    finalizeCodeBlockEdge(vm, m_codeBlock);
+    Heap::ScriptExecutableSpaceAndSets::outputConstraintsSetFor(*subspace()).remove(this);
+    Heap::ScriptExecutableSpaceAndSets::finalizerSetFor(*subspace()).remove(this);
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/GlobalExecutable.h (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/GlobalExecutable.h	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/GlobalExecutable.h	2022-04-01 00:33:33 UTC (rev 292191)
@@ -25,7 +25,6 @@
 
 #pragma once
 
-#include "ExecutableToCodeBlockEdge.h"
 #include "ScriptExecutable.h"
 
 namespace JSC {
@@ -48,12 +47,32 @@
         ASSERT(endColumn != UINT_MAX);
     }
 
+    DECLARE_VISIT_CHILDREN;
+    DECLARE_VISIT_OUTPUT_CONSTRAINTS;
+
+    void finalizeUnconditionally(VM&);
+
 protected:
+    friend class ScriptExecutable;
     GlobalExecutable(Structure* structure, VM& vm, const SourceCode& sourceCode, bool isInStrictContext, DerivedContextType derivedContextType, bool isInArrowFunctionContext, bool isInsideOrdinaryFunction, EvalContextType evalContextType, Intrinsic intrinsic)
         : Base(structure, vm, sourceCode, isInStrictContext ? StrictModeLexicalFeature : NoLexicalFeatures, derivedContextType, isInArrowFunctionContext, isInsideOrdinaryFunction, evalContextType, intrinsic)
     {
     }
 
+    CodeBlock* codeBlock() const
+    {
+        return m_codeBlock.get();
+    }
+
+    UnlinkedCodeBlock* unlinkedCodeBlock() const
+    {
+        return m_unlinkedCodeBlock.get();
+    }
+
+    CodeBlock* replaceCodeBlockWith(VM&, CodeBlock*);
+
+    WriteBarrier<CodeBlock> m_codeBlock;
+    WriteBarrier<UnlinkedCodeBlock> m_unlinkedCodeBlock;
     int m_lastLine { -1 };
     unsigned m_endColumn { UINT_MAX };
 };

Modified: trunk/Source/_javascript_Core/runtime/IndirectEvalExecutable.cpp (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/IndirectEvalExecutable.cpp	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/IndirectEvalExecutable.cpp	2022-04-01 00:33:33 UTC (rev 292191)
@@ -65,7 +65,7 @@
         return nullptr;
     }
 
-    executable->m_unlinkedEvalCodeBlock.set(vm, executable, unlinkedEvalCode);
+    executable->m_unlinkedCodeBlock.set(vm, executable, unlinkedEvalCode);
 
     return executable;
 }

Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2022-04-01 00:33:33 UTC (rev 292191)
@@ -31,6 +31,7 @@
 #include "CatchScope.h"
 #include "CommonIdentifiers.h"
 #include "CallFrame.h"
+#include "FunctionExecutableInlines.h"
 #include "GeneratorPrototype.h"
 #include "JSBoundFunction.h"
 #include "JSCInlines.h"

Modified: trunk/Source/_javascript_Core/runtime/JSModuleRecord.cpp (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/JSModuleRecord.cpp	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/JSModuleRecord.cpp	2022-04-01 00:33:33 UTC (rev 292191)
@@ -96,7 +96,7 @@
     RETURN_IF_EXCEPTION(scope, Synchronousness::Sync);
     m_moduleProgramExecutable.set(vm, this, executable);
 
-    return executable->unlinkedModuleProgramCodeBlock()->isAsync() ? Synchronousness::Async : Synchronousness::Sync;
+    return executable->unlinkedCodeBlock()->isAsync() ? Synchronousness::Async : Synchronousness::Sync;
 }
 
 void JSModuleRecord::instantiateDeclarations(JSGlobalObject* globalObject, ModuleProgramExecutable* moduleProgramExecutable, JSValue scriptFetcher)
@@ -209,7 +209,7 @@
     // section 15.2.1.16.4 step 16-a-iv.
     // Initialize heap allocated function declarations.
     // They can be called before the body of the module is executed under circular dependencies.
-    UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock = moduleProgramExecutable->unlinkedModuleProgramCodeBlock();
+    UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock = moduleProgramExecutable->unlinkedCodeBlock();
     for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) {
         UnlinkedFunctionExecutable* unlinkedFunctionExecutable = unlinkedCodeBlock->functionDecl(i);
         SymbolTableEntry entry = symbolTable->get(unlinkedFunctionExecutable->name().impl());

Modified: trunk/Source/_javascript_Core/runtime/ModuleProgramExecutable.cpp (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/ModuleProgramExecutable.cpp	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/ModuleProgramExecutable.cpp	2022-04-01 00:33:33 UTC (rev 292191)
@@ -62,7 +62,7 @@
         return nullptr;
     }
 
-    executable->m_unlinkedModuleProgramCodeBlock.set(globalObject->vm(), executable, unlinkedModuleProgramCode);
+    executable->m_unlinkedCodeBlock.set(globalObject->vm(), executable, unlinkedModuleProgramCode);
 
     executable->m_moduleEnvironmentSymbolTable.set(globalObject->vm(), executable, jsCast<SymbolTable*>(unlinkedModuleProgramCode->constantRegister(VirtualRegister(unlinkedModuleProgramCode->moduleEnvironmentSymbolTableConstantRegisterOffset())).get())->cloneScopePart(globalObject->vm()));
 
@@ -85,9 +85,7 @@
     ModuleProgramExecutable* thisObject = jsCast<ModuleProgramExecutable*>(cell);
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
     Base::visitChildren(thisObject, visitor);
-    visitor.append(thisObject->m_unlinkedModuleProgramCodeBlock);
     visitor.append(thisObject->m_moduleEnvironmentSymbolTable);
-    visitor.append(thisObject->m_moduleProgramCodeBlock);
     if (TemplateObjectMap* map = thisObject->m_templateObjectMap.get()) {
         Locker locker { thisObject->cellLock() };
         for (auto& entry : *map)

Modified: trunk/Source/_javascript_Core/runtime/ModuleProgramExecutable.h (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/ModuleProgramExecutable.h	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/ModuleProgramExecutable.h	2022-04-01 00:33:33 UTC (rev 292191)
@@ -25,7 +25,6 @@
 
 #pragma once
 
-#include "ExecutableToCodeBlockEdge.h"
 #include "GlobalExecutable.h"
 
 namespace JSC {
@@ -46,11 +45,16 @@
 
     static void destroy(JSCell*);
 
-    ModuleProgramCodeBlock* codeBlock()
+    ModuleProgramCodeBlock* codeBlock() const
     {
-        return bitwise_cast<ModuleProgramCodeBlock*>(ExecutableToCodeBlockEdge::unwrap(m_moduleProgramCodeBlock.get()));
+        return bitwise_cast<ModuleProgramCodeBlock*>(Base::codeBlock());
     }
 
+    UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock() const
+    {
+        return bitwise_cast<UnlinkedModuleProgramCodeBlock*>(Base::unlinkedCodeBlock());
+    }
+
     Ref<JITCode> generatedJITCode()
     {
         return generatedJITCodeForCall();
@@ -63,7 +67,6 @@
 
     DECLARE_INFO;
 
-    UnlinkedModuleProgramCodeBlock* unlinkedModuleProgramCodeBlock() { return m_unlinkedModuleProgramCodeBlock.get(); }
     bool isAsync() const { return features() & AwaitFeature; }
 
     SymbolTable* moduleEnvironmentSymbolTable() { return m_moduleEnvironmentSymbolTable.get(); }
@@ -78,9 +81,7 @@
 
     DECLARE_VISIT_CHILDREN;
 
-    WriteBarrier<UnlinkedModuleProgramCodeBlock> m_unlinkedModuleProgramCodeBlock;
     WriteBarrier<SymbolTable> m_moduleEnvironmentSymbolTable;
-    WriteBarrier<ExecutableToCodeBlockEdge> m_moduleProgramCodeBlock;
     std::unique_ptr<TemplateObjectMap> m_templateObjectMap;
 };
 

Modified: trunk/Source/_javascript_Core/runtime/ProgramExecutable.cpp (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/ProgramExecutable.cpp	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/ProgramExecutable.cpp	2022-04-01 00:33:33 UTC (rev 292191)
@@ -150,9 +150,8 @@
         }
     }
 
+    m_unlinkedCodeBlock.set(vm, this, unlinkedCodeBlock);
 
-    m_unlinkedProgramCodeBlock.set(vm, this, unlinkedCodeBlock);
-
     BatchedTransitionOptimizer optimizer(vm, globalObject);
 
     for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) {
@@ -216,8 +215,6 @@
     ProgramExecutable* thisObject = jsCast<ProgramExecutable*>(cell);
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
     Base::visitChildren(thisObject, visitor);
-    visitor.append(thisObject->m_unlinkedProgramCodeBlock);
-    visitor.append(thisObject->m_programCodeBlock);
     if (TemplateObjectMap* map = thisObject->m_templateObjectMap.get()) {
         Locker locker { thisObject->cellLock() };
         for (auto& entry : *map)

Modified: trunk/Source/_javascript_Core/runtime/ProgramExecutable.h (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/ProgramExecutable.h	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/ProgramExecutable.h	2022-04-01 00:33:33 UTC (rev 292191)
@@ -25,7 +25,6 @@
 
 #pragma once
 
-#include "ExecutableToCodeBlockEdge.h"
 #include "GlobalExecutable.h"
 
 namespace JSC {
@@ -56,11 +55,16 @@
 
     static void destroy(JSCell*);
 
-    ProgramCodeBlock* codeBlock()
+    ProgramCodeBlock* codeBlock() const
     {
-        return bitwise_cast<ProgramCodeBlock*>(ExecutableToCodeBlockEdge::unwrap(m_programCodeBlock.get()));
+        return bitwise_cast<ProgramCodeBlock*>(Base::codeBlock());
     }
 
+    UnlinkedProgramCodeBlock* unlinkedCodeBlock() const
+    {
+        return bitwise_cast<UnlinkedProgramCodeBlock*>(Base::unlinkedCodeBlock());
+    }
+
     Ref<JITCode> generatedJITCode()
     {
         return generatedJITCodeForCall();
@@ -83,8 +87,6 @@
 
     DECLARE_VISIT_CHILDREN;
 
-    WriteBarrier<UnlinkedProgramCodeBlock> m_unlinkedProgramCodeBlock;
-    WriteBarrier<ExecutableToCodeBlockEdge> m_programCodeBlock;
     std::unique_ptr<TemplateObjectMap> m_templateObjectMap;
 };
 

Modified: trunk/Source/_javascript_Core/runtime/ScriptExecutable.cpp (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/ScriptExecutable.cpp	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/ScriptExecutable.cpp	2022-04-01 00:33:33 UTC (rev 292191)
@@ -29,6 +29,7 @@
 #include "Debugger.h"
 #include "EvalCodeBlock.h"
 #include "FunctionCodeBlock.h"
+#include "FunctionExecutableInlines.h"
 #include "GlobalExecutable.h"
 #include "IsoCellSetInlines.h"
 #include "JIT.h"
@@ -86,20 +87,20 @@
     }
     case EvalExecutableType: {
         EvalExecutable* executable = static_cast<EvalExecutable*>(this);
-        executable->m_evalCodeBlock.clear();
-        executable->m_unlinkedEvalCodeBlock.clear();
+        executable->m_codeBlock.clear();
+        executable->m_unlinkedCodeBlock.clear();
         break;
     }
     case ProgramExecutableType: {
         ProgramExecutable* executable = static_cast<ProgramExecutable*>(this);
-        executable->m_programCodeBlock.clear();
-        executable->m_unlinkedProgramCodeBlock.clear();
+        executable->m_codeBlock.clear();
+        executable->m_unlinkedCodeBlock.clear();
         break;
     }
     case ModuleProgramExecutableType: {
         ModuleProgramExecutable* executable = static_cast<ModuleProgramExecutable*>(this);
-        executable->m_moduleProgramCodeBlock.clear();
-        executable->m_unlinkedModuleProgramCodeBlock.clear();
+        executable->m_codeBlock.clear();
+        executable->m_unlinkedCodeBlock.clear();
         executable->m_moduleEnvironmentSymbolTable.clear();
         break;
     }
@@ -108,7 +109,7 @@
         break;
     }
 
-    ASSERT(&Heap::SpaceAndSet::setFor(*subspace()) == &clearableCodeSet);
+    ASSERT(&Heap::ScriptExecutableSpaceAndSets::clearableCodeSetFor(*subspace()) == &clearableCodeSet);
     clearableCodeSet.remove(this);
 }
 
@@ -131,8 +132,7 @@
         
         ASSERT(kind == CodeForCall);
         
-        oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_programCodeBlock.get());
-        executable->m_programCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
+        oldCodeBlock = executable->replaceCodeBlockWith(vm, codeBlock);
         break;
     }
 
@@ -142,8 +142,7 @@
 
         ASSERT(kind == CodeForCall);
 
-        oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_moduleProgramCodeBlock.get());
-        executable->m_moduleProgramCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
+        oldCodeBlock = executable->replaceCodeBlockWith(vm, codeBlock);
         break;
     }
 
@@ -153,8 +152,7 @@
         
         ASSERT(kind == CodeForCall);
         
-        oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_evalCodeBlock.get());
-        executable->m_evalCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
+        oldCodeBlock = executable->replaceCodeBlockWith(vm, codeBlock);
         break;
     }
         
@@ -162,16 +160,7 @@
         FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
         FunctionCodeBlock* codeBlock = static_cast<FunctionCodeBlock*>(genericCodeBlock);
         
-        switch (kind) {
-        case CodeForCall:
-            oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_codeBlockForCall.get());
-            executable->m_codeBlockForCall.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
-            break;
-        case CodeForConstruct:
-            oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_codeBlockForConstruct.get());
-            executable->m_codeBlockForConstruct.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock));
-            break;
-        }
+        oldCodeBlock = executable->replaceCodeBlockWith(vm, kind, codeBlock);
         break;
     }
     }
@@ -187,7 +176,7 @@
         break;
     }
 
-    auto& clearableCodeSet = Heap::SpaceAndSet::setFor(*subspace());
+    auto& clearableCodeSet = Heap::ScriptExecutableSpaceAndSets::clearableCodeSetFor(*subspace());
     if (hasClearableCode(vm))
         clearableCodeSet.add(this);
     else
@@ -225,23 +214,23 @@
 
     if (structure(vm)->classInfo() == FunctionExecutable::info()) {
         auto* executable = static_cast<const FunctionExecutable*>(this);
-        if (executable->m_codeBlockForCall || executable->m_codeBlockForConstruct)
+        if (executable->eitherCodeBlock())
             return true;
 
     } else if (structure(vm)->classInfo() == EvalExecutable::info()) {
         auto* executable = static_cast<const EvalExecutable*>(this);
-        if (executable->m_evalCodeBlock || executable->m_unlinkedEvalCodeBlock)
+        if (executable->m_codeBlock || executable->m_unlinkedCodeBlock)
             return true;
 
     } else if (structure(vm)->classInfo() == ProgramExecutable::info()) {
         auto* executable = static_cast<const ProgramExecutable*>(this);
-        if (executable->m_programCodeBlock || executable->m_unlinkedProgramCodeBlock)
+        if (executable->m_codeBlock || executable->m_unlinkedCodeBlock)
             return true;
 
     } else if (structure(vm)->classInfo() == ModuleProgramExecutable::info()) {
         auto* executable = static_cast<const ModuleProgramExecutable*>(this);
-        if (executable->m_moduleProgramCodeBlock
-            || executable->m_unlinkedModuleProgramCodeBlock
+        if (executable->m_codeBlock
+            || executable->m_unlinkedCodeBlock
             || executable->m_moduleEnvironmentSymbolTable)
             return true;
     }
@@ -261,25 +250,25 @@
     if (classInfo(vm) == EvalExecutable::info()) {
         EvalExecutable* executable = jsCast<EvalExecutable*>(this);
         RELEASE_ASSERT(kind == CodeForCall);
-        RELEASE_ASSERT(!executable->m_evalCodeBlock);
+        RELEASE_ASSERT(!executable->m_codeBlock);
         RELEASE_ASSERT(!function);
-        RELEASE_AND_RETURN(throwScope, EvalCodeBlock::create(vm, executable, executable->m_unlinkedEvalCodeBlock.get(), scope));
+        RELEASE_AND_RETURN(throwScope, EvalCodeBlock::create(vm, executable, executable->unlinkedCodeBlock(), scope));
     }
 
     if (classInfo(vm) == ProgramExecutable::info()) {
         ProgramExecutable* executable = jsCast<ProgramExecutable*>(this);
         RELEASE_ASSERT(kind == CodeForCall);
-        RELEASE_ASSERT(!executable->m_programCodeBlock);
+        RELEASE_ASSERT(!executable->m_codeBlock);
         RELEASE_ASSERT(!function);
-        RELEASE_AND_RETURN(throwScope, ProgramCodeBlock::create(vm, executable, executable->m_unlinkedProgramCodeBlock.get(), scope));
+        RELEASE_AND_RETURN(throwScope, ProgramCodeBlock::create(vm, executable, executable->unlinkedCodeBlock(), scope));
     }
 
     if (classInfo(vm) == ModuleProgramExecutable::info()) {
         ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
         RELEASE_ASSERT(kind == CodeForCall);
-        RELEASE_ASSERT(!executable->m_moduleProgramCodeBlock);
+        RELEASE_ASSERT(!executable->m_codeBlock);
         RELEASE_ASSERT(!function);
-        RELEASE_AND_RETURN(throwScope, ModuleProgramCodeBlock::create(vm, executable, executable->m_unlinkedModuleProgramCodeBlock.get(), scope));
+        RELEASE_AND_RETURN(throwScope, ModuleProgramCodeBlock::create(vm, executable, executable->unlinkedCodeBlock(), scope));
     }
 
     RELEASE_ASSERT(classInfo(vm) == FunctionExecutable::info());
@@ -535,4 +524,62 @@
     return 0;
 }
 
+template<typename Visitor>
+void ScriptExecutable::runConstraint(const ConcurrentJSLocker& locker, Visitor& visitor, CodeBlock* codeBlock)
+{
+    ASSERT(codeBlock);
+    codeBlock->propagateTransitions(locker, visitor);
+    codeBlock->determineLiveness(locker, visitor);
+}
+
+template void ScriptExecutable::runConstraint(const ConcurrentJSLocker&, AbstractSlotVisitor&, CodeBlock*);
+template void ScriptExecutable::runConstraint(const ConcurrentJSLocker&, SlotVisitor&, CodeBlock*);
+
+template<typename Visitor>
+void ScriptExecutable::visitCodeBlockEdge(Visitor& visitor, CodeBlock* codeBlock)
+{
+    ASSERT(codeBlock);
+
+    ConcurrentJSLocker locker(codeBlock->m_lock);
+
+    if (codeBlock->shouldVisitStrongly(locker, visitor))
+        visitor.appendUnbarriered(codeBlock);
+
+    if (JITCode::isOptimizingJIT(codeBlock->jitType())) {
+        // If we jettison ourselves we'll install our alternative, so make sure that it
+        // survives GC even if we don't.
+        visitor.append(codeBlock->m_alternative);
+    }
+
+    // NOTE: There are two sides to this constraint, with different requirements for correctness.
+    // Because everything is ultimately protected with weak references and jettisoning, it's
+    // always "OK" to claim that something is dead prematurely and it's "OK" to keep things alive.
+    // But both choices could lead to bad perf - either recomp cycles or leaks.
+    //
+    // Determining CodeBlock liveness: This part is the most consequential. We want to keep the
+    // output constraint active so long as we think that we may yet prove that the CodeBlock is
+    // live but we haven't done it yet.
+    //
+    // Marking Structures if profitable: It's important that we do a pass of this. Logically, this
+    // seems like it is a constraint of CodeBlock. But we have always first run this as a result
+    // of the edge being marked even before we determine the liveness of the CodeBlock. This
+    // allows a CodeBlock to mark itself by first proving that all of the Structures it weakly
+    // depends on could be strongly marked. (This part is also called propagateTransitions.)
+    //
+    // As a weird caveat, we only fixpoint the constraints so long as the CodeBlock is not live.
+    // This means that we may overlook structure marking opportunities created by other marking
+    // that happens after the CodeBlock is marked. This was an accidental policy decision from a
+    // long time ago, but it is probably OK, since it's only worthwhile to keep fixpointing the
+    // structure marking if we still have unmarked structures after the first round. We almost
+    // never will because we will mark-if-profitable based on the owning global object being
+    // already marked. We mark it just in case that hadn't happened yet. And if the CodeBlock is
+    // not yet marked because it weakly depends on a structure that we did not yet mark, then we
+    // will keep fixpointing until the end.
+    visitor.appendUnbarriered(codeBlock->globalObject());
+    runConstraint(locker, visitor, codeBlock);
+}
+
+template void ScriptExecutable::visitCodeBlockEdge(AbstractSlotVisitor&, CodeBlock*);
+template void ScriptExecutable::visitCodeBlockEdge(SlotVisitor&, CodeBlock*);
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/ScriptExecutable.h (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/ScriptExecutable.h	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/ScriptExecutable.h	2022-04-01 00:33:33 UTC (rev 292191)
@@ -139,6 +139,12 @@
 
     static TemplateObjectMap& ensureTemplateObjectMapImpl(std::unique_ptr<TemplateObjectMap>& dest);
 
+    template<typename Visitor>
+    static void runConstraint(const ConcurrentJSLocker&, Visitor&, CodeBlock*);
+    template<typename Visitor>
+    static void visitCodeBlockEdge(Visitor&, CodeBlock*);
+    void finalizeCodeBlockEdge(VM&, WriteBarrier<CodeBlock>&);
+
     SourceCode m_source;
     Intrinsic m_intrinsic { NoIntrinsic };
     bool m_didTryToEnterInLoop { false };

Copied: trunk/Source/_javascript_Core/runtime/ScriptExecutableInlines.h (from rev 292190, trunk/Source/_javascript_Core/runtime/FunctionExecutableInlines.h) (0 => 292191)


--- trunk/Source/_javascript_Core/runtime/ScriptExecutableInlines.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/ScriptExecutableInlines.h	2022-04-01 00:33:33 UTC (rev 292191)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "ScriptExecutable.h"
+
+namespace JSC {
+
+inline void ScriptExecutable::finalizeCodeBlockEdge(VM& vm, WriteBarrier<CodeBlock>& codeBlockEdge)
+{
+    auto* codeBlock = codeBlockEdge.get();
+    if (!codeBlock)
+        return;
+
+    if (!vm.heap.isMarked(codeBlock)) {
+        if (codeBlock->shouldJettisonDueToWeakReference(vm))
+            codeBlock->jettison(Profiler::JettisonDueToWeakReference);
+        else
+            codeBlock->jettison(Profiler::JettisonDueToOldAge);
+        if (codeBlock == codeBlockEdge.get())
+            codeBlockEdge.clear();
+    }
+}
+
+} // namespace JSC
+

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2022-04-01 00:33:33 UTC (rev 292191)
@@ -47,7 +47,6 @@
 #include "ErrorInstance.h"
 #include "EvalCodeBlock.h"
 #include "Exception.h"
-#include "ExecutableToCodeBlockEdge.h"
 #include "FTLThunks.h"
 #include "FileBasedFuzzerAgent.h"
 #include "FunctionCodeBlock.h"
@@ -298,7 +297,6 @@
     hashMapBucketSetStructure.set(*this, HashMapBucket<HashMapBucketDataKey>::createStructure(*this, nullptr, jsNull()));
     hashMapBucketMapStructure.set(*this, HashMapBucket<HashMapBucketDataKeyValue>::createStructure(*this, nullptr, jsNull()));
     bigIntStructure.set(*this, JSBigInt::createStructure(*this, nullptr, jsNull()));
-    executableToCodeBlockEdgeStructure.set(*this, ExecutableToCodeBlockEdge::createStructure(*this, nullptr, jsNull()));
 
     // Eagerly initialize constant cells since the concurrent compiler can access them.
     if (Options::useJIT()) {

Modified: trunk/Source/_javascript_Core/runtime/VM.h (292190 => 292191)


--- trunk/Source/_javascript_Core/runtime/VM.h	2022-04-01 00:28:42 UTC (rev 292190)
+++ trunk/Source/_javascript_Core/runtime/VM.h	2022-04-01 00:33:33 UTC (rev 292191)
@@ -373,9 +373,6 @@
 
     FOR_EACH_JSC_DYNAMIC_ISO_SUBSPACE(DEFINE_DYNAMIC_ISO_SUBSPACE_ACCESSOR_IMPL)
 
-    ALWAYS_INLINE IsoCellSet& executableToCodeBlockEdgesWithConstraints() { return heap.executableToCodeBlockEdgesWithConstraints; }
-    ALWAYS_INLINE IsoCellSet& executableToCodeBlockEdgesWithFinalizers() { return heap.executableToCodeBlockEdgesWithFinalizers; }
-
     ALWAYS_INLINE GCClient::IsoSubspace& codeBlockSpace() { return clientHeap.codeBlockSpace; }
 
     DEFINE_DYNAMIC_ISO_SUBSPACE_ACCESSOR(evalExecutableSpace)
@@ -441,7 +438,6 @@
     Strong<Structure> hashMapBucketSetStructure;
     Strong<Structure> hashMapBucketMapStructure;
     Strong<Structure> bigIntStructure;
-    Strong<Structure> executableToCodeBlockEdgeStructure;
 
     Strong<JSPropertyNameEnumerator> m_emptyPropertyNameEnumerator;
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to