Adresa
:
[go:
nahoru
,
domu
]
WebKit Bugzilla
Attachment 358507 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-20190107191604.patch (text/plain), 121.10 KB, created by
Tadeu Zagallo
on 2019-01-07 10:16:12 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Tadeu Zagallo
Created:
2019-01-07 10:16:12 PST
Size:
121.10 KB
patch
obsolete
>Subversion Revision: 239675 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index ef46089a850bdc2a4206b553d0b522e5b16d5ed7..a4eaeb8a1e07ea2363aa0084587d5e9ec27ba719 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,199 @@ >+2019-01-07 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. Also, during 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. >+ >+ * 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::Encoder): >+ (JSC::Encoder::~Encoder): >+ (JSC::Encoder::vm): >+ (JSC::Encoder::mallocOffset): >+ (JSC::Encoder::malloc): >+ (JSC::Encoder::offsetOf): >+ (JSC::Encoder::cachePtr): >+ (JSC::Encoder::offsetForPtr): >+ (JSC::Encoder::release): >+ (JSC::Decoder::Decoder): >+ (JSC::Decoder::~Decoder): >+ (JSC::Decoder::vm): >+ (JSC::Decoder::offsetOf): >+ (JSC::Decoder::cacheOffset): >+ (JSC::Decoder::addFinalizer): >+ (JSC::encode): >+ (JSC::decode): >+ (JSC::CachedObject::sizeOf): >+ (JSC::CachedObject::cast): >+ (JSC::VariableLengthObject::buffer const): >+ (JSC::VariableLengthObject::buffer): >+ (JSC::VariableLengthObject::allocate): >+ (JSC::CachedPtr::encode): >+ (JSC::CachedPtr::decode const): >+ (JSC::CachedPtr::operator->): >+ (JSC::CachedPtr::operator-> 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::CachedRareData::encode): >+ (JSC::CachedRareData::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::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::CachedCodeBlockType>::decode const): >+ (JSC::UnlinkedProgramCodeBlock::UnlinkedProgramCodeBlock): >+ (JSC::UnlinkedModuleProgramCodeBlock::UnlinkedModuleProgramCodeBlock): >+ (JSC::UnlinkedEvalCodeBlock::UnlinkedEvalCodeBlock): >+ (JSC::CachedFunctionExecutable::encode): >+ (JSC::CachedFunctionExecutable::decode const): >+ (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): >+ (JSC::CachedCodeBlockType>::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: >+ (JSC::JSBigInt::offsetOfData): Deleted. >+ (JSC::JSBigInt::dataStorage): Deleted. >+ * 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-04 Tadeu Zagallo <tzagallo@apple.com> > > Baseline version of get_by_id may corrupt metadata >diff --git a/Source/WTF/ChangeLog b/Source/WTF/ChangeLog >index 9de0c6b121c84122d2fe3c0dbcb71542b79e0ba8..4a7835dfd71d4ef426c8bb38a95d03ba648026d8 100644 >--- a/Source/WTF/ChangeLog >+++ b/Source/WTF/ChangeLog >@@ -1,3 +1,16 @@ >+2019-01-07 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-02 Alex Christensen <achristensen@webkit.org> > > Homograph with LATIN SMALL LETTER R WITH FISHHOOK >diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >index 02c352f10a27082f58e338d96e5b2ec55e709f66..e7a4079b1a74025899a805d4c93928d13b029ffc 100644 >--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >@@ -3140,6 +3140,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>"; }; >@@ -3254,6 +3255,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>"; }; >@@ -6583,6 +6585,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 cba4c4ba6004f930d5ca8563310a6243e36449e5..5e3e7973ac805c0bc23e29bc9f2c86f6601c6c2d 100644 >--- a/Source/JavaScriptCore/Sources.txt >+++ b/Source/JavaScriptCore/Sources.txt >@@ -710,6 +710,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 86db8693f60e773b61ba37358ca3ee937dc0f35d..3b03b4fb50c0419dd796ce8e2500bc1d88a71c7e 100644 >--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp >+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp >@@ -864,7 +864,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 6c766a8ab229db0f683e66c06b7d5c50b8e81217..b79f90f4b7be30babec9a98718fdd7402ac37adb 100644 >--- a/Source/JavaScriptCore/bytecode/CodeBlock.h >+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h >@@ -886,7 +886,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..d93154bc6b5c36d4a84971252d0632e440d4ad0a 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 struct CachedInstructionStream; > public: > size_t sizeInBytes() const; > >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h >index f0e9d64c854a3f536752d4874692d27877d67049..0b236a02d59dc258e90890c925a3c88b05c507fc 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, typename CachedCodeBlockType> >+struct 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, typename CachedCodeBlockType> >+ UnlinkedCodeBlock(Decoder&, Structure*, const CachedCodeBlock<CodeBlockType, CachedCodeBlockType>&); >+ > ~UnlinkedCodeBlock(); > > void finishCreation(VM& vm) >@@ -378,6 +385,9 @@ private: > friend class BytecodeRewriter; > friend class BytecodeGenerator; > >+ template<typename CodeBlockType, typename CachedCodeBlockType> >+ friend struct 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..2ac74ae98b50cf22617bc942945e02384d12cf62 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedEvalCodeBlock.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedEvalCodeBlock.h >@@ -29,6 +29,8 @@ > > namespace JSC { > >+struct 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..6a30aa3d1e52ee9696ce796325c5059bfbf922ce 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedFunctionCodeBlock.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedFunctionCodeBlock.h >@@ -29,6 +29,8 @@ > > namespace JSC { > >+struct 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..375f47897dcd5b069576255ec3c7ae1c7cd457d8 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; >+struct 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..869961587cdd51717ff63c167dbf249bd60e384e 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, typename CachedCodeBlockType> >+ UnlinkedGlobalCodeBlock(Decoder& decoder, Structure* structure, const CachedCodeBlock<CodeBlockType, CachedCodeBlockType>& cachedCodeBlock) >+ : Base(decoder, structure, cachedCodeBlock) >+ { >+ } > }; > > } >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedMetadataTable.h b/Source/JavaScriptCore/bytecode/UnlinkedMetadataTable.h >index 3e3e8dfb4d5bbc464f5e6a2344caaca994949ef1..d990cd78c3ed1a639f6410468dfa3aebb066d69c 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 struct CachedMetadataTable; > > public: > struct LinkingData { >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedModuleProgramCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedModuleProgramCodeBlock.h >index 0e9c5f5bdde6c7562b66a03bc0a98c87adbd9302..e64dce6125477dd5c5412ced92be25604b5f3846 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedModuleProgramCodeBlock.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedModuleProgramCodeBlock.h >@@ -29,6 +29,9 @@ > > namespace JSC { > >+class Decoder; >+struct 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..9d7e435afd8ca5fb0a74e955d3625911a628aa16 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedProgramCodeBlock.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedProgramCodeBlock.h >@@ -29,6 +29,8 @@ > > namespace JSC { > >+struct 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 f945e178e58c53f1fc392700e265508b8fcd2f2e..be95751f7597552fc24584b6eb789acdb7cff2fc 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" >@@ -1985,8 +1986,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) >@@ -2849,6 +2853,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 313cfa45aaf922b07b045bbee0363859cbd4c09b..0134955defdaf17215db5a9633e6022357b9670a 100644 >--- a/Source/JavaScriptCore/parser/SourceCode.h >+++ b/Source/JavaScriptCore/parser/SourceCode.h >@@ -33,6 +33,8 @@ > namespace JSC { > > class SourceCode : public UnlinkedSourceCode { >+ friend struct CachedSourceCode; >+ > public: > SourceCode() > : UnlinkedSourceCode() >diff --git a/Source/JavaScriptCore/parser/SourceCodeKey.h b/Source/JavaScriptCore/parser/SourceCodeKey.h >index a8e603c26a0b60362a02deac0516169d57558021..38481217baf3935d501ac251559b0d4268b4db81 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 struct CachedSourceCodeKey; >+ > public: > SourceCodeFlags() = default; > >@@ -70,6 +72,8 @@ private: > }; > > class SourceCodeKey { >+ friend struct 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..490a88aa831d1cb7af5ff1a6a71ce0ca9267af1c 100644 >--- a/Source/JavaScriptCore/parser/UnlinkedSourceCode.h >+++ b/Source/JavaScriptCore/parser/UnlinkedSourceCode.h >@@ -35,6 +35,9 @@ > namespace JSC { > > class UnlinkedSourceCode { >+ template<typename SourceType, typename CacheType> >+ friend struct CachedUnlinkedSourceCodeShape; >+ > public: > UnlinkedSourceCode() > : m_provider(0) >diff --git a/Source/JavaScriptCore/parser/VariableEnvironment.h b/Source/JavaScriptCore/parser/VariableEnvironment.h >index 129b5ea6bd9b726a1d9a4011ef9690f8cc6b0dd3..36f9ddf81776ccb0a76fee08a0a58c3807a935c6 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 struct 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..a41cd9d2db201a511c75f79c911b65d9ea6851bf >--- /dev/null >+++ b/Source/JavaScriptCore/runtime/CachedTypes.cpp >@@ -0,0 +1,1833 @@ >+/* >+ * 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. >+ */ >+ >+#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); >+ >+public: >+ Encoder(VM& vm) >+ : m_vm(vm) >+ , m_offset(0) >+ { >+ m_buffer = (uint8_t*)fastZeroedMalloc(s_maxSize); >+ } >+ >+ ~Encoder() >+ { >+ if (m_buffer) >+ fastFree(m_buffer); >+ } >+ >+ VM& vm() { return m_vm; } >+ >+ ptrdiff_t mallocOffset(unsigned size) >+ { >+ m_offset = WTF::roundUpToMultipleOf(sizeof(void*), m_offset); >+ ASSERT(static_cast<size_t>(m_offset + size) < s_maxSize); >+ ptrdiff_t result = m_offset; >+ m_offset += size; >+ return result; >+ } >+ >+ uint8_t* malloc(unsigned size) >+ { >+ ptrdiff_t offset = mallocOffset(size); >+ return m_buffer + offset; >+ } >+ >+ template<typename T> >+ T* malloc() >+ { >+ return reinterpret_cast<T*>(malloc(sizeof(T))); >+ } >+ >+ ptrdiff_t offsetOf(const void* address) >+ { >+ const uint8_t* addr = static_cast<const uint8_t*>(address); >+ ASSERT(addr >= m_buffer && addr < m_buffer + m_offset); >+ return addr - m_buffer; >+ } >+ >+ 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() >+ { >+ MallocPtr<uint8_t> buffer = adoptMallocPtr(m_buffer); >+ m_buffer = nullptr; >+ return { WTFMove(buffer), m_offset }; >+ } >+ >+private: >+ unsigned s_maxSize = 10 * MB; >+ >+ VM& m_vm; >+ uint8_t* m_buffer; >+ ptrdiff_t m_offset; >+ HashMap<const void*, ptrdiff_t> m_ptrToOffsetMap; >+}; >+ >+class Decoder { >+ WTF_MAKE_NONCOPYABLE(Decoder); >+ >+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, typename Dst> >+struct CachedObject { >+ using SourceType_ = Source; >+ >+ static unsigned sizeOf(const Source& source) >+ { >+ unsigned size = 0; >+ computeOutOfLineSize(size, source); >+ return size; >+ } >+ >+ template<typename T> >+ static T& cast(T* source) >+ { >+ return *source; >+ } >+ >+ template<typename T, typename = std::enable_if_t<!std::is_pointer<T>::value>> >+ static T& cast(T& source) >+ { >+ return source; >+ } >+ >+ template<typename T> >+ static const T& cast(const T* const source) >+ { >+ return *source; >+ } >+ >+ template<typename T, typename = std::enable_if_t<!std::is_pointer<T>::value>> >+ static const T& cast(const T& source) >+ { >+ return source; >+ } >+}; >+ >+template<typename Source, typename Dst> >+struct VariableLengthObject : public CachedObject<Source, Dst> { >+private: >+ constexpr static ptrdiff_t s_invalidOffset = PTRDIFF_MAX; >+public: >+ ptrdiff_t offset { s_invalidOffset }; >+ >+ const uint8_t* buffer() const >+ { >+ ASSERT(offset != s_invalidOffset); >+ return reinterpret_cast<const uint8_t*>(this) + offset; >+ } >+ >+ uint8_t* buffer() >+ { >+ ASSERT(offset != s_invalidOffset); >+ return reinterpret_cast<uint8_t*>(this) + offset; >+ } >+ >+ template<typename T> >+ const T* buffer() const >+ { >+ return reinterpret_cast<const T*>(buffer()); >+ } >+ >+ template<typename T> >+ T* buffer() >+ { >+ return reinterpret_cast<T*>(buffer()); >+ } >+ >+ uint8_t* allocate(Encoder& encoder, size_t size) >+ { >+ ptrdiff_t offsetOffset = encoder.offsetOf(&offset); >+ ptrdiff_t allocationOffset = encoder.mallocOffset(size); >+ offset = allocationOffset - offsetOffset; >+ return buffer(); >+ } >+ >+ template<typename T> >+ T* allocate(Encoder& encoder, unsigned size = 1) >+ { >+ allocate(encoder, sizeof(T) * size); >+ return buffer<T>(); >+ } >+}; >+ >+template<typename T, typename ST = SourceType<T>> >+struct CachedPtr : public VariableLengthObject<ST*, CachedPtr<T>> { >+ bool isEmpty; >+ >+ void encode(Encoder& encoder, const ST* src) >+ { >+ isEmpty = !src; >+ if (isEmpty) >+ return; >+ >+ if (WTF::Optional<ptrdiff_t> offset = encoder.offsetForPtr(src)) { >+ this->offset = *offset - encoder.offsetOf(&this->offset); >+ return; >+ } >+ >+ T* cachedObject = this->template allocate<T>(encoder); >+ cachedObject->encode(encoder, *src); >+ encoder.cachePtr(src, encoder.offsetOf(cachedObject)); >+ } >+ >+ template<typename... Args> >+ ST* decode(Decoder& decoder, Args... args) const >+ { >+ if (isEmpty) >+ return nullptr; >+ >+ ptrdiff_t bufferOffset = decoder.offsetOf(this->buffer()); >+ if (WTF::Optional<void*> ptr = decoder.ptrForOffset(bufferOffset)) >+ return reinterpret_cast<ST*>(*ptr); >+ >+ ST* ptr = operator->()->decode(decoder, args...); >+ decoder.cacheOffset(bufferOffset, ptr); >+ return ptr; >+ } >+ >+ T* operator->() >+ { >+ if (isEmpty) >+ return nullptr; >+ return this->template buffer<T>(); >+ } >+ >+ const T* operator->() const >+ { >+ if (isEmpty) >+ return nullptr; >+ return this->template buffer<T>(); >+ } >+}; >+ >+template<typename T, typename ST = SourceType<T>> >+struct CachedRefPtr : public CachedObject<RefPtr<ST>, CachedRefPtr<T>> { >+ CachedPtr<T, ST> ptr; >+ >+ void encode(Encoder& encoder, const ST* src) >+ { >+ ptr.encode(encoder, src); >+ } >+ >+ void encode(Encoder& encoder, const RefPtr<ST> src) >+ { >+ encode(encoder, src.get()); >+ } >+ >+ RefPtr<ST> decode(Decoder& decoder) const >+ { >+ ST* decodedPtr = ptr.decode(decoder); >+ decoder.addFinalizer(decoder.offsetOf(ptr.buffer()), [=] { derefIfNotNull(decodedPtr); }); >+ refIfNotNull(decodedPtr); >+ return adoptRef(decodedPtr); >+ } >+ >+ void decode(Decoder& decoder, RefPtr<ST>& src) const >+ { >+ src = decode(decoder); >+ } >+}; >+ >+template<typename T, typename ST = SourceType<T>> >+struct CachedWriteBarrier : public CachedObject<WriteBarrier<ST>, CachedWriteBarrier<T>> { >+ CachedPtr<T, ST> ptr; >+ >+ void encode(Encoder& encoder, const WriteBarrier<ST> src) >+ { >+ ptr.encode(encoder, src.get()); >+ } >+ >+ void decode(Decoder& decoder, WriteBarrier<ST>& src, const JSCell* owner) const >+ { >+ ST* decodedPtr = ptr.decode(decoder); >+ if (decodedPtr) >+ src.set(decoder.vm(), owner, decodedPtr); >+ } >+}; >+ >+template<typename T, size_t IC = 0, typename OH = CrashOnOverflow> >+struct CachedVector : public VariableLengthObject<Vector<SourceType<T>, IC, OH>, CachedVector<T, IC, OH>> { >+ unsigned size; >+ >+ void encode(Encoder& encoder, const Vector<SourceType<T>, IC, OH>& vector) >+ { >+ size = vector.size(); >+ T* buffer = this->template allocate<T>(encoder, size); >+ for (unsigned i = 0; i < size; ++i) >+ ::JSC::encode(encoder, buffer[i], vector[i]); >+ } >+ >+ template<typename... Args> >+ void decode(Decoder& decoder, Vector<SourceType<T>, IC, OH>& vector, Args... args) const >+ { >+ vector.resizeToFit(size); >+ const T* buffer = this->template buffer<T>(); >+ for (unsigned i = 0; i < size; ++i) >+ ::JSC::decode(decoder, buffer[i], vector[i], args...); >+ } >+}; >+ >+template<typename Fst, typename Snd> >+struct CachedPair : public CachedObject<std::pair<SourceType<Fst>, SourceType<Snd>>, CachedPair<Fst, Snd>> { >+ Fst fst; >+ Snd snd; >+ >+ void encode(Encoder& encoder, const std::pair<SourceType<Fst>, SourceType<Snd>>& pair) >+ { >+ ::JSC::encode(encoder, fst, std::get<0>(pair)); >+ ::JSC::encode(encoder, snd, std::get<1>(pair)); >+ } >+ >+ void decode(Decoder& decoder, std::pair<SourceType<Fst>, SourceType<Snd>>& pair) const >+ { >+ ::JSC::decode(decoder, fst, std::get<0>(pair)); >+ ::JSC::decode(decoder, snd, std::get<1>(pair)); >+ } >+}; >+ >+template<typename Key, typename Value, typename HashArg = typename DefaultHash<SourceType<Key>>::Hash, typename KeyTraitsArg = HashTraits<SourceType<Key>>, typename MappedTraitsArg = HashTraits<SourceType<Value>>> >+struct CachedHashMap : public VariableLengthObject<HashMap<SourceType<Key>, SourceType<Value>, HashArg, KeyTraitsArg, MappedTraitsArg>, CachedHashMap<Key, Value, HashArg, KeyTraitsArg, MappedTraitsArg>> { >+ >+ CachedVector<CachedPair<Key, Value>> entries; >+ >+ template<typename K, typename V> >+ using Map = HashMap<K, V, HashArg, KeyTraitsArg, MappedTraitsArg>; >+ >+ void encode(Encoder& encoder, const Map<SourceType<Key>, SourceType<Value>>& map) >+ { >+ entries.size = map.size(); >+ SourceType<decltype(entries)> entriesVector(map.size()); >+ unsigned i = 0; >+ for (const auto& it : map) >+ entriesVector[i++] = { it.key, it.value }; >+ entries.encode(encoder, entriesVector); >+ } >+ >+ void decode(Decoder& decoder, Map<SourceType<Key>, SourceType<Value>>& map) const >+ { >+ SourceType<decltype(entries)> decodedEntries; >+ entries.decode(decoder, decodedEntries); >+ for (const auto& pair : decodedEntries) >+ map.set(std::get<0>(pair), std::get<1>(pair)); >+ } >+}; >+ >+struct CachedUniquedStringImpl : public VariableLengthObject<UniquedStringImpl, CachedUniquedStringImpl> { >+ bool is8Bit : 1; >+ bool isSymbol : 1; >+ bool isAtomic : 1; >+ unsigned length; >+ >+ void encode(Encoder& encoder, const StringImpl& string) >+ { >+ isAtomic = string.isAtomic(); >+ isSymbol = string.isSymbol(); >+ StringImpl* impl = const_cast<StringImpl*>(&string); >+ if (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(); >+ } >+ } >+ >+ is8Bit = impl->is8Bit(); >+ length = impl->length(); >+ >+ if (!length) >+ return; >+ >+ unsigned size = length; >+ const void* payload; >+ if (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 (!isSymbol) >+ return AtomicStringImpl::add(buffer, length).leakRef(); >+ >+ if (!length) >+ return &SymbolImpl::createNullSymbol().leakRef(); >+ >+ Identifier ident = Identifier::fromString(&decoder.vm(), buffer, length); >+ String str = decoder.vm().propertyNames->lookUpPrivateName(ident)->string(); >+ StringImpl* impl = str.releaseImpl().get(); >+ ASSERT(impl->isSymbol()); >+ return static_cast<UniquedStringImpl*>(impl); >+ }; >+ >+ if (is8Bit) >+ return create(this->buffer<LChar>()); >+ return create(this->buffer<UChar>()); >+ } >+}; >+ >+struct CachedStringImpl : public VariableLengthObject<StringImpl, CachedStringImpl> { >+ CachedUniquedStringImpl uniquedStringImpl; >+ >+ void encode(Encoder& encoder, const StringImpl& impl) >+ { >+ uniquedStringImpl.encode(encoder, impl); >+ } >+ >+ StringImpl* decode(Decoder& decoder) const >+ { >+ return uniquedStringImpl.decode(decoder); >+ } >+}; >+ >+struct CachedString : public VariableLengthObject<String, CachedString> { >+ CachedRefPtr<CachedUniquedStringImpl> impl; >+ >+ void encode(Encoder& encoder, const String& string) >+ { >+ impl.encode(encoder, static_cast<UniquedStringImpl*>(string.impl())); >+ } >+ >+ String decode(Decoder& decoder) const >+ { >+ return String((RefPtr<StringImpl>)impl.decode(decoder)); >+ } >+ >+ void decode(Decoder& decoder, String& dst) const >+ { >+ dst = decode(decoder); >+ } >+}; >+ >+struct CachedIdentifier : public VariableLengthObject<Identifier, CachedIdentifier> { >+ CachedString string; >+ >+ void encode(Encoder& encoder, const Identifier& identifier) >+ { >+ string.encode(encoder, identifier.string()); >+ } >+ >+ Identifier decode(Decoder& decoder) const >+ { >+ String str = 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); >+ } >+}; >+ >+template<typename T> >+struct CachedOptional : public VariableLengthObject<WTF::Optional<SourceType<T>>, CachedOptional<T>> { >+ bool isEmpty; >+ >+ void encode(Encoder& encoder, const WTF::Optional<SourceType<T>>& source) >+ { >+ isEmpty = !source; >+ >+ if (isEmpty) >+ return; >+ >+ this->template allocate<T>(encoder)->encode(encoder, *source); >+ } >+ >+ WTF::Optional<SourceType<T>> decode(Decoder& decoder) const >+ { >+ if (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 (isEmpty) >+ return nullptr; >+ >+ return this->template buffer<T>()->decode(decoder); >+ } >+}; >+ >+struct CachedSimpleJumpTable : public CachedObject<UnlinkedSimpleJumpTable, CachedSimpleJumpTable> { >+ int32_t min; >+ CachedVector<int32_t> branchOffsets; >+ >+ void encode(Encoder& encoder, const UnlinkedSimpleJumpTable& jumpTable) >+ { >+ min = jumpTable.min; >+ branchOffsets.encode(encoder, jumpTable.branchOffsets); >+ } >+ >+ void decode(Decoder& decoder, UnlinkedSimpleJumpTable& jumpTable) const >+ { >+ jumpTable.min = min; >+ branchOffsets.decode(decoder, jumpTable.branchOffsets); >+ } >+}; >+ >+struct CachedStringJumpTable : public CachedObject<UnlinkedStringJumpTable, CachedStringJumpTable> { >+ CachedHashMap<CachedRefPtr<CachedStringImpl>, UnlinkedStringJumpTable:: OffsetLocation> offsetTable; >+ >+ void encode(Encoder& encoder, const UnlinkedStringJumpTable& jumpTable) >+ { >+ offsetTable.encode(encoder, jumpTable.offsetTable); >+ } >+ >+ void decode(Decoder& decoder, UnlinkedStringJumpTable& jumpTable) const >+ { >+ offsetTable.decode(decoder, jumpTable.offsetTable); >+ } >+}; >+ >+struct CachedRareData : public CachedObject<UnlinkedCodeBlock::RareData, CachedRareData> { >+ CachedVector<UnlinkedHandlerInfo> exceptionHandlers; >+ >+ // Jump Tables >+ CachedVector<CachedSimpleJumpTable> switchJumpTables; >+ CachedVector<CachedStringJumpTable> stringSwitchJumpTables; >+ >+ CachedVector<ExpressionRangeInfo::FatPosition> expressionInfoFatPositions; >+ >+ CachedHashMap<unsigned, UnlinkedCodeBlock::RareData::TypeProfilerExpressionRange> typeProfilerInfoMap; >+ CachedVector<InstructionStream::Offset> opProfileControlFlowBytecodeOffsets; >+ >+ >+ void encode(Encoder& encoder, const UnlinkedCodeBlock::RareData& rareData) >+ { >+ exceptionHandlers.encode(encoder, rareData.m_exceptionHandlers); >+ switchJumpTables.encode(encoder, rareData.m_switchJumpTables); >+ stringSwitchJumpTables.encode(encoder, rareData.m_stringSwitchJumpTables); >+ expressionInfoFatPositions.encode(encoder, rareData.m_expressionInfoFatPositions); >+ typeProfilerInfoMap.encode(encoder, rareData.m_typeProfilerInfoMap); >+ opProfileControlFlowBytecodeOffsets.encode(encoder, rareData.m_opProfileControlFlowBytecodeOffsets); >+ } >+ >+ UnlinkedCodeBlock::RareData* decode(Decoder& decoder) const >+ { >+ UnlinkedCodeBlock::RareData* rareData = new UnlinkedCodeBlock::RareData { }; >+ exceptionHandlers.decode(decoder, rareData->m_exceptionHandlers); >+ switchJumpTables.decode(decoder, rareData->m_switchJumpTables); >+ stringSwitchJumpTables.decode(decoder, rareData->m_stringSwitchJumpTables); >+ expressionInfoFatPositions.decode(decoder, rareData->m_expressionInfoFatPositions); >+ typeProfilerInfoMap.decode(decoder, rareData->m_typeProfilerInfoMap); >+ opProfileControlFlowBytecodeOffsets.decode(decoder, rareData->m_opProfileControlFlowBytecodeOffsets); >+ return rareData; >+ } >+ >+}; >+ >+struct CachedBitVector : public VariableLengthObject<BitVector, CachedBitVector> { >+ unsigned size; >+ >+ void encode(Encoder& encoder, const BitVector& bitVector) >+ { >+ size = bitVector.size(); >+ uint8_t* buffer = this->allocate(encoder, size); >+ memcpy(buffer, bitVector.bits(), size); >+ } >+ >+ void decode(Decoder&, BitVector& bitVector) const >+ { >+ bitVector.ensureSize(size); >+ memcpy(bitVector.bits(), this->buffer(), size); >+ } >+}; >+ >+template<typename T, typename HashArg = typename DefaultHash<T>::Hash> >+struct CachedHashSet : public CachedObject<HashSet<SourceType<T>, HashArg>, CachedHashSet<T, HashArg>> { >+ CachedVector<T> entries; >+ >+ void encode(Encoder& encoder, const HashSet<SourceType<T>, HashArg>& set) >+ { >+ SourceType<decltype(entries)> entriesVector(set.size()); >+ unsigned i = 0; >+ for (const auto& item : set) >+ entriesVector[i++] = item; >+ entries.encode(encoder, entriesVector); >+ } >+ >+ void decode(Decoder& decoder, HashSet<SourceType<T>, HashArg>& set) const >+ { >+ SourceType<decltype(entries)> entriesVector; >+ entries.decode(decoder, entriesVector); >+ for (const auto& item : entriesVector) >+ set.add(item); >+ } >+}; >+ >+struct CachedConstantIdentifierSetEntry : public VariableLengthObject<ConstantIdentifierSetEntry, CachedConstantIdentifierSetEntry> { >+ unsigned constant; >+ CachedHashSet<CachedRefPtr<CachedUniquedStringImpl>, IdentifierRepHash> set; >+ >+ void encode(Encoder& encoder, const ConstantIdentifierSetEntry& entry) >+ { >+ constant = std::get<1>(entry); >+ set.encode(encoder, std::get<0>(entry)); >+ } >+ >+ void decode(Decoder& decoder, ConstantIdentifierSetEntry& entry) const >+ { >+ std::get<1>(entry) = constant; >+ set.decode(decoder, std::get<0>(entry)); >+ } >+}; >+ >+struct CachedVariableEnvironment : public CachedObject<VariableEnvironment, CachedVariableEnvironment> { >+ >+ bool isEverythingCaptured; >+ CachedHashMap<CachedRefPtr<CachedUniquedStringImpl>, VariableEnvironmentEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, VariableEnvironmentEntryHashTraits> map; >+ >+ void encode(Encoder& encoder, const VariableEnvironment& env) >+ { >+ isEverythingCaptured = env.m_isEverythingCaptured; >+ map.encode(encoder, env.m_map); >+ } >+ >+ void decode(Decoder& decoder, VariableEnvironment& env) const >+ { >+ env.m_isEverythingCaptured = isEverythingCaptured; >+ map.decode(decoder, env.m_map); >+ } >+}; >+ >+template<typename T, typename ST = SourceType<T>> >+struct CachedArray : public VariableLengthObject<ST*, CachedArray<T, ST>> { >+ void encode(Encoder& encoder, const ST* 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, ST* 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...); >+ } >+}; >+ >+struct CachedScopedArgumentsTable : public CachedObject<ScopedArgumentsTable, CachedScopedArgumentsTable> { >+ uint32_t length; >+ CachedArray<ScopeOffset> arguments; >+ >+ void encode(Encoder& encoder, const ScopedArgumentsTable& scopedArgumentsTable) >+ { >+ length = scopedArgumentsTable.m_length; >+ arguments.encode(encoder, scopedArgumentsTable.m_arguments.get(), length); >+ } >+ >+ ScopedArgumentsTable* decode(Decoder& decoder) const >+ { >+ ScopedArgumentsTable* scopedArgumentsTable = ScopedArgumentsTable::create(decoder.vm(), length); >+ arguments.decode(decoder, scopedArgumentsTable->m_arguments.get(), length); >+ return scopedArgumentsTable; >+ } >+}; >+ >+struct CachedSymbolTableEntry : public CachedObject<SymbolTableEntry, CachedSymbolTableEntry> { >+ intptr_t bits; >+ >+ void encode(Encoder&, const SymbolTableEntry& symbolTableEntry) >+ { >+ bits = symbolTableEntry.m_bits | SymbolTableEntry::SlimFlag; >+ } >+ >+ void decode(Decoder&, SymbolTableEntry& symbolTableEntry) const >+ { >+ symbolTableEntry.m_bits = bits; >+ } >+}; >+ >+struct CachedSymbolTable : public CachedObject<SymbolTable, CachedSymbolTable> { >+ CachedHashMap<CachedRefPtr<CachedUniquedStringImpl>, CachedSymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, SymbolTableIndexHashTraits> map; >+ ScopeOffset maxScopeOffset; >+ unsigned usesNonStrictEval : 1; >+ unsigned nestedLexicalScope : 1; >+ unsigned scopeType : 3; >+ // FIXME: do we need to cached this eventually? >+ // CachedPtr<SymbolTableRareData> rareData; >+ CachedPtr<CachedScopedArgumentsTable> arguments; >+ >+ void encode(Encoder& encoder, const SymbolTable& symbolTable) >+ { >+ ASSERT(!symbolTable.m_rareData); >+ map.encode(encoder, symbolTable.m_map); >+ maxScopeOffset = symbolTable.m_maxScopeOffset; >+ usesNonStrictEval = symbolTable.m_usesNonStrictEval; >+ nestedLexicalScope = symbolTable.m_nestedLexicalScope; >+ scopeType = symbolTable.m_scopeType; >+ arguments.encode(encoder, symbolTable.m_arguments.get()); >+ } >+ >+ SymbolTable* decode(Decoder& decoder) const >+ { >+ SymbolTable* symbolTable = SymbolTable::create(decoder.vm()); >+ map.decode(decoder, symbolTable->m_map); >+ symbolTable->m_maxScopeOffset = maxScopeOffset; >+ symbolTable->m_usesNonStrictEval = usesNonStrictEval; >+ symbolTable->m_nestedLexicalScope = nestedLexicalScope; >+ symbolTable->m_scopeType = scopeType; >+ ScopedArgumentsTable* scopedArgumentsTable = arguments.decode(decoder); >+ if (scopedArgumentsTable) >+ symbolTable->m_arguments.set(decoder.vm(), symbolTable, scopedArgumentsTable); >+ return symbolTable; >+ } >+}; >+ >+struct CachedJSValue; >+struct CachedImmutableButterfly : public CachedObject<JSImmutableButterfly, CachedImmutableButterfly> { >+ IndexingType indexingType; >+ unsigned length; >+ union { >+ CachedArray<double> cachedDoubles; >+ CachedArray<CachedJSValue, WriteBarrier<Unknown>> cachedValues; >+ }; >+ >+ void encode(Encoder& encoder, JSImmutableButterfly& immutableButterfly) >+ { >+ length = immutableButterfly.length(); >+ indexingType = immutableButterfly.indexingMode(); // this is confusing, not sure why we have to use indexingMode vs indexingType >+ if (hasDouble(indexingType)) >+ cachedDoubles.encode(encoder, immutableButterfly.toButterfly()->contiguousDouble().data(), length); >+ else >+ cachedValues.encode(encoder, immutableButterfly.toButterfly()->contiguous().data(), length); >+ } >+ >+ JSImmutableButterfly* decode(Decoder& decoder) const >+ { >+ JSImmutableButterfly* immutableButterfly = JSImmutableButterfly::create(decoder.vm(), indexingType, length); >+ if (hasDouble(indexingType)) >+ cachedDoubles.decode(decoder, immutableButterfly->toButterfly()->contiguousDouble().data(), length, immutableButterfly); >+ else >+ cachedValues.decode(decoder, immutableButterfly->toButterfly()->contiguous().data(), length, immutableButterfly); >+ return immutableButterfly; >+ } >+}; >+ >+struct CachedRegExp : public CachedObject<RegExp, CachedRegExp> { >+ CachedString patternString; >+ RegExpFlags flags; >+ >+ void encode(Encoder& encoder, const RegExp& regExp) >+ { >+ patternString.encode(encoder, regExp.m_patternString); >+ flags = regExp.m_flags; >+ } >+ >+ RegExp* decode(Decoder& decoder) const >+ { >+ String pattern { patternString.decode(decoder) }; >+ return RegExp::create(decoder.vm(), pattern, flags); >+ } >+}; >+ >+struct CachedTemplateObjectDescriptor : public CachedObject<TemplateObjectDescriptor, CachedTemplateObjectDescriptor> { >+ CachedVector<CachedString, 4> rawStrings; >+ CachedVector<CachedOptional<CachedString>, 4> cookedStrings; >+ >+ void encode(Encoder& encoder, const TemplateObjectDescriptor& templateObjectDescriptor) >+ { >+ rawStrings.encode(encoder, templateObjectDescriptor.rawStrings()); >+ cookedStrings.encode(encoder, templateObjectDescriptor.cookedStrings()); >+ } >+ >+ Ref<TemplateObjectDescriptor> decode(Decoder& decoder) const >+ { >+ TemplateObjectDescriptor::StringVector decodedRawStrings; >+ TemplateObjectDescriptor::OptionalStringVector decodedCookedStrings; >+ rawStrings.decode(decoder, decodedRawStrings); >+ cookedStrings.decode(decoder, decodedCookedStrings); >+ return TemplateObjectDescriptor::create(WTFMove(decodedRawStrings), WTFMove(decodedCookedStrings)); >+ } >+}; >+ >+struct CachedBigInt : public VariableLengthObject<JSBigInt, CachedBigInt> { >+ unsigned length; >+ bool sign; >+ >+ void encode(Encoder& encoder, JSBigInt& bigInt) >+ { >+ length = bigInt.length(); >+ sign = bigInt.sign(); >+ >+ if (!length) >+ return; >+ >+ unsigned size = sizeof(JSBigInt::Digit) * length; >+ this->allocate(encoder, size); >+ memcpy(this->buffer(), bigInt.dataStorage(), size); >+ } >+ >+ JSBigInt* decode(Decoder& decoder) const >+ { >+ JSBigInt* bigInt = JSBigInt::createWithLengthUnchecked(decoder.vm(), length); >+ bigInt->setSign(sign); >+ memcpy(bigInt->dataStorage(), this->buffer(), sizeof(JSBigInt::Digit) * length); >+ return bigInt; >+ } >+}; >+ >+struct CachedJSValue : public VariableLengthObject<WriteBarrier<Unknown>, CachedJSValue> { >+ enum class EncodedType : uint8_t { >+ JSValue, >+ SymbolTable, >+ String, >+ ImmutableButterfly, >+ RegExp, >+ TemplateObjectDescriptor, >+ BigInt, >+ }; >+ >+ EncodedType type; >+ >+ void encode(Encoder& encoder, const WriteBarrier<Unknown> value) >+ { >+ JSValue v = value.get(); >+ >+ if (!v.isCell() || v.isEmpty()) { >+ type = EncodedType::JSValue; >+ *this->allocate<EncodedJSValue>(encoder) = JSValue::encode(v); >+ return; >+ } >+ >+ JSCell* cell = v.asCell(); >+ const ClassInfo* classInfo = cell->classInfo(encoder.vm()); >+ >+ if (classInfo == SymbolTable::info()) { >+ type = EncodedType::SymbolTable; >+ this->allocate<CachedSymbolTable>(encoder)->encode(encoder, *jsCast<SymbolTable*>(cell)); >+ return; >+ } >+ >+ if (classInfo == JSString::info()) { >+ type = EncodedType::String; >+ StringImpl* impl = asString(cell)->tryGetValue().impl(); >+ ASSERT(!impl || !impl->isSymbol()); >+ this->allocate<CachedUniquedStringImpl>(encoder)->encode(encoder, *impl); >+ return; >+ } >+ >+ if (classInfo == JSImmutableButterfly::info()) { >+ type = EncodedType::ImmutableButterfly; >+ this->allocate<CachedImmutableButterfly>(encoder)->encode(encoder, *jsCast<JSImmutableButterfly*>(cell)); >+ return; >+ } >+ >+ if (classInfo == RegExp::info()) { >+ type = EncodedType::RegExp; >+ this->allocate<CachedRegExp>(encoder)->encode(encoder, *jsCast<RegExp*>(cell)); >+ return; >+ } >+ >+ if (classInfo == JSTemplateObjectDescriptor::info()) { >+ type = EncodedType::TemplateObjectDescriptor; >+ this->allocate<CachedTemplateObjectDescriptor>(encoder)->encode(encoder, jsCast<JSTemplateObjectDescriptor*>(cell)->descriptor()); >+ return; >+ } >+ >+ if (classInfo == JSBigInt::info()) { >+ type = EncodedType::BigInt; >+ this->allocate<CachedBigInt>(encoder)->encode(encoder, *jsCast<JSBigInt*>(cell)); >+ return; >+ } >+ >+ RELEASE_ASSERT_NOT_REACHED(); >+ } >+ >+ void decode(Decoder& decoder, WriteBarrier<Unknown>& value, const JSCell* owner) const >+ { >+ JSValue v; >+ switch (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); >+ } >+}; >+ >+struct CachedInstructionStream : public CachedObject<InstructionStream, CachedInstructionStream> { >+ CachedVector<uint8_t, 0, UnsafeVectorOverflow> instructions; >+ >+ void encode(Encoder& encoder, const InstructionStream& stream) >+ { >+ instructions.encode(encoder, stream.m_instructions); >+ } >+ >+ InstructionStream* decode(Decoder& decoder) const >+ { >+ Vector<uint8_t, 0, UnsafeVectorOverflow> instructionsVector; >+ instructions.decode(decoder, instructionsVector); >+ return new InstructionStream(WTFMove(instructionsVector)); >+ } >+}; >+ >+struct CachedMetadataTable : public CachedObject<UnlinkedMetadataTable, CachedMetadataTable> { >+ bool hasMetadata; >+ std::array<unsigned, UnlinkedMetadataTable::s_offsetTableEntries> metadata; >+ >+ void encode(Encoder&, const UnlinkedMetadataTable& metadataTable) >+ { >+ ASSERT(metadataTable.m_isFinalized); >+ hasMetadata = metadataTable.m_hasMetadata; >+ if (!hasMetadata) >+ return; >+ for (unsigned i = UnlinkedMetadataTable::s_offsetTableEntries; i--;) >+ metadata[i] = metadataTable.buffer()[i]; >+ } >+ >+ void decode(Decoder&, UnlinkedMetadataTable& metadataTable) const >+ { >+ metadataTable.m_isFinalized = true; >+ metadataTable.m_isLinked = false; >+ metadataTable.m_hasMetadata = hasMetadata; >+ for (unsigned i = UnlinkedMetadataTable::s_offsetTableEntries; i--;) >+ metadataTable.buffer()[i] = metadata[i]; >+ } >+}; >+ >+struct CachedSourceOrigin : public CachedObject<SourceOrigin, CachedSourceOrigin> { >+ CachedString string; >+ >+ void encode(Encoder& encoder, const SourceOrigin& sourceOrigin) >+ { >+ string.encode(encoder, sourceOrigin.string()); >+ } >+ >+ SourceOrigin decode(Decoder& decoder) const >+ { >+ return SourceOrigin { string.decode(decoder) }; >+ } >+}; >+ >+struct CachedTextPosition : public CachedObject<TextPosition, CachedTextPosition> { >+ int line; >+ int column; >+ >+ void encode(Encoder&, TextPosition textPosition) >+ { >+ line = textPosition.m_line.zeroBasedInt(); >+ column = textPosition.m_column.zeroBasedInt(); >+ } >+ >+ TextPosition decode(Decoder&) const >+ { >+ return TextPosition { OrdinalNumber::fromZeroBasedInt(line), OrdinalNumber::fromZeroBasedInt(column) }; >+ } >+}; >+ >+template <typename ST, typename CachedType> >+struct CachedSourceProviderShape : public CachedObject<ST, CachedType> { >+ bool validated : 1; >+ CachedSourceOrigin sourceOrigin; >+ CachedString url; >+ CachedString sourceURLDirective; >+ CachedString sourceMappingURLDirective; >+ CachedTextPosition startPosition; >+ >+ void encode(Encoder& encoder, const SourceProvider& sourceProvider) >+ { >+ validated = sourceProvider.isValid(); >+ sourceOrigin.encode(encoder, sourceProvider.sourceOrigin()); >+ url.encode(encoder, sourceProvider.url()); >+ sourceURLDirective.encode(encoder, sourceProvider.sourceURL()); >+ sourceMappingURLDirective.encode(encoder, sourceProvider.sourceMappingURL()); >+ startPosition.encode(encoder, sourceProvider.startPosition()); >+ } >+ >+ void decode(Decoder& decoder, SourceProvider& sourceProvider) const >+ { >+ if (validated) >+ sourceProvider.setValid(); >+ sourceProvider.setSourceURLDirective(sourceURLDirective.decode(decoder)); >+ sourceProvider.setSourceMappingURLDirective(sourceMappingURLDirective.decode(decoder)); >+ } >+}; >+ >+struct CachedStringSourceProvider : public CachedSourceProviderShape<StringSourceProvider, CachedStringSourceProvider> { >+ using Base = CachedSourceProviderShape<StringSourceProvider, CachedStringSourceProvider>; >+ >+ CachedString source; >+ >+ void encode(Encoder& encoder, const StringSourceProvider& sourceProvider) >+ { >+ Base::encode(encoder, sourceProvider); >+ source.encode(encoder, sourceProvider.source().toString()); >+ } >+ >+ StringSourceProvider* decode(Decoder& decoder, SourceProviderSourceType sourceType) const >+ { >+ String decodedSource = source.decode(decoder); >+ SourceOrigin decodedSourceOrigin = sourceOrigin.decode(decoder); >+ String decodedURL = url.decode(decoder); >+ TextPosition decodedStartPosition = startPosition.decode(decoder); >+ >+ Ref<StringSourceProvider> sourceProvider = StringSourceProvider::create(decodedSource, decodedSourceOrigin, URL(URL(), decodedURL), decodedStartPosition, sourceType); >+ Base::decode(decoder, sourceProvider.get()); >+ return &sourceProvider.leakRef(); >+ } >+}; >+ >+#if ENABLE(WEBASSEMBLY) >+struct CachedWebAssemblySourceProvider : public CachedSourceProviderShape<WebAssemblySourceProvider, CachedWebAssemblySourceProvider> { >+ using Base = CachedSourceProviderShape<WebAssemblySourceProvider, CachedWebAssemblySourceProvider>; >+ >+ CachedVector<uint8_t> data; >+ >+ void encode(Encoder& encoder, const WebAssemblySourceProvider& sourceProvider) >+ { >+ Base::encode(encoder, sourceProvider); >+ data.encode(encoder, sourceProvider.data()); >+ } >+ >+ WebAssemblySourceProvider* decode(Decoder& decoder) const >+ { >+ Vector<uint8_t> decodedData; >+ SourceOrigin decodedSourceOrigin = sourceOrigin.decode(decoder); >+ String decodedURL = url.decode(decoder); >+ >+ data.decode(decoder, decodedData); >+ >+ Ref<WebAssemblySourceProvider> sourceProvider = WebAssemblySourceProvider::create(WTFMove(decodedData), decodedSourceOrigin, URL(URL(), decodedURL)); >+ Base::decode(decoder, sourceProvider.get()); >+ >+ return &sourceProvider.leakRef(); >+ } >+}; >+#endif >+ >+struct CachedSourceProvider : public VariableLengthObject<SourceProvider, CachedSourceProvider> { >+ SourceProviderSourceType sourceType; >+ >+ void encode(Encoder& encoder, const SourceProvider& sourceProvider) >+ { >+ sourceType = sourceProvider.sourceType(); >+ switch (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 (sourceType) { >+ case SourceProviderSourceType::Program: >+ case SourceProviderSourceType::Module: >+ return this->buffer<CachedStringSourceProvider>()->decode(decoder, sourceType); >+#if ENABLE(WEBASSEMBLY) >+ case SourceProviderSourceType::WebAssembly: >+ return this->buffer<CachedWebAssemblySourceProvider>()->decode(decoder); >+#endif >+ default: >+ RELEASE_ASSERT_NOT_REACHED(); >+ } >+ } >+}; >+ >+template<typename ST, typename CacheType> >+struct CachedUnlinkedSourceCodeShape : public CachedObject<ST, CacheType> { >+ CachedPtr<CachedSourceProvider> provider; >+ int startOffset; >+ int endOffset; >+ >+ void encode(Encoder& encoder, const UnlinkedSourceCode& sourceCode) >+ { >+ provider.encode(encoder, sourceCode.m_provider.get()); >+ startOffset = sourceCode.startOffset(); >+ endOffset = sourceCode.endOffset(); >+ } >+ >+ void decode(Decoder& decoder, UnlinkedSourceCode& sourceCode) const >+ { >+ sourceCode.m_provider = provider.decode(decoder); >+ sourceCode.m_startOffset = startOffset; >+ sourceCode.m_endOffset = endOffset; >+ } >+}; >+ >+ >+struct CachedUnlinkedSourceCode : public CachedUnlinkedSourceCodeShape<UnlinkedSourceCode, CachedUnlinkedSourceCode> { }; >+ >+struct CachedSourceCode : public CachedUnlinkedSourceCodeShape<SourceCode, CachedSourceCode> { >+ using Base = CachedUnlinkedSourceCodeShape<SourceCode, CachedSourceCode>; >+ >+ int firstLine; >+ int startColumn; >+ >+ void encode(Encoder& encoder, const SourceCode& sourceCode) >+ { >+ Base::encode(encoder, sourceCode); >+ firstLine = sourceCode.firstLine().zeroBasedInt(); >+ startColumn = sourceCode.startColumn().zeroBasedInt(); >+ } >+ >+ void decode(Decoder& decoder, SourceCode& sourceCode) const >+ { >+ Base::decode(decoder, sourceCode); >+ sourceCode.m_firstLine = OrdinalNumber::fromZeroBasedInt(firstLine); >+ sourceCode.m_startColumn = OrdinalNumber::fromZeroBasedInt(startColumn); >+ } >+}; >+ >+struct CachedFunctionExecutable : public CachedObject<UnlinkedFunctionExecutable, CachedFunctionExecutable> { >+ >+ void encode(Encoder&, const UnlinkedFunctionExecutable&); >+ UnlinkedFunctionExecutable* decode(Decoder&) const; >+ >+ unsigned firstLineOffset; >+ unsigned lineCount; >+ unsigned unlinkedFunctionNameStart; >+ unsigned unlinkedBodyStartColumn; >+ unsigned unlinkedBodyEndColumn; >+ unsigned startOffset; >+ unsigned sourceLength; >+ unsigned parametersStartOffset; >+ unsigned typeProfilingStartOffset; >+ unsigned typeProfilingEndOffset; >+ unsigned parameterCount; >+ CodeFeatures features; >+ SourceParseMode sourceParseMode; >+ unsigned isInStrictContext : 1; >+ unsigned hasCapturedVariables : 1; >+ unsigned isBuiltinFunction : 1; >+ unsigned isBuiltinDefaultClassConstructor : 1; >+ unsigned constructAbility: 1; >+ unsigned constructorKind : 2; >+ unsigned functionMode : 2; // FunctionMode >+ unsigned scriptMode: 1; // JSParserScriptMode >+ unsigned superBinding : 1; >+ unsigned derivedContextType: 2; >+ >+ CachedSourceCode classSource; >+ >+ CachedIdentifier name; >+ CachedIdentifier ecmaName; >+ CachedIdentifier inferredName; >+ >+ CachedVariableEnvironment parentScopeTDZVariables; >+ >+ CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock> unlinkedCodeBlockForCall; >+ CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock> unlinkedCodeBlockForConstruct; >+}; >+ >+template<typename CodeBlockType, typename CachedCodeBlockType> >+struct CachedCodeBlock : public CachedObject<CodeBlockType, CachedCodeBlockType> { >+ void encode(Encoder&, const UnlinkedCodeBlock&); >+ void decode(Decoder&, UnlinkedCodeBlock&) const; >+ >+ VirtualRegister thisRegister; >+ VirtualRegister scopeRegister; >+ VirtualRegister globalObjectRegister; >+ >+ unsigned usesEval : 1; >+ unsigned isStrictMode : 1; >+ unsigned isConstructor : 1; >+ unsigned hasCapturedVariables : 1; >+ unsigned isBuiltinFunction : 1; >+ unsigned superBinding : 1; >+ unsigned scriptMode: 1; >+ unsigned isArrowFunctionContext : 1; >+ unsigned isClassContext : 1; >+ unsigned wasCompiledWithDebuggingOpcodes : 1; >+ unsigned constructorKind : 2; >+ unsigned derivedContextType : 2; >+ unsigned evalContextType : 2; >+ unsigned hasTailCalls : 1; >+ >+ unsigned lineCount; >+ unsigned endColumn; >+ >+ int numVars; >+ int numCalleeLocals; >+ int numParameters; >+ >+ CodeFeatures features; >+ SourceParseMode parseMode; >+ CodeType codeType; >+ >+ std::array<unsigned, LinkTimeConstantCount> linkTimeConstants; >+ CachedMetadataTable metadata; >+ >+ CachedOptional<CachedRareData> rareData; >+ >+ CachedString sourceURLDirective; >+ CachedString sourceMappingURLDirective; >+ >+ CachedPtr<CachedInstructionStream> instructions; >+ CachedVector<InstructionStream::Offset> jumpTargets; >+ CachedVector<InstructionStream::Offset> propertyAccessInstructions; >+ CachedVector<CachedJSValue> constantRegisters; >+ CachedVector<SourceCodeRepresentation> constantsSourceCodeRepresentation; >+ CachedVector<ExpressionRangeInfo> expressionInfo; >+ CachedHashMap<InstructionStream::Offset, int> outOfLineJumpTargets; >+ >+ CachedVector<CachedConstantIdentifierSetEntry> constantIdentifierSets; >+ CachedVector<CachedIdentifier> identifiers; >+ CachedVector<CachedBitVector> bitVectors; >+ CachedVector<CachedWriteBarrier<CachedFunctionExecutable>> functionDecls; >+ CachedVector<CachedWriteBarrier<CachedFunctionExecutable>> functionExprs; >+}; >+ >+struct CachedProgramCodeBlock : public CachedCodeBlock<UnlinkedProgramCodeBlock, CachedProgramCodeBlock> { >+ using Base = CachedCodeBlock<UnlinkedProgramCodeBlock, CachedProgramCodeBlock>; >+ using Base::encode; >+ >+ CachedVariableEnvironment varDeclarations; >+ CachedVariableEnvironment lexicalDeclarations; >+ >+ void encode(Encoder& encoder, const UnlinkedProgramCodeBlock& codeBlock) >+ { >+ Base::encode(encoder, codeBlock); >+ varDeclarations.encode(encoder, codeBlock.m_varDeclarations); >+ 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); >+ varDeclarations.decode(decoder, codeBlock->m_varDeclarations); >+ lexicalDeclarations.decode(decoder, codeBlock->m_lexicalDeclarations); >+ return codeBlock; >+ } >+}; >+ >+struct CachedModuleCodeBlock : public CachedCodeBlock<UnlinkedModuleProgramCodeBlock, CachedModuleCodeBlock> { >+ using Base = CachedCodeBlock<UnlinkedModuleProgramCodeBlock, CachedModuleCodeBlock>; >+ using Base::encode; >+ >+ int moduleEnvironmentSymbolTableConstantRegisterOffset; >+ >+ void encode(Encoder& encoder, const UnlinkedModuleProgramCodeBlock& codeBlock) >+ { >+ Base::encode(encoder, codeBlock); >+ 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 = moduleEnvironmentSymbolTableConstantRegisterOffset; >+ return codeBlock; >+ } >+}; >+ >+struct CachedEvalCodeBlock : public CachedCodeBlock<UnlinkedEvalCodeBlock, CachedEvalCodeBlock> { >+ using Base = CachedCodeBlock<UnlinkedEvalCodeBlock, CachedEvalCodeBlock>; >+ using Base::encode; >+ >+ CachedVector<CachedIdentifier, 0, UnsafeVectorOverflow> variables; >+ CachedVector<CachedIdentifier, 0, UnsafeVectorOverflow> functionHoistingCandidates; >+ >+ void encode(Encoder& encoder, const UnlinkedEvalCodeBlock& codeBlock) >+ { >+ Base::encode(encoder, codeBlock); >+ variables.encode(encoder, codeBlock.m_variables); >+ 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); >+ variables.decode(decoder, codeBlock->m_variables); >+ functionHoistingCandidates.decode(decoder, codeBlock->m_functionHoistingCandidates); >+ return codeBlock; >+ } >+}; >+ >+struct CachedFunctionCodeBlock : public CachedCodeBlock<UnlinkedFunctionCodeBlock, CachedFunctionCodeBlock> { >+ using Base = CachedCodeBlock<UnlinkedFunctionCodeBlock, CachedFunctionCodeBlock>; >+ >+ 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, typename CachedCodeBlockType> >+ALWAYS_INLINE UnlinkedCodeBlock::UnlinkedCodeBlock(Decoder& decoder, Structure* structure, const CachedCodeBlock<CodeBlockType, CachedCodeBlockType>& cachedCodeBlock) >+ : Base(decoder.vm(), structure) >+ , m_instructions(cachedCodeBlock.instructions.decode(decoder)) >+ , m_liveness(nullptr) >+ , m_thisRegister(cachedCodeBlock.thisRegister) >+ , m_scopeRegister(cachedCodeBlock.scopeRegister) >+ , m_globalObjectRegister(cachedCodeBlock.globalObjectRegister) >+ >+ , m_sourceURLDirective(cachedCodeBlock.sourceURLDirective.decode(decoder)) >+ , m_sourceMappingURLDirective(cachedCodeBlock.sourceMappingURLDirective.decode(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.decodeAsPtr(decoder)) >+{ >+} >+ >+template<typename CodeBlockType, typename CachedCodeBlockType> >+ALWAYS_INLINE void CachedCodeBlock<CodeBlockType, CachedCodeBlockType>::decode(Decoder& decoder, UnlinkedCodeBlock& codeBlock) const >+{ >+ for (unsigned i = LinkTimeConstantCount; i--;) >+ codeBlock.m_linkTimeConstants[i] = linkTimeConstants[i]; >+ >+ metadata.decode(decoder, codeBlock.m_metadata); >+ propertyAccessInstructions.decode(decoder, codeBlock.m_propertyAccessInstructions); >+ constantRegisters.decode(decoder, codeBlock.m_constantRegisters, &codeBlock); >+ constantsSourceCodeRepresentation.decode(decoder, codeBlock.m_constantsSourceCodeRepresentation); >+ expressionInfo.decode(decoder, codeBlock.m_expressionInfo); >+ outOfLineJumpTargets.decode(decoder, codeBlock.m_outOfLineJumpTargets); >+ jumpTargets.decode(decoder, codeBlock.m_jumpTargets); >+ constantIdentifierSets.decode(decoder, codeBlock.m_constantIdentifierSets); >+ identifiers.decode(decoder, codeBlock.m_identifiers); >+ bitVectors.decode(decoder, codeBlock.m_bitVectors); >+ functionDecls.decode(decoder, codeBlock.m_functionDecls, &codeBlock); >+ 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) >+{ >+ firstLineOffset = executable.m_firstLineOffset; >+ lineCount = executable.m_lineCount; >+ unlinkedFunctionNameStart = executable.m_unlinkedFunctionNameStart; >+ unlinkedBodyStartColumn = executable.m_unlinkedBodyStartColumn; >+ unlinkedBodyEndColumn = executable.m_unlinkedBodyEndColumn; >+ startOffset = executable.m_startOffset; >+ sourceLength = executable.m_sourceLength; >+ parametersStartOffset = executable.m_parametersStartOffset; >+ typeProfilingStartOffset = executable.m_typeProfilingStartOffset; >+ typeProfilingEndOffset = executable.m_typeProfilingEndOffset; >+ parameterCount = executable.m_parameterCount; >+ >+ features = executable.m_features; >+ sourceParseMode = executable.m_sourceParseMode; >+ >+ isInStrictContext = executable.m_isInStrictContext; >+ hasCapturedVariables = executable.m_hasCapturedVariables; >+ isBuiltinFunction = executable.m_isBuiltinFunction; >+ isBuiltinDefaultClassConstructor = executable.m_isBuiltinDefaultClassConstructor; >+ constructAbility = executable.m_constructAbility; >+ constructorKind = executable.m_constructorKind; >+ functionMode = executable.m_functionMode; >+ scriptMode = executable.m_scriptMode; >+ superBinding = executable.m_superBinding; >+ derivedContextType = executable.m_derivedContextType; >+ >+ classSource.encode(encoder, executable.m_classSource); >+ >+ name.encode(encoder, executable.name()); >+ ecmaName.encode(encoder, executable.ecmaName()); >+ inferredName.encode(encoder, executable.inferredName()); >+ >+ parentScopeTDZVariables.encode(encoder, executable.parentScopeTDZVariables()); >+ >+ unlinkedCodeBlockForCall.encode(encoder, executable.m_unlinkedCodeBlockForCall); >+ unlinkedCodeBlockForConstruct.encode(encoder, executable.m_unlinkedCodeBlockForConstruct); >+} >+ >+ALWAYS_INLINE UnlinkedFunctionExecutable* CachedFunctionExecutable::decode(Decoder& decoder) const >+{ >+ VariableEnvironment env; >+ parentScopeTDZVariables.decode(decoder, env); >+ >+ UnlinkedFunctionExecutable* executable = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(decoder.vm().heap)) UnlinkedFunctionExecutable(decoder, env, *this); >+ executable->finishCreation(decoder.vm()); >+ >+ classSource.decode(decoder, executable->m_classSource); >+ unlinkedCodeBlockForCall.decode(decoder, executable->m_unlinkedCodeBlockForCall, executable); >+ 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.decode(decoder)) >+ , m_ecmaName(cachedExecutable.ecmaName.decode(decoder)) >+ , m_inferredName(cachedExecutable.inferredName.decode(decoder)) >+ >+ , m_parentScopeTDZVariables(decoder.vm().m_compactVariableMap->get(parentScopeTDZVariables)) >+{ >+} >+ >+template<typename CodeBlockType, typename CachedCodeBlockType> >+ALWAYS_INLINE void CachedCodeBlock<CodeBlockType, CachedCodeBlockType>::encode(Encoder& encoder, const UnlinkedCodeBlock& codeBlock) >+{ >+ thisRegister = codeBlock.m_thisRegister; >+ scopeRegister = codeBlock.m_scopeRegister; >+ globalObjectRegister = codeBlock.m_globalObjectRegister; >+ usesEval = codeBlock.m_usesEval; >+ isStrictMode = codeBlock.m_isStrictMode; >+ isConstructor = codeBlock.m_isConstructor; >+ hasCapturedVariables = codeBlock.m_hasCapturedVariables; >+ isBuiltinFunction = codeBlock.m_isBuiltinFunction; >+ superBinding = codeBlock.m_superBinding; >+ scriptMode = codeBlock.m_scriptMode; >+ isArrowFunctionContext = codeBlock.m_isArrowFunctionContext; >+ isClassContext = codeBlock.m_isClassContext; >+ wasCompiledWithDebuggingOpcodes = codeBlock.m_wasCompiledWithDebuggingOpcodes; >+ constructorKind = codeBlock.m_constructorKind; >+ derivedContextType = codeBlock.m_derivedContextType; >+ evalContextType = codeBlock.m_evalContextType; >+ hasTailCalls = codeBlock.m_hasTailCalls; >+ lineCount = codeBlock.m_lineCount; >+ endColumn = codeBlock.m_endColumn; >+ numVars = codeBlock.m_numVars; >+ numCalleeLocals = codeBlock.m_numCalleeLocals; >+ numParameters = codeBlock.m_numParameters; >+ features = codeBlock.m_features; >+ parseMode = codeBlock.m_parseMode; >+ codeType = codeBlock.m_codeType; >+ >+ for (unsigned i = LinkTimeConstantCount; i--;) >+ linkTimeConstants[i] = codeBlock.m_linkTimeConstants[i]; >+ >+ metadata.encode(encoder, codeBlock.m_metadata); >+ rareData.encode(encoder, codeBlock.m_rareData); >+ >+ sourceURLDirective.encode(encoder, codeBlock.m_sourceURLDirective.impl()); >+ sourceMappingURLDirective.encode(encoder, codeBlock.m_sourceURLDirective.impl()); >+ >+ instructions.encode(encoder, codeBlock.m_instructions.get()); >+ propertyAccessInstructions.encode(encoder, codeBlock.m_propertyAccessInstructions); >+ constantRegisters.encode(encoder, codeBlock.m_constantRegisters); >+ constantsSourceCodeRepresentation.encode(encoder, codeBlock.m_constantsSourceCodeRepresentation); >+ expressionInfo.encode(encoder, codeBlock.m_expressionInfo); >+ jumpTargets.encode(encoder, codeBlock.m_jumpTargets); >+ outOfLineJumpTargets.encode(encoder, codeBlock.m_outOfLineJumpTargets); >+ >+ constantIdentifierSets.encode(encoder, codeBlock.m_constantIdentifierSets); >+ identifiers.encode(encoder, codeBlock.m_identifiers); >+ bitVectors.encode(encoder, codeBlock.m_bitVectors); >+ functionDecls.encode(encoder, codeBlock.m_functionDecls); >+ functionExprs.encode(encoder, codeBlock.m_functionExprs); >+} >+ >+struct CachedSourceCodeKey : public CachedObject<SourceCodeKey, CachedSourceCodeKey> { >+ CachedUnlinkedSourceCode sourceCode; >+ CachedString name; >+ unsigned flags; >+ unsigned hash; >+ int functionConstructorParametersEndPosition; >+ >+ void encode(Encoder& encoder, const SourceCodeKey& key) >+ { >+ sourceCode.encode(encoder, key.m_sourceCode); >+ name.encode(encoder, key.m_name); >+ flags = key.m_flags.m_flags; >+ hash = key.hash(); >+ functionConstructorParametersEndPosition = key.m_functionConstructorParametersEndPosition; >+ } >+ >+ void decode(Decoder& decoder, SourceCodeKey& key) const >+ { >+ sourceCode.decode(decoder, key.m_sourceCode); >+ name.decode(decoder, key.m_name); >+ key.m_flags.m_flags = flags; >+ key.m_hash = hash; >+ key.m_functionConstructorParametersEndPosition = functionConstructorParametersEndPosition; >+ } >+}; >+ >+struct GenericCacheEntry { >+ CachedCodeBlockTag tag; >+ >+ std::pair<SourceCodeKey, UnlinkedCodeBlock*> decode(Decoder&) const; >+}; >+ >+template<typename UnlinkedCodeBlockType> >+struct CacheEntry : public GenericCacheEntry { >+ CachedSourceCodeKey key; >+ CachedPtr<CachedCodeBlockType<UnlinkedCodeBlockType>> codeBlock; >+ >+ void encode(Encoder& encoder, std::pair<SourceCodeKey, const UnlinkedCodeBlockType*> pair) >+ { >+ tag = CachedCodeBlockTypeImpl<UnlinkedCodeBlockType>::tag; >+ key.encode(encoder, pair.first); >+ codeBlock.encode(encoder, pair.second); >+ } >+ >+private: >+ friend GenericCacheEntry; >+ >+ std::pair<SourceCodeKey, UnlinkedCodeBlockType*> decode(Decoder& decoder) const >+ { >+ SourceCodeKey decodedKey; >+ key.decode(decoder, decodedKey); >+ return { WTFMove(decodedKey), codeBlock.decode(decoder) }; >+ } >+}; >+ >+std::pair<SourceCodeKey, UnlinkedCodeBlock*> GenericCacheEntry::decode(Decoder& decoder) const >+{ >+ switch (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(); >+ } >+} >+ >+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..e2a657810717294a94f81784a2e71c48a8ad5b2e 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 struct 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 66cec3af79f6a813d98b30678e7d4fdf86ec6126..962d87e9926dace3766f5973d096d88227e1de71 100644 >--- a/Source/JavaScriptCore/runtime/Options.cpp >+++ b/Source/JavaScriptCore/runtime/Options.cpp >@@ -517,6 +517,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 e67d9393e0c268f8917c98229c1af348ae21f361..48f6e62a7a02b941a9c31e881ca6cb1f29d224b6 100644 >--- a/Source/JavaScriptCore/runtime/Options.h >+++ b/Source/JavaScriptCore/runtime/Options.h >@@ -508,6 +508,8 @@ constexpr bool enableWebAssemblyStreamingApi = false; > v(bool, traceLLIntExecution, false, Configurable, nullptr) \ > v(bool, traceLLIntSlowPath, false, Configurable, nullptr) \ > v(bool, traceBaselineJITExecution, false, Normal, nullptr) \ >+ 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..8930454a4c23ba89869ed464f743b29b32e9029a 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 struct 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..5f50344a305cd8f077013074fde0fdd2ec33ad23 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 struct 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 02af4a016034c97a32622b51b04fc296e52bd751..7bcb42f2d7ea2e7113b9f38578e45bca78f41b8d 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..220f037bb1e01a809a1d7aeb19920ef7ab35c255 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 struct CachedSymbolTableEntry; >+ > private: > static VarOffset varOffsetFromBits(intptr_t bits) > { >@@ -436,6 +438,8 @@ struct SymbolTableIndexHashTraits : HashTraits<SymbolTableEntry> { > }; > > class SymbolTable final : public JSCell { >+ friend struct 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..41d9722e5f374049c248c5cebb82678a0534ca50 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 { >+struct 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 struct JSC::CachedBitVector; >+ > static unsigned bitsInPointer() > { > return sizeof(void*) << 3; >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 3e68f076c1e3ffc6d8e97632187f9ba97e3a8df2..4e6114809a26c32a67947757e074cf6b1ceb6e68 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,20 @@ >+2019-01-07 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: Added. >+ * Scripts/run-jsc-stress-tests: >+ > 2019-01-06 Fujii Hironori <Hironori.Fujii@sony.com> > > [Win][Clang] Fix compilation warnings of MiniBrowser >diff --git a/Tools/Scripts/jsc-stress-test-helpers/bytecode-cache-test-helper b/Tools/Scripts/jsc-stress-test-helpers/bytecode-cache-test-helper >new file mode 100644 >index 0000000000000000000000000000000000000000..c8c92921db8d4dd25027440c6cf4fd1f9faf7e88 >--- /dev/null >+++ b/Tools/Scripts/jsc-stress-test-helpers/bytecode-cache-test-helper >@@ -0,0 +1,48 @@ >+#!/usr/bin/env ruby >+ >+# 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 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. >+ >+require 'rubygems' >+require 'fileutils' >+require 'json' >+require 'shellwords' >+require 'tmpdir' >+ >+def mysys(*cmd) >+ raise "Command #{cmd.inspect} failed: #{$?.inspect}" unless system(*cmd) >+end >+ >+pathToVM = ARGV[0] >+inputFile = ARGV[1] >+extraOptions = ARGV[2..-1] >+diskCachePath = Dir.mktmpdir [inputFile, 'bytecode-cache'] >+ >+begin >+ ENV["JSC_diskCachePath"] = diskCachePath >+ mysys(pathToVM, inputFile, *extraOptions) >+ ENV["JSC_forceDiskCache"] = "true" >+ mysys(pathToVM, inputFile, *extraOptions) >+ensure >+ FileUtils.rm_rf(diskCachePath) >+end >diff --git a/Tools/Scripts/run-jsc-stress-tests b/Tools/Scripts/run-jsc-stress-tests >index 35a9eb1c55e102b52dd4557023d92d1603e0c5a1..3af4e8c58ec8fd24e55330b14e4f3f3056c2a39b 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", ["ruby", (pathToHelpers + "bytecode-cache-test-helper").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