WebKit Bugzilla
Attachment 359697 Details for
Bug 192782
: [JSC] Cache bytecode to disk
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-192782-20190121192003.patch (text/plain), 134.29 KB, created by
Tadeu Zagallo
on 2019-01-21 10:20:17 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Tadeu Zagallo
Created:
2019-01-21 10:20:17 PST
Size:
134.29 KB
patch
obsolete
>Subversion Revision: 240233 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index dbc7d46ad189e0e9407da5935177173aa925c0b8..35a6f0409dbf96b9e8027ffe19a326f9ee89406d 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,260 @@ >+2019-01-21 Tadeu Zagallo <tzagallo@apple.com> >+ >+ Cache bytecode to disk >+ https://bugs.webkit.org/show_bug.cgi?id=192782 >+ <rdar://problem/46084932> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add the logic to serialize and deserialize the new JSC bytecode. For now, >+ the cache is only used for tests. >+ >+ Each class that can be serialized has a counterpart in CachedTypes, which >+ handles the decoding and encoding. When decoding, the cached objects are >+ mmap'd from disk, but only used for creating instances of the respective >+ in-memory version of each object. Ideally, the mmap'd objects should be >+ used at runtime in the future. >+ >+ * CMakeLists.txt: >+ * JavaScriptCore.xcodeproj/project.pbxproj: >+ * Sources.txt: >+ * builtins/BuiltinNames.cpp: >+ (JSC::BuiltinNames::BuiltinNames): >+ * builtins/BuiltinNames.h: >+ * bytecode/CodeBlock.cpp: >+ (JSC::CodeBlock::setConstantIdentifierSetRegisters): >+ * bytecode/CodeBlock.h: >+ * bytecode/HandlerInfo.h: >+ (JSC::UnlinkedHandlerInfo::UnlinkedHandlerInfo): >+ * bytecode/InstructionStream.h: >+ * bytecode/UnlinkedCodeBlock.h: >+ (JSC::UnlinkedCodeBlock::addSetConstant): >+ (JSC::UnlinkedCodeBlock::constantIdentifierSets): >+ * bytecode/UnlinkedEvalCodeBlock.h: >+ * bytecode/UnlinkedFunctionCodeBlock.h: >+ * bytecode/UnlinkedFunctionExecutable.h: >+ * bytecode/UnlinkedGlobalCodeBlock.h: >+ (JSC::UnlinkedGlobalCodeBlock::UnlinkedGlobalCodeBlock): >+ * bytecode/UnlinkedMetadataTable.h: >+ * bytecode/UnlinkedModuleProgramCodeBlock.h: >+ * bytecode/UnlinkedProgramCodeBlock.h: >+ * interpreter/Interpreter.cpp: >+ * jsc.cpp: >+ (functionQuit): >+ (runJSC): >+ * parser/SourceCode.h: >+ * parser/SourceCodeKey.h: >+ (JSC::SourceCodeKey::operator!= const): >+ * parser/UnlinkedSourceCode.h: >+ * parser/VariableEnvironment.h: >+ * runtime/CachedTypes.cpp: Added. >+ (JSC::Encoder::Allocation::buffer const): >+ (JSC::Encoder::Allocation::offset const): >+ (JSC::Encoder::Allocation::Allocation): >+ (JSC::Encoder::Encoder): >+ (JSC::Encoder::vm): >+ (JSC::Encoder::malloc): >+ (JSC::Encoder::offsetOf): >+ (JSC::Encoder::cachePtr): >+ (JSC::Encoder::offsetForPtr): >+ (JSC::Encoder::release): >+ (JSC::Encoder::Page::Page): >+ (JSC::Encoder::Page::malloc): >+ (JSC::Encoder::Page::buffer const): >+ (JSC::Encoder::Page::size const): >+ (JSC::Encoder::Page::getOffset const): >+ (JSC::Encoder::allocateNewPage): >+ (JSC::Decoder::Decoder): >+ (JSC::Decoder::~Decoder): >+ (JSC::Decoder::vm): >+ (JSC::Decoder::offsetOf): >+ (JSC::Decoder::cacheOffset): >+ (JSC::Decoder::addFinalizer): >+ (JSC::encode): >+ (JSC::decode): >+ (JSC::VariableLengthObject::buffer const): >+ (JSC::VariableLengthObject::allocate): >+ (JSC::CachedPtr::encode): >+ (JSC::CachedPtr::decode const): >+ (JSC::CachedPtr::operator-> const): >+ (JSC::CachedPtr::get const): >+ (JSC::CachedRefPtr::encode): >+ (JSC::CachedRefPtr::decode const): >+ (JSC::CachedWriteBarrier::encode): >+ (JSC::CachedWriteBarrier::decode const): >+ (JSC::CachedVector::encode): >+ (JSC::CachedVector::decode const): >+ (JSC::CachedPair::encode): >+ (JSC::CachedPair::decode const): >+ (JSC::CachedHashMap::encode): >+ (JSC::CachedHashMap::decode const): >+ (JSC::CachedUniquedStringImpl::encode): >+ (JSC::CachedUniquedStringImpl::decode const): >+ (JSC::CachedStringImpl::encode): >+ (JSC::CachedStringImpl::decode const): >+ (JSC::CachedString::encode): >+ (JSC::CachedString::decode const): >+ (JSC::CachedIdentifier::encode): >+ (JSC::CachedIdentifier::decode const): >+ (JSC::CachedOptional::encode): >+ (JSC::CachedOptional::decode const): >+ (JSC::CachedOptional::decodeAsPtr const): >+ (JSC::CachedSimpleJumpTable::encode): >+ (JSC::CachedSimpleJumpTable::decode const): >+ (JSC::CachedStringJumpTable::encode): >+ (JSC::CachedStringJumpTable::decode const): >+ (JSC::CachedCodeBlockRareData::encode): >+ (JSC::CachedCodeBlockRareData::decode const): >+ (JSC::CachedBitVector::encode): >+ (JSC::CachedBitVector::decode const): >+ (JSC::CachedHashSet::encode): >+ (JSC::CachedHashSet::decode const): >+ (JSC::CachedConstantIdentifierSetEntry::encode): >+ (JSC::CachedConstantIdentifierSetEntry::decode const): >+ (JSC::CachedVariableEnvironment::encode): >+ (JSC::CachedVariableEnvironment::decode const): >+ (JSC::CachedArray::encode): >+ (JSC::CachedArray::decode const): >+ (JSC::CachedScopedArgumentsTable::encode): >+ (JSC::CachedScopedArgumentsTable::decode const): >+ (JSC::CachedSymbolTableEntry::encode): >+ (JSC::CachedSymbolTableEntry::decode const): >+ (JSC::CachedSymbolTable::encode): >+ (JSC::CachedSymbolTable::decode const): >+ (JSC::CachedImmutableButterfly::encode): >+ (JSC::CachedImmutableButterfly::decode const): >+ (JSC::CachedRegExp::encode): >+ (JSC::CachedRegExp::decode const): >+ (JSC::CachedTemplateObjectDescriptor::encode): >+ (JSC::CachedTemplateObjectDescriptor::decode const): >+ (JSC::CachedBigInt::encode): >+ (JSC::CachedBigInt::decode const): >+ (JSC::CachedJSValue::encode): >+ (JSC::CachedJSValue::decode const): >+ (JSC::CachedInstructionStream::encode): >+ (JSC::CachedInstructionStream::decode const): >+ (JSC::CachedMetadataTable::encode): >+ (JSC::CachedMetadataTable::decode const): >+ (JSC::CachedSourceOrigin::encode): >+ (JSC::CachedSourceOrigin::decode const): >+ (JSC::CachedTextPosition::encode): >+ (JSC::CachedTextPosition::decode const): >+ (JSC::CachedSourceProviderShape::encode): >+ (JSC::CachedSourceProviderShape::decode const): >+ (JSC::CachedStringSourceProvider::encode): >+ (JSC::CachedStringSourceProvider::decode const): >+ (JSC::CachedWebAssemblySourceProvider::encode): >+ (JSC::CachedWebAssemblySourceProvider::decode const): >+ (JSC::CachedSourceProvider::encode): >+ (JSC::CachedSourceProvider::decode const): >+ (JSC::CachedUnlinkedSourceCodeShape::encode): >+ (JSC::CachedUnlinkedSourceCodeShape::decode const): >+ (JSC::CachedSourceCode::encode): >+ (JSC::CachedSourceCode::decode const): >+ (JSC::CachedFunctionExecutable::firstLineOffset const): >+ (JSC::CachedFunctionExecutable::lineCount const): >+ (JSC::CachedFunctionExecutable::unlinkedFunctionNameStart const): >+ (JSC::CachedFunctionExecutable::unlinkedBodyStartColumn const): >+ (JSC::CachedFunctionExecutable::unlinkedBodyEndColumn const): >+ (JSC::CachedFunctionExecutable::startOffset const): >+ (JSC::CachedFunctionExecutable::sourceLength const): >+ (JSC::CachedFunctionExecutable::parametersStartOffset const): >+ (JSC::CachedFunctionExecutable::typeProfilingStartOffset const): >+ (JSC::CachedFunctionExecutable::typeProfilingEndOffset const): >+ (JSC::CachedFunctionExecutable::parameterCount const): >+ (JSC::CachedFunctionExecutable::features const): >+ (JSC::CachedFunctionExecutable::sourceParseMode const): >+ (JSC::CachedFunctionExecutable::isInStrictContext const): >+ (JSC::CachedFunctionExecutable::hasCapturedVariables const): >+ (JSC::CachedFunctionExecutable::isBuiltinFunction const): >+ (JSC::CachedFunctionExecutable::isBuiltinDefaultClassConstructor const): >+ (JSC::CachedFunctionExecutable::constructAbility const): >+ (JSC::CachedFunctionExecutable::constructorKind const): >+ (JSC::CachedFunctionExecutable::functionMode const): >+ (JSC::CachedFunctionExecutable::scriptMode const): >+ (JSC::CachedFunctionExecutable::superBinding const): >+ (JSC::CachedFunctionExecutable::derivedContextType const): >+ (JSC::CachedFunctionExecutable::name const): >+ (JSC::CachedFunctionExecutable::ecmaName const): >+ (JSC::CachedFunctionExecutable::inferredName const): >+ (JSC::CachedCodeBlock::instructions const): >+ (JSC::CachedCodeBlock::thisRegister const): >+ (JSC::CachedCodeBlock::scopeRegister const): >+ (JSC::CachedCodeBlock::globalObjectRegister const): >+ (JSC::CachedCodeBlock::sourceURLDirective const): >+ (JSC::CachedCodeBlock::sourceMappingURLDirective const): >+ (JSC::CachedCodeBlock::usesEval const): >+ (JSC::CachedCodeBlock::isStrictMode const): >+ (JSC::CachedCodeBlock::isConstructor const): >+ (JSC::CachedCodeBlock::hasCapturedVariables const): >+ (JSC::CachedCodeBlock::isBuiltinFunction const): >+ (JSC::CachedCodeBlock::superBinding const): >+ (JSC::CachedCodeBlock::scriptMode const): >+ (JSC::CachedCodeBlock::isArrowFunctionContext const): >+ (JSC::CachedCodeBlock::isClassContext const): >+ (JSC::CachedCodeBlock::wasCompiledWithDebuggingOpcodes const): >+ (JSC::CachedCodeBlock::constructorKind const): >+ (JSC::CachedCodeBlock::derivedContextType const): >+ (JSC::CachedCodeBlock::evalContextType const): >+ (JSC::CachedCodeBlock::hasTailCalls const): >+ (JSC::CachedCodeBlock::lineCount const): >+ (JSC::CachedCodeBlock::endColumn const): >+ (JSC::CachedCodeBlock::numVars const): >+ (JSC::CachedCodeBlock::numCalleeLocals const): >+ (JSC::CachedCodeBlock::numParameters const): >+ (JSC::CachedCodeBlock::features const): >+ (JSC::CachedCodeBlock::parseMode const): >+ (JSC::CachedCodeBlock::codeType const): >+ (JSC::CachedCodeBlock::rareData const): >+ (JSC::CachedProgramCodeBlock::encode): >+ (JSC::CachedProgramCodeBlock::decode const): >+ (JSC::CachedModuleCodeBlock::encode): >+ (JSC::CachedModuleCodeBlock::decode const): >+ (JSC::CachedEvalCodeBlock::encode): >+ (JSC::CachedEvalCodeBlock::decode const): >+ (JSC::CachedFunctionCodeBlock::encode): >+ (JSC::CachedFunctionCodeBlock::decode const): >+ (JSC::UnlinkedFunctionCodeBlock::UnlinkedFunctionCodeBlock): >+ (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): >+ (JSC::CachedCodeBlock<CodeBlockType>::decode const): >+ (JSC::UnlinkedProgramCodeBlock::UnlinkedProgramCodeBlock): >+ (JSC::UnlinkedModuleProgramCodeBlock::UnlinkedModuleProgramCodeBlock): >+ (JSC::UnlinkedEvalCodeBlock::UnlinkedEvalCodeBlock): >+ (JSC::CachedFunctionExecutable::encode): >+ (JSC::CachedFunctionExecutable::decode const): >+ (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): >+ (JSC::CachedCodeBlock<CodeBlockType>::encode): >+ (JSC::CachedSourceCodeKey::encode): >+ (JSC::CachedSourceCodeKey::decode const): >+ (JSC::CacheEntry::encode): >+ (JSC::CacheEntry:: const): >+ (JSC:: const): >+ (JSC::encodeCodeBlock): >+ (JSC::decodeCodeBlockImpl): >+ * runtime/CachedTypes.h: Copied from Source/JavaScriptCore/bytecode/UnlinkedGlobalCodeBlock.h. >+ (JSC::decodeCodeBlock): >+ * runtime/CodeCache.cpp: >+ (JSC::CodeCacheMap::pruneSlowCase): >+ (JSC::CodeCache::getUnlinkedGlobalCodeBlock): >+ (JSC::CodeCache::getUnlinkedGlobalFunctionExecutable): >+ (JSC::CodeCache::write): >+ * runtime/CodeCache.h: >+ (JSC::CodeCacheMap::begin): >+ (JSC::CodeCacheMap::end): >+ (JSC::CodeCacheMap::fetchFromDiskImpl): >+ (JSC::CodeCacheMap::findCacheAndUpdateAge): >+ (JSC::writeCodeBlock): >+ * runtime/JSBigInt.cpp: >+ * runtime/JSBigInt.h: >+ * runtime/Options.cpp: >+ (JSC::recomputeDependentOptions): >+ * runtime/Options.h: >+ * runtime/RegExp.h: >+ * runtime/ScopedArgumentsTable.h: >+ * runtime/StackFrame.h: >+ * runtime/StructureInlines.h: >+ * runtime/SymbolTable.h: >+ > 2019-01-20 Saam Barati <sbarati@apple.com> > > DFG: When inlining DataView set* intrinsics we need to set undefined as our result >diff --git a/Source/WTF/ChangeLog b/Source/WTF/ChangeLog >index c33e3e76e2e8dc7c64095089a7bb6ac52c305643..1cb398f4edb50663ebae06513de47a1925c6d5cf 100644 >--- a/Source/WTF/ChangeLog >+++ b/Source/WTF/ChangeLog >@@ -1,3 +1,16 @@ >+2019-01-21 Tadeu Zagallo <tzagallo@apple.com> >+ >+ Cache bytecode to disk >+ https://bugs.webkit.org/show_bug.cgi?id=192782 >+ <rdar://problem/46084932> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ BitVectors have to be friends with JSC::CacheBitVector to allow >+ serializing its buffer as part of the bytecode cache encoding. >+ >+ * wtf/BitVector.h: >+ > 2019-01-20 Saam Barati <sbarati@apple.com> > > Rollout r240210: It broke tests on iOS >diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt >index 6acdfb13426465bc48bf1d7a5db7775f3849a59d..ea858b168249a1c12d3b11c60351da287dd0c44a 100644 >--- a/Source/JavaScriptCore/CMakeLists.txt >+++ b/Source/JavaScriptCore/CMakeLists.txt >@@ -833,6 +833,7 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS > runtime/JSGlobalLexicalEnvironment.h > runtime/JSGlobalObject.h > runtime/JSGlobalObjectInlines.h >+ runtime/JSImmutableButterfly.h > runtime/JSInternalPromise.h > runtime/JSInternalPromiseDeferred.h > runtime/JSMicrotask.h >@@ -848,6 +849,7 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS > runtime/JSPromise.h > runtime/JSPromiseConstructor.h > runtime/JSPromiseDeferred.h >+ runtime/JSPropertyNameEnumerator.h > runtime/JSProxy.h > runtime/JSRunLoopTimer.h > runtime/JSScope.h >diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >index 3e744dbe845f88d10ec4898d286f240facf3290c..852cc04e9403d9506530e619c7f6187119addacb 100644 >--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >@@ -826,7 +826,7 @@ > 262D85B71C0D650F006ACB61 /* AirFixPartialRegisterStalls.h in Headers */ = {isa = PBXBuildFile; fileRef = 262D85B51C0D650F006ACB61 /* AirFixPartialRegisterStalls.h */; }; > 2684D4381C00161C0081D663 /* AirLiveness.h in Headers */ = {isa = PBXBuildFile; fileRef = 2684D4371C00161C0081D663 /* AirLiveness.h */; }; > 269D636E1BFBE5D100101B1D /* FTLOutput.h in Headers */ = {isa = PBXBuildFile; fileRef = 269D636D1BFBE5D000101B1D /* FTLOutput.h */; }; >- 2A05ABD61961DF2400341750 /* JSPropertyNameEnumerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A05ABD41961DF2400341750 /* JSPropertyNameEnumerator.h */; }; >+ 2A05ABD61961DF2400341750 /* JSPropertyNameEnumerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A05ABD41961DF2400341750 /* JSPropertyNameEnumerator.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 2A111246192FCE79005EE18D /* CustomGetterSetter.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A111244192FCE79005EE18D /* CustomGetterSetter.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 2A48D1911772365B00C65A5F /* APICallbackFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = C211B574176A224D000E2A23 /* APICallbackFunction.h */; }; > 2A4BB7F318A41179008A0FCD /* JSManagedValueInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 2A4BB7F218A41179008A0FCD /* JSManagedValueInternal.h */; }; >@@ -1062,7 +1062,7 @@ > 53EAFE2F208DFAB4007D524B /* testapi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 531D4E191F59CDD200EC836C /* testapi.cpp */; }; > 53EE01B6218F691600AD1F8D /* JSScript.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EE01B5218F690F00AD1F8D /* JSScript.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 53EE01B8218F7EFF00AD1F8D /* JSScriptInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EE01B7218F7EFF00AD1F8D /* JSScriptInternal.h */; }; >- 53F11F41209138D700E411A7 /* JSImmutableButterfly.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F11F40209138D700E411A7 /* JSImmutableButterfly.h */; }; >+ 53F11F41209138D700E411A7 /* JSImmutableButterfly.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F11F40209138D700E411A7 /* JSImmutableButterfly.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 53F40E851D58F9770099A1B6 /* WasmSections.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E841D58F9770099A1B6 /* WasmSections.h */; }; > 53F40E8B1D5901BB0099A1B6 /* WasmFunctionParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E8A1D5901BB0099A1B6 /* WasmFunctionParser.h */; }; > 53F40E8D1D5901F20099A1B6 /* WasmParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 53F40E8C1D5901F20099A1B6 /* WasmParser.h */; }; >@@ -3128,6 +3128,7 @@ > 14386A731DD69895008652C4 /* DirectEvalExecutable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectEvalExecutable.h; sourceTree = "<group>"; }; > 14386A761DD6989C008652C4 /* IndirectEvalExecutable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IndirectEvalExecutable.cpp; sourceTree = "<group>"; }; > 14386A771DD6989C008652C4 /* IndirectEvalExecutable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndirectEvalExecutable.h; sourceTree = "<group>"; }; >+ 143BE26521C857770020CD17 /* CachedTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedTypes.h; sourceTree = "<group>"; }; > 1440051F0A531D3B0005F061 /* Node.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Node.h; path = tests/Node.h; sourceTree = "<group>"; }; > 144005200A531D3B0005F061 /* Node.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = Node.c; path = tests/Node.c; sourceTree = "<group>"; }; > 144007480A536CC20005F061 /* NodeList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NodeList.h; path = tests/NodeList.h; sourceTree = "<group>"; }; >@@ -3242,6 +3243,7 @@ > 14D857740A4696C80032146C /* testapi.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = testapi.js; path = API/tests/testapi.js; sourceTree = "<group>"; }; > 14DA818E0D99FD2000B0A4FB /* JSLexicalEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSLexicalEnvironment.h; sourceTree = "<group>"; }; > 14DA818F0D99FD2000B0A4FB /* JSLexicalEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSLexicalEnvironment.cpp; sourceTree = "<group>"; }; >+ 14DAFA4521E3B871004B68F7 /* CachedTypes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CachedTypes.cpp; sourceTree = "<group>"; }; > 14DE0D680D02431400AACCA2 /* JSGlobalObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = JSGlobalObject.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; > 14DF04D916B3996D0016A513 /* StaticPropertyAnalysis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StaticPropertyAnalysis.h; sourceTree = "<group>"; }; > 14E84F9914EE1ACC00D6D5D4 /* WeakBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakBlock.cpp; sourceTree = "<group>"; }; >@@ -6600,6 +6602,8 @@ > 9E729409190F0306001A91B5 /* BundlePath.mm */, > 0FB7F38B15ED8E3800F167B2 /* Butterfly.h */, > 0FB7F38C15ED8E3800F167B2 /* ButterflyInlines.h */, >+ 14DAFA4521E3B871004B68F7 /* CachedTypes.cpp */, >+ 143BE26521C857770020CD17 /* CachedTypes.h */, > 0FEC3C5F1F379F5300F59B6C /* CagedBarrierPtr.h */, > BCA62DFE0E2826230004F30D /* CallData.cpp */, > 145C507F0D9DF63B0088F6B9 /* CallData.h */, >diff --git a/Source/JavaScriptCore/Sources.txt b/Source/JavaScriptCore/Sources.txt >index 949edcaa5b538b858adc34c1124dc6c1edd62255..258d49ced1e2d59ddbdf147f4acb1894938dba14 100644 >--- a/Source/JavaScriptCore/Sources.txt >+++ b/Source/JavaScriptCore/Sources.txt >@@ -713,6 +713,7 @@ runtime/BooleanConstructor.cpp > runtime/BooleanObject.cpp > runtime/BooleanPrototype.cpp > runtime/CallData.cpp >+runtime/CachedTypes.cpp > runtime/CatchScope.cpp > runtime/ClassInfo.cpp > runtime/ClonedArguments.cpp >diff --git a/Source/JavaScriptCore/builtins/BuiltinNames.cpp b/Source/JavaScriptCore/builtins/BuiltinNames.cpp >index 45de82e7cb58a283b20fcae5982bbb5c04da9175..a0f853a6e05dc4618ff04de59019b1ea13d6b37f 100644 >--- a/Source/JavaScriptCore/builtins/BuiltinNames.cpp >+++ b/Source/JavaScriptCore/builtins/BuiltinNames.cpp >@@ -63,6 +63,7 @@ BuiltinNames::BuiltinNames(VM* vm, CommonIdentifiers* commonIdentifiers) > JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PRIVATE_TO_PUBLIC_ENTRY) > JSC_FOREACH_BUILTIN_FUNCTION_NAME(INITIALIZE_PUBLIC_TO_PRIVATE_ENTRY) > JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PUBLIC_TO_PRIVATE_ENTRY) >+ JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALIZE_SYMBOL_PRIVATE_TO_PUBLIC_ENTRY) > JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALIZE_SYMBOL_PUBLIC_TO_PRIVATE_ENTRY) > m_privateToPublicMap.add(m_dollarVMPrivateName.impl(), &m_dollarVMName); > m_publicToPrivateMap.add(m_dollarVMName.impl(), &m_dollarVMPrivateName); >diff --git a/Source/JavaScriptCore/builtins/BuiltinNames.h b/Source/JavaScriptCore/builtins/BuiltinNames.h >index f66b8cb51eb402d8736fd7dd0d2d0e7a292f4512..8531db260bd0701b371901b674bff5df0bfbd875 100644 >--- a/Source/JavaScriptCore/builtins/BuiltinNames.h >+++ b/Source/JavaScriptCore/builtins/BuiltinNames.h >@@ -213,6 +213,7 @@ extern SymbolImpl::StaticSymbolImpl polyProtoPrivateName; > // We commandeer the publicToPrivateMap to allow us to convert private symbol names into the appropriate symbol. > // e.g. @iteratorSymbol points to Symbol.iterator in this map rather than to a an actual private name. > // FIXME: This is a weird hack and we shouldn't need to do this. >+#define INITIALIZE_SYMBOL_PRIVATE_TO_PUBLIC_ENTRY(name) m_privateToPublicMap.add(m_##name##Symbol.impl(), &m_##name##SymbolPrivateIdentifier); > #define INITIALIZE_SYMBOL_PUBLIC_TO_PRIVATE_ENTRY(name) m_publicToPrivateMap.add(m_##name##SymbolPrivateIdentifier.impl(), &m_##name##Symbol); > > class BuiltinNames { >diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp >index 68d3d2d2be79f405dc94d071a140499f25943006..dccc4111487375dc18b6addb539a1086772eaa51 100644 >--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp >+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp >@@ -869,7 +869,7 @@ CodeBlock::~CodeBlock() > #endif // ENABLE(JIT) > } > >-void CodeBlock::setConstantIdentifierSetRegisters(VM& vm, const Vector<ConstantIndentifierSetEntry>& constants) >+void CodeBlock::setConstantIdentifierSetRegisters(VM& vm, const Vector<ConstantIdentifierSetEntry>& constants) > { > auto scope = DECLARE_THROW_SCOPE(vm); > JSGlobalObject* globalObject = m_globalObject.get(); >diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h >index 94e6bd2ee0efb2ba074cea250d82f73182a6e113..c747426b38e566ebb9e842ce23ed59384eb0ae20 100644 >--- a/Source/JavaScriptCore/bytecode/CodeBlock.h >+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h >@@ -890,7 +890,7 @@ private: > > void updateAllPredictionsAndCountLiveness(unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles); > >- void setConstantIdentifierSetRegisters(VM&, const Vector<ConstantIndentifierSetEntry>& constants); >+ void setConstantIdentifierSetRegisters(VM&, const Vector<ConstantIdentifierSetEntry>& constants); > > void setConstantRegisters(const Vector<WriteBarrier<Unknown>>& constants, const Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation); > >diff --git a/Source/JavaScriptCore/bytecode/HandlerInfo.h b/Source/JavaScriptCore/bytecode/HandlerInfo.h >index 66c3b768775620776d263ff098de6f46b66e7783..7f465d2ae93799b91df78714194fca34bd2a1a12 100644 >--- a/Source/JavaScriptCore/bytecode/HandlerInfo.h >+++ b/Source/JavaScriptCore/bytecode/HandlerInfo.h >@@ -89,6 +89,10 @@ struct HandlerInfoBase { > }; > > struct UnlinkedHandlerInfo : public HandlerInfoBase { >+ UnlinkedHandlerInfo() >+ { >+ } >+ > UnlinkedHandlerInfo(uint32_t start, uint32_t end, uint32_t target, HandlerType handlerType) > { > this->start = start; >diff --git a/Source/JavaScriptCore/bytecode/InstructionStream.h b/Source/JavaScriptCore/bytecode/InstructionStream.h >index 70ede3e41c5d5c489d796fcfc0c1ccd998d29ed5..b40480a5e7958df0a417ff12200cd955ed002a1f 100644 >--- a/Source/JavaScriptCore/bytecode/InstructionStream.h >+++ b/Source/JavaScriptCore/bytecode/InstructionStream.h >@@ -39,6 +39,7 @@ class InstructionStream { > using InstructionBuffer = Vector<uint8_t, 0, UnsafeVectorOverflow>; > > friend class InstructionStreamWriter; >+ friend class CachedInstructionStream; > public: > size_t sizeInBytes() const; > >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h >index f0e9d64c854a3f536752d4874692d27877d67049..148a53521fa762c257a652bbe3d3c1284b6686ec 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h >@@ -65,12 +65,15 @@ class UnlinkedFunctionCodeBlock; > class UnlinkedFunctionExecutable; > struct ExecutableInfo; > >+template<typename CodeBlockType> >+class CachedCodeBlock; >+ > typedef unsigned UnlinkedValueProfile; > typedef unsigned UnlinkedArrayProfile; > typedef unsigned UnlinkedArrayAllocationProfile; > typedef unsigned UnlinkedObjectAllocationProfile; > typedef unsigned UnlinkedLLIntCallLinkInfo; >-using ConstantIndentifierSetEntry = std::pair<IdentifierSet, unsigned>; >+using ConstantIdentifierSetEntry = std::pair<IdentifierSet, unsigned>; > > struct UnlinkedStringJumpTable { > struct OffsetLocation { >@@ -168,7 +171,7 @@ public: > unsigned result = m_constantRegisters.size(); > m_constantRegisters.append(WriteBarrier<Unknown>()); > m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other); >- m_constantIdentifierSets.append(ConstantIndentifierSetEntry(set, result)); >+ m_constantIdentifierSets.append(ConstantIdentifierSetEntry(set, result)); > } > > unsigned addConstant(JSValue v, SourceCodeRepresentation sourceCodeRepresentation = SourceCodeRepresentation::Other) >@@ -202,7 +205,7 @@ public: > return m_linkTimeConstants[index]; > } > const Vector<WriteBarrier<Unknown>>& constantRegisters() { return m_constantRegisters; } >- const Vector<ConstantIndentifierSetEntry>& constantIdentifierSets() { return m_constantIdentifierSets; } >+ const Vector<ConstantIdentifierSetEntry>& constantIdentifierSets() { return m_constantIdentifierSets; } > const WriteBarrier<Unknown>& constantRegister(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex]; } > ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; } > ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); } >@@ -367,6 +370,10 @@ public: > > protected: > UnlinkedCodeBlock(VM*, Structure*, CodeType, const ExecutableInfo&, DebuggerMode); >+ >+ template<typename CodeBlockType> >+ UnlinkedCodeBlock(Decoder&, Structure*, const CachedCodeBlock<CodeBlockType>&); >+ > ~UnlinkedCodeBlock(); > > void finishCreation(VM& vm) >@@ -378,6 +385,9 @@ private: > friend class BytecodeRewriter; > friend class BytecodeGenerator; > >+ template<typename CodeBlockType> >+ friend class CachedCodeBlock; >+ > void applyModification(BytecodeRewriter&, InstructionStreamWriter&); > > void createRareDataIfNecessary() >@@ -444,7 +454,7 @@ private: > Vector<Identifier> m_identifiers; > Vector<BitVector> m_bitVectors; > Vector<WriteBarrier<Unknown>> m_constantRegisters; >- Vector<ConstantIndentifierSetEntry> m_constantIdentifierSets; >+ Vector<ConstantIdentifierSetEntry> m_constantIdentifierSets; > Vector<SourceCodeRepresentation> m_constantsSourceCodeRepresentation; > typedef Vector<WriteBarrier<UnlinkedFunctionExecutable>> FunctionExpressionVector; > FunctionExpressionVector m_functionDecls; >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedEvalCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedEvalCodeBlock.h >index 9987b4313343b6cb752a420b358d9a3603172f26..2f32379a01f435c3d018df651935a2e2b03cd01e 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedEvalCodeBlock.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedEvalCodeBlock.h >@@ -29,6 +29,8 @@ > > namespace JSC { > >+class CachedEvalCodeBlock; >+ > class UnlinkedEvalCodeBlock final : public UnlinkedGlobalCodeBlock { > public: > typedef UnlinkedGlobalCodeBlock Base; >@@ -59,11 +61,15 @@ public: > m_functionHoistingCandidates = WTFMove(functionHoistingCandidates); > } > private: >+ friend CachedEvalCodeBlock; >+ > UnlinkedEvalCodeBlock(VM* vm, Structure* structure, const ExecutableInfo& info, DebuggerMode debuggerMode) > : Base(vm, structure, EvalCode, info, debuggerMode) > { > } > >+ UnlinkedEvalCodeBlock(Decoder&, const CachedEvalCodeBlock&); >+ > Vector<Identifier, 0, UnsafeVectorOverflow> m_variables; > Vector<Identifier, 0, UnsafeVectorOverflow> m_functionHoistingCandidates; > >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedFunctionCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedFunctionCodeBlock.h >index b5482b65c8b8efb3aa306a413bd54603491a9013..65aafc88e597cb20f49fd3272bde15a10dcbdd58 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedFunctionCodeBlock.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedFunctionCodeBlock.h >@@ -29,6 +29,8 @@ > > namespace JSC { > >+class CachedFunctionCodeBlock; >+ > class UnlinkedFunctionCodeBlock final : public UnlinkedCodeBlock { > public: > typedef UnlinkedCodeBlock Base; >@@ -44,10 +46,14 @@ public: > static void destroy(JSCell*); > > private: >+ friend CachedFunctionCodeBlock; >+ > UnlinkedFunctionCodeBlock(VM* vm, Structure* structure, CodeType codeType, const ExecutableInfo& info, DebuggerMode debuggerMode) > : Base(vm, structure, codeType, info, debuggerMode) > { > } >+ >+ UnlinkedFunctionCodeBlock(Decoder&, const CachedFunctionCodeBlock&); > > public: > static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h >index 526898c951d82175979881102f9dc7d615b01522..6526cd90cbbaa69e26cc0a1c0ac77b68c195fb56 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h >@@ -39,11 +39,13 @@ > > namespace JSC { > >+class Decoder; > class FunctionMetadataNode; > class FunctionExecutable; > class ParserError; > class SourceProvider; > class UnlinkedFunctionCodeBlock; >+class CachedFunctionExecutable; > > enum UnlinkedFunctionKind { > UnlinkedNormalFunction, >@@ -54,6 +56,7 @@ class UnlinkedFunctionExecutable final : public JSCell { > public: > friend class CodeCache; > friend class VM; >+ friend CachedFunctionExecutable; > > typedef JSCell Base; > static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; >@@ -147,6 +150,7 @@ public: > > private: > UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, JSParserScriptMode, VariableEnvironment&, JSC::DerivedContextType, bool isBuiltinDefaultClassConstructor); >+ UnlinkedFunctionExecutable(Decoder&, VariableEnvironment&, const CachedFunctionExecutable&); > > unsigned m_firstLineOffset; > unsigned m_lineCount; >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedGlobalCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedGlobalCodeBlock.h >index 343862e6470fe1b1a42485d8769e277d72c1508e..3d042ef486c7d12caf0d32d602e16fb212f6e075 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedGlobalCodeBlock.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedGlobalCodeBlock.h >@@ -38,6 +38,12 @@ protected: > : Base(vm, structure, codeType, info, debuggerMode) > { > } >+ >+ template<typename CodeBlockType> >+ UnlinkedGlobalCodeBlock(Decoder& decoder, Structure* structure, const CachedCodeBlock<CodeBlockType>& cachedCodeBlock) >+ : Base(decoder, structure, cachedCodeBlock) >+ { >+ } > }; > > } >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedMetadataTable.h b/Source/JavaScriptCore/bytecode/UnlinkedMetadataTable.h >index 3e3e8dfb4d5bbc464f5e6a2344caaca994949ef1..f94707e3b185d7716b416a4933eca6c951a4d5ef 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedMetadataTable.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedMetadataTable.h >@@ -35,6 +35,7 @@ class MetadataTable; > class UnlinkedMetadataTable { > friend class LLIntOffsetsExtractor; > friend class MetadataTable; >+ friend class CachedMetadataTable; > > public: > struct LinkingData { >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedModuleProgramCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedModuleProgramCodeBlock.h >index 0e9c5f5bdde6c7562b66a03bc0a98c87adbd9302..3933bfd3e3ae24e6f64f5e0a9d9d1190213006d1 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedModuleProgramCodeBlock.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedModuleProgramCodeBlock.h >@@ -29,6 +29,9 @@ > > namespace JSC { > >+class Decoder; >+class CachedModuleCodeBlock; >+ > class UnlinkedModuleProgramCodeBlock final : public UnlinkedGlobalCodeBlock { > public: > typedef UnlinkedGlobalCodeBlock Base; >@@ -74,11 +77,15 @@ public: > } > > private: >+ friend CachedModuleCodeBlock; >+ > UnlinkedModuleProgramCodeBlock(VM* vm, Structure* structure, const ExecutableInfo& info, DebuggerMode debuggerMode) > : Base(vm, structure, ModuleCode, info, debuggerMode) > { > } > >+ UnlinkedModuleProgramCodeBlock(Decoder&, const CachedModuleCodeBlock&); >+ > int m_moduleEnvironmentSymbolTableConstantRegisterOffset { 0 }; > > public: >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedProgramCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedProgramCodeBlock.h >index afe26aed1a503ab23fd8f447f9dec2dc06ca5826..76844a37a411952eedaba45c782ddf5553b0cdfe 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedProgramCodeBlock.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedProgramCodeBlock.h >@@ -29,6 +29,8 @@ > > namespace JSC { > >+class CachedProgramCodeBlock; >+ > class UnlinkedProgramCodeBlock final : public UnlinkedGlobalCodeBlock { > public: > typedef UnlinkedGlobalCodeBlock Base; >@@ -50,11 +52,15 @@ public: > const VariableEnvironment& lexicalDeclarations() const { return m_lexicalDeclarations; } > > private: >+ friend CachedProgramCodeBlock; >+ > UnlinkedProgramCodeBlock(VM* vm, Structure* structure, const ExecutableInfo& info, DebuggerMode debuggerMode) > : Base(vm, structure, GlobalCode, info, debuggerMode) > { > } > >+ UnlinkedProgramCodeBlock(Decoder&, const CachedProgramCodeBlock&); >+ > VariableEnvironment m_varDeclarations; > VariableEnvironment m_lexicalDeclarations; > >diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp >index ad653618b428fca06be04ddb66c0f3d31d2b264c..8e8256028b1037db2b307acd17d05b7f358f47d0 100644 >--- a/Source/JavaScriptCore/interpreter/Interpreter.cpp >+++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp >@@ -35,6 +35,7 @@ > #include "CallFrameClosure.h" > #include "CatchScope.h" > #include "CodeBlock.h" >+#include "CodeCache.h" > #include "DirectArguments.h" > #include "Heap.h" > #include "Debugger.h" >diff --git a/Source/JavaScriptCore/jsc.cpp b/Source/JavaScriptCore/jsc.cpp >index b5d47dd3db9ad8ba6f845bb32114fb0daf8d8f65..deba637f1213d943b24021f25402cd2fd985a91a 100644 >--- a/Source/JavaScriptCore/jsc.cpp >+++ b/Source/JavaScriptCore/jsc.cpp >@@ -28,6 +28,7 @@ > #include "ButterflyInlines.h" > #include "CatchScope.h" > #include "CodeBlock.h" >+#include "CodeCache.h" > #include "Completion.h" > #include "ConfigFile.h" > #include "Disassembler.h" >@@ -1988,8 +1989,11 @@ EncodedJSValue JSC_HOST_CALL functionFailNextNewCodeBlock(ExecState* exec) > return JSValue::encode(jsUndefined()); > } > >-EncodedJSValue JSC_HOST_CALL functionQuit(ExecState*) >+EncodedJSValue JSC_HOST_CALL functionQuit(ExecState* exec) > { >+ VM& vm = exec->vm(); >+ vm.codeCache()->write(vm); >+ > jscExit(EXIT_SUCCESS); > > #if COMPILER(MSVC) >@@ -2876,6 +2880,8 @@ int runJSC(const CommandLine& options, bool isWorker, const Func& func) > #endif > } > >+ vm.codeCache()->write(vm); >+ > if (isWorker) { > JSLockHolder locker(vm); > // This is needed because we don't want the worker's main >diff --git a/Source/JavaScriptCore/parser/SourceCode.h b/Source/JavaScriptCore/parser/SourceCode.h >index c3c0f7346b05536b5c099d43371586436fd3d9c2..fbe4c9a0df1cc1af00b252857ee9c784fa27af4e 100644 >--- a/Source/JavaScriptCore/parser/SourceCode.h >+++ b/Source/JavaScriptCore/parser/SourceCode.h >@@ -33,6 +33,8 @@ > namespace JSC { > > class SourceCode : public UnlinkedSourceCode { >+ friend class CachedSourceCode; >+ > public: > SourceCode() > : UnlinkedSourceCode() >diff --git a/Source/JavaScriptCore/parser/SourceCodeKey.h b/Source/JavaScriptCore/parser/SourceCodeKey.h >index a8e603c26a0b60362a02deac0516169d57558021..cc3abe21faf5714bf99801dfb9eed4283481f189 100644 >--- a/Source/JavaScriptCore/parser/SourceCodeKey.h >+++ b/Source/JavaScriptCore/parser/SourceCodeKey.h >@@ -37,6 +37,8 @@ enum class TypeProfilerEnabled { No, Yes }; > enum class ControlFlowProfilerEnabled { No, Yes }; > > class SourceCodeFlags { >+ friend class CachedSourceCodeKey; >+ > public: > SourceCodeFlags() = default; > >@@ -70,6 +72,8 @@ private: > }; > > class SourceCodeKey { >+ friend class CachedSourceCodeKey; >+ > public: > SourceCodeKey() > { >@@ -114,6 +118,11 @@ public: > && string() == other.string(); > } > >+ bool operator!=(const SourceCodeKey& other) const >+ { >+ return !(*this == other); >+ } >+ > struct Hash { > static unsigned hash(const SourceCodeKey& key) { return key.hash(); } > static bool equal(const SourceCodeKey& a, const SourceCodeKey& b) { return a == b; } >diff --git a/Source/JavaScriptCore/parser/UnlinkedSourceCode.h b/Source/JavaScriptCore/parser/UnlinkedSourceCode.h >index 6ec590b53e6c9c327e4244d0b119b36d096fc81e..aaaad3f412f8f3fa5bc1f2febfb14cc74de22424 100644 >--- a/Source/JavaScriptCore/parser/UnlinkedSourceCode.h >+++ b/Source/JavaScriptCore/parser/UnlinkedSourceCode.h >@@ -35,6 +35,9 @@ > namespace JSC { > > class UnlinkedSourceCode { >+ template<typename SourceType> >+ friend class CachedUnlinkedSourceCodeShape; >+ > public: > UnlinkedSourceCode() > : m_provider(0) >diff --git a/Source/JavaScriptCore/parser/VariableEnvironment.h b/Source/JavaScriptCore/parser/VariableEnvironment.h >index 129b5ea6bd9b726a1d9a4011ef9690f8cc6b0dd3..d84b2e1fb218ec49cd95e5bd85dc7650cfa609d9 100644 >--- a/Source/JavaScriptCore/parser/VariableEnvironment.h >+++ b/Source/JavaScriptCore/parser/VariableEnvironment.h >@@ -116,6 +116,8 @@ public: > bool isEverythingCaptured() const { return m_isEverythingCaptured; } > > private: >+ friend class CachedVariableEnvironment; >+ > Map m_map; > bool m_isEverythingCaptured { false }; > }; >diff --git a/Source/JavaScriptCore/runtime/CachedTypes.cpp b/Source/JavaScriptCore/runtime/CachedTypes.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..9d9554c5a784e62cab5d0d132a03fc9d25039b3a >--- /dev/null >+++ b/Source/JavaScriptCore/runtime/CachedTypes.cpp >@@ -0,0 +1,2021 @@ >+/* >+ * Copyright (C) 2019 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 "CachedTypes.h" >+ >+#include "BytecodeLivenessAnalysis.h" >+#include "JSCast.h" >+#include "JSImmutableButterfly.h" >+#include "JSTemplateObjectDescriptor.h" >+#include "ScopedArgumentsTable.h" >+#include "SourceCodeKey.h" >+#include "UnlinkedEvalCodeBlock.h" >+#include "UnlinkedFunctionCodeBlock.h" >+#include "UnlinkedMetadataTableInlines.h" >+#include "UnlinkedModuleProgramCodeBlock.h" >+#include "UnlinkedProgramCodeBlock.h" >+#include <wtf/FastMalloc.h> >+#include <wtf/Forward.h> >+#include <wtf/Optional.h> >+#include <wtf/text/AtomicStringImpl.h> >+ >+namespace JSC { >+ >+template <typename T, typename = void> >+struct SourceTypeImpl { >+ using type = T; >+}; >+ >+template<typename T> >+struct SourceTypeImpl<T, std::enable_if_t<!std::is_fundamental<T>::value && !std::is_same<typename T::SourceType_, void>::value>> { >+ using type = typename T::SourceType_; >+ >+}; >+ >+template<typename T> >+using SourceType = typename SourceTypeImpl<T>::type; >+ >+class Encoder { >+ WTF_MAKE_NONCOPYABLE(Encoder); >+ WTF_FORBID_HEAP_ALLOCATION; >+ >+public: >+ class Allocation { >+ friend class Encoder; >+ >+ public: >+ uint8_t* buffer() const { return m_buffer; } >+ ptrdiff_t offset() const { return m_offset; } >+ >+ private: >+ Allocation(uint8_t* buffer, ptrdiff_t offset) >+ : m_buffer(buffer) >+ , m_offset(offset) >+ { >+ } >+ >+ uint8_t* m_buffer; >+ ptrdiff_t m_offset; >+ }; >+ >+ Encoder(VM& vm) >+ : m_vm(vm) >+ , m_baseOffset(0) >+ , m_currentPage(nullptr) >+ { >+ allocateNewPage(); >+ } >+ >+ VM& vm() { return m_vm; } >+ >+ Allocation malloc(unsigned size) >+ { >+ ASSERT(size); >+ ptrdiff_t offset; >+ if (m_currentPage->malloc(size, offset)) >+ return Allocation { m_currentPage->buffer() + offset, m_baseOffset + offset }; >+ allocateNewPage(size); >+ return malloc(size); >+ } >+ >+ template<typename T> >+ T* malloc() >+ { >+ return reinterpret_cast<T*>(malloc(sizeof(T)).buffer()); >+ } >+ >+ ptrdiff_t offsetOf(const void* address) >+ { >+ ptrdiff_t offset; >+ ptrdiff_t baseOffset = 0; >+ for (const auto& page : m_pages) { >+ if (page.getOffset(address, offset)) >+ return baseOffset + offset; >+ baseOffset += page.size(); >+ } >+ RELEASE_ASSERT_NOT_REACHED(); >+ return 0; >+ } >+ >+ void cachePtr(const void* ptr, ptrdiff_t offset) >+ { >+ m_ptrToOffsetMap.add(ptr, offset); >+ } >+ >+ WTF::Optional<ptrdiff_t> offsetForPtr(const void* ptr) >+ { >+ auto it = m_ptrToOffsetMap.find(ptr); >+ if (it == m_ptrToOffsetMap.end()) >+ return WTF::nullopt; >+ return { it->value }; >+ } >+ >+ std::pair<MallocPtr<uint8_t>, size_t> release() >+ { >+ size_t size = m_baseOffset + m_currentPage->size(); >+ MallocPtr<uint8_t> buffer = MallocPtr<uint8_t>::malloc(size); >+ unsigned offset = 0; >+ for (const auto& page : m_pages) { >+ memcpy(buffer.get() + offset, page.buffer(), page.size()); >+ offset += page.size(); >+ } >+ RELEASE_ASSERT(offset == size); >+ return { WTFMove(buffer), size }; >+ } >+ >+private: >+ class Page { >+ public: >+ Page(size_t size) >+ : m_offset(0) >+ , m_capacity(size) >+ { >+ m_buffer = MallocPtr<uint8_t>::malloc(size); >+ } >+ >+ bool malloc(size_t size, ptrdiff_t& result) >+ { >+ size_t alignment = std::min(alignof(std::max_align_t), static_cast<size_t>(WTF::roundUpToPowerOfTwo(size))); >+ ptrdiff_t offset = WTF::roundUpToMultipleOf(alignment, m_offset); >+ size = WTF::roundUpToMultipleOf(alignment, size); >+ if (static_cast<size_t>(offset + size) > m_capacity) >+ return false; >+ >+ result = offset; >+ m_offset = offset + size; >+ return true; >+ } >+ >+ uint8_t* buffer() const { return m_buffer.get(); } >+ size_t size() const { return static_cast<size_t>(m_offset); } >+ >+ bool getOffset(const void* address, ptrdiff_t& result) const >+ { >+ const uint8_t* addr = static_cast<const uint8_t*>(address); >+ if (addr >= m_buffer.get() && addr < m_buffer.get() + m_offset) { >+ result = addr - m_buffer.get(); >+ return true; >+ } >+ return false; >+ } >+ >+ private: >+ MallocPtr<uint8_t> m_buffer; >+ ptrdiff_t m_offset; >+ size_t m_capacity; >+ }; >+ >+ void allocateNewPage(size_t size = 0) >+ { >+ static size_t minPageSize = WTF::pageSize(); >+ if (m_currentPage) >+ m_baseOffset += m_currentPage->size(); >+ if (size < minPageSize) >+ size = minPageSize; >+ else >+ size = WTF::roundUpToMultipleOf(minPageSize, size); >+ m_pages.append(Page { size }); >+ m_currentPage = &m_pages.last(); >+ } >+ >+ VM& m_vm; >+ ptrdiff_t m_baseOffset; >+ Page* m_currentPage; >+ Vector<Page> m_pages; >+ HashMap<const void*, ptrdiff_t> m_ptrToOffsetMap; >+}; >+ >+class Decoder { >+ WTF_MAKE_NONCOPYABLE(Decoder); >+ WTF_FORBID_HEAP_ALLOCATION; >+ >+public: >+ Decoder(VM& vm, const void* baseAddress, size_t size) >+ : m_vm(vm) >+ , m_baseAddress(reinterpret_cast<const uint8_t*>(baseAddress)) >+#ifndef NDEBUG >+ , m_size(size) >+#endif >+ { >+ UNUSED_PARAM(size); >+ } >+ >+ ~Decoder() >+ { >+ for (auto& pair : m_finalizers) >+ pair.value(); >+ } >+ >+ VM& vm() { return m_vm; } >+ >+ ptrdiff_t offsetOf(const void* ptr) >+ { >+ const uint8_t* addr = static_cast<const uint8_t*>(ptr); >+ ASSERT(addr >= m_baseAddress && addr < m_baseAddress + m_size); >+ return addr - m_baseAddress; >+ } >+ >+ void cacheOffset(ptrdiff_t offset, void* ptr) >+ { >+ m_offsetToPtrMap.add(offset, ptr); >+ } >+ >+ WTF::Optional<void*> ptrForOffset(ptrdiff_t offset) >+ { >+ auto it = m_offsetToPtrMap.find(offset); >+ if (it == m_offsetToPtrMap.end()) >+ return WTF::nullopt; >+ return { it->value }; >+ } >+ >+ template<typename Functor> >+ void addFinalizer(ptrdiff_t offset, const Functor& fn) >+ { >+ m_finalizers.add(offset, fn); >+ } >+ >+private: >+ VM& m_vm; >+ const uint8_t* m_baseAddress; >+#ifndef NDEBUG >+ size_t m_size; >+#endif >+ HashMap<ptrdiff_t, void*> m_offsetToPtrMap; >+ HashMap<ptrdiff_t, std::function<void()>> m_finalizers; >+}; >+ >+template<typename T> >+static std::enable_if_t<std::is_same<T, SourceType<T>>::value> encode(Encoder&, T& dst, const SourceType<T>& src) >+{ >+ dst = src; >+} >+ >+template<typename T> >+static std::enable_if_t<!std::is_same<T, SourceType<T>>::value> encode(Encoder& encoder, T& dst, const SourceType<T>& src) >+{ >+ dst.encode(encoder, src); >+} >+ >+template<typename T, typename... Args> >+static std::enable_if_t<std::is_same<T, SourceType<T>>::value> decode(Decoder&, const T& src, SourceType<T>& dst, Args...) >+{ >+ dst = src; >+} >+ >+template<typename T, typename... Args> >+static std::enable_if_t<!std::is_same<T, SourceType<T>>::value> decode(Decoder& decoder, const T& src, SourceType<T>& dst, Args... args) >+{ >+ src.decode(decoder, dst, args...); >+} >+ >+template<typename T> >+static std::enable_if_t<std::is_same<T, SourceType<T>>::value, T> decode(Decoder&, T src) >+{ >+ return src; >+} >+ >+template<typename T> >+static std::enable_if_t<!std::is_same<T, SourceType<T>>::value, SourceType<T>>&& decode(Decoder& decoder, const T& src) >+{ >+ return src.decode(decoder); >+} >+ >+template<typename Source> >+class CachedObject { >+ WTF_MAKE_NONCOPYABLE(CachedObject<Source>); >+ WTF_FORBID_HEAP_ALLOCATION; >+ >+public: >+ using SourceType_ = Source; >+}; >+ >+template<typename Source> >+class VariableLengthObject : public CachedObject<Source> { >+ template<typename, typename> >+ friend struct CachedPtr; >+ >+protected: >+ const uint8_t* buffer() const >+ { >+ ASSERT(m_offset != s_invalidOffset); >+ return reinterpret_cast<const uint8_t*>(this) + m_offset; >+ } >+ >+ template<typename T> >+ const T* buffer() const >+ { >+ return reinterpret_cast<const T*>(buffer()); >+ } >+ >+ uint8_t* allocate(Encoder& encoder, size_t size) >+ { >+ if (!size) >+ return nullptr; >+ >+ ptrdiff_t offsetOffset = encoder.offsetOf(&m_offset); >+ auto result = encoder.malloc(size); >+ m_offset = result.offset() - offsetOffset; >+ return result.buffer(); >+ } >+ >+ template<typename T> >+ T* allocate(Encoder& encoder, unsigned size = 1) >+ { >+ uint8_t* result = allocate(encoder, sizeof(T) * size); >+ return reinterpret_cast<T*>(result); >+ } >+ >+private: >+ constexpr static ptrdiff_t s_invalidOffset = std::numeric_limits<ptrdiff_t>::max(); >+ >+ ptrdiff_t m_offset { s_invalidOffset }; >+ >+}; >+ >+template<typename T, typename Source = SourceType<T>> >+class CachedPtr : public VariableLengthObject<Source*> { >+ template<typename, typename> >+ friend struct CachedRefPtr; >+ >+public: >+ void encode(Encoder& encoder, const Source* src) >+ { >+ m_isEmpty = !src; >+ if (m_isEmpty) >+ return; >+ >+ if (WTF::Optional<ptrdiff_t> offset = encoder.offsetForPtr(src)) { >+ this->m_offset = *offset - encoder.offsetOf(&this->m_offset); >+ return; >+ } >+ >+ T* cachedObject = this->template allocate<T>(encoder); >+ cachedObject->encode(encoder, *src); >+ encoder.cachePtr(src, encoder.offsetOf(cachedObject)); >+ } >+ >+ template<typename... Args> >+ Source* decode(Decoder& decoder, Args... args) const >+ { >+ if (m_isEmpty) >+ return nullptr; >+ >+ ptrdiff_t bufferOffset = decoder.offsetOf(this->buffer()); >+ if (WTF::Optional<void*> ptr = decoder.ptrForOffset(bufferOffset)) >+ return reinterpret_cast<Source*>(*ptr); >+ >+ Source* ptr = get()->decode(decoder, args...); >+ decoder.cacheOffset(bufferOffset, ptr); >+ return ptr; >+ } >+ >+ const T* operator->() const { return get(); } >+ >+private: >+ const T* get() const >+ { >+ if (m_isEmpty) >+ return nullptr; >+ return this->template buffer<T>(); >+ } >+ >+ bool m_isEmpty; >+ >+}; >+ >+template<typename T, typename Source = SourceType<T>> >+class CachedRefPtr : public CachedObject<RefPtr<Source>> { >+public: >+ void encode(Encoder& encoder, const Source* src) >+ { >+ m_ptr.encode(encoder, src); >+ } >+ >+ void encode(Encoder& encoder, const RefPtr<Source> src) >+ { >+ encode(encoder, src.get()); >+ } >+ >+ RefPtr<Source> decode(Decoder& decoder) const >+ { >+ Source* decodedPtr = m_ptr.decode(decoder); >+ if (!decodedPtr) >+ return nullptr; >+ decoder.addFinalizer(decoder.offsetOf(m_ptr.buffer()), [=] { derefIfNotNull(decodedPtr); }); >+ refIfNotNull(decodedPtr); >+ return adoptRef(decodedPtr); >+ } >+ >+ void decode(Decoder& decoder, RefPtr<Source>& src) const >+ { >+ src = decode(decoder); >+ } >+ >+private: >+ CachedPtr<T, Source> m_ptr; >+}; >+ >+template<typename T, typename Source = SourceType<T>> >+class CachedWriteBarrier : public CachedObject<WriteBarrier<Source>> { >+public: >+ void encode(Encoder& encoder, const WriteBarrier<Source> src) >+ { >+ m_ptr.encode(encoder, src.get()); >+ } >+ >+ void decode(Decoder& decoder, WriteBarrier<Source>& src, const JSCell* owner) const >+ { >+ Source* decodedPtr = m_ptr.decode(decoder); >+ if (decodedPtr) >+ src.set(decoder.vm(), owner, decodedPtr); >+ } >+ >+private: >+ CachedPtr<T, Source> m_ptr; >+}; >+ >+template<typename T, size_t InlineCapacity = 0, typename OverflowHandler = CrashOnOverflow> >+class CachedVector : public VariableLengthObject<Vector<SourceType<T>, InlineCapacity, OverflowHandler>> { >+public: >+ void encode(Encoder& encoder, const Vector<SourceType<T>, InlineCapacity, OverflowHandler>& vector) >+ { >+ m_size = vector.size(); >+ T* buffer = this->template allocate<T>(encoder, m_size); >+ for (unsigned i = 0; i < m_size; ++i) >+ ::JSC::encode(encoder, buffer[i], vector[i]); >+ } >+ >+ template<typename... Args> >+ void decode(Decoder& decoder, Vector<SourceType<T>, InlineCapacity, OverflowHandler>& vector, Args... args) const >+ { >+ vector.resizeToFit(m_size); >+ const T* buffer = this->template buffer<T>(); >+ for (unsigned i = 0; i < m_size; ++i) >+ ::JSC::decode(decoder, buffer[i], vector[i], args...); >+ } >+ >+private: >+ unsigned m_size; >+}; >+ >+template<typename First, typename Second> >+class CachedPair : public CachedObject<std::pair<SourceType<First>, SourceType<Second>>> { >+public: >+ void encode(Encoder& encoder, const std::pair<SourceType<First>, SourceType<Second>>& pair) >+ { >+ ::JSC::encode(encoder, m_first, pair.first); >+ ::JSC::encode(encoder, m_second, pair.second); >+ } >+ >+ void decode(Decoder& decoder, std::pair<SourceType<First>, SourceType<Second>>& pair) const >+ { >+ ::JSC::decode(decoder, m_first, pair.first); >+ ::JSC::decode(decoder, m_second, pair.second); >+ } >+ >+private: >+ First m_first; >+ Second m_second; >+}; >+ >+template<typename Key, typename Value, typename HashArg = typename DefaultHash<SourceType<Key>>::Hash, typename KeyTraitsArg = HashTraits<SourceType<Key>>, typename MappedTraitsArg = HashTraits<SourceType<Value>>> >+class CachedHashMap : public VariableLengthObject<HashMap<SourceType<Key>, SourceType<Value>, HashArg, KeyTraitsArg, MappedTraitsArg>> { >+ template<typename K, typename V> >+ using Map = HashMap<K, V, HashArg, KeyTraitsArg, MappedTraitsArg>; >+ >+public: >+ void encode(Encoder& encoder, const Map<SourceType<Key>, SourceType<Value>>& map) >+ { >+ SourceType<decltype(m_entries)> entriesVector(map.size()); >+ unsigned i = 0; >+ for (const auto& it : map) >+ entriesVector[i++] = { it.key, it.value }; >+ m_entries.encode(encoder, entriesVector); >+ } >+ >+ void decode(Decoder& decoder, Map<SourceType<Key>, SourceType<Value>>& map) const >+ { >+ SourceType<decltype(m_entries)> decodedEntries; >+ m_entries.decode(decoder, decodedEntries); >+ for (const auto& pair : decodedEntries) >+ map.set(pair.first, pair.second); >+ } >+ >+private: >+ CachedVector<CachedPair<Key, Value>> m_entries; >+}; >+ >+class CachedUniquedStringImpl : public VariableLengthObject<UniquedStringImpl> { >+public: >+ void encode(Encoder& encoder, const StringImpl& string) >+ { >+ m_isAtomic = string.isAtomic(); >+ m_isSymbol = string.isSymbol(); >+ StringImpl* impl = const_cast<StringImpl*>(&string); >+ if (m_isSymbol) { >+ SymbolImpl* symbol = static_cast<SymbolImpl*>(impl); >+ if (!symbol->isNullSymbol()) { >+ Identifier uid = Identifier::fromUid(&encoder.vm(), symbol); >+ impl = encoder.vm().propertyNames->lookUpPublicName(uid).string().impl(); >+ } >+ } >+ >+ m_is8Bit = impl->is8Bit(); >+ m_length = impl->length(); >+ >+ if (!m_length) >+ return; >+ >+ unsigned size = m_length; >+ const void* payload; >+ if (m_is8Bit) >+ payload = impl->characters8(); >+ else { >+ payload = impl->characters16(); >+ size *= 2; >+ } >+ >+ uint8_t* buffer = this->allocate(encoder, size); >+ memcpy(buffer, payload, size); >+ } >+ >+ UniquedStringImpl* decode(Decoder& decoder) const >+ { >+ auto create = [&](const auto* buffer) -> UniquedStringImpl* { >+ if (!m_isSymbol) >+ return AtomicStringImpl::add(buffer, m_length).leakRef(); >+ >+ if (!m_length) >+ return &SymbolImpl::createNullSymbol().leakRef(); >+ >+ Identifier ident = Identifier::fromString(&decoder.vm(), buffer, m_length); >+ String str = decoder.vm().propertyNames->lookUpPrivateName(ident)->string(); >+ StringImpl* impl = str.releaseImpl().get(); >+ ASSERT(impl->isSymbol()); >+ return static_cast<UniquedStringImpl*>(impl); >+ }; >+ >+ if (m_is8Bit) >+ return create(this->buffer<LChar>()); >+ return create(this->buffer<UChar>()); >+ } >+ >+private: >+ bool m_is8Bit : 1; >+ bool m_isSymbol : 1; >+ bool m_isAtomic : 1; >+ unsigned m_length; >+}; >+ >+class CachedStringImpl : public VariableLengthObject<StringImpl> { >+public: >+ void encode(Encoder& encoder, const StringImpl& impl) >+ { >+ m_uniquedStringImpl.encode(encoder, impl); >+ } >+ >+ StringImpl* decode(Decoder& decoder) const >+ { >+ return m_uniquedStringImpl.decode(decoder); >+ } >+ >+private: >+ CachedUniquedStringImpl m_uniquedStringImpl; >+}; >+ >+class CachedString : public VariableLengthObject<String> { >+public: >+ void encode(Encoder& encoder, const String& string) >+ { >+ m_impl.encode(encoder, static_cast<UniquedStringImpl*>(string.impl())); >+ } >+ >+ String decode(Decoder& decoder) const >+ { >+ return String(static_cast<RefPtr<StringImpl>>(m_impl.decode(decoder))); >+ } >+ >+ void decode(Decoder& decoder, String& dst) const >+ { >+ dst = decode(decoder); >+ } >+ >+private: >+ CachedRefPtr<CachedUniquedStringImpl> m_impl; >+}; >+ >+class CachedIdentifier : public VariableLengthObject<Identifier> { >+public: >+ void encode(Encoder& encoder, const Identifier& identifier) >+ { >+ m_string.encode(encoder, identifier.string()); >+ } >+ >+ Identifier decode(Decoder& decoder) const >+ { >+ String str = m_string.decode(decoder); >+ if (str.isNull()) >+ return Identifier(); >+ >+ return Identifier::fromUid(&decoder.vm(), (UniquedStringImpl*)str.impl()); >+ } >+ >+ void decode(Decoder& decoder, Identifier& ident) const >+ { >+ ident = decode(decoder); >+ } >+ >+private: >+ CachedString m_string; >+}; >+ >+template<typename T> >+class CachedOptional : public VariableLengthObject<WTF::Optional<SourceType<T>>> { >+public: >+ void encode(Encoder& encoder, const WTF::Optional<SourceType<T>>& source) >+ { >+ m_isEmpty = !source; >+ >+ if (m_isEmpty) >+ return; >+ >+ this->template allocate<T>(encoder)->encode(encoder, *source); >+ } >+ >+ WTF::Optional<SourceType<T>> decode(Decoder& decoder) const >+ { >+ if (m_isEmpty) >+ return WTF::nullopt; >+ >+ return { this->template buffer<T>()->decode(decoder) }; >+ } >+ >+ void decode(Decoder& decoder, WTF::Optional<SourceType<T>>& dst) const >+ { >+ dst = decode(decoder); >+ } >+ >+ void encode(Encoder& encoder, const std::unique_ptr<SourceType<T>>& source) >+ { >+ if (!source) >+ encode(encoder, WTF::nullopt); >+ else >+ encode(encoder, { *source }); >+ } >+ >+ SourceType<T>* decodeAsPtr(Decoder& decoder) const >+ { >+ if (m_isEmpty) >+ return nullptr; >+ >+ return this->template buffer<T>()->decode(decoder); >+ } >+ >+private: >+ bool m_isEmpty; >+}; >+ >+class CachedSimpleJumpTable : public CachedObject<UnlinkedSimpleJumpTable> { >+public: >+ void encode(Encoder& encoder, const UnlinkedSimpleJumpTable& jumpTable) >+ { >+ m_min = jumpTable.min; >+ m_branchOffsets.encode(encoder, jumpTable.branchOffsets); >+ } >+ >+ void decode(Decoder& decoder, UnlinkedSimpleJumpTable& jumpTable) const >+ { >+ jumpTable.min = m_min; >+ m_branchOffsets.decode(decoder, jumpTable.branchOffsets); >+ } >+ >+private: >+ int32_t m_min; >+ CachedVector<int32_t> m_branchOffsets; >+}; >+ >+class CachedStringJumpTable : public CachedObject<UnlinkedStringJumpTable> { >+public: >+ void encode(Encoder& encoder, const UnlinkedStringJumpTable& jumpTable) >+ { >+ m_offsetTable.encode(encoder, jumpTable.offsetTable); >+ } >+ >+ void decode(Decoder& decoder, UnlinkedStringJumpTable& jumpTable) const >+ { >+ m_offsetTable.decode(decoder, jumpTable.offsetTable); >+ } >+ >+private: >+ CachedHashMap<CachedRefPtr<CachedStringImpl>, UnlinkedStringJumpTable:: OffsetLocation> m_offsetTable; >+}; >+ >+class CachedCodeBlockRareData : public CachedObject<UnlinkedCodeBlock::RareData> { >+public: >+ void encode(Encoder& encoder, const UnlinkedCodeBlock::RareData& rareData) >+ { >+ m_exceptionHandlers.encode(encoder, rareData.m_exceptionHandlers); >+ m_switchJumpTables.encode(encoder, rareData.m_switchJumpTables); >+ m_stringSwitchJumpTables.encode(encoder, rareData.m_stringSwitchJumpTables); >+ m_expressionInfoFatPositions.encode(encoder, rareData.m_expressionInfoFatPositions); >+ m_typeProfilerInfoMap.encode(encoder, rareData.m_typeProfilerInfoMap); >+ m_opProfileControlFlowBytecodeOffsets.encode(encoder, rareData.m_opProfileControlFlowBytecodeOffsets); >+ } >+ >+ UnlinkedCodeBlock::RareData* decode(Decoder& decoder) const >+ { >+ UnlinkedCodeBlock::RareData* rareData = new UnlinkedCodeBlock::RareData { }; >+ m_exceptionHandlers.decode(decoder, rareData->m_exceptionHandlers); >+ m_switchJumpTables.decode(decoder, rareData->m_switchJumpTables); >+ m_stringSwitchJumpTables.decode(decoder, rareData->m_stringSwitchJumpTables); >+ m_expressionInfoFatPositions.decode(decoder, rareData->m_expressionInfoFatPositions); >+ m_typeProfilerInfoMap.decode(decoder, rareData->m_typeProfilerInfoMap); >+ m_opProfileControlFlowBytecodeOffsets.decode(decoder, rareData->m_opProfileControlFlowBytecodeOffsets); >+ return rareData; >+ } >+ >+private: >+ CachedVector<UnlinkedHandlerInfo> m_exceptionHandlers; >+ CachedVector<CachedSimpleJumpTable> m_switchJumpTables; >+ CachedVector<CachedStringJumpTable> m_stringSwitchJumpTables; >+ CachedVector<ExpressionRangeInfo::FatPosition> m_expressionInfoFatPositions; >+ CachedHashMap<unsigned, UnlinkedCodeBlock::RareData::TypeProfilerExpressionRange> m_typeProfilerInfoMap; >+ CachedVector<InstructionStream::Offset> m_opProfileControlFlowBytecodeOffsets; >+}; >+ >+class CachedBitVector : public VariableLengthObject<BitVector> { >+public: >+ void encode(Encoder& encoder, const BitVector& bitVector) >+ { >+ m_size = bitVector.size(); >+ uint8_t* buffer = this->allocate(encoder, m_size); >+ memcpy(buffer, bitVector.bits(), m_size); >+ } >+ >+ void decode(Decoder&, BitVector& bitVector) const >+ { >+ bitVector.ensureSize(m_size); >+ memcpy(bitVector.bits(), this->buffer(), m_size); >+ } >+ >+private: >+ unsigned m_size; >+}; >+ >+template<typename T, typename HashArg = typename DefaultHash<T>::Hash> >+class CachedHashSet : public CachedObject<HashSet<SourceType<T>, HashArg>> { >+public: >+ void encode(Encoder& encoder, const HashSet<SourceType<T>, HashArg>& set) >+ { >+ SourceType<decltype(m_entries)> entriesVector(set.size()); >+ unsigned i = 0; >+ for (const auto& item : set) >+ entriesVector[i++] = item; >+ m_entries.encode(encoder, entriesVector); >+ } >+ >+ void decode(Decoder& decoder, HashSet<SourceType<T>, HashArg>& set) const >+ { >+ SourceType<decltype(m_entries)> entriesVector; >+ m_entries.decode(decoder, entriesVector); >+ for (const auto& item : entriesVector) >+ set.add(item); >+ } >+ >+private: >+ CachedVector<T> m_entries; >+}; >+ >+class CachedConstantIdentifierSetEntry : public VariableLengthObject<ConstantIdentifierSetEntry> { >+public: >+ void encode(Encoder& encoder, const ConstantIdentifierSetEntry& entry) >+ { >+ m_constant = entry.second; >+ m_set.encode(encoder, entry.first); >+ } >+ >+ void decode(Decoder& decoder, ConstantIdentifierSetEntry& entry) const >+ { >+ entry.second = m_constant; >+ m_set.decode(decoder, entry.first); >+ } >+ >+private: >+ unsigned m_constant; >+ CachedHashSet<CachedRefPtr<CachedUniquedStringImpl>, IdentifierRepHash> m_set; >+}; >+ >+class CachedVariableEnvironment : public CachedObject<VariableEnvironment> { >+public: >+ void encode(Encoder& encoder, const VariableEnvironment& env) >+ { >+ m_isEverythingCaptured = env.m_isEverythingCaptured; >+ m_map.encode(encoder, env.m_map); >+ } >+ >+ void decode(Decoder& decoder, VariableEnvironment& env) const >+ { >+ env.m_isEverythingCaptured = m_isEverythingCaptured; >+ m_map.decode(decoder, env.m_map); >+ } >+ >+private: >+ bool m_isEverythingCaptured; >+ CachedHashMap<CachedRefPtr<CachedUniquedStringImpl>, VariableEnvironmentEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, VariableEnvironmentEntryHashTraits> m_map; >+}; >+ >+template<typename T, typename Source = SourceType<T>> >+class CachedArray : public VariableLengthObject<Source*> { >+public: >+ void encode(Encoder& encoder, const Source* array, unsigned size) >+ { >+ T* dst = this->template allocate<T>(encoder, size); >+ for (unsigned i = 0; i < size; ++i) >+ ::JSC::encode(encoder, dst[i], array[i]); >+ } >+ >+ template<typename... Args> >+ void decode(Decoder& decoder, Source* array, unsigned size, Args... args) const >+ { >+ const T* buffer = this->template buffer<T>(); >+ for (unsigned i = 0; i < size; ++i) >+ ::JSC::decode(decoder, buffer[i], array[i], args...); >+ } >+}; >+ >+class CachedScopedArgumentsTable : public CachedObject<ScopedArgumentsTable> { >+public: >+ void encode(Encoder& encoder, const ScopedArgumentsTable& scopedArgumentsTable) >+ { >+ m_length = scopedArgumentsTable.m_length; >+ m_arguments.encode(encoder, scopedArgumentsTable.m_arguments.get(), m_length); >+ } >+ >+ ScopedArgumentsTable* decode(Decoder& decoder) const >+ { >+ ScopedArgumentsTable* scopedArgumentsTable = ScopedArgumentsTable::create(decoder.vm(), m_length); >+ m_arguments.decode(decoder, scopedArgumentsTable->m_arguments.get(), m_length); >+ return scopedArgumentsTable; >+ } >+ >+private: >+ uint32_t m_length; >+ CachedArray<ScopeOffset> m_arguments; >+}; >+ >+class CachedSymbolTableEntry : public CachedObject<SymbolTableEntry> { >+public: >+ void encode(Encoder&, const SymbolTableEntry& symbolTableEntry) >+ { >+ m_bits = symbolTableEntry.m_bits | SymbolTableEntry::SlimFlag; >+ } >+ >+ void decode(Decoder&, SymbolTableEntry& symbolTableEntry) const >+ { >+ symbolTableEntry.m_bits = m_bits; >+ } >+ >+private: >+ intptr_t m_bits; >+}; >+ >+class CachedSymbolTable : public CachedObject<SymbolTable> { >+public: >+ void encode(Encoder& encoder, const SymbolTable& symbolTable) >+ { >+ ASSERT(!symbolTable.m_rareData); >+ m_map.encode(encoder, symbolTable.m_map); >+ m_maxScopeOffset = symbolTable.m_maxScopeOffset; >+ m_usesNonStrictEval = symbolTable.m_usesNonStrictEval; >+ m_nestedLexicalScope = symbolTable.m_nestedLexicalScope; >+ m_scopeType = symbolTable.m_scopeType; >+ m_arguments.encode(encoder, symbolTable.m_arguments.get()); >+ } >+ >+ SymbolTable* decode(Decoder& decoder) const >+ { >+ SymbolTable* symbolTable = SymbolTable::create(decoder.vm()); >+ m_map.decode(decoder, symbolTable->m_map); >+ symbolTable->m_maxScopeOffset = m_maxScopeOffset; >+ symbolTable->m_usesNonStrictEval = m_usesNonStrictEval; >+ symbolTable->m_nestedLexicalScope = m_nestedLexicalScope; >+ symbolTable->m_scopeType = m_scopeType; >+ ScopedArgumentsTable* scopedArgumentsTable = m_arguments.decode(decoder); >+ if (scopedArgumentsTable) >+ symbolTable->m_arguments.set(decoder.vm(), symbolTable, scopedArgumentsTable); >+ return symbolTable; >+ } >+ >+private: >+ CachedHashMap<CachedRefPtr<CachedUniquedStringImpl>, CachedSymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, SymbolTableIndexHashTraits> m_map; >+ ScopeOffset m_maxScopeOffset; >+ unsigned m_usesNonStrictEval : 1; >+ unsigned m_nestedLexicalScope : 1; >+ unsigned m_scopeType : 3; >+ // FIXME: do we need to cached this eventually? >+ // CachedPtr<SymbolTableRareData> rareData; >+ CachedPtr<CachedScopedArgumentsTable> m_arguments; >+}; >+ >+class CachedJSValue; >+class CachedImmutableButterfly : public CachedObject<JSImmutableButterfly> { >+public: >+ void encode(Encoder& encoder, JSImmutableButterfly& immutableButterfly) >+ { >+ m_length = immutableButterfly.length(); >+ m_indexingType = immutableButterfly.indexingTypeAndMisc(); >+ if (hasDouble(m_indexingType)) >+ m_cachedDoubles.encode(encoder, immutableButterfly.toButterfly()->contiguousDouble().data(), m_length); >+ else >+ m_cachedValues.encode(encoder, immutableButterfly.toButterfly()->contiguous().data(), m_length); >+ } >+ >+ JSImmutableButterfly* decode(Decoder& decoder) const >+ { >+ JSImmutableButterfly* immutableButterfly = JSImmutableButterfly::create(decoder.vm(), m_indexingType, m_length); >+ if (hasDouble(m_indexingType)) >+ m_cachedDoubles.decode(decoder, immutableButterfly->toButterfly()->contiguousDouble().data(), m_length, immutableButterfly); >+ else >+ m_cachedValues.decode(decoder, immutableButterfly->toButterfly()->contiguous().data(), m_length, immutableButterfly); >+ return immutableButterfly; >+ } >+ >+private: >+ IndexingType m_indexingType; >+ unsigned m_length; >+ union { >+ CachedArray<double> m_cachedDoubles; >+ CachedArray<CachedJSValue, WriteBarrier<Unknown>> m_cachedValues; >+ }; >+}; >+ >+class CachedRegExp : public CachedObject<RegExp> { >+public: >+ void encode(Encoder& encoder, const RegExp& regExp) >+ { >+ m_patternString.encode(encoder, regExp.m_patternString); >+ m_flags = regExp.m_flags; >+ } >+ >+ RegExp* decode(Decoder& decoder) const >+ { >+ String pattern { m_patternString.decode(decoder) }; >+ return RegExp::create(decoder.vm(), pattern, m_flags); >+ } >+ >+private: >+ CachedString m_patternString; >+ RegExpFlags m_flags; >+}; >+ >+class CachedTemplateObjectDescriptor : public CachedObject<TemplateObjectDescriptor> { >+public: >+ void encode(Encoder& encoder, const TemplateObjectDescriptor& templateObjectDescriptor) >+ { >+ m_rawStrings.encode(encoder, templateObjectDescriptor.rawStrings()); >+ m_cookedStrings.encode(encoder, templateObjectDescriptor.cookedStrings()); >+ } >+ >+ Ref<TemplateObjectDescriptor> decode(Decoder& decoder) const >+ { >+ TemplateObjectDescriptor::StringVector decodedRawStrings; >+ TemplateObjectDescriptor::OptionalStringVector decodedCookedStrings; >+ m_rawStrings.decode(decoder, decodedRawStrings); >+ m_cookedStrings.decode(decoder, decodedCookedStrings); >+ return TemplateObjectDescriptor::create(WTFMove(decodedRawStrings), WTFMove(decodedCookedStrings)); >+ } >+ >+private: >+ CachedVector<CachedString, 4> m_rawStrings; >+ CachedVector<CachedOptional<CachedString>, 4> m_cookedStrings; >+}; >+ >+class CachedBigInt : public VariableLengthObject<JSBigInt> { >+public: >+ void encode(Encoder& encoder, JSBigInt& bigInt) >+ { >+ m_length = bigInt.length(); >+ m_sign = bigInt.sign(); >+ >+ if (!m_length) >+ return; >+ >+ unsigned size = sizeof(JSBigInt::Digit) * m_length; >+ uint8_t* buffer = this->allocate(encoder, size); >+ memcpy(buffer, bigInt.dataStorage(), size); >+ } >+ >+ JSBigInt* decode(Decoder& decoder) const >+ { >+ JSBigInt* bigInt = JSBigInt::createWithLengthUnchecked(decoder.vm(), m_length); >+ bigInt->setSign(m_sign); >+ memcpy(bigInt->dataStorage(), this->buffer(), sizeof(JSBigInt::Digit) * m_length); >+ return bigInt; >+ } >+ >+private: >+ unsigned m_length; >+ bool m_sign; >+}; >+ >+class CachedJSValue : public VariableLengthObject<WriteBarrier<Unknown>> { >+public: >+ void encode(Encoder& encoder, const WriteBarrier<Unknown> value) >+ { >+ JSValue v = value.get(); >+ >+ if (!v.isCell() || v.isEmpty()) { >+ m_type = EncodedType::JSValue; >+ *this->allocate<EncodedJSValue>(encoder) = JSValue::encode(v); >+ return; >+ } >+ >+ JSCell* cell = v.asCell(); >+ VM& vm = encoder.vm(); >+ >+ if (auto* symbolTable = jsDynamicCast<SymbolTable*>(vm, cell)) { >+ m_type = EncodedType::SymbolTable; >+ this->allocate<CachedSymbolTable>(encoder)->encode(encoder, *symbolTable); >+ return; >+ } >+ >+ if (auto* string = jsDynamicCast<JSString*>(vm, cell)) { >+ m_type = EncodedType::String; >+ StringImpl* impl = string->tryGetValue().impl(); >+ this->allocate<CachedUniquedStringImpl>(encoder)->encode(encoder, *impl); >+ return; >+ } >+ >+ if (auto* immutableButterfly = jsDynamicCast<JSImmutableButterfly*>(vm, cell)) { >+ m_type = EncodedType::ImmutableButterfly; >+ this->allocate<CachedImmutableButterfly>(encoder)->encode(encoder, *immutableButterfly); >+ return; >+ } >+ >+ if (auto* regexp = jsDynamicCast<RegExp*>(vm, cell)) { >+ m_type = EncodedType::RegExp; >+ this->allocate<CachedRegExp>(encoder)->encode(encoder, *regexp); >+ return; >+ } >+ >+ if (auto* templateObjectDescriptor = jsDynamicCast<JSTemplateObjectDescriptor*>(vm, cell)) { >+ m_type = EncodedType::TemplateObjectDescriptor; >+ this->allocate<CachedTemplateObjectDescriptor>(encoder)->encode(encoder, templateObjectDescriptor->descriptor()); >+ return; >+ } >+ >+ if (auto* bigInt = jsDynamicCast<JSBigInt*>(vm, cell)) { >+ m_type = EncodedType::BigInt; >+ this->allocate<CachedBigInt>(encoder)->encode(encoder, *bigInt); >+ return; >+ } >+ >+ RELEASE_ASSERT_NOT_REACHED(); >+ } >+ >+ void decode(Decoder& decoder, WriteBarrier<Unknown>& value, const JSCell* owner) const >+ { >+ JSValue v; >+ switch (m_type) { >+ case EncodedType::JSValue: >+ v = JSValue::decode(*this->buffer<EncodedJSValue>()); >+ break; >+ case EncodedType::SymbolTable: >+ v = this->buffer<CachedSymbolTable>()->decode(decoder); >+ break; >+ case EncodedType::String: { >+ UniquedStringImpl* impl = this->buffer<CachedUniquedStringImpl>()->decode(decoder); >+ v = JSString::create(decoder.vm(), adoptRef(*impl)); >+ break; >+ } >+ case EncodedType::ImmutableButterfly: >+ v = this->buffer<CachedImmutableButterfly>()->decode(decoder); >+ break; >+ case EncodedType::RegExp: >+ v = this->buffer<CachedRegExp>()->decode(decoder); >+ break; >+ case EncodedType::TemplateObjectDescriptor: >+ v = JSTemplateObjectDescriptor::create(decoder.vm(), this->buffer<CachedTemplateObjectDescriptor>()->decode(decoder)); >+ break; >+ case EncodedType::BigInt: >+ v = this->buffer<CachedBigInt>()->decode(decoder); >+ break; >+ default: >+ RELEASE_ASSERT_NOT_REACHED(); >+ } >+ value.set(decoder.vm(), owner, v); >+ } >+ >+private: >+ enum class EncodedType : uint8_t { >+ JSValue, >+ SymbolTable, >+ String, >+ ImmutableButterfly, >+ RegExp, >+ TemplateObjectDescriptor, >+ BigInt, >+ }; >+ >+ EncodedType m_type; >+}; >+ >+class CachedInstructionStream : public CachedObject<InstructionStream> { >+public: >+ void encode(Encoder& encoder, const InstructionStream& stream) >+ { >+ m_instructions.encode(encoder, stream.m_instructions); >+ } >+ >+ InstructionStream* decode(Decoder& decoder) const >+ { >+ Vector<uint8_t, 0, UnsafeVectorOverflow> instructionsVector; >+ m_instructions.decode(decoder, instructionsVector); >+ return new InstructionStream(WTFMove(instructionsVector)); >+ } >+ >+private: >+ CachedVector<uint8_t, 0, UnsafeVectorOverflow> m_instructions; >+}; >+ >+class CachedMetadataTable : public CachedObject<UnlinkedMetadataTable> { >+public: >+ void encode(Encoder&, const UnlinkedMetadataTable& metadataTable) >+ { >+ ASSERT(metadataTable.m_isFinalized); >+ m_hasMetadata = metadataTable.m_hasMetadata; >+ if (!m_hasMetadata) >+ return; >+ for (unsigned i = UnlinkedMetadataTable::s_offsetTableEntries; i--;) >+ m_metadata[i] = metadataTable.buffer()[i]; >+ } >+ >+ void decode(Decoder&, UnlinkedMetadataTable& metadataTable) const >+ { >+ metadataTable.m_isFinalized = true; >+ metadataTable.m_isLinked = false; >+ metadataTable.m_hasMetadata = m_hasMetadata; >+ for (unsigned i = UnlinkedMetadataTable::s_offsetTableEntries; i--;) >+ metadataTable.buffer()[i] = m_metadata[i]; >+ } >+ >+private: >+ bool m_hasMetadata; >+ std::array<unsigned, UnlinkedMetadataTable::s_offsetTableEntries> m_metadata; >+}; >+ >+class CachedSourceOrigin : public CachedObject<SourceOrigin> { >+public: >+ void encode(Encoder& encoder, const SourceOrigin& sourceOrigin) >+ { >+ m_string.encode(encoder, sourceOrigin.string()); >+ } >+ >+ SourceOrigin decode(Decoder& decoder) const >+ { >+ return SourceOrigin { m_string.decode(decoder) }; >+ } >+ >+private: >+ CachedString m_string; >+}; >+ >+class CachedTextPosition : public CachedObject<TextPosition> { >+public: >+ void encode(Encoder&, TextPosition textPosition) >+ { >+ m_line = textPosition.m_line.zeroBasedInt(); >+ m_column = textPosition.m_column.zeroBasedInt(); >+ } >+ >+ TextPosition decode(Decoder&) const >+ { >+ return TextPosition { OrdinalNumber::fromZeroBasedInt(m_line), OrdinalNumber::fromZeroBasedInt(m_column) }; >+ } >+ >+private: >+ int m_line; >+ int m_column; >+}; >+ >+template <typename Source, typename CachedType> >+class CachedSourceProviderShape : public CachedObject<Source> { >+public: >+ void encode(Encoder& encoder, const SourceProvider& sourceProvider) >+ { >+ m_sourceOrigin.encode(encoder, sourceProvider.sourceOrigin()); >+ m_url.encode(encoder, sourceProvider.url()); >+ m_sourceURLDirective.encode(encoder, sourceProvider.sourceURL()); >+ m_sourceMappingURLDirective.encode(encoder, sourceProvider.sourceMappingURL()); >+ m_startPosition.encode(encoder, sourceProvider.startPosition()); >+ } >+ >+ void decode(Decoder& decoder, SourceProvider& sourceProvider) const >+ { >+ sourceProvider.setSourceURLDirective(m_sourceURLDirective.decode(decoder)); >+ sourceProvider.setSourceMappingURLDirective(m_sourceMappingURLDirective.decode(decoder)); >+ } >+ >+protected: >+ CachedSourceOrigin m_sourceOrigin; >+ CachedString m_url; >+ CachedString m_sourceURLDirective; >+ CachedString m_sourceMappingURLDirective; >+ CachedTextPosition m_startPosition; >+}; >+ >+class CachedStringSourceProvider : public CachedSourceProviderShape<StringSourceProvider, CachedStringSourceProvider> { >+ using Base = CachedSourceProviderShape<StringSourceProvider, CachedStringSourceProvider>; >+ >+public: >+ void encode(Encoder& encoder, const StringSourceProvider& sourceProvider) >+ { >+ Base::encode(encoder, sourceProvider); >+ m_source.encode(encoder, sourceProvider.source().toString()); >+ } >+ >+ StringSourceProvider* decode(Decoder& decoder, SourceProviderSourceType sourceType) const >+ { >+ String decodedSource = m_source.decode(decoder); >+ SourceOrigin decodedSourceOrigin = m_sourceOrigin.decode(decoder); >+ String decodedURL = m_url.decode(decoder); >+ TextPosition decodedStartPosition = m_startPosition.decode(decoder); >+ >+ Ref<StringSourceProvider> sourceProvider = StringSourceProvider::create(decodedSource, decodedSourceOrigin, URL(URL(), decodedURL), decodedStartPosition, sourceType); >+ Base::decode(decoder, sourceProvider.get()); >+ return &sourceProvider.leakRef(); >+ } >+ >+private: >+ CachedString m_source; >+}; >+ >+#if ENABLE(WEBASSEMBLY) >+class CachedWebAssemblySourceProvider : public CachedSourceProviderShape<WebAssemblySourceProvider, CachedWebAssemblySourceProvider> { >+ using Base = CachedSourceProviderShape<WebAssemblySourceProvider, CachedWebAssemblySourceProvider>; >+ >+public: >+ void encode(Encoder& encoder, const WebAssemblySourceProvider& sourceProvider) >+ { >+ Base::encode(encoder, sourceProvider); >+ m_data.encode(encoder, sourceProvider.data()); >+ } >+ >+ WebAssemblySourceProvider* decode(Decoder& decoder) const >+ { >+ Vector<uint8_t> decodedData; >+ SourceOrigin decodedSourceOrigin = m_sourceOrigin.decode(decoder); >+ String decodedURL = m_url.decode(decoder); >+ >+ m_data.decode(decoder, decodedData); >+ >+ Ref<WebAssemblySourceProvider> sourceProvider = WebAssemblySourceProvider::create(WTFMove(decodedData), decodedSourceOrigin, URL(URL(), decodedURL)); >+ Base::decode(decoder, sourceProvider.get()); >+ >+ return &sourceProvider.leakRef(); >+ } >+ >+private: >+ CachedVector<uint8_t> m_data; >+}; >+#endif >+ >+class CachedSourceProvider : public VariableLengthObject<SourceProvider> { >+public: >+ void encode(Encoder& encoder, const SourceProvider& sourceProvider) >+ { >+ m_sourceType = sourceProvider.sourceType(); >+ switch (m_sourceType) { >+ case SourceProviderSourceType::Program: >+ case SourceProviderSourceType::Module: >+ this->allocate<CachedStringSourceProvider>(encoder)->encode(encoder, reinterpret_cast<const StringSourceProvider&>(sourceProvider)); >+ break; >+#if ENABLE(WEBASSEMBLY) >+ case SourceProviderSourceType::WebAssembly: >+ this->allocate<CachedWebAssemblySourceProvider>(encoder)->encode(encoder, reinterpret_cast<const WebAssemblySourceProvider&>(sourceProvider)); >+ break; >+#endif >+ default: >+ RELEASE_ASSERT_NOT_REACHED(); >+ } >+ } >+ >+ SourceProvider* decode(Decoder& decoder) const >+ { >+ switch (m_sourceType) { >+ case SourceProviderSourceType::Program: >+ case SourceProviderSourceType::Module: >+ return this->buffer<CachedStringSourceProvider>()->decode(decoder, m_sourceType); >+#if ENABLE(WEBASSEMBLY) >+ case SourceProviderSourceType::WebAssembly: >+ return this->buffer<CachedWebAssemblySourceProvider>()->decode(decoder); >+#endif >+ default: >+ RELEASE_ASSERT_NOT_REACHED(); >+ } >+ } >+ >+private: >+ SourceProviderSourceType m_sourceType; >+}; >+ >+template<typename Source> >+class CachedUnlinkedSourceCodeShape : public CachedObject<Source> { >+public: >+ void encode(Encoder& encoder, const UnlinkedSourceCode& sourceCode) >+ { >+ m_provider.encode(encoder, sourceCode.m_provider.get()); >+ m_startOffset = sourceCode.startOffset(); >+ m_endOffset = sourceCode.endOffset(); >+ } >+ >+ void decode(Decoder& decoder, UnlinkedSourceCode& sourceCode) const >+ { >+ sourceCode.m_provider = m_provider.decode(decoder); >+ sourceCode.m_startOffset = m_startOffset; >+ sourceCode.m_endOffset = m_endOffset; >+ } >+ >+private: >+ CachedPtr<CachedSourceProvider> m_provider; >+ int m_startOffset; >+ int m_endOffset; >+}; >+ >+ >+class CachedUnlinkedSourceCode : public CachedUnlinkedSourceCodeShape<UnlinkedSourceCode> { }; >+ >+class CachedSourceCode : public CachedUnlinkedSourceCodeShape<SourceCode> { >+ using Base = CachedUnlinkedSourceCodeShape<SourceCode>; >+ >+public: >+ void encode(Encoder& encoder, const SourceCode& sourceCode) >+ { >+ Base::encode(encoder, sourceCode); >+ m_firstLine = sourceCode.firstLine().zeroBasedInt(); >+ m_startColumn = sourceCode.startColumn().zeroBasedInt(); >+ } >+ >+ void decode(Decoder& decoder, SourceCode& sourceCode) const >+ { >+ Base::decode(decoder, sourceCode); >+ sourceCode.m_firstLine = OrdinalNumber::fromZeroBasedInt(m_firstLine); >+ sourceCode.m_startColumn = OrdinalNumber::fromZeroBasedInt(m_startColumn); >+ } >+ >+private: >+ int m_firstLine; >+ int m_startColumn; >+}; >+ >+class CachedFunctionExecutable : public CachedObject<UnlinkedFunctionExecutable> { >+public: >+ void encode(Encoder&, const UnlinkedFunctionExecutable&); >+ UnlinkedFunctionExecutable* decode(Decoder&) const; >+ >+ unsigned firstLineOffset() const { return m_firstLineOffset; } >+ unsigned lineCount() const { return m_lineCount; } >+ unsigned unlinkedFunctionNameStart() const { return m_unlinkedFunctionNameStart; } >+ unsigned unlinkedBodyStartColumn() const { return m_unlinkedBodyStartColumn; } >+ unsigned unlinkedBodyEndColumn() const { return m_unlinkedBodyEndColumn; } >+ unsigned startOffset() const { return m_startOffset; } >+ unsigned sourceLength() const { return m_sourceLength; } >+ unsigned parametersStartOffset() const { return m_parametersStartOffset; } >+ unsigned typeProfilingStartOffset() const { return m_typeProfilingStartOffset; } >+ unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; } >+ unsigned parameterCount() const { return m_parameterCount; } >+ >+ CodeFeatures features() const { return m_features; } >+ SourceParseMode sourceParseMode() const { return m_sourceParseMode; } >+ >+ unsigned isInStrictContext() const { return m_isInStrictContext; } >+ unsigned hasCapturedVariables() const { return m_hasCapturedVariables; } >+ unsigned isBuiltinFunction() const { return m_isBuiltinFunction; } >+ unsigned isBuiltinDefaultClassConstructor() const { return m_isBuiltinDefaultClassConstructor; } >+ unsigned constructAbility() const { return m_constructAbility; } >+ unsigned constructorKind() const { return m_constructorKind; } >+ unsigned functionMode() const { return m_functionMode; } >+ unsigned scriptMode() const { return m_scriptMode; } >+ unsigned superBinding() const { return m_superBinding; } >+ unsigned derivedContextType() const { return m_derivedContextType; } >+ >+ Identifier name(Decoder& decoder) const { return m_name.decode(decoder); } >+ Identifier ecmaName(Decoder& decoder) const { return m_ecmaName.decode(decoder); } >+ Identifier inferredName(Decoder& decoder) const { return m_inferredName.decode(decoder); } >+ >+private: >+ unsigned m_firstLineOffset; >+ unsigned m_lineCount; >+ unsigned m_unlinkedFunctionNameStart; >+ unsigned m_unlinkedBodyStartColumn; >+ unsigned m_unlinkedBodyEndColumn; >+ unsigned m_startOffset; >+ unsigned m_sourceLength; >+ unsigned m_parametersStartOffset; >+ unsigned m_typeProfilingStartOffset; >+ unsigned m_typeProfilingEndOffset; >+ unsigned m_parameterCount; >+ CodeFeatures m_features; >+ SourceParseMode m_sourceParseMode; >+ unsigned m_isInStrictContext : 1; >+ unsigned m_hasCapturedVariables : 1; >+ unsigned m_isBuiltinFunction : 1; >+ unsigned m_isBuiltinDefaultClassConstructor : 1; >+ unsigned m_constructAbility: 1; >+ unsigned m_constructorKind : 2; >+ unsigned m_functionMode : 2; // FunctionMode >+ unsigned m_scriptMode: 1; // JSParserScriptMode >+ unsigned m_superBinding : 1; >+ unsigned m_derivedContextType: 2; >+ >+ CachedSourceCode m_classSource; >+ >+ CachedIdentifier m_name; >+ CachedIdentifier m_ecmaName; >+ CachedIdentifier m_inferredName; >+ >+ CachedVariableEnvironment m_parentScopeTDZVariables; >+ >+ CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForCall; >+ CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForConstruct; >+}; >+ >+template<typename CodeBlockType> >+class CachedCodeBlock : public CachedObject<CodeBlockType> { >+public: >+ void encode(Encoder&, const UnlinkedCodeBlock&); >+ void decode(Decoder&, UnlinkedCodeBlock&) const; >+ >+ InstructionStream* instructions(Decoder& decoder) const { return m_instructions.decode(decoder); } >+ >+ VirtualRegister thisRegister() const { return m_thisRegister; } >+ VirtualRegister scopeRegister() const { return m_scopeRegister; } >+ VirtualRegister globalObjectRegister() const { return m_globalObjectRegister; } >+ >+ String sourceURLDirective(Decoder& decoder) const { return m_sourceURLDirective.decode(decoder); } >+ String sourceMappingURLDirective(Decoder& decoder) const { return m_sourceMappingURLDirective.decode(decoder); } >+ >+ unsigned usesEval() const { return m_usesEval; } >+ unsigned isStrictMode() const { return m_isStrictMode; } >+ unsigned isConstructor() const { return m_isConstructor; } >+ unsigned hasCapturedVariables() const { return m_hasCapturedVariables; } >+ unsigned isBuiltinFunction() const { return m_isBuiltinFunction; } >+ unsigned superBinding() const { return m_superBinding; } >+ unsigned scriptMode() const { return m_scriptMode; } >+ unsigned isArrowFunctionContext() const { return m_isArrowFunctionContext; } >+ unsigned isClassContext() const { return m_isClassContext; } >+ unsigned wasCompiledWithDebuggingOpcodes() const { return m_wasCompiledWithDebuggingOpcodes; } >+ unsigned constructorKind() const { return m_constructorKind; } >+ unsigned derivedContextType() const { return m_derivedContextType; } >+ unsigned evalContextType() const { return m_evalContextType; } >+ unsigned hasTailCalls() const { return m_hasTailCalls; } >+ unsigned lineCount() const { return m_lineCount; } >+ unsigned endColumn() const { return m_endColumn; } >+ >+ int numVars() const { return m_numVars; } >+ int numCalleeLocals() const { return m_numCalleeLocals; } >+ int numParameters() const { return m_numParameters; } >+ >+ CodeFeatures features() const { return m_features; } >+ SourceParseMode parseMode() const { return m_parseMode; } >+ CodeType codeType() const { return m_codeType; } >+ >+ UnlinkedCodeBlock::RareData* rareData(Decoder& decoder) const { return m_rareData.decodeAsPtr(decoder); } >+ >+private: >+ VirtualRegister m_thisRegister; >+ VirtualRegister m_scopeRegister; >+ VirtualRegister m_globalObjectRegister; >+ >+ unsigned m_usesEval : 1; >+ unsigned m_isStrictMode : 1; >+ unsigned m_isConstructor : 1; >+ unsigned m_hasCapturedVariables : 1; >+ unsigned m_isBuiltinFunction : 1; >+ unsigned m_superBinding : 1; >+ unsigned m_scriptMode: 1; >+ unsigned m_isArrowFunctionContext : 1; >+ unsigned m_isClassContext : 1; >+ unsigned m_wasCompiledWithDebuggingOpcodes : 1; >+ unsigned m_constructorKind : 2; >+ unsigned m_derivedContextType : 2; >+ unsigned m_evalContextType : 2; >+ unsigned m_hasTailCalls : 1; >+ >+ unsigned m_lineCount; >+ unsigned m_endColumn; >+ >+ int m_numVars; >+ int m_numCalleeLocals; >+ int m_numParameters; >+ >+ CodeFeatures m_features; >+ SourceParseMode m_parseMode; >+ CodeType m_codeType; >+ >+ std::array<unsigned, LinkTimeConstantCount> m_linkTimeConstants; >+ CachedMetadataTable m_metadata; >+ >+ CachedOptional<CachedCodeBlockRareData> m_rareData; >+ >+ CachedString m_sourceURLDirective; >+ CachedString m_sourceMappingURLDirective; >+ >+ CachedPtr<CachedInstructionStream> m_instructions; >+ CachedVector<InstructionStream::Offset> m_jumpTargets; >+ CachedVector<InstructionStream::Offset> m_propertyAccessInstructions; >+ CachedVector<CachedJSValue> m_constantRegisters; >+ CachedVector<SourceCodeRepresentation> m_constantsSourceCodeRepresentation; >+ CachedVector<ExpressionRangeInfo> m_expressionInfo; >+ CachedHashMap<InstructionStream::Offset, int> m_outOfLineJumpTargets; >+ >+ CachedVector<CachedConstantIdentifierSetEntry> m_constantIdentifierSets; >+ CachedVector<CachedIdentifier> m_identifiers; >+ CachedVector<CachedBitVector> m_bitVectors; >+ CachedVector<CachedWriteBarrier<CachedFunctionExecutable>> m_functionDecls; >+ CachedVector<CachedWriteBarrier<CachedFunctionExecutable>> m_functionExprs; >+}; >+ >+class CachedProgramCodeBlock : public CachedCodeBlock<UnlinkedProgramCodeBlock> { >+ using Base = CachedCodeBlock<UnlinkedProgramCodeBlock>; >+ >+public: >+ void encode(Encoder& encoder, const UnlinkedProgramCodeBlock& codeBlock) >+ { >+ Base::encode(encoder, codeBlock); >+ m_varDeclarations.encode(encoder, codeBlock.m_varDeclarations); >+ m_lexicalDeclarations.encode(encoder, codeBlock.m_lexicalDeclarations); >+ } >+ >+ UnlinkedProgramCodeBlock* decode(Decoder& decoder) const >+ { >+ UnlinkedProgramCodeBlock* codeBlock = new (NotNull, allocateCell<UnlinkedProgramCodeBlock>(decoder.vm().heap)) UnlinkedProgramCodeBlock(decoder, *this); >+ codeBlock->finishCreation(decoder.vm()); >+ Base::decode(decoder, *codeBlock); >+ m_varDeclarations.decode(decoder, codeBlock->m_varDeclarations); >+ m_lexicalDeclarations.decode(decoder, codeBlock->m_lexicalDeclarations); >+ return codeBlock; >+ } >+ >+private: >+ CachedVariableEnvironment m_varDeclarations; >+ CachedVariableEnvironment m_lexicalDeclarations; >+}; >+ >+class CachedModuleCodeBlock : public CachedCodeBlock<UnlinkedModuleProgramCodeBlock> { >+ using Base = CachedCodeBlock<UnlinkedModuleProgramCodeBlock>; >+ >+public: >+ void encode(Encoder& encoder, const UnlinkedModuleProgramCodeBlock& codeBlock) >+ { >+ Base::encode(encoder, codeBlock); >+ m_moduleEnvironmentSymbolTableConstantRegisterOffset = codeBlock.m_moduleEnvironmentSymbolTableConstantRegisterOffset; >+ } >+ >+ UnlinkedModuleProgramCodeBlock* decode(Decoder& decoder) const >+ { >+ UnlinkedModuleProgramCodeBlock* codeBlock = new (NotNull, allocateCell<UnlinkedModuleProgramCodeBlock>(decoder.vm().heap)) UnlinkedModuleProgramCodeBlock(decoder, *this); >+ codeBlock->finishCreation(decoder.vm()); >+ Base::decode(decoder, *codeBlock); >+ codeBlock->m_moduleEnvironmentSymbolTableConstantRegisterOffset = m_moduleEnvironmentSymbolTableConstantRegisterOffset; >+ return codeBlock; >+ } >+ >+private: >+ int m_moduleEnvironmentSymbolTableConstantRegisterOffset; >+}; >+ >+class CachedEvalCodeBlock : public CachedCodeBlock<UnlinkedEvalCodeBlock> { >+ using Base = CachedCodeBlock<UnlinkedEvalCodeBlock>; >+ >+public: >+ void encode(Encoder& encoder, const UnlinkedEvalCodeBlock& codeBlock) >+ { >+ Base::encode(encoder, codeBlock); >+ m_variables.encode(encoder, codeBlock.m_variables); >+ m_functionHoistingCandidates.encode(encoder, codeBlock.m_functionHoistingCandidates); >+ } >+ >+ UnlinkedEvalCodeBlock* decode(Decoder& decoder) const >+ { >+ UnlinkedEvalCodeBlock* codeBlock = new (NotNull, allocateCell<UnlinkedEvalCodeBlock>(decoder.vm().heap)) UnlinkedEvalCodeBlock(decoder, *this); >+ codeBlock->finishCreation(decoder.vm()); >+ Base::decode(decoder, *codeBlock); >+ m_variables.decode(decoder, codeBlock->m_variables); >+ m_functionHoistingCandidates.decode(decoder, codeBlock->m_functionHoistingCandidates); >+ return codeBlock; >+ } >+ >+private: >+ CachedVector<CachedIdentifier, 0, UnsafeVectorOverflow> m_variables; >+ CachedVector<CachedIdentifier, 0, UnsafeVectorOverflow> m_functionHoistingCandidates; >+}; >+ >+class CachedFunctionCodeBlock : public CachedCodeBlock<UnlinkedFunctionCodeBlock> { >+ using Base = CachedCodeBlock<UnlinkedFunctionCodeBlock>; >+ >+public: >+ void encode(Encoder& encoder, const UnlinkedFunctionCodeBlock& codeBlock) >+ { >+ Base::encode(encoder, codeBlock); >+ } >+ >+ UnlinkedFunctionCodeBlock* decode(Decoder& decoder) const >+ { >+ UnlinkedFunctionCodeBlock* codeBlock = new (NotNull, allocateCell<UnlinkedFunctionCodeBlock>(decoder.vm().heap)) UnlinkedFunctionCodeBlock(decoder, *this); >+ codeBlock->finishCreation(decoder.vm()); >+ Base::decode(decoder, *codeBlock); >+ return codeBlock; >+ } >+}; >+ >+ALWAYS_INLINE UnlinkedFunctionCodeBlock::UnlinkedFunctionCodeBlock(Decoder& decoder, const CachedFunctionCodeBlock& cachedCodeBlock) >+ : Base(decoder, decoder.vm().unlinkedFunctionCodeBlockStructure.get(), cachedCodeBlock) >+{ >+} >+ >+template<typename T> >+struct CachedCodeBlockTypeImpl; >+ >+enum CachedCodeBlockTag { >+ CachedProgramCodeBlockTag, >+ CachedModuleCodeBlockTag, >+ CachedEvalCodeBlockTag, >+}; >+ >+template<> >+struct CachedCodeBlockTypeImpl<UnlinkedProgramCodeBlock> { >+ using type = CachedProgramCodeBlock; >+ static constexpr CachedCodeBlockTag tag = CachedProgramCodeBlockTag; >+}; >+ >+template<> >+struct CachedCodeBlockTypeImpl<UnlinkedModuleProgramCodeBlock> { >+ using type = CachedModuleCodeBlock; >+ static constexpr CachedCodeBlockTag tag = CachedModuleCodeBlockTag; >+}; >+ >+template<> >+struct CachedCodeBlockTypeImpl<UnlinkedEvalCodeBlock> { >+ using type = CachedEvalCodeBlock; >+ static constexpr CachedCodeBlockTag tag = CachedEvalCodeBlockTag; >+}; >+ >+template<typename T> >+using CachedCodeBlockType = typename CachedCodeBlockTypeImpl<T>::type; >+ >+template<typename CodeBlockType> >+ALWAYS_INLINE UnlinkedCodeBlock::UnlinkedCodeBlock(Decoder& decoder, Structure* structure, const CachedCodeBlock<CodeBlockType>& cachedCodeBlock) >+ : Base(decoder.vm(), structure) >+ , m_instructions(cachedCodeBlock.instructions(decoder)) >+ , m_liveness(nullptr) >+ , m_thisRegister(cachedCodeBlock.thisRegister()) >+ , m_scopeRegister(cachedCodeBlock.scopeRegister()) >+ , m_globalObjectRegister(cachedCodeBlock.globalObjectRegister()) >+ >+ , m_sourceURLDirective(cachedCodeBlock.sourceURLDirective(decoder)) >+ , m_sourceMappingURLDirective(cachedCodeBlock.sourceMappingURLDirective(decoder)) >+ >+ , m_usesEval(cachedCodeBlock.usesEval()) >+ , m_isStrictMode(cachedCodeBlock.isStrictMode()) >+ , m_isConstructor(cachedCodeBlock.isConstructor()) >+ , m_hasCapturedVariables(cachedCodeBlock.hasCapturedVariables()) >+ , m_isBuiltinFunction(cachedCodeBlock.isBuiltinFunction()) >+ , m_superBinding(cachedCodeBlock.superBinding()) >+ , m_scriptMode(cachedCodeBlock.scriptMode()) >+ , m_isArrowFunctionContext(cachedCodeBlock.isArrowFunctionContext()) >+ , m_isClassContext(cachedCodeBlock.isClassContext()) >+ , m_wasCompiledWithDebuggingOpcodes(cachedCodeBlock.wasCompiledWithDebuggingOpcodes()) >+ , m_constructorKind(cachedCodeBlock.constructorKind()) >+ , m_derivedContextType(cachedCodeBlock.derivedContextType()) >+ , m_evalContextType(cachedCodeBlock.evalContextType()) >+ , m_hasTailCalls(cachedCodeBlock.hasTailCalls()) >+ , m_lineCount(cachedCodeBlock.lineCount()) >+ , m_endColumn(cachedCodeBlock.endColumn()) >+ , m_numVars(cachedCodeBlock.numVars()) >+ , m_numCalleeLocals(cachedCodeBlock.numCalleeLocals()) >+ , m_numParameters(cachedCodeBlock.numParameters()) >+ , m_features(cachedCodeBlock.features()) >+ , m_parseMode(cachedCodeBlock.parseMode()) >+ , m_codeType(cachedCodeBlock.codeType()) >+ , m_rareData(cachedCodeBlock.rareData(decoder)) >+{ >+} >+ >+template<typename CodeBlockType> >+ALWAYS_INLINE void CachedCodeBlock<CodeBlockType>::decode(Decoder& decoder, UnlinkedCodeBlock& codeBlock) const >+{ >+ for (unsigned i = LinkTimeConstantCount; i--;) >+ codeBlock.m_linkTimeConstants[i] = m_linkTimeConstants[i]; >+ >+ m_metadata.decode(decoder, codeBlock.m_metadata); >+ m_propertyAccessInstructions.decode(decoder, codeBlock.m_propertyAccessInstructions); >+ m_constantRegisters.decode(decoder, codeBlock.m_constantRegisters, &codeBlock); >+ m_constantsSourceCodeRepresentation.decode(decoder, codeBlock.m_constantsSourceCodeRepresentation); >+ m_expressionInfo.decode(decoder, codeBlock.m_expressionInfo); >+ m_outOfLineJumpTargets.decode(decoder, codeBlock.m_outOfLineJumpTargets); >+ m_jumpTargets.decode(decoder, codeBlock.m_jumpTargets); >+ m_constantIdentifierSets.decode(decoder, codeBlock.m_constantIdentifierSets); >+ m_identifiers.decode(decoder, codeBlock.m_identifiers); >+ m_bitVectors.decode(decoder, codeBlock.m_bitVectors); >+ m_functionDecls.decode(decoder, codeBlock.m_functionDecls, &codeBlock); >+ m_functionExprs.decode(decoder, codeBlock.m_functionExprs, &codeBlock); >+} >+ >+ALWAYS_INLINE UnlinkedProgramCodeBlock::UnlinkedProgramCodeBlock(Decoder& decoder, const CachedProgramCodeBlock& cachedCodeBlock) >+ : Base(decoder, decoder.vm().unlinkedProgramCodeBlockStructure.get(), cachedCodeBlock) >+{ >+} >+ >+ALWAYS_INLINE UnlinkedModuleProgramCodeBlock::UnlinkedModuleProgramCodeBlock(Decoder& decoder, const CachedModuleCodeBlock& cachedCodeBlock) >+ : Base(decoder, decoder.vm().unlinkedModuleProgramCodeBlockStructure.get(), cachedCodeBlock) >+{ >+} >+ >+ALWAYS_INLINE UnlinkedEvalCodeBlock::UnlinkedEvalCodeBlock(Decoder& decoder, const CachedEvalCodeBlock& cachedCodeBlock) >+ : Base(decoder, decoder.vm().unlinkedEvalCodeBlockStructure.get(), cachedCodeBlock) >+{ >+} >+ >+ALWAYS_INLINE void CachedFunctionExecutable::encode(Encoder& encoder, const UnlinkedFunctionExecutable& executable) >+{ >+ m_firstLineOffset = executable.m_firstLineOffset; >+ m_lineCount = executable.m_lineCount; >+ m_unlinkedFunctionNameStart = executable.m_unlinkedFunctionNameStart; >+ m_unlinkedBodyStartColumn = executable.m_unlinkedBodyStartColumn; >+ m_unlinkedBodyEndColumn = executable.m_unlinkedBodyEndColumn; >+ m_startOffset = executable.m_startOffset; >+ m_sourceLength = executable.m_sourceLength; >+ m_parametersStartOffset = executable.m_parametersStartOffset; >+ m_typeProfilingStartOffset = executable.m_typeProfilingStartOffset; >+ m_typeProfilingEndOffset = executable.m_typeProfilingEndOffset; >+ m_parameterCount = executable.m_parameterCount; >+ >+ m_features = executable.m_features; >+ m_sourceParseMode = executable.m_sourceParseMode; >+ >+ m_isInStrictContext = executable.m_isInStrictContext; >+ m_hasCapturedVariables = executable.m_hasCapturedVariables; >+ m_isBuiltinFunction = executable.m_isBuiltinFunction; >+ m_isBuiltinDefaultClassConstructor = executable.m_isBuiltinDefaultClassConstructor; >+ m_constructAbility = executable.m_constructAbility; >+ m_constructorKind = executable.m_constructorKind; >+ m_functionMode = executable.m_functionMode; >+ m_scriptMode = executable.m_scriptMode; >+ m_superBinding = executable.m_superBinding; >+ m_derivedContextType = executable.m_derivedContextType; >+ >+ m_classSource.encode(encoder, executable.m_classSource); >+ >+ m_name.encode(encoder, executable.name()); >+ m_ecmaName.encode(encoder, executable.ecmaName()); >+ m_inferredName.encode(encoder, executable.inferredName()); >+ >+ m_parentScopeTDZVariables.encode(encoder, executable.parentScopeTDZVariables()); >+ >+ m_unlinkedCodeBlockForCall.encode(encoder, executable.m_unlinkedCodeBlockForCall); >+ m_unlinkedCodeBlockForConstruct.encode(encoder, executable.m_unlinkedCodeBlockForConstruct); >+} >+ >+ALWAYS_INLINE UnlinkedFunctionExecutable* CachedFunctionExecutable::decode(Decoder& decoder) const >+{ >+ VariableEnvironment env; >+ m_parentScopeTDZVariables.decode(decoder, env); >+ >+ UnlinkedFunctionExecutable* executable = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(decoder.vm().heap)) UnlinkedFunctionExecutable(decoder, env, *this); >+ executable->finishCreation(decoder.vm()); >+ >+ m_classSource.decode(decoder, executable->m_classSource); >+ m_unlinkedCodeBlockForCall.decode(decoder, executable->m_unlinkedCodeBlockForCall, executable); >+ m_unlinkedCodeBlockForConstruct.decode(decoder, executable->m_unlinkedCodeBlockForConstruct, executable); >+ >+ return executable; >+} >+ >+ALWAYS_INLINE UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(Decoder& decoder, VariableEnvironment& parentScopeTDZVariables, const CachedFunctionExecutable& cachedExecutable) >+ : Base(decoder.vm(), decoder.vm().unlinkedFunctionExecutableStructure.get()) >+ , m_firstLineOffset(cachedExecutable.firstLineOffset()) >+ , m_lineCount(cachedExecutable.lineCount()) >+ , m_unlinkedFunctionNameStart(cachedExecutable.unlinkedFunctionNameStart()) >+ , m_unlinkedBodyStartColumn(cachedExecutable.unlinkedBodyStartColumn()) >+ , m_unlinkedBodyEndColumn(cachedExecutable.unlinkedBodyEndColumn()) >+ , m_startOffset(cachedExecutable.startOffset()) >+ , m_sourceLength(cachedExecutable.sourceLength()) >+ , m_parametersStartOffset(cachedExecutable.parametersStartOffset()) >+ , m_typeProfilingStartOffset(cachedExecutable.typeProfilingStartOffset()) >+ , m_typeProfilingEndOffset(cachedExecutable.typeProfilingEndOffset()) >+ , m_parameterCount(cachedExecutable.parameterCount()) >+ , m_features(cachedExecutable.features()) >+ , m_sourceParseMode(cachedExecutable.sourceParseMode()) >+ , m_isInStrictContext(cachedExecutable.isInStrictContext()) >+ , m_hasCapturedVariables(cachedExecutable.hasCapturedVariables()) >+ , m_isBuiltinFunction(cachedExecutable.isBuiltinFunction()) >+ , m_isBuiltinDefaultClassConstructor(cachedExecutable.isBuiltinDefaultClassConstructor()) >+ , m_constructAbility(cachedExecutable.constructAbility()) >+ , m_constructorKind(cachedExecutable.constructorKind()) >+ , m_functionMode(cachedExecutable.functionMode()) >+ , m_scriptMode(cachedExecutable.scriptMode()) >+ , m_superBinding(cachedExecutable.superBinding()) >+ , m_derivedContextType(cachedExecutable.derivedContextType()) >+ >+ , m_name(cachedExecutable.name(decoder)) >+ , m_ecmaName(cachedExecutable.ecmaName(decoder)) >+ , m_inferredName(cachedExecutable.inferredName(decoder)) >+ >+ , m_parentScopeTDZVariables(decoder.vm().m_compactVariableMap->get(parentScopeTDZVariables)) >+{ >+} >+ >+template<typename CodeBlockType> >+ALWAYS_INLINE void CachedCodeBlock<CodeBlockType>::encode(Encoder& encoder, const UnlinkedCodeBlock& codeBlock) >+{ >+ m_thisRegister = codeBlock.m_thisRegister; >+ m_scopeRegister = codeBlock.m_scopeRegister; >+ m_globalObjectRegister = codeBlock.m_globalObjectRegister; >+ m_usesEval = codeBlock.m_usesEval; >+ m_isStrictMode = codeBlock.m_isStrictMode; >+ m_isConstructor = codeBlock.m_isConstructor; >+ m_hasCapturedVariables = codeBlock.m_hasCapturedVariables; >+ m_isBuiltinFunction = codeBlock.m_isBuiltinFunction; >+ m_superBinding = codeBlock.m_superBinding; >+ m_scriptMode = codeBlock.m_scriptMode; >+ m_isArrowFunctionContext = codeBlock.m_isArrowFunctionContext; >+ m_isClassContext = codeBlock.m_isClassContext; >+ m_wasCompiledWithDebuggingOpcodes = codeBlock.m_wasCompiledWithDebuggingOpcodes; >+ m_constructorKind = codeBlock.m_constructorKind; >+ m_derivedContextType = codeBlock.m_derivedContextType; >+ m_evalContextType = codeBlock.m_evalContextType; >+ m_hasTailCalls = codeBlock.m_hasTailCalls; >+ m_lineCount = codeBlock.m_lineCount; >+ m_endColumn = codeBlock.m_endColumn; >+ m_numVars = codeBlock.m_numVars; >+ m_numCalleeLocals = codeBlock.m_numCalleeLocals; >+ m_numParameters = codeBlock.m_numParameters; >+ m_features = codeBlock.m_features; >+ m_parseMode = codeBlock.m_parseMode; >+ m_codeType = codeBlock.m_codeType; >+ >+ for (unsigned i = LinkTimeConstantCount; i--;) >+ m_linkTimeConstants[i] = codeBlock.m_linkTimeConstants[i]; >+ >+ m_metadata.encode(encoder, codeBlock.m_metadata); >+ m_rareData.encode(encoder, codeBlock.m_rareData); >+ >+ m_sourceURLDirective.encode(encoder, codeBlock.m_sourceURLDirective.impl()); >+ m_sourceMappingURLDirective.encode(encoder, codeBlock.m_sourceURLDirective.impl()); >+ >+ m_instructions.encode(encoder, codeBlock.m_instructions.get()); >+ m_propertyAccessInstructions.encode(encoder, codeBlock.m_propertyAccessInstructions); >+ m_constantRegisters.encode(encoder, codeBlock.m_constantRegisters); >+ m_constantsSourceCodeRepresentation.encode(encoder, codeBlock.m_constantsSourceCodeRepresentation); >+ m_expressionInfo.encode(encoder, codeBlock.m_expressionInfo); >+ m_jumpTargets.encode(encoder, codeBlock.m_jumpTargets); >+ m_outOfLineJumpTargets.encode(encoder, codeBlock.m_outOfLineJumpTargets); >+ >+ m_constantIdentifierSets.encode(encoder, codeBlock.m_constantIdentifierSets); >+ m_identifiers.encode(encoder, codeBlock.m_identifiers); >+ m_bitVectors.encode(encoder, codeBlock.m_bitVectors); >+ m_functionDecls.encode(encoder, codeBlock.m_functionDecls); >+ m_functionExprs.encode(encoder, codeBlock.m_functionExprs); >+} >+ >+class CachedSourceCodeKey : public CachedObject<SourceCodeKey> { >+public: >+ void encode(Encoder& encoder, const SourceCodeKey& key) >+ { >+ m_sourceCode.encode(encoder, key.m_sourceCode); >+ m_name.encode(encoder, key.m_name); >+ m_flags = key.m_flags.m_flags; >+ m_hash = key.hash(); >+ m_functionConstructorParametersEndPosition = key.m_functionConstructorParametersEndPosition; >+ } >+ >+ void decode(Decoder& decoder, SourceCodeKey& key) const >+ { >+ m_sourceCode.decode(decoder, key.m_sourceCode); >+ m_name.decode(decoder, key.m_name); >+ key.m_flags.m_flags = m_flags; >+ key.m_hash = m_hash; >+ key.m_functionConstructorParametersEndPosition = m_functionConstructorParametersEndPosition; >+ } >+ >+private: >+ CachedUnlinkedSourceCode m_sourceCode; >+ CachedString m_name; >+ unsigned m_flags; >+ unsigned m_hash; >+ int m_functionConstructorParametersEndPosition; >+}; >+ >+class GenericCacheEntry { >+public: >+ std::pair<SourceCodeKey, UnlinkedCodeBlock*> decode(Decoder&) const; >+ >+protected: >+ CachedCodeBlockTag m_tag; >+}; >+ >+template<typename UnlinkedCodeBlockType> >+class CacheEntry : public GenericCacheEntry { >+public: >+ void encode(Encoder& encoder, std::pair<SourceCodeKey, const UnlinkedCodeBlockType*> pair) >+ { >+ m_tag = CachedCodeBlockTypeImpl<UnlinkedCodeBlockType>::tag; >+ m_key.encode(encoder, pair.first); >+ m_codeBlock.encode(encoder, pair.second); >+ } >+ >+private: >+ friend GenericCacheEntry; >+ >+ std::pair<SourceCodeKey, UnlinkedCodeBlockType*> decode(Decoder& decoder) const >+ { >+ ASSERT(m_tag == CachedCodeBlockTypeImpl<UnlinkedCodeBlockType>::tag); >+ SourceCodeKey decodedKey; >+ m_key.decode(decoder, decodedKey); >+ return { WTFMove(decodedKey), m_codeBlock.decode(decoder) }; >+ } >+ >+ CachedSourceCodeKey m_key; >+ CachedPtr<CachedCodeBlockType<UnlinkedCodeBlockType>> m_codeBlock; >+}; >+ >+std::pair<SourceCodeKey, UnlinkedCodeBlock*> GenericCacheEntry::decode(Decoder& decoder) const >+{ >+ switch (m_tag) { >+ case CachedProgramCodeBlockTag: >+ return reinterpret_cast<const CacheEntry<UnlinkedProgramCodeBlock>*>(this)->decode(decoder); >+ case CachedModuleCodeBlockTag: >+ return reinterpret_cast<const CacheEntry<UnlinkedModuleProgramCodeBlock>*>(this)->decode(decoder); >+ case CachedEvalCodeBlockTag: >+ // We do not cache eval code blocks >+ RELEASE_ASSERT_NOT_REACHED(); >+ } >+ RELEASE_ASSERT_NOT_REACHED(); >+#if COMPILER(MSVC) >+ // Without this, MSVC will complain that this path does not return a value. >+ return reinterpret_cast<const CacheEntry<UnlinkedEvalCodeBlock>*>(this)->decode(decoder); >+#endif >+} >+ >+template<typename UnlinkedCodeBlockType> >+void encodeCodeBlock(Encoder& encoder, const SourceCodeKey& key, const UnlinkedCodeBlock* codeBlock) >+{ >+ auto* entry = encoder.template malloc<CacheEntry<UnlinkedCodeBlockType>>(); >+ entry->encode(encoder, { key, jsCast<const UnlinkedCodeBlockType*>(codeBlock) }); >+} >+ >+std::pair<MallocPtr<uint8_t>, size_t> encodeCodeBlock(VM& vm, const SourceCodeKey& key, const UnlinkedCodeBlock* codeBlock) >+{ >+ const ClassInfo* classInfo = codeBlock->classInfo(vm); >+ >+ Encoder encoder(vm); >+ if (classInfo == UnlinkedProgramCodeBlock::info()) >+ encodeCodeBlock<UnlinkedProgramCodeBlock>(encoder, key, codeBlock); >+ else if (classInfo == UnlinkedModuleProgramCodeBlock::info()) >+ encodeCodeBlock<UnlinkedModuleProgramCodeBlock>(encoder, key, codeBlock); >+ else >+ ASSERT(classInfo == UnlinkedEvalCodeBlock::info()); >+ >+ return encoder.release(); >+} >+ >+UnlinkedCodeBlock* decodeCodeBlockImpl(VM& vm, const SourceCodeKey& key, const void* buffer, size_t size) >+{ >+ const auto* cachedEntry = reinterpret_cast<const GenericCacheEntry*>(buffer); >+ Decoder decoder(vm, buffer, size); >+ std::pair<SourceCodeKey, UnlinkedCodeBlock*> entry; >+ { >+ DeferGC deferGC(vm.heap); >+ entry = cachedEntry->decode(decoder); >+ } >+ >+ if (entry.first != key) >+ return nullptr; >+ return entry.second; >+} >+ >+} // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/CachedTypes.h b/Source/JavaScriptCore/runtime/CachedTypes.h >new file mode 100644 >index 0000000000000000000000000000000000000000..bcb8acb6ce570e9726389c26d70bcba21da8d4ad >--- /dev/null >+++ b/Source/JavaScriptCore/runtime/CachedTypes.h >@@ -0,0 +1,46 @@ >+/* >+ * Copyright (C) 2018 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 "JSCast.h" >+#include <wtf/MallocPtr.h> >+ >+namespace JSC { >+ >+class SourceCodeKey; >+class UnlinkedCodeBlock; >+ >+std::pair<MallocPtr<uint8_t>, size_t> encodeCodeBlock(VM&, const SourceCodeKey&, const UnlinkedCodeBlock*); >+UnlinkedCodeBlock* decodeCodeBlockImpl(VM&, const SourceCodeKey&, const void*, size_t); >+ >+ >+template<typename UnlinkedCodeBlockType> >+UnlinkedCodeBlockType* decodeCodeBlock(VM& vm, const SourceCodeKey& key, const void* buffer, size_t size) >+{ >+ return jsCast<UnlinkedCodeBlockType*>(decodeCodeBlockImpl(vm, key, buffer, size)); >+} >+ >+} // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/CodeCache.cpp b/Source/JavaScriptCore/runtime/CodeCache.cpp >index 46017921a46efc641725d0a2352529035af5f3ad..c32d204b6cd8968181cb0d1df0eab83ec11819d4 100644 >--- a/Source/JavaScriptCore/runtime/CodeCache.cpp >+++ b/Source/JavaScriptCore/runtime/CodeCache.cpp >@@ -43,6 +43,9 @@ void CodeCacheMap::pruneSlowCase() > > while (m_size > m_capacity || !canPruneQuickly()) { > MapType::iterator it = m_map.begin(); >+ >+ writeCodeBlock(*it->value.cell->vm(), it->key, it->value); >+ > m_size -= it->key.length(); > m_map.remove(it); > } >@@ -59,9 +62,8 @@ UnlinkedCodeBlockType* CodeCache::getUnlinkedGlobalCodeBlock(VM& vm, ExecutableT > vm.typeProfiler() ? TypeProfilerEnabled::Yes : TypeProfilerEnabled::No, > vm.controlFlowProfiler() ? ControlFlowProfilerEnabled::Yes : ControlFlowProfilerEnabled::No, > WTF::nullopt); >- SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key); >- if (cache && Options::useCodeCache()) { >- UnlinkedCodeBlockType* unlinkedCodeBlock = jsCast<UnlinkedCodeBlockType*>(cache->cell.get()); >+ UnlinkedCodeBlockType* unlinkedCodeBlock = m_sourceCode.findCacheAndUpdateAge<UnlinkedCodeBlockType>(vm, key); >+ if (unlinkedCodeBlock && Options::useCodeCache()) { > unsigned lineCount = unlinkedCodeBlock->lineCount(); > unsigned startColumn = unlinkedCodeBlock->startColumn() + source.startColumn().oneBasedInt(); > bool endColumnIsOnStartLine = !lineCount; >@@ -71,9 +73,9 @@ UnlinkedCodeBlockType* CodeCache::getUnlinkedGlobalCodeBlock(VM& vm, ExecutableT > source.provider()->setSourceMappingURLDirective(unlinkedCodeBlock->sourceMappingURLDirective()); > return unlinkedCodeBlock; > } >- >+ > VariableEnvironment variablesUnderTDZ; >- UnlinkedCodeBlockType* unlinkedCodeBlock = generateUnlinkedCodeBlock<UnlinkedCodeBlockType, ExecutableType>(vm, executable, source, strictMode, scriptMode, debuggerMode, error, evalContextType, &variablesUnderTDZ); >+ unlinkedCodeBlock = generateUnlinkedCodeBlock<UnlinkedCodeBlockType, ExecutableType>(vm, executable, source, strictMode, scriptMode, debuggerMode, error, evalContextType, &variablesUnderTDZ); > > if (unlinkedCodeBlock && Options::useCodeCache()) > m_sourceCode.addCache(key, SourceCodeValue(vm, unlinkedCodeBlock, m_sourceCode.age())); >@@ -110,9 +112,8 @@ UnlinkedFunctionExecutable* CodeCache::getUnlinkedGlobalFunctionExecutable(VM& v > vm.typeProfiler() ? TypeProfilerEnabled::Yes : TypeProfilerEnabled::No, > vm.controlFlowProfiler() ? ControlFlowProfilerEnabled::Yes : ControlFlowProfilerEnabled::No, > functionConstructorParametersEndPosition); >- SourceCodeValue* cache = m_sourceCode.findCacheAndUpdateAge(key); >- if (cache && Options::useCodeCache()) { >- UnlinkedFunctionExecutable* executable = jsCast<UnlinkedFunctionExecutable*>(cache->cell.get()); >+ UnlinkedFunctionExecutable* executable = m_sourceCode.findCacheAndUpdateAge<UnlinkedFunctionExecutable>(vm, key); >+ if (executable && Options::useCodeCache()) { > source.provider()->setSourceURLDirective(executable->sourceURLDirective()); > source.provider()->setSourceMappingURLDirective(executable->sourceMappingURLDirective()); > return executable; >@@ -155,4 +156,10 @@ UnlinkedFunctionExecutable* CodeCache::getUnlinkedGlobalFunctionExecutable(VM& v > return functionExecutable; > } > >+void CodeCache::write(VM& vm) >+{ >+ for (const auto& it : m_sourceCode) >+ writeCodeBlock(vm, it.key, it.value); >+} >+ > } >diff --git a/Source/JavaScriptCore/runtime/CodeCache.h b/Source/JavaScriptCore/runtime/CodeCache.h >index 8a4419f96ca8fa4a629be0e9a7827cbaf68cff86..99395f2cd2841139a035c8b1589bb939c69c5702 100644 >--- a/Source/JavaScriptCore/runtime/CodeCache.h >+++ b/Source/JavaScriptCore/runtime/CodeCache.h >@@ -26,6 +26,7 @@ > #pragma once > > #include "BytecodeGenerator.h" >+#include "CachedTypes.h" > #include "ExecutableInfo.h" > #include "JSCInlines.h" > #include "Parser.h" >@@ -37,6 +38,7 @@ > #include "UnlinkedEvalCodeBlock.h" > #include "UnlinkedModuleProgramCodeBlock.h" > #include "UnlinkedProgramCodeBlock.h" >+#include <sys/stat.h> > #include <wtf/Forward.h> > #include <wtf/text/WTFString.h> > >@@ -89,13 +91,76 @@ public: > { > } > >- SourceCodeValue* findCacheAndUpdateAge(const SourceCodeKey& key) >+ iterator begin() { return m_map.begin(); } >+ iterator end() { return m_map.end(); } >+ >+ template<typename UnlinkedCodeBlockType> >+ UnlinkedCodeBlockType* fetchFromDiskImpl(VM& vm, const SourceCodeKey& key) >+ { >+#if OS(DARWIN) >+ const char* cachePath = Options::diskCachePath(); >+ if (!cachePath) >+ return nullptr; >+ >+ unsigned hash = key.hash(); >+ char filename[512]; >+ int count = snprintf(filename, 512, "%s/%u.cache", cachePath, hash); >+ if (count < 0 || count > 512) >+ return nullptr; >+ >+ int fd = open(filename, O_RDONLY); >+ if (fd == -1) >+ return nullptr; >+ >+ int rc = flock(fd, LOCK_SH | LOCK_NB); >+ if (rc) { >+ close(fd); >+ return nullptr; >+ } >+ >+ struct stat sb; >+ int res = fstat(fd, &sb); >+ size_t size = static_cast<size_t>(sb.st_size); >+ if (res || !size) >+ return nullptr; >+ >+ const void* buffer = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0); >+ UnlinkedCodeBlockType* unlinkedCodeBlock = decodeCodeBlock<UnlinkedCodeBlockType>(vm, key, buffer, size); >+ >+ if (!unlinkedCodeBlock) >+ return nullptr; >+ >+ addCache(key, SourceCodeValue(vm, unlinkedCodeBlock, m_age)); >+ return unlinkedCodeBlock; >+#else >+ UNUSED_PARAM(vm); >+ UNUSED_PARAM(key); >+ return nullptr; >+#endif >+ } >+ >+ template<typename UnlinkedCodeBlockType> >+ std::enable_if_t<std::is_base_of<UnlinkedCodeBlock, UnlinkedCodeBlockType>::value && !std::is_same<UnlinkedCodeBlockType, UnlinkedEvalCodeBlock>::value, UnlinkedCodeBlockType*> >+ fetchFromDisk(VM& vm, const SourceCodeKey& key) >+ { >+ UnlinkedCodeBlockType* codeBlock = fetchFromDiskImpl<UnlinkedCodeBlockType>(vm, key); >+ if (UNLIKELY(Options::forceDiskCache())) >+ RELEASE_ASSERT(codeBlock); >+ return codeBlock; >+ } >+ >+ template<typename T> >+ std::enable_if_t<!std::is_base_of<UnlinkedCodeBlock, T>::value || std::is_same<T, UnlinkedEvalCodeBlock>::value, T*> >+ fetchFromDisk(VM&, const SourceCodeKey&) { return nullptr; } >+ >+ template<typename UnlinkedCodeBlockType> >+ UnlinkedCodeBlockType* findCacheAndUpdateAge(VM& vm, const SourceCodeKey& key) > { > prune(); > > iterator findResult = m_map.find(key); > if (findResult == m_map.end()) >- return nullptr; >+ return fetchFromDisk<UnlinkedCodeBlockType>(vm, key); > > int64_t age = m_age - findResult->value.age; > if (age > m_capacity) { >@@ -115,7 +180,7 @@ public: > findResult->value.age = m_age; > m_age += key.length(); > >- return &findResult->value; >+ return jsCast<UnlinkedCodeBlockType*>(findResult->value.cell.get()); > } > > AddResult addCache(const SourceCodeKey& key, const SourceCodeValue& value) >@@ -197,6 +262,7 @@ public: > UnlinkedFunctionExecutable* getUnlinkedGlobalFunctionExecutable(VM&, const Identifier&, const SourceCode&, DebuggerMode, Optional<int> functionConstructorParametersEndPosition, ParserError&); > > void clear() { m_sourceCode.clear(); } >+ JS_EXPORT_PRIVATE void write(VM&); > > private: > template <class UnlinkedCodeBlockType, class ExecutableType> >@@ -256,4 +322,36 @@ UnlinkedCodeBlockType* generateUnlinkedCodeBlock(VM& vm, ExecutableType* executa > return unlinkedCodeBlock; > } > >+ALWAYS_INLINE static void writeCodeBlock(VM& vm, const SourceCodeKey& key, const SourceCodeValue& value) >+{ >+#if OS(DARWIN) >+ const char* cachePath = Options::diskCachePath(); >+ if (LIKELY(!cachePath)) >+ return; >+ >+ UnlinkedCodeBlock* codeBlock = jsDynamicCast<UnlinkedCodeBlock*>(vm, value.cell.get()); >+ if (!codeBlock) >+ return; >+ >+ unsigned hash = key.hash(); >+ char filename[512]; >+ int count = snprintf(filename, 512, "%s/%u.cache", cachePath, hash); >+ if (count < 0 || count > 512) >+ return; >+ >+ std::pair<MallocPtr<uint8_t>, size_t> result = encodeCodeBlock(vm, key, codeBlock); >+ >+ int fd = open(filename, O_CREAT | O_WRONLY, 0666); >+ int rc = flock(fd, LOCK_EX | LOCK_NB); >+ if (!rc) >+ ::write(fd, result.first.get(), result.second); >+ close(fd); >+#else >+ UNUSED_PARAM(vm); >+ UNUSED_PARAM(key); >+ UNUSED_PARAM(value); >+#endif >+} >+ >+ > } // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.cpp b/Source/JavaScriptCore/runtime/JSBigInt.cpp >index ca531636b781e869ea78f76d25b5e4aead416185..2bcaa9b6762d252f0b31ee1a8949cdd83746800e 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.cpp >+++ b/Source/JavaScriptCore/runtime/JSBigInt.cpp >@@ -1688,11 +1688,6 @@ bool JSBigInt::getPrimitiveNumber(ExecState* exec, double& number, JSValue& resu > return true; > } > >-inline size_t JSBigInt::offsetOfData() >-{ >- return WTF::roundUpToMultipleOf<sizeof(Digit)>(sizeof(JSBigInt)); >-} >- > template <typename CharType> > JSBigInt* JSBigInt::parseInt(ExecState* exec, CharType* data, unsigned length, ErrorParseMode errorParseMode) > { >@@ -1795,11 +1790,6 @@ JSBigInt* JSBigInt::parseInt(ExecState* exec, VM& vm, CharType* data, unsigned l > return nullptr; > } > >-inline JSBigInt::Digit* JSBigInt::dataStorage() >-{ >- return reinterpret_cast<Digit*>(reinterpret_cast<char*>(this) + offsetOfData()); >-} >- > inline JSBigInt::Digit JSBigInt::digit(unsigned n) > { > ASSERT(n < length()); >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.h b/Source/JavaScriptCore/runtime/JSBigInt.h >index 2b3bf9307d8dbbb1107533ed830347bcdd4a610b..dbbf63ded1c8cbd48ea7b9fcb5b0e8515b5fea9d 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.h >+++ b/Source/JavaScriptCore/runtime/JSBigInt.h >@@ -38,6 +38,7 @@ namespace JSC { > class JSBigInt final : public JSCell { > using Base = JSCell; > static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal | OverridesToThis; >+ friend class CachedBigInt; > > public: > >@@ -228,8 +229,15 @@ private: > static Optional<Digit> toShiftAmount(JSBigInt* x); > > static size_t allocationSize(unsigned length); >- static size_t offsetOfData(); >- Digit* dataStorage(); >+ inline static size_t offsetOfData() >+ { >+ return WTF::roundUpToMultipleOf<sizeof(Digit)>(sizeof(JSBigInt)); >+ } >+ >+ inline Digit* dataStorage() >+ { >+ return reinterpret_cast<Digit*>(reinterpret_cast<char*>(this) + offsetOfData()); >+ } > > Digit digit(unsigned); > void setDigit(unsigned, Digit); >diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp >index 9fc34fb9fabc3d00db1fd9971aa0996dfc3d45d4..8b05ca82300bc79a229ac60f86bb45667eefda5e 100644 >--- a/Source/JavaScriptCore/runtime/Options.cpp >+++ b/Source/JavaScriptCore/runtime/Options.cpp >@@ -524,6 +524,12 @@ static void recomputeDependentOptions() > // https://bugs.webkit.org/show_bug.cgi?id=177956 > Options::useProbeOSRExit() = false; > #endif >+ >+ if (!Options::useCodeCache()) >+ Options::diskCachePath() = nullptr; >+ >+ if (!Options::diskCachePath()) >+ Options::forceDiskCache() = false; > } > > void Options::initialize() >diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h >index 4c9f6b6b4e169adcca81249349730212f1382137..ad73bfdf181a29e46acfb7c68778241eb2ffcc58 100644 >--- a/Source/JavaScriptCore/runtime/Options.h >+++ b/Source/JavaScriptCore/runtime/Options.h >@@ -509,6 +509,8 @@ constexpr bool enableWebAssemblyStreamingApi = false; > v(bool, traceLLIntSlowPath, false, Configurable, nullptr) \ > v(bool, traceBaselineJITExecution, false, Normal, nullptr) \ > v(unsigned, thresholdForGlobalLexicalBindingEpoch, UINT_MAX, Normal, "Threshold for global lexical binding epoch. If the epoch reaches to this value, CodeBlock metadata for scope operations will be revised globally. It needs to be greater than 1.") \ >+ v(optionString, diskCachePath, nullptr, Restricted, "") \ >+ v(bool, forceDiskCache, false, Restricted, "") \ > > > enum OptionEquivalence { >diff --git a/Source/JavaScriptCore/runtime/RegExp.h b/Source/JavaScriptCore/runtime/RegExp.h >index 83aad356038eb2ec76e6b8bd37c7476cec91352e..03add45fb55704cfa02d6e5a23cb02c8047bbe59 100644 >--- a/Source/JavaScriptCore/runtime/RegExp.h >+++ b/Source/JavaScriptCore/runtime/RegExp.h >@@ -41,6 +41,8 @@ class VM; > JS_EXPORT_PRIVATE RegExpFlags regExpFlags(const String&); > > class RegExp final : public JSCell { >+ friend class CachedRegExp; >+ > public: > typedef JSCell Base; > static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; >diff --git a/Source/JavaScriptCore/runtime/ScopedArgumentsTable.h b/Source/JavaScriptCore/runtime/ScopedArgumentsTable.h >index 40e7c7ec2fd60b5842a57285ac97b0f6a959395d..e81234297b0bb8a025802f37a89847088a5ae135 100644 >--- a/Source/JavaScriptCore/runtime/ScopedArgumentsTable.h >+++ b/Source/JavaScriptCore/runtime/ScopedArgumentsTable.h >@@ -39,6 +39,8 @@ namespace JSC { > // makes sense because such modifications are so uncommon. You'd have to do something crazy like > // "delete arguments[i]" or some variant of defineOwnProperty. > class ScopedArgumentsTable final : public JSCell { >+ friend class CachedScopedArgumentsTable; >+ > public: > typedef JSCell Base; > static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; >diff --git a/Source/JavaScriptCore/runtime/StackFrame.h b/Source/JavaScriptCore/runtime/StackFrame.h >index ed982e31f55bbbc91628d23417812bb4f6c68711..5eedee6f8186daea30409813d45346ac075efd80 100644 >--- a/Source/JavaScriptCore/runtime/StackFrame.h >+++ b/Source/JavaScriptCore/runtime/StackFrame.h >@@ -25,6 +25,7 @@ > > #pragma once > >+#include "Heap.h" > #include "WasmIndexOrName.h" > #include "WriteBarrier.h" > #include <limits.h> >diff --git a/Source/JavaScriptCore/runtime/StructureInlines.h b/Source/JavaScriptCore/runtime/StructureInlines.h >index 38264427015491a3476392351e5f5656f6c103de..4a30f37dd75a63150375b891f9de8210d4433f0c 100644 >--- a/Source/JavaScriptCore/runtime/StructureInlines.h >+++ b/Source/JavaScriptCore/runtime/StructureInlines.h >@@ -31,6 +31,7 @@ > #include "PropertyMapHashTable.h" > #include "Structure.h" > #include "StructureChain.h" >+#include "StructureRareDataInlines.h" > > namespace JSC { > >diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h >index 9157d5b829200fb6a965ea3bc78696e532a92b95..59691b2ec41ec7ae97ad40c984901564cffd4019 100644 >--- a/Source/JavaScriptCore/runtime/SymbolTable.h >+++ b/Source/JavaScriptCore/runtime/SymbolTable.h >@@ -73,6 +73,8 @@ static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int> > // copy: SymbolTableEntry --> FatEntry -----^ > > struct SymbolTableEntry { >+ friend class CachedSymbolTableEntry; >+ > private: > static VarOffset varOffsetFromBits(intptr_t bits) > { >@@ -436,6 +438,8 @@ struct SymbolTableIndexHashTraits : HashTraits<SymbolTableEntry> { > }; > > class SymbolTable final : public JSCell { >+ friend class CachedSymbolTable; >+ > public: > typedef JSCell Base; > static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; >diff --git a/Source/WTF/wtf/BitVector.h b/Source/WTF/wtf/BitVector.h >index 755cd7a9aa576c6f7a4db14c0d9e302c78db5178..b8bb365b59d7ebac79ac689a444da592723c50ef 100644 >--- a/Source/WTF/wtf/BitVector.h >+++ b/Source/WTF/wtf/BitVector.h >@@ -33,6 +33,10 @@ > #include <wtf/PrintStream.h> > #include <wtf/StdLibExtras.h> > >+namespace JSC { >+class CachedBitVector; >+} >+ > namespace WTF { > > // This is a space-efficient, resizeable bitvector class. In the common case it >@@ -338,6 +342,8 @@ public: > iterator end() const { return iterator(*this, size()); } > > private: >+ friend class JSC::CachedBitVector; >+ > static unsigned bitsInPointer() > { > return sizeof(void*) << 3; >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 9628c5608cc525e3af69b8b82cde325fb2f8175b..275f1c11ab891eb967ec7e70bf17b7b89868d1bd 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,20 @@ >+2019-01-21 Tadeu Zagallo <tzagallo@apple.com> >+ >+ Cache bytecode to disk >+ https://bugs.webkit.org/show_bug.cgi?id=192782 >+ <rdar://problem/46084932> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add test helper to execute bytecode-cache tests: it executes each test >+ twice, the first with JSC_diskCachePath set to a temporary directory >+ and second with JSC_forceDiskCache=true (in addition to the cache path) >+ to guarantee that only the disk cache is being used and no new >+ UnlinkedCodeBlocks are being created. >+ >+ * Scripts/jsc-stress-test-helpers/bytecode-cache-test-helper.sh: Added. >+ * Scripts/run-jsc-stress-tests: >+ > 2019-01-20 Saam Barati <sbarati@apple.com> > > Rollout r240210: It broke tests on iOS >diff --git a/Tools/Scripts/jsc-stress-test-helpers/bytecode-cache-test-helper.sh b/Tools/Scripts/jsc-stress-test-helpers/bytecode-cache-test-helper.sh >new file mode 100644 >index 0000000000000000000000000000000000000000..83e2d5933161f47bcabae6508880fc5f7a5bdbe6 >--- /dev/null >+++ b/Tools/Scripts/jsc-stress-test-helpers/bytecode-cache-test-helper.sh >@@ -0,0 +1,50 @@ >+# Copyright (C) 2019 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 AND ITS CONTRIBUTORS "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 OR ITS 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. >+ >+set -e >+ >+mysys() { >+ set +e >+ eval "$*" >+ exitCode=$? >+ if [ $exitCode != 0 ]; then >+ echo "Command '$*' failed" >+ return $exitCode >+ fi >+} >+ >+pathToVM=$1 >+shift >+inputFile=$1 >+shift >+extraOptions=( "$@" ) >+diskCachePath=$(mktemp -d -t "bytecode-cache") >+ >+_trap_exit() { rm -rf "$diskCachePath"; } >+trap _trap_exit EXIT >+ >+export JSC_diskCachePath=$diskCachePath >+mysys "$pathToVM" "$inputFile" "${extraOptions[@]}" >+export JSC_forceDiskCache=true >+mysys "$pathToVM" "$inputFile" "${extraOptions[@]}" >+ >diff --git a/Tools/Scripts/run-jsc-stress-tests b/Tools/Scripts/run-jsc-stress-tests >index 949e3f5b552011b51ad22df3ea0b5abe36b30ad9..10b76e1ce3b6c6835985a579800b92e03b72cd01 100755 >--- a/Tools/Scripts/run-jsc-stress-tests >+++ b/Tools/Scripts/run-jsc-stress-tests >@@ -655,6 +655,15 @@ def runDefault(*optionalTestSpecificOptions) > run("default", *(FTL_OPTIONS + optionalTestSpecificOptions)) > end > >+def runBytecodeCache(*optionalTestSpecificOptions) >+ unless $hostOS == "darwin" >+ skip >+ return >+ end >+ options = BASE_OPTIONS + $testSpecificRequiredOptions + FTL_OPTIONS + optionalTestSpecificOptions >+ addRunCommand("bytecode-cache", ["sh", (pathToHelpers + "bytecode-cache-test-helper.sh").to_s, pathToVM.to_s, $benchmark.to_s] + options, silentOutputHandler, simpleErrorHandler) >+end >+ > def runBigIntEnabled(*optionalTestSpecificOptions) > # FIXME: <rdar://problem/40331121> > if $remote or ($architecture !~ /x86/i and $hostOS == "darwin") >@@ -751,6 +760,7 @@ def defaultRun > defaultQuickRun > else > runDefault >+ runBytecodeCache > if $jitTests > runNoLLInt > runNoCJITValidatePhases
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 192782
:
357490
|
358112
|
358275
|
358362
|
358507
|
358594
|
358679
|
359316
|
359489
|
359530
|
359688
|
359697
|
359741