Changeset 292191 in webkit
- Timestamp:
- Mar 31, 2022, 5:33:33 PM (5 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 2 deleted
- 30 edited
- 1 copied
-
CMakeLists.txt (modified) (2 diffs)
-
ChangeLog (modified) (1 diff)
-
JavaScriptCore.xcodeproj/project.pbxproj (modified) (8 diffs)
-
Sources.txt (modified) (1 diff)
-
bytecode/CodeBlock.cpp (modified) (7 diffs)
-
bytecode/CodeBlock.h (modified) (7 diffs)
-
bytecode/ExecutableToCodeBlockEdge.cpp (deleted)
-
bytecode/ExecutableToCodeBlockEdge.h (deleted)
-
heap/Heap.cpp (modified) (6 diffs)
-
heap/Heap.h (modified) (6 diffs)
-
heap/IsoCellSet.h (modified) (2 diffs)
-
jit/JIT.cpp (modified) (1 diff)
-
llint/LowLevelInterpreter.asm (modified) (2 diffs)
-
runtime/DirectEvalExecutable.cpp (modified) (1 diff)
-
runtime/EvalExecutable.cpp (modified) (1 diff)
-
runtime/EvalExecutable.h (modified) (4 diffs)
-
runtime/FunctionExecutable.cpp (modified) (4 diffs)
-
runtime/FunctionExecutable.h (modified) (5 diffs)
-
runtime/FunctionExecutableInlines.h (modified) (2 diffs)
-
runtime/GlobalExecutable.cpp (modified) (2 diffs)
-
runtime/GlobalExecutable.h (modified) (3 diffs)
-
runtime/IndirectEvalExecutable.cpp (modified) (1 diff)
-
runtime/JSFunction.cpp (modified) (1 diff)
-
runtime/JSModuleRecord.cpp (modified) (2 diffs)
-
runtime/ModuleProgramExecutable.cpp (modified) (2 diffs)
-
runtime/ModuleProgramExecutable.h (modified) (4 diffs)
-
runtime/ProgramExecutable.cpp (modified) (2 diffs)
-
runtime/ProgramExecutable.h (modified) (3 diffs)
-
runtime/ScriptExecutable.cpp (modified) (13 diffs)
-
runtime/ScriptExecutable.h (modified) (1 diff)
-
runtime/ScriptExecutableInlines.h (copied) (copied from trunk/Source/JavaScriptCore/runtime/FunctionExecutableInlines.h ) (2 diffs)
-
runtime/VM.cpp (modified) (2 diffs)
-
runtime/VM.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/CMakeLists.txt
r292083 r292191 628 628 bytecode/DirectEvalCodeCache.h 629 629 bytecode/ExecutableInfo.h 630 bytecode/ExecutableToCodeBlockEdge.h631 630 bytecode/ExecutionCounter.h 632 631 bytecode/ExitKind.h … … 1154 1153 runtime/Scribble.h 1155 1154 runtime/ScriptExecutable.h 1155 runtime/ScriptExecutableInlines.h 1156 1156 runtime/ScriptFetchParameters.h 1157 1157 runtime/ScriptFetcher.h -
trunk/Source/JavaScriptCore/ChangeLog
r292181 r292191 1 2022-03-31 Yusuke Suzuki <ysuzuki@apple.com> 2 3 [JSC] Remove ExecutableToCodeBlockEdge 4 https://bugs.webkit.org/show_bug.cgi?id=238485 5 6 Reviewed by Keith Miller. 7 8 It turned out that getting CodeBlock from JSFunction is critical. As we start using unlinked Baseline, we are loading 9 CodeBlock from JSFunction instead of embedding it, and it roughly contributes to 0.5% regression in Speedometer2. 10 It is also crucial to some other places: bound function thunk, remote function thunk, and virtual function calls. 11 While the subsequent patch will embed CodeBlock into CallLinkInfo to make it fast, we also would like to keep loading 12 CodeBlock from JSFunction faster since this is still used in bound function thunk etc. 13 14 In this patch, we remove ExecutableToCodeBlockEdge to remove one-level indirection between Executable to CodeBlock. 15 We can delegate ExecutableToCodeBlockEdge's job to existing Executables so that we can keep the current weak-edge 16 feature without introducing ExecutableToCodeBlockEdge. It also removes ExecutableToCodeBlockEdge allocations and 17 shrinks sizeof(CodeBlock) by 8 byte. 18 19 We move key functions from ExecutableToCodeBlockEdge to ScriptExecutable, and we maintain Executable-to-CodeBlock edge 20 in Executable side. 21 22 Local testing showed that 0.3% progression in Speedometer2. 23 24 * CMakeLists.txt: 25 * JavaScriptCore.xcodeproj/project.pbxproj: 26 * Sources.txt: 27 * bytecode/CodeBlock.cpp: 28 (JSC::CodeBlock::finishCreation): 29 (JSC::CodeBlock::visitChildrenImpl): 30 (JSC::CodeBlock::visitChildren): 31 (JSC::CodeBlock::finalizeUnconditionally): 32 (JSC::CodeBlock::stronglyVisitStrongReferences): 33 (JSC::CodeBlock::finishCreationCommon): Deleted. 34 * bytecode/CodeBlock.h: 35 (JSC::CodeBlock::ownerEdge const): Deleted. 36 * bytecode/ExecutableToCodeBlockEdge.cpp: Removed. 37 * bytecode/ExecutableToCodeBlockEdge.h: Removed. 38 * heap/Heap.cpp: 39 (JSC::Heap::Heap): 40 (JSC::Heap::finalizeUnconditionalFinalizers): 41 (JSC::Heap::deleteAllCodeBlocks): 42 (JSC::Heap::addCoreConstraints): 43 * heap/Heap.h: 44 (JSC::Heap::ScriptExecutableSpaceAndSet::ScriptExecutableSpaceAndSet): 45 (JSC::Heap::ScriptExecutableSpaceAndSet::setAndSpaceFor): 46 (JSC::Heap::ScriptExecutableSpaceAndSet::clearableCodeSetFor): 47 (JSC::Heap::ScriptExecutableSpaceAndSet::outputConstraintsSetFor): 48 (JSC::Heap::ScriptExecutableSpaceAndSet::finalizerSetFor): 49 * heap/IsoCellSet.h: 50 * jit/JIT.cpp: 51 (JSC::JIT::emitPutCodeBlockToFrameInPrologue): 52 * llint/LowLevelInterpreter.asm: 53 * runtime/DirectEvalExecutable.cpp: 54 (JSC::DirectEvalExecutable::create): 55 * runtime/EvalExecutable.cpp: 56 (JSC::EvalExecutable::visitChildrenImpl): 57 * runtime/EvalExecutable.h: 58 (JSC::EvalExecutable::codeBlock const): 59 (JSC::EvalExecutable::unlinkedCodeBlock const): 60 (JSC::EvalExecutable::numVariables): 61 (JSC::EvalExecutable::numFunctionHoistingCandidates): 62 (JSC::EvalExecutable::numTopLevelFunctionDecls): 63 (JSC::EvalExecutable::allowDirectEvalCache const): 64 (JSC::EvalExecutable::codeBlock): Deleted. 65 * runtime/FunctionExecutable.cpp: 66 (JSC::FunctionExecutable::baselineCodeBlockFor): 67 (JSC::shouldKeepInConstraintSet): 68 (JSC::FunctionExecutable::visitChildrenImpl): 69 (JSC::FunctionExecutable::visitOutputConstraintsImpl): 70 * runtime/FunctionExecutable.h: 71 * runtime/FunctionExecutableInlines.h: 72 (JSC::FunctionExecutable::finalizeUnconditionally): 73 (JSC::FunctionExecutable::replaceCodeBlockWith): 74 (JSC::FunctionExecutable::toString): 75 * runtime/GlobalExecutable.cpp: 76 (JSC::GlobalExecutable::visitChildrenImpl): 77 (JSC::GlobalExecutable::visitOutputConstraintsImpl): 78 (JSC::GlobalExecutable::replaceCodeBlockWith): 79 (JSC::GlobalExecutable::finalizeUnconditionally): 80 * runtime/GlobalExecutable.h: 81 (JSC::GlobalExecutable::codeBlock const): 82 (JSC::GlobalExecutable::unlinkedCodeBlock const): 83 * runtime/IndirectEvalExecutable.cpp: 84 (JSC::IndirectEvalExecutable::createImpl): 85 * runtime/JSFunction.cpp: 86 * runtime/JSModuleRecord.cpp: 87 (JSC::JSModuleRecord::link): 88 (JSC::JSModuleRecord::instantiateDeclarations): 89 * runtime/ModuleProgramExecutable.cpp: 90 (JSC::ModuleProgramExecutable::create): 91 (JSC::ModuleProgramExecutable::visitChildrenImpl): 92 * runtime/ModuleProgramExecutable.h: 93 * runtime/ProgramExecutable.cpp: 94 (JSC::ProgramExecutable::initializeGlobalProperties): 95 (JSC::ProgramExecutable::visitChildrenImpl): 96 * runtime/ProgramExecutable.h: 97 * runtime/ScriptExecutable.cpp: 98 (JSC::ScriptExecutable::clearCode): 99 (JSC::ScriptExecutable::installCode): 100 (JSC::ScriptExecutable::hasClearableCode const): 101 (JSC::ScriptExecutable::newCodeBlockFor): 102 (JSC::ScriptExecutable::runConstraint): 103 (JSC::ScriptExecutable::visitCodeBlockEdge): 104 * runtime/ScriptExecutable.h: 105 * runtime/ScriptExecutableInlines.h: Copied from Source/JavaScriptCore/runtime/FunctionExecutableInlines.h. 106 (JSC::ScriptExecutable::finalizeCodeBlockEdge): 107 * runtime/VM.cpp: 108 (JSC::VM::VM): 109 * runtime/VM.h: 110 (JSC::VM::executableToCodeBlockEdgesWithConstraints): Deleted. 111 (JSC::VM::executableToCodeBlockEdgesWithFinalizers): Deleted. 112 1 113 2022-03-31 Patrick Angle <pangle@apple.com> 2 114 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r292083 r292191 371 371 0F5E0FE72086AD480097F0DE /* IsoSubspacePerVM.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5E0FE52086AD460097F0DE /* IsoSubspacePerVM.h */; settings = {ATTRIBUTES = (Private, ); }; }; 372 372 0F5EF91F16878F7D003E5C25 /* JITThunks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5EF91C16878F78003E5C25 /* JITThunks.h */; settings = {ATTRIBUTES = (Private, ); }; }; 373 0F60FE901FFC37020003320A /* ExecutableToCodeBlockEdge.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F60FE8E1FFC36FD0003320A /* ExecutableToCodeBlockEdge.h */; settings = {ATTRIBUTES = (Private, ); }; };374 373 0F61832A1C45BF070072450B /* AirCCallingConvention.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6183211C45BF070072450B /* AirCCallingConvention.h */; }; 375 374 0F61832D1C45BF070072450B /* AirEmitShuffle.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6183241C45BF070072450B /* AirEmitShuffle.h */; }; … … 1990 1989 E386FD7F26E867B800E4C28B /* TemporalPlainTimePrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = E386FD7926E867B800E4C28B /* TemporalPlainTimePrototype.h */; }; 1991 1990 E3893A1D2203A7C600E79A74 /* AsyncFromSyncIteratorPrototype.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = E3893A1C2203A7C600E79A74 /* AsyncFromSyncIteratorPrototype.lut.h */; }; 1991 E38DB2E727F588F80027BD3F /* ScriptExecutableInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E38DB2E627F588F70027BD3F /* ScriptExecutableInlines.h */; }; 1992 1992 E38E8790254B978400F6F9E4 /* JSDateMath.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9788FC221471AD0C0068CE2D /* JSDateMath.cpp */; }; 1993 1993 E39006212208BFC4001019CF /* SubspaceAccess.h in Headers */ = {isa = PBXBuildFile; fileRef = E39006202208BFC3001019CF /* SubspaceAccess.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 2898 2898 0F5EF91B16878F78003E5C25 /* JITThunks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITThunks.cpp; sourceTree = "<group>"; }; 2899 2899 0F5EF91C16878F78003E5C25 /* JITThunks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITThunks.h; sourceTree = "<group>"; }; 2900 0F60FE8D1FFC36FC0003320A /* ExecutableToCodeBlockEdge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExecutableToCodeBlockEdge.cpp; sourceTree = "<group>"; };2901 0F60FE8E1FFC36FD0003320A /* ExecutableToCodeBlockEdge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExecutableToCodeBlockEdge.h; sourceTree = "<group>"; };2902 2900 0F6183201C45BF070072450B /* AirCCallingConvention.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirCCallingConvention.cpp; path = b3/air/AirCCallingConvention.cpp; sourceTree = "<group>"; }; 2903 2901 0F6183211C45BF070072450B /* AirCCallingConvention.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirCCallingConvention.h; path = b3/air/AirCCallingConvention.h; sourceTree = "<group>"; }; … … 5480 5478 E38D060C1F8E814100649CF2 /* ScriptFetchParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptFetchParameters.h; sourceTree = "<group>"; }; 5481 5479 E38D060D1F8E814100649CF2 /* JSScriptFetchParameters.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSScriptFetchParameters.cpp; sourceTree = "<group>"; }; 5480 E38DB2E627F588F70027BD3F /* ScriptExecutableInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptExecutableInlines.h; sourceTree = "<group>"; }; 5482 5481 E39006202208BFC3001019CF /* SubspaceAccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SubspaceAccess.h; sourceTree = "<group>"; }; 5483 5482 E3915C062309682900CB2561 /* WasmContext.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WasmContext.cpp; sourceTree = "<group>"; }; … … 8225 8224 147341E01DC2CE9600AA29BA /* ScriptExecutable.cpp */, 8226 8225 147341CD1DC02D7900AA29BA /* ScriptExecutable.h */, 8226 E38DB2E627F588F70027BD3F /* ScriptExecutableInlines.h */, 8227 8227 8852151A9C3842389B3215B7 /* ScriptFetcher.h */, 8228 8228 E38D060C1F8E814100649CF2 /* ScriptFetchParameters.h */, … … 8978 8978 14AD91061DCA92940014F9FE /* EvalCodeBlock.h */, 8979 8979 14142E521B796EDD00F4BF4B /* ExecutableInfo.h */, 8980 0F60FE8D1FFC36FC0003320A /* ExecutableToCodeBlockEdge.cpp */,8981 0F60FE8E1FFC36FD0003320A /* ExecutableToCodeBlockEdge.h */,8982 8980 0F56A1D415001CF2002992B1 /* ExecutionCounter.cpp */, 8983 8981 0F56A1D115000F31002992B1 /* ExecutionCounter.h */, … … 10274 10272 14142E531B796EDD00F4BF4B /* ExecutableInfo.h in Headers */, 10275 10273 0F5193F7266C432D00483A2C /* ExecutableMemoryHandle.h in Headers */, 10276 0F60FE901FFC37020003320A /* ExecutableToCodeBlockEdge.h in Headers */,10277 10274 0F56A1D315000F35002992B1 /* ExecutionCounter.h in Headers */, 10278 10275 0F44A7B020BF68620022B171 /* ExitFlag.h in Headers */, … … 11045 11042 A5FD007E189B0B4C00633231 /* ScriptCallStackFactory.h in Headers */, 11046 11043 147341CE1DC02D7900AA29BA /* ScriptExecutable.h in Headers */, 11044 E38DB2E727F588F80027BD3F /* ScriptExecutableInlines.h in Headers */, 11047 11045 CEAE7D7B889B477BA93ABA6C /* ScriptFetcher.h in Headers */, 11048 11046 E3201C1E1F8E824C0076A032 /* ScriptFetchParameters.h in Headers */, -
trunk/Source/JavaScriptCore/Sources.txt
r290209 r292191 230 230 bytecode/DirectEvalCodeCache.cpp 231 231 bytecode/EvalCodeBlock.cpp 232 bytecode/ExecutableToCodeBlockEdge.cpp233 232 bytecode/ExecutionCounter.cpp 234 233 bytecode/ExitFlag.cpp -
trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp
r291779 r292191 312 312 { 313 313 Base::finishCreation(vm); 314 finishCreationCommon(vm);315 314 316 315 optimizeAfterWarmUp(); … … 368 367 { 369 368 Base::finishCreation(vm); 370 finishCreationCommon(vm);371 369 372 370 ASSERT(vm.heap.isDeferred()); … … 765 763 766 764 return true; 767 }768 769 void CodeBlock::finishCreationCommon(VM& vm)770 {771 m_ownerEdge.set(vm, this, ExecutableToCodeBlockEdge::create(vm, this));772 765 } 773 766 … … 1052 1045 ASSERT_GC_OBJECT_INHERITS(thisObject, info()); 1053 1046 Base::visitChildren(cell, visitor); 1054 visitor.append(thisObject->m_ownerEdge);1055 1047 thisObject->visitChildren(visitor); 1056 1048 } … … 1080 1072 stronglyVisitWeakReferences(locker, visitor); 1081 1073 1082 Heap:: SpaceAndSet::setFor(*subspace()).add(this);1074 Heap::CodeBlockSpaceAndSet::setFor(*subspace()).add(this); 1083 1075 } 1084 1076 … … 1668 1660 updateActivity(); 1669 1661 1670 Heap:: SpaceAndSet::setFor(*subspace()).remove(this);1662 Heap::CodeBlockSpaceAndSet::setFor(*subspace()).remove(this); 1671 1663 1672 1664 // In CodeBlock::shouldVisitStrongly() we may have decided to skip visiting this … … 1835 1827 1836 1828 visitor.append(m_globalObject); 1837 visitor.append(m_ownerExecutable); // This is extra important since it causes the Executable ToCodeBlockEdge to be marked.1829 visitor.append(m_ownerExecutable); // This is extra important since it causes the Executable -> CodeBlock edge activated. 1838 1830 visitor.append(m_unlinkedCode); 1839 1831 if (m_rareData) -
trunk/Source/JavaScriptCore/bytecode/CodeBlock.h
r290788 r292191 88 88 class BytecodeLivenessAnalysis; 89 89 class CodeBlockSet; 90 class ExecutableToCodeBlockEdge;91 90 class JSModuleEnvironment; 92 91 class LLIntOffsetsExtractor; … … 94 93 class MetadataTable; 95 94 class RegisterAtOffsetList; 95 class ScriptExecutable; 96 96 class StructureStubInfo; 97 97 class BaselineJITCode; … … 135 135 void finishCreation(VM&, CopyParsedBlockTag, CodeBlock& other); 136 136 bool finishCreation(VM&, ScriptExecutable* ownerExecutable, UnlinkedCodeBlock*, JSScope*); 137 138 void finishCreationCommon(VM&);139 137 140 138 WriteBarrier<JSGlobalObject> m_globalObject; … … 370 368 ScriptExecutable* ownerExecutable() const { return m_ownerExecutable.get(); } 371 369 372 ExecutableToCodeBlockEdge* ownerEdge() const { return m_ownerEdge.get(); }373 374 370 VM& vm() const { return *m_vm; } 375 371 … … 850 846 private: 851 847 friend class CodeBlockSet; 852 friend class ExecutableToCodeBlockEdge; 848 friend class FunctionExecutable; 849 friend class ScriptExecutable; 853 850 854 851 template<typename Visitor> ALWAYS_INLINE void visitChildren(Visitor&); … … 924 921 WriteBarrier<UnlinkedCodeBlock> m_unlinkedCode; 925 922 WriteBarrier<ScriptExecutable> m_ownerExecutable; 926 WriteBarrier<ExecutableToCodeBlockEdge> m_ownerEdge;927 923 // m_vm must be a pointer (instead of a reference) because the JSCLLIntOffsetsExtractor 928 924 // cannot handle it being a reference. … … 976 972 }; 977 973 #if !ASSERT_ENABLED && COMPILER(GCC_COMPATIBLE) 978 static_assert(sizeof(CodeBlock) <= 2 56, "Keep it small for memory saving");974 static_assert(sizeof(CodeBlock) <= 240, "Keep it small for memory saving"); 979 975 #endif 980 976 -
trunk/Source/JavaScriptCore/heap/Heap.cpp
r290129 r292191 369 369 FOR_EACH_JSC_COMMON_ISO_SUBSPACE(INIT_SERVER_ISO_SUBSPACE) 370 370 FOR_EACH_JSC_STRUCTURE_ISO_SUBSPACE(INIT_SERVER_STRUCTURE_ISO_SUBSPACE) 371 , executableToCodeBlockEdgesWithConstraints(executableToCodeBlockEdgeSpace)372 , executableToCodeBlockEdgesWithFinalizers(executableToCodeBlockEdgeSpace)373 371 , codeBlockSpaceAndSet ISO_SUBSPACE_INIT(*this, destructibleCellHeapCellType, CodeBlock) // Hash:0x77e66ec9 374 372 , functionExecutableSpaceAndSet ISO_SUBSPACE_INIT(*this, destructibleCellHeapCellType, FunctionExecutable) // Hash:0x5d158f3 … … 675 673 VM& vm = this->vm(); 676 674 vm.builtinExecutables()->finalizeUnconditionally(); 677 finalizeMarkedUnconditionalFinalizers<FunctionExecutable>(functionExecutableSpaceAndSet.space); 675 676 { 677 // We run this before CodeBlock's unconditional finalizer since CodeBlock looks at the owner executable's installed CodeBlock in its finalizeUnconditionally. 678 679 // FunctionExecutable requires all live instances to run finalizers. Thus, we do not use finalizer set. 680 finalizeMarkedUnconditionalFinalizers<FunctionExecutable>(functionExecutableSpaceAndSet.space); 681 682 finalizeMarkedUnconditionalFinalizers<ProgramExecutable>(programExecutableSpaceAndSet.finalizerSet); 683 if (m_evalExecutableSpace) 684 finalizeMarkedUnconditionalFinalizers<EvalExecutable>(m_evalExecutableSpace->finalizerSet); 685 if (m_moduleProgramExecutableSpace) 686 finalizeMarkedUnconditionalFinalizers<ModuleProgramExecutable>(m_moduleProgramExecutableSpace->finalizerSet); 687 } 688 678 689 finalizeMarkedUnconditionalFinalizers<SymbolTable>(symbolTableSpace); 679 finalizeMarkedUnconditionalFinalizers<ExecutableToCodeBlockEdge>(executableToCodeBlockEdgesWithFinalizers); // We run this before CodeBlock's unconditional finalizer since CodeBlock looks at the owner executable's installed CodeBlock in its finalizeUnconditionally. 690 680 691 forEachCodeBlockSpace( 681 692 [&] (auto& space) { … … 1004 1015 [&] (auto& spaceAndSet) { 1005 1016 HeapIterationScope heapIterationScope(*this); 1006 auto& set = spaceAndSet. set;1017 auto& set = spaceAndSet.clearableCodeSet; 1007 1018 set.forEachLiveCell( 1008 1019 [&] (HeapCell* cell, HeapCell::Kind) { … … 2918 2929 { 2919 2930 SetRootMarkReasonScope rootScope(visitor, RootMarkReason::ExecutableToCodeBlockEdges); 2920 add(heap->executableToCodeBlockEdgesWithConstraints); 2931 add(heap->functionExecutableSpaceAndSet.outputConstraintsSet); 2932 add(heap->programExecutableSpaceAndSet.outputConstraintsSet); 2933 if (heap->m_evalExecutableSpace) 2934 add(heap->m_evalExecutableSpace->outputConstraintsSet); 2935 if (heap->m_moduleProgramExecutableSpace) 2936 add(heap->m_moduleProgramExecutableSpace->outputConstraintsSet); 2921 2937 } 2922 2938 if (heap->m_weakMapSpace) { … … 3170 3186 #undef DEFINE_DYNAMIC_ISO_SUBSPACE_MEMBER_SLOW 3171 3187 3172 #define DEFINE_DYNAMIC_SPACE_AND_SET_MEMBER_SLOW(name, heapCellType, type ) \3188 #define DEFINE_DYNAMIC_SPACE_AND_SET_MEMBER_SLOW(name, heapCellType, type, spaceType) \ 3173 3189 IsoSubspace* Heap::name##Slow() \ 3174 3190 { \ 3175 3191 ASSERT(!m_##name); \ 3176 auto space = makeUnique< SpaceAndSet> ISO_SUBSPACE_INIT(*this, heapCellType, type); \3192 auto space = makeUnique<spaceType> ISO_SUBSPACE_INIT(*this, heapCellType, type); \ 3177 3193 WTF::storeStoreFence(); \ 3178 3194 m_##name = WTFMove(space); \ … … 3180 3196 } 3181 3197 3182 DEFINE_DYNAMIC_SPACE_AND_SET_MEMBER_SLOW(evalExecutableSpace, destructibleCellHeapCellType, EvalExecutable ) // Hash:0x958e3e9d3183 DEFINE_DYNAMIC_SPACE_AND_SET_MEMBER_SLOW(moduleProgramExecutableSpace, destructibleCellHeapCellType, ModuleProgramExecutable ) // Hash:0x6506fa3c3198 DEFINE_DYNAMIC_SPACE_AND_SET_MEMBER_SLOW(evalExecutableSpace, destructibleCellHeapCellType, EvalExecutable, Heap::ScriptExecutableSpaceAndSets) // Hash:0x958e3e9d 3199 DEFINE_DYNAMIC_SPACE_AND_SET_MEMBER_SLOW(moduleProgramExecutableSpace, destructibleCellHeapCellType, ModuleProgramExecutable, Heap::ScriptExecutableSpaceAndSets) // Hash:0x6506fa3c 3184 3200 3185 3201 #undef DEFINE_DYNAMIC_SPACE_AND_SET_MEMBER_SLOW -
trunk/Source/JavaScriptCore/heap/Heap.h
r290209 r292191 121 121 v(domAttributeGetterSetterSpace, cellHeapCellType, DOMAttributeGetterSetter) \ 122 122 v(exceptionSpace, destructibleCellHeapCellType, Exception) \ 123 v(executableToCodeBlockEdgeSpace, cellHeapCellType, ExecutableToCodeBlockEdge) \124 123 v(functionSpace, cellHeapCellType, JSFunction) \ 125 124 v(getterSetterSpace, cellHeapCellType, GetterSetter) \ … … 1030 1029 #undef DEFINE_DYNAMIC_ISO_SUBSPACE_MEMBER 1031 1030 1032 IsoCellSet executableToCodeBlockEdgesWithConstraints; 1033 IsoCellSet executableToCodeBlockEdgesWithFinalizers; 1034 1035 #define DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(name) \ 1031 #define DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(name, type) \ 1036 1032 template<SubspaceAccess mode> \ 1037 1033 IsoSubspace* name() \ … … 1044 1040 } \ 1045 1041 IsoSubspace* name##Slow(); \ 1046 std::unique_ptr< SpaceAndSet> m_##name;1042 std::unique_ptr<type> m_##name; 1047 1043 1048 1044 struct SpaceAndSet { … … 1068 1064 }; 1069 1065 1070 SpaceAndSet codeBlockSpaceAndSet; 1066 using CodeBlockSpaceAndSet = SpaceAndSet; 1067 CodeBlockSpaceAndSet codeBlockSpaceAndSet; 1071 1068 1072 1069 template<typename Func> … … 1076 1073 } 1077 1074 1078 DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(evalExecutableSpace) 1079 DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(moduleProgramExecutableSpace) 1080 SpaceAndSet functionExecutableSpaceAndSet; 1081 SpaceAndSet programExecutableSpaceAndSet; 1075 struct ScriptExecutableSpaceAndSets { 1076 WTF_MAKE_STRUCT_FAST_ALLOCATED; 1077 1078 IsoSubspace space; 1079 IsoCellSet clearableCodeSet; 1080 IsoCellSet outputConstraintsSet; 1081 IsoCellSet finalizerSet; 1082 1083 template<typename... Arguments> 1084 ScriptExecutableSpaceAndSets(Arguments&&... arguments) 1085 : space(std::forward<Arguments>(arguments)...) 1086 , clearableCodeSet(space) 1087 , outputConstraintsSet(space) 1088 , finalizerSet(space) 1089 { 1090 } 1091 1092 static ScriptExecutableSpaceAndSets& setAndSpaceFor(Subspace& space) 1093 { 1094 return *bitwise_cast<ScriptExecutableSpaceAndSets*>( 1095 bitwise_cast<char*>(&space) - 1096 OBJECT_OFFSETOF(ScriptExecutableSpaceAndSets, space)); 1097 } 1098 1099 static IsoCellSet& clearableCodeSetFor(Subspace& space) { return setAndSpaceFor(space).clearableCodeSet; } 1100 static IsoCellSet& outputConstraintsSetFor(Subspace& space) { return setAndSpaceFor(space).outputConstraintsSet; } 1101 static IsoCellSet& finalizerSetFor(Subspace& space) { return setAndSpaceFor(space).finalizerSet; } 1102 }; 1103 1104 DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(evalExecutableSpace, ScriptExecutableSpaceAndSets) 1105 DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER(moduleProgramExecutableSpace, ScriptExecutableSpaceAndSets) 1106 ScriptExecutableSpaceAndSets functionExecutableSpaceAndSet; 1107 ScriptExecutableSpaceAndSets programExecutableSpaceAndSet; 1082 1108 1083 1109 template<typename Func> … … 1092 1118 } 1093 1119 1094 SpaceAndSet unlinkedFunctionExecutableSpaceAndSet; 1120 using UnlinkedFunctionExecutableSpaceAndSet = SpaceAndSet; 1121 UnlinkedFunctionExecutableSpaceAndSet unlinkedFunctionExecutableSpaceAndSet; 1095 1122 1096 1123 Vector<IsoSubspacePerVM*> perVMIsoSubspaces; -
trunk/Source/JavaScriptCore/heap/IsoCellSet.h
r273138 r292191 30 30 #include <wtf/ConcurrentVector.h> 31 31 #include <wtf/FastBitVector.h> 32 #include <wtf/Noncopyable.h> 33 #include <wtf/Nonmovable.h> 32 34 #include <wtf/SentinelLinkedList.h> 33 35 #include <wtf/SharedTask.h> … … 41 43 // removal. Each such set should be thought of as a 0.8% increase in object size for objects in that 42 44 // IsoSubspace (it's like adding 1 bit every 16 bytes, or 1 bit every 128 bits). 43 class IsoCellSet : public PackedRawSentinelNode<IsoCellSet> { 45 class IsoCellSet final : public PackedRawSentinelNode<IsoCellSet> { 46 WTF_MAKE_NONCOPYABLE(IsoCellSet); 47 WTF_MAKE_NONMOVABLE(IsoCellSet); 44 48 public: 45 49 IsoCellSet(IsoSubspace& subspace); -
trunk/Source/JavaScriptCore/jit/JIT.cpp
r292083 r292191 216 216 else 217 217 loadPtr(Address(result, FunctionExecutable::offsetOfCodeBlockForCall()), result); 218 219 loadPtr(Address(result, ExecutableToCodeBlockEdge::offsetOfCodeBlock()), result);220 218 emitPutToCallFrameHeader(result, CallFrameSlot::codeBlock); 221 219 -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
r292080 r292191 1494 1494 .isExecutable: 1495 1495 loadp FunctionExecutable::m_codeBlockForCall[targetRegister], targetRegister 1496 loadp ExecutableToCodeBlockEdge::m_codeBlock[targetRegister], targetRegister1497 1496 end 1498 1497 … … 1508 1507 .isExecutable: 1509 1508 loadp FunctionExecutable::m_codeBlockForConstruct[targetRegister], targetRegister 1510 loadp ExecutableToCodeBlockEdge::m_codeBlock[targetRegister], targetRegister1511 1509 end 1512 1510 -
trunk/Source/JavaScriptCore/runtime/DirectEvalExecutable.cpp
r287303 r292191 64 64 } 65 65 66 executable->m_unlinked EvalCodeBlock.set(vm, executable, unlinkedEvalCode);66 executable->m_unlinkedCodeBlock.set(vm, executable, unlinkedEvalCode); 67 67 68 68 return executable; -
trunk/Source/JavaScriptCore/runtime/EvalExecutable.cpp
r291779 r292191 57 57 ASSERT_GC_OBJECT_INHERITS(thisObject, info()); 58 58 Base::visitChildren(thisObject, visitor); 59 visitor.append(thisObject->m_unlinkedEvalCodeBlock);60 visitor.append(thisObject->m_evalCodeBlock);61 59 if (TemplateObjectMap* map = thisObject->m_templateObjectMap.get()) { 62 60 Locker locker { thisObject->cellLock() }; -
trunk/Source/JavaScriptCore/runtime/EvalExecutable.h
r290129 r292191 26 26 #pragma once 27 27 28 #include "ExecutableToCodeBlockEdge.h"29 28 #include "GlobalExecutable.h" 30 29 #include "UnlinkedEvalCodeBlock.h" … … 40 39 static void destroy(JSCell*); 41 40 42 EvalCodeBlock* codeBlock() 41 EvalCodeBlock* codeBlock() const 43 42 { 44 return bitwise_cast<EvalCodeBlock*>(ExecutableToCodeBlockEdge::unwrap(m_evalCodeBlock.get())); 43 return bitwise_cast<EvalCodeBlock*>(Base::codeBlock()); 44 } 45 46 UnlinkedEvalCodeBlock* unlinkedCodeBlock() const 47 { 48 return bitwise_cast<UnlinkedEvalCodeBlock*>(Base::unlinkedCodeBlock()); 45 49 } 46 50 … … 63 67 DECLARE_INFO; 64 68 65 unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); }66 unsigned numFunctionHoistingCandidates() { return m_unlinkedEvalCodeBlock->numFunctionHoistingCandidates(); }67 unsigned numTopLevelFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); }68 bool allowDirectEvalCache() const { return m_unlinkedEvalCodeBlock->allowDirectEvalCache(); }69 unsigned numVariables() { return unlinkedCodeBlock()->numVariables(); } 70 unsigned numFunctionHoistingCandidates() { return unlinkedCodeBlock()->numFunctionHoistingCandidates(); } 71 unsigned numTopLevelFunctionDecls() { return unlinkedCodeBlock()->numberOfFunctionDecls(); } 72 bool allowDirectEvalCache() const { return unlinkedCodeBlock()->allowDirectEvalCache(); } 69 73 NeedsClassFieldInitializer needsClassFieldInitializer() const { return static_cast<NeedsClassFieldInitializer>(m_needsClassFieldInitializer); } 70 74 PrivateBrandRequirement privateBrandRequirement() const { return static_cast<PrivateBrandRequirement>(m_privateBrandRequirement); } … … 83 87 unsigned m_privateBrandRequirement : 1; 84 88 85 WriteBarrier<ExecutableToCodeBlockEdge> m_evalCodeBlock;86 WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock;87 89 std::unique_ptr<TemplateObjectMap> m_templateObjectMap; 88 90 }; -
trunk/Source/JavaScriptCore/runtime/FunctionExecutable.cpp
r291779 r292191 25 25 26 26 #include "config.h" 27 #include "FunctionExecutable.h" 27 28 28 29 #include "CodeBlock.h" 29 30 #include "FunctionCodeBlock.h" 31 #include "FunctionExecutableInlines.h" 30 32 #include "FunctionOverrides.h" 33 #include "IsoCellSetInlines.h" 31 34 #include "JSCJSValueInlines.h" 32 35 … … 56 59 FunctionCodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKind kind) 57 60 { 58 ExecutableToCodeBlockEdge* edge;61 CodeBlock* codeBlock = nullptr; 59 62 if (kind == CodeForCall) 60 edge = m_codeBlockForCall.get();63 codeBlock = codeBlockForCall(); 61 64 else { 62 65 RELEASE_ASSERT(kind == CodeForConstruct); 63 edge = m_codeBlockForConstruct.get();64 } 65 if (! edge)66 codeBlock = codeBlockForConstruct(); 67 } 68 if (!codeBlock) 66 69 return nullptr; 67 return static_cast<FunctionCodeBlock*>(edge->codeBlock()->baselineAlternative()); 70 return static_cast<FunctionCodeBlock*>(codeBlock->baselineAlternative()); 71 } 72 73 template<typename Visitor> 74 static inline bool shouldKeepInConstraintSet(Visitor& visitor, CodeBlock* codeBlockForCall, CodeBlock* codeBlockForConstruct) 75 { 76 // If either CodeBlock is not marked yet, we will run output-constraints. 77 return (codeBlockForCall && !visitor.isMarked(codeBlockForCall)) || (codeBlockForConstruct && !visitor.isMarked(codeBlockForConstruct)); 68 78 } 69 79 … … 71 81 void FunctionExecutable::visitChildrenImpl(JSCell* cell, Visitor& visitor) 72 82 { 83 VM& vm = visitor.vm(); 73 84 FunctionExecutable* thisObject = jsCast<FunctionExecutable*>(cell); 74 85 ASSERT_GC_OBJECT_INHERITS(thisObject, info()); 75 86 Base::visitChildren(thisObject, visitor); 76 87 visitor.append(thisObject->m_topLevelExecutable); 77 visitor.append(thisObject->m_codeBlockForCall);78 visitor.append(thisObject->m_codeBlockForConstruct);79 88 visitor.append(thisObject->m_unlinkedExecutable); 80 89 if (RareData* rareData = thisObject->m_rareData.get()) { … … 87 96 } 88 97 } 98 99 // Since FunctionExecutable's finalizer always needs to be run, we do not track FunctionExecutable via finalizerSet. 100 auto* codeBlockForCall = thisObject->m_codeBlockForCall.get(); 101 if (codeBlockForCall) 102 visitCodeBlockEdge(visitor, codeBlockForCall); 103 auto* codeBlockForConstruct = thisObject->m_codeBlockForConstruct.get(); 104 if (codeBlockForConstruct) 105 visitCodeBlockEdge(visitor, codeBlockForConstruct); 106 107 if (shouldKeepInConstraintSet(visitor, codeBlockForCall, codeBlockForConstruct)) 108 vm.heap.functionExecutableSpaceAndSet.outputConstraintsSet.add(thisObject); 89 109 } 90 110 91 111 DEFINE_VISIT_CHILDREN(FunctionExecutable); 112 113 template<typename Visitor> 114 void FunctionExecutable::visitOutputConstraintsImpl(JSCell* cell, Visitor& visitor) 115 { 116 VM& vm = visitor.vm(); 117 auto* executable = jsCast<FunctionExecutable*>(cell); 118 auto* codeBlockForCall = executable->m_codeBlockForCall.get(); 119 if (codeBlockForCall) { 120 if (!visitor.isMarked(codeBlockForCall)) 121 runConstraint(NoLockingNecessary, visitor, codeBlockForCall); 122 } 123 auto* codeBlockForConstruct = executable->codeBlockForConstruct(); 124 if (codeBlockForConstruct) { 125 if (!visitor.isMarked(codeBlockForConstruct)) 126 runConstraint(NoLockingNecessary, visitor, codeBlockForConstruct); 127 } 128 129 if (!shouldKeepInConstraintSet(visitor, codeBlockForCall, codeBlockForConstruct)) 130 vm.heap.functionExecutableSpaceAndSet.outputConstraintsSet.remove(executable); 131 } 132 133 DEFINE_VISIT_OUTPUT_CONSTRAINTS(FunctionExecutable); 92 134 93 135 FunctionExecutable* FunctionExecutable::fromGlobalCode( -
trunk/Source/JavaScriptCore/runtime/FunctionExecutable.h
r290129 r292191 26 26 #pragma once 27 27 28 #include "ExecutableToCodeBlockEdge.h"29 28 #include "JSFunction.h" 30 29 #include "ScriptExecutable.h" … … 70 69 // for answering questions that that don't vary between call and construct -- 71 70 // for example, argumentsRegister(). 72 FunctionCodeBlock* eitherCodeBlock() 73 { 74 ExecutableToCodeBlockEdge* edge; 75 if (m_codeBlockForCall) 76 edge = m_codeBlockForCall.get(); 77 else 78 edge = m_codeBlockForConstruct.get(); 79 return bitwise_cast<FunctionCodeBlock*>(ExecutableToCodeBlockEdge::unwrap(edge)); 71 FunctionCodeBlock* eitherCodeBlock() const 72 { 73 if (auto* result = codeBlockForCall()) 74 return result; 75 return codeBlockForConstruct(); 80 76 } 81 77 82 78 bool isGeneratedForCall() const 83 79 { 84 return !! m_codeBlockForCall;85 } 86 87 FunctionCodeBlock* codeBlockForCall() 88 { 89 return bitwise_cast<FunctionCodeBlock*>( ExecutableToCodeBlockEdge::unwrap(m_codeBlockForCall.get()));80 return !!codeBlockForCall(); 81 } 82 83 FunctionCodeBlock* codeBlockForCall() const 84 { 85 return bitwise_cast<FunctionCodeBlock*>(m_codeBlockForCall.get()); 90 86 } 91 87 92 88 bool isGeneratedForConstruct() const 93 89 { 94 return !! m_codeBlockForConstruct;95 } 96 97 FunctionCodeBlock* codeBlockForConstruct() 98 { 99 return bitwise_cast<FunctionCodeBlock*>( ExecutableToCodeBlockEdge::unwrap(m_codeBlockForConstruct.get()));90 return !!codeBlockForConstruct(); 91 } 92 93 FunctionCodeBlock* codeBlockForConstruct() const 94 { 95 return bitwise_cast<FunctionCodeBlock*>(m_codeBlockForConstruct.get()); 100 96 } 101 97 … … 122 118 return baselineCodeBlockFor(kind); 123 119 } 120 121 FunctionCodeBlock* replaceCodeBlockWith(VM&, CodeSpecializationKind, CodeBlock*); 124 122 125 123 RefPtr<TypeSet> returnStatementTypeSet() … … 163 161 164 162 DECLARE_VISIT_CHILDREN; 163 DECLARE_VISIT_OUTPUT_CONSTRAINTS; 165 164 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) 166 165 { … … 332 331 WriteBarrier<ScriptExecutable> m_topLevelExecutable; 333 332 WriteBarrier<UnlinkedFunctionExecutable> m_unlinkedExecutable; 334 WriteBarrier< ExecutableToCodeBlockEdge> m_codeBlockForCall;335 WriteBarrier< ExecutableToCodeBlockEdge> m_codeBlockForConstruct;333 WriteBarrier<CodeBlock> m_codeBlockForCall; 334 WriteBarrier<CodeBlock> m_codeBlockForConstruct; 336 335 InferredValue<JSFunction> m_singleton; 337 336 Box<InlineWatchpointSet> m_polyProtoWatchpoint; -
trunk/Source/JavaScriptCore/runtime/FunctionExecutableInlines.h
r278462 r292191 28 28 #include "FunctionExecutable.h" 29 29 #include "InferredValueInlines.h" 30 #include "ScriptExecutableInlines.h" 30 31 31 32 namespace JSC { … … 34 35 { 35 36 m_singleton.finalizeUnconditionally(vm); 37 finalizeCodeBlockEdge(vm, m_codeBlockForCall); 38 finalizeCodeBlockEdge(vm, m_codeBlockForConstruct); 39 vm.heap.functionExecutableSpaceAndSet.outputConstraintsSet.remove(this); 36 40 } 37 41 38 JSString* FunctionExecutable::toString(JSGlobalObject* globalObject) 42 inline FunctionCodeBlock* FunctionExecutable::replaceCodeBlockWith(VM& vm, CodeSpecializationKind kind, CodeBlock* newCodeBlock) 43 { 44 if (kind == CodeForCall) { 45 FunctionCodeBlock* oldCodeBlock = codeBlockForCall(); 46 m_codeBlockForCall.setMayBeNull(vm, this, newCodeBlock); 47 return oldCodeBlock; 48 } 49 ASSERT(kind == CodeForConstruct); 50 FunctionCodeBlock* oldCodeBlock = codeBlockForConstruct(); 51 m_codeBlockForConstruct.setMayBeNull(vm, this, newCodeBlock); 52 return oldCodeBlock; 53 } 54 55 inline JSString* FunctionExecutable::toString(JSGlobalObject* globalObject) 39 56 { 40 57 RareData& rareData = ensureRareData(); -
trunk/Source/JavaScriptCore/runtime/GlobalExecutable.cpp
r291779 r292191 27 27 #include "GlobalExecutable.h" 28 28 29 #include "IsoCellSetInlines.h" 29 30 #include "JSCellInlines.h" 31 #include "ScriptExecutableInlines.h" 30 32 31 33 namespace JSC { … … 33 35 const ClassInfo GlobalExecutable::s_info = { "GlobalExecutable"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(GlobalExecutable) }; 34 36 37 template<typename Visitor> 38 void GlobalExecutable::visitChildrenImpl(JSCell* cell, Visitor& visitor) 39 { 40 auto* executable = jsCast<GlobalExecutable*>(cell); 41 ASSERT_GC_OBJECT_INHERITS(executable, info()); 42 Base::visitChildren(executable, visitor); 43 visitor.append(executable->m_unlinkedCodeBlock); 44 45 if (auto* codeBlock = executable->codeBlock()) { 46 // If CodeBlocks is not marked yet, we will run output-constraints. 47 // We maintain the invariant that, whenever we see unmarked CodeBlock, then we must run finalizer. 48 // And whenever we set a bit on outputConstraintsSet, we must already set a bit in finalizerSet. 49 visitCodeBlockEdge(visitor, codeBlock); 50 if (!visitor.isMarked(codeBlock)) { 51 Heap::ScriptExecutableSpaceAndSets::finalizerSetFor(*executable->subspace()).add(executable); 52 Heap::ScriptExecutableSpaceAndSets::outputConstraintsSetFor(*executable->subspace()).add(executable); 53 } 54 } 55 } 56 57 DEFINE_VISIT_CHILDREN(GlobalExecutable); 58 59 template<typename Visitor> 60 void GlobalExecutable::visitOutputConstraintsImpl(JSCell* cell, Visitor& visitor) 61 { 62 auto* executable = jsCast<GlobalExecutable*>(cell); 63 if (CodeBlock* codeBlock = executable->codeBlock()) { 64 if (!visitor.isMarked(codeBlock)) 65 runConstraint(NoLockingNecessary, visitor, codeBlock); 66 if (visitor.isMarked(codeBlock)) 67 Heap::ScriptExecutableSpaceAndSets::outputConstraintsSetFor(*executable->subspace()).remove(executable); 68 } 69 } 70 71 DEFINE_VISIT_OUTPUT_CONSTRAINTS(GlobalExecutable); 72 73 CodeBlock* GlobalExecutable::replaceCodeBlockWith(VM& vm, CodeBlock* newCodeBlock) 74 { 75 CodeBlock* oldCodeBlock = codeBlock(); 76 m_codeBlock.setMayBeNull(vm, this, newCodeBlock); 77 return oldCodeBlock; 78 } 79 80 void GlobalExecutable::finalizeUnconditionally(VM& vm) 81 { 82 finalizeCodeBlockEdge(vm, m_codeBlock); 83 Heap::ScriptExecutableSpaceAndSets::outputConstraintsSetFor(*subspace()).remove(this); 84 Heap::ScriptExecutableSpaceAndSets::finalizerSetFor(*subspace()).remove(this); 85 } 86 35 87 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/GlobalExecutable.h
r278588 r292191 26 26 #pragma once 27 27 28 #include "ExecutableToCodeBlockEdge.h"29 28 #include "ScriptExecutable.h" 30 29 … … 49 48 } 50 49 50 DECLARE_VISIT_CHILDREN; 51 DECLARE_VISIT_OUTPUT_CONSTRAINTS; 52 53 void finalizeUnconditionally(VM&); 54 51 55 protected: 56 friend class ScriptExecutable; 52 57 GlobalExecutable(Structure* structure, VM& vm, const SourceCode& sourceCode, bool isInStrictContext, DerivedContextType derivedContextType, bool isInArrowFunctionContext, bool isInsideOrdinaryFunction, EvalContextType evalContextType, Intrinsic intrinsic) 53 58 : Base(structure, vm, sourceCode, isInStrictContext ? StrictModeLexicalFeature : NoLexicalFeatures, derivedContextType, isInArrowFunctionContext, isInsideOrdinaryFunction, evalContextType, intrinsic) … … 55 60 } 56 61 62 CodeBlock* codeBlock() const 63 { 64 return m_codeBlock.get(); 65 } 66 67 UnlinkedCodeBlock* unlinkedCodeBlock() const 68 { 69 return m_unlinkedCodeBlock.get(); 70 } 71 72 CodeBlock* replaceCodeBlockWith(VM&, CodeBlock*); 73 74 WriteBarrier<CodeBlock> m_codeBlock; 75 WriteBarrier<UnlinkedCodeBlock> m_unlinkedCodeBlock; 57 76 int m_lastLine { -1 }; 58 77 unsigned m_endColumn { UINT_MAX }; -
trunk/Source/JavaScriptCore/runtime/IndirectEvalExecutable.cpp
r287303 r292191 66 66 } 67 67 68 executable->m_unlinked EvalCodeBlock.set(vm, executable, unlinkedEvalCode);68 executable->m_unlinkedCodeBlock.set(vm, executable, unlinkedEvalCode); 69 69 70 70 return executable; -
trunk/Source/JavaScriptCore/runtime/JSFunction.cpp
r291779 r292191 32 32 #include "CommonIdentifiers.h" 33 33 #include "CallFrame.h" 34 #include "FunctionExecutableInlines.h" 34 35 #include "GeneratorPrototype.h" 35 36 #include "JSBoundFunction.h" -
trunk/Source/JavaScriptCore/runtime/JSModuleRecord.cpp
r291779 r292191 97 97 m_moduleProgramExecutable.set(vm, this, executable); 98 98 99 return executable->unlinked ModuleProgramCodeBlock()->isAsync() ? Synchronousness::Async : Synchronousness::Sync;99 return executable->unlinkedCodeBlock()->isAsync() ? Synchronousness::Async : Synchronousness::Sync; 100 100 } 101 101 … … 210 210 // Initialize heap allocated function declarations. 211 211 // They can be called before the body of the module is executed under circular dependencies. 212 UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock = moduleProgramExecutable->unlinked ModuleProgramCodeBlock();212 UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock = moduleProgramExecutable->unlinkedCodeBlock(); 213 213 for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) { 214 214 UnlinkedFunctionExecutable* unlinkedFunctionExecutable = unlinkedCodeBlock->functionDecl(i); -
trunk/Source/JavaScriptCore/runtime/ModuleProgramExecutable.cpp
r291779 r292191 63 63 } 64 64 65 executable->m_unlinked ModuleProgramCodeBlock.set(globalObject->vm(), executable, unlinkedModuleProgramCode);65 executable->m_unlinkedCodeBlock.set(globalObject->vm(), executable, unlinkedModuleProgramCode); 66 66 67 67 executable->m_moduleEnvironmentSymbolTable.set(globalObject->vm(), executable, jsCast<SymbolTable*>(unlinkedModuleProgramCode->constantRegister(VirtualRegister(unlinkedModuleProgramCode->moduleEnvironmentSymbolTableConstantRegisterOffset())).get())->cloneScopePart(globalObject->vm())); … … 86 86 ASSERT_GC_OBJECT_INHERITS(thisObject, info()); 87 87 Base::visitChildren(thisObject, visitor); 88 visitor.append(thisObject->m_unlinkedModuleProgramCodeBlock);89 88 visitor.append(thisObject->m_moduleEnvironmentSymbolTable); 90 visitor.append(thisObject->m_moduleProgramCodeBlock);91 89 if (TemplateObjectMap* map = thisObject->m_templateObjectMap.get()) { 92 90 Locker locker { thisObject->cellLock() }; -
trunk/Source/JavaScriptCore/runtime/ModuleProgramExecutable.h
r290129 r292191 26 26 #pragma once 27 27 28 #include "ExecutableToCodeBlockEdge.h"29 28 #include "GlobalExecutable.h" 30 29 … … 47 46 static void destroy(JSCell*); 48 47 49 ModuleProgramCodeBlock* codeBlock() 48 ModuleProgramCodeBlock* codeBlock() const 50 49 { 51 return bitwise_cast<ModuleProgramCodeBlock*>(ExecutableToCodeBlockEdge::unwrap(m_moduleProgramCodeBlock.get())); 50 return bitwise_cast<ModuleProgramCodeBlock*>(Base::codeBlock()); 51 } 52 53 UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock() const 54 { 55 return bitwise_cast<UnlinkedModuleProgramCodeBlock*>(Base::unlinkedCodeBlock()); 52 56 } 53 57 … … 64 68 DECLARE_INFO; 65 69 66 UnlinkedModuleProgramCodeBlock* unlinkedModuleProgramCodeBlock() { return m_unlinkedModuleProgramCodeBlock.get(); }67 70 bool isAsync() const { return features() & AwaitFeature; } 68 71 … … 79 82 DECLARE_VISIT_CHILDREN; 80 83 81 WriteBarrier<UnlinkedModuleProgramCodeBlock> m_unlinkedModuleProgramCodeBlock;82 84 WriteBarrier<SymbolTable> m_moduleEnvironmentSymbolTable; 83 WriteBarrier<ExecutableToCodeBlockEdge> m_moduleProgramCodeBlock;84 85 std::unique_ptr<TemplateObjectMap> m_templateObjectMap; 85 86 }; -
trunk/Source/JavaScriptCore/runtime/ProgramExecutable.cpp
r291779 r292191 151 151 } 152 152 153 154 m_unlinkedProgramCodeBlock.set(vm, this, unlinkedCodeBlock); 153 m_unlinkedCodeBlock.set(vm, this, unlinkedCodeBlock); 155 154 156 155 BatchedTransitionOptimizer optimizer(vm, globalObject); … … 217 216 ASSERT_GC_OBJECT_INHERITS(thisObject, info()); 218 217 Base::visitChildren(thisObject, visitor); 219 visitor.append(thisObject->m_unlinkedProgramCodeBlock);220 visitor.append(thisObject->m_programCodeBlock);221 218 if (TemplateObjectMap* map = thisObject->m_templateObjectMap.get()) { 222 219 Locker locker { thisObject->cellLock() }; -
trunk/Source/JavaScriptCore/runtime/ProgramExecutable.h
r290129 r292191 26 26 #pragma once 27 27 28 #include "ExecutableToCodeBlockEdge.h"29 28 #include "GlobalExecutable.h" 30 29 … … 57 56 static void destroy(JSCell*); 58 57 59 ProgramCodeBlock* codeBlock() 58 ProgramCodeBlock* codeBlock() const 60 59 { 61 return bitwise_cast<ProgramCodeBlock*>(ExecutableToCodeBlockEdge::unwrap(m_programCodeBlock.get())); 60 return bitwise_cast<ProgramCodeBlock*>(Base::codeBlock()); 61 } 62 63 UnlinkedProgramCodeBlock* unlinkedCodeBlock() const 64 { 65 return bitwise_cast<UnlinkedProgramCodeBlock*>(Base::unlinkedCodeBlock()); 62 66 } 63 67 … … 84 88 DECLARE_VISIT_CHILDREN; 85 89 86 WriteBarrier<UnlinkedProgramCodeBlock> m_unlinkedProgramCodeBlock;87 WriteBarrier<ExecutableToCodeBlockEdge> m_programCodeBlock;88 90 std::unique_ptr<TemplateObjectMap> m_templateObjectMap; 89 91 }; -
trunk/Source/JavaScriptCore/runtime/ScriptExecutable.cpp
r291779 r292191 30 30 #include "EvalCodeBlock.h" 31 31 #include "FunctionCodeBlock.h" 32 #include "FunctionExecutableInlines.h" 32 33 #include "GlobalExecutable.h" 33 34 #include "IsoCellSetInlines.h" … … 87 88 case EvalExecutableType: { 88 89 EvalExecutable* executable = static_cast<EvalExecutable*>(this); 89 executable->m_ evalCodeBlock.clear();90 executable->m_unlinked EvalCodeBlock.clear();90 executable->m_codeBlock.clear(); 91 executable->m_unlinkedCodeBlock.clear(); 91 92 break; 92 93 } 93 94 case ProgramExecutableType: { 94 95 ProgramExecutable* executable = static_cast<ProgramExecutable*>(this); 95 executable->m_ programCodeBlock.clear();96 executable->m_unlinked ProgramCodeBlock.clear();96 executable->m_codeBlock.clear(); 97 executable->m_unlinkedCodeBlock.clear(); 97 98 break; 98 99 } 99 100 case ModuleProgramExecutableType: { 100 101 ModuleProgramExecutable* executable = static_cast<ModuleProgramExecutable*>(this); 101 executable->m_ moduleProgramCodeBlock.clear();102 executable->m_unlinked ModuleProgramCodeBlock.clear();102 executable->m_codeBlock.clear(); 103 executable->m_unlinkedCodeBlock.clear(); 103 104 executable->m_moduleEnvironmentSymbolTable.clear(); 104 105 break; … … 109 110 } 110 111 111 ASSERT(&Heap::S paceAndSet::setFor(*subspace()) == &clearableCodeSet);112 ASSERT(&Heap::ScriptExecutableSpaceAndSets::clearableCodeSetFor(*subspace()) == &clearableCodeSet); 112 113 clearableCodeSet.remove(this); 113 114 } … … 132 133 ASSERT(kind == CodeForCall); 133 134 134 oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_programCodeBlock.get()); 135 executable->m_programCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock)); 135 oldCodeBlock = executable->replaceCodeBlockWith(vm, codeBlock); 136 136 break; 137 137 } … … 143 143 ASSERT(kind == CodeForCall); 144 144 145 oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_moduleProgramCodeBlock.get()); 146 executable->m_moduleProgramCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock)); 145 oldCodeBlock = executable->replaceCodeBlockWith(vm, codeBlock); 147 146 break; 148 147 } … … 154 153 ASSERT(kind == CodeForCall); 155 154 156 oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_evalCodeBlock.get()); 157 executable->m_evalCodeBlock.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock)); 155 oldCodeBlock = executable->replaceCodeBlockWith(vm, codeBlock); 158 156 break; 159 157 } … … 163 161 FunctionCodeBlock* codeBlock = static_cast<FunctionCodeBlock*>(genericCodeBlock); 164 162 165 switch (kind) { 166 case CodeForCall: 167 oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_codeBlockForCall.get()); 168 executable->m_codeBlockForCall.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock)); 169 break; 170 case CodeForConstruct: 171 oldCodeBlock = ExecutableToCodeBlockEdge::deactivateAndUnwrap(executable->m_codeBlockForConstruct.get()); 172 executable->m_codeBlockForConstruct.setMayBeNull(vm, this, ExecutableToCodeBlockEdge::wrapAndActivate(codeBlock)); 173 break; 174 } 163 oldCodeBlock = executable->replaceCodeBlockWith(vm, kind, codeBlock); 175 164 break; 176 165 } … … 188 177 } 189 178 190 auto& clearableCodeSet = Heap::S paceAndSet::setFor(*subspace());179 auto& clearableCodeSet = Heap::ScriptExecutableSpaceAndSets::clearableCodeSetFor(*subspace()); 191 180 if (hasClearableCode(vm)) 192 181 clearableCodeSet.add(this); … … 226 215 if (structure(vm)->classInfo() == FunctionExecutable::info()) { 227 216 auto* executable = static_cast<const FunctionExecutable*>(this); 228 if (executable-> m_codeBlockForCall || executable->m_codeBlockForConstruct)217 if (executable->eitherCodeBlock()) 229 218 return true; 230 219 231 220 } else if (structure(vm)->classInfo() == EvalExecutable::info()) { 232 221 auto* executable = static_cast<const EvalExecutable*>(this); 233 if (executable->m_ evalCodeBlock || executable->m_unlinkedEvalCodeBlock)222 if (executable->m_codeBlock || executable->m_unlinkedCodeBlock) 234 223 return true; 235 224 236 225 } else if (structure(vm)->classInfo() == ProgramExecutable::info()) { 237 226 auto* executable = static_cast<const ProgramExecutable*>(this); 238 if (executable->m_ programCodeBlock || executable->m_unlinkedProgramCodeBlock)227 if (executable->m_codeBlock || executable->m_unlinkedCodeBlock) 239 228 return true; 240 229 241 230 } else if (structure(vm)->classInfo() == ModuleProgramExecutable::info()) { 242 231 auto* executable = static_cast<const ModuleProgramExecutable*>(this); 243 if (executable->m_ moduleProgramCodeBlock244 || executable->m_unlinked ModuleProgramCodeBlock232 if (executable->m_codeBlock 233 || executable->m_unlinkedCodeBlock 245 234 || executable->m_moduleEnvironmentSymbolTable) 246 235 return true; … … 262 251 EvalExecutable* executable = jsCast<EvalExecutable*>(this); 263 252 RELEASE_ASSERT(kind == CodeForCall); 264 RELEASE_ASSERT(!executable->m_ evalCodeBlock);253 RELEASE_ASSERT(!executable->m_codeBlock); 265 254 RELEASE_ASSERT(!function); 266 RELEASE_AND_RETURN(throwScope, EvalCodeBlock::create(vm, executable, executable-> m_unlinkedEvalCodeBlock.get(), scope));255 RELEASE_AND_RETURN(throwScope, EvalCodeBlock::create(vm, executable, executable->unlinkedCodeBlock(), scope)); 267 256 } 268 257 … … 270 259 ProgramExecutable* executable = jsCast<ProgramExecutable*>(this); 271 260 RELEASE_ASSERT(kind == CodeForCall); 272 RELEASE_ASSERT(!executable->m_ programCodeBlock);261 RELEASE_ASSERT(!executable->m_codeBlock); 273 262 RELEASE_ASSERT(!function); 274 RELEASE_AND_RETURN(throwScope, ProgramCodeBlock::create(vm, executable, executable-> m_unlinkedProgramCodeBlock.get(), scope));263 RELEASE_AND_RETURN(throwScope, ProgramCodeBlock::create(vm, executable, executable->unlinkedCodeBlock(), scope)); 275 264 } 276 265 … … 278 267 ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this); 279 268 RELEASE_ASSERT(kind == CodeForCall); 280 RELEASE_ASSERT(!executable->m_ moduleProgramCodeBlock);269 RELEASE_ASSERT(!executable->m_codeBlock); 281 270 RELEASE_ASSERT(!function); 282 RELEASE_AND_RETURN(throwScope, ModuleProgramCodeBlock::create(vm, executable, executable-> m_unlinkedModuleProgramCodeBlock.get(), scope));271 RELEASE_AND_RETURN(throwScope, ModuleProgramCodeBlock::create(vm, executable, executable->unlinkedCodeBlock(), scope)); 283 272 } 284 273 … … 536 525 } 537 526 527 template<typename Visitor> 528 void ScriptExecutable::runConstraint(const ConcurrentJSLocker& locker, Visitor& visitor, CodeBlock* codeBlock) 529 { 530 ASSERT(codeBlock); 531 codeBlock->propagateTransitions(locker, visitor); 532 codeBlock->determineLiveness(locker, visitor); 533 } 534 535 template void ScriptExecutable::runConstraint(const ConcurrentJSLocker&, AbstractSlotVisitor&, CodeBlock*); 536 template void ScriptExecutable::runConstraint(const ConcurrentJSLocker&, SlotVisitor&, CodeBlock*); 537 538 template<typename Visitor> 539 void ScriptExecutable::visitCodeBlockEdge(Visitor& visitor, CodeBlock* codeBlock) 540 { 541 ASSERT(codeBlock); 542 543 ConcurrentJSLocker locker(codeBlock->m_lock); 544 545 if (codeBlock->shouldVisitStrongly(locker, visitor)) 546 visitor.appendUnbarriered(codeBlock); 547 548 if (JITCode::isOptimizingJIT(codeBlock->jitType())) { 549 // If we jettison ourselves we'll install our alternative, so make sure that it 550 // survives GC even if we don't. 551 visitor.append(codeBlock->m_alternative); 552 } 553 554 // NOTE: There are two sides to this constraint, with different requirements for correctness. 555 // Because everything is ultimately protected with weak references and jettisoning, it's 556 // always "OK" to claim that something is dead prematurely and it's "OK" to keep things alive. 557 // But both choices could lead to bad perf - either recomp cycles or leaks. 558 // 559 // Determining CodeBlock liveness: This part is the most consequential. We want to keep the 560 // output constraint active so long as we think that we may yet prove that the CodeBlock is 561 // live but we haven't done it yet. 562 // 563 // Marking Structures if profitable: It's important that we do a pass of this. Logically, this 564 // seems like it is a constraint of CodeBlock. But we have always first run this as a result 565 // of the edge being marked even before we determine the liveness of the CodeBlock. This 566 // allows a CodeBlock to mark itself by first proving that all of the Structures it weakly 567 // depends on could be strongly marked. (This part is also called propagateTransitions.) 568 // 569 // As a weird caveat, we only fixpoint the constraints so long as the CodeBlock is not live. 570 // This means that we may overlook structure marking opportunities created by other marking 571 // that happens after the CodeBlock is marked. This was an accidental policy decision from a 572 // long time ago, but it is probably OK, since it's only worthwhile to keep fixpointing the 573 // structure marking if we still have unmarked structures after the first round. We almost 574 // never will because we will mark-if-profitable based on the owning global object being 575 // already marked. We mark it just in case that hadn't happened yet. And if the CodeBlock is 576 // not yet marked because it weakly depends on a structure that we did not yet mark, then we 577 // will keep fixpointing until the end. 578 visitor.appendUnbarriered(codeBlock->globalObject()); 579 runConstraint(locker, visitor, codeBlock); 580 } 581 582 template void ScriptExecutable::visitCodeBlockEdge(AbstractSlotVisitor&, CodeBlock*); 583 template void ScriptExecutable::visitCodeBlockEdge(SlotVisitor&, CodeBlock*); 584 538 585 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/ScriptExecutable.h
r283903 r292191 140 140 static TemplateObjectMap& ensureTemplateObjectMapImpl(std::unique_ptr<TemplateObjectMap>& dest); 141 141 142 template<typename Visitor> 143 static void runConstraint(const ConcurrentJSLocker&, Visitor&, CodeBlock*); 144 template<typename Visitor> 145 static void visitCodeBlockEdge(Visitor&, CodeBlock*); 146 void finalizeCodeBlockEdge(VM&, WriteBarrier<CodeBlock>&); 147 142 148 SourceCode m_source; 143 149 Intrinsic m_intrinsic { NoIntrinsic }; -
trunk/Source/JavaScriptCore/runtime/ScriptExecutableInlines.h
r292190 r292191 1 1 /* 2 * Copyright (C) 20 19Apple Inc. All rights reserved.2 * Copyright (C) 2022 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 26 26 #pragma once 27 27 28 #include "FunctionExecutable.h" 29 #include "InferredValueInlines.h" 28 #include "ScriptExecutable.h" 30 29 31 30 namespace JSC { 32 31 33 inline void FunctionExecutable::finalizeUnconditionally(VM& vm)32 inline void ScriptExecutable::finalizeCodeBlockEdge(VM& vm, WriteBarrier<CodeBlock>& codeBlockEdge) 34 33 { 35 m_singleton.finalizeUnconditionally(vm); 36 } 34 auto* codeBlock = codeBlockEdge.get(); 35 if (!codeBlock) 36 return; 37 37 38 JSString* FunctionExecutable::toString(JSGlobalObject* globalObject) 39 { 40 RareData& rareData = ensureRareData(); 41 if (!rareData.m_asString) 42 return toStringSlow(globalObject); 43 return rareData.m_asString.get(); 38 if (!vm.heap.isMarked(codeBlock)) { 39 if (codeBlock->shouldJettisonDueToWeakReference(vm)) 40 codeBlock->jettison(Profiler::JettisonDueToWeakReference); 41 else 42 codeBlock->jettison(Profiler::JettisonDueToOldAge); 43 if (codeBlock == codeBlockEdge.get()) 44 codeBlockEdge.clear(); 45 } 44 46 } 45 47 -
trunk/Source/JavaScriptCore/runtime/VM.cpp
r290768 r292191 48 48 #include "EvalCodeBlock.h" 49 49 #include "Exception.h" 50 #include "ExecutableToCodeBlockEdge.h"51 50 #include "FTLThunks.h" 52 51 #include "FileBasedFuzzerAgent.h" … … 299 298 hashMapBucketMapStructure.set(*this, HashMapBucket<HashMapBucketDataKeyValue>::createStructure(*this, nullptr, jsNull())); 300 299 bigIntStructure.set(*this, JSBigInt::createStructure(*this, nullptr, jsNull())); 301 executableToCodeBlockEdgeStructure.set(*this, ExecutableToCodeBlockEdge::createStructure(*this, nullptr, jsNull()));302 300 303 301 // Eagerly initialize constant cells since the concurrent compiler can access them. -
trunk/Source/JavaScriptCore/runtime/VM.h
r290869 r292191 374 374 FOR_EACH_JSC_DYNAMIC_ISO_SUBSPACE(DEFINE_DYNAMIC_ISO_SUBSPACE_ACCESSOR_IMPL) 375 375 376 ALWAYS_INLINE IsoCellSet& executableToCodeBlockEdgesWithConstraints() { return heap.executableToCodeBlockEdgesWithConstraints; }377 ALWAYS_INLINE IsoCellSet& executableToCodeBlockEdgesWithFinalizers() { return heap.executableToCodeBlockEdgesWithFinalizers; }378 379 376 ALWAYS_INLINE GCClient::IsoSubspace& codeBlockSpace() { return clientHeap.codeBlockSpace; } 380 377 … … 442 439 Strong<Structure> hashMapBucketMapStructure; 443 440 Strong<Structure> bigIntStructure; 444 Strong<Structure> executableToCodeBlockEdgeStructure;445 441 446 442 Strong<JSPropertyNameEnumerator> m_emptyPropertyNameEnumerator;
Note:
See TracChangeset
for help on using the changeset viewer.