Changeset 244143 in webkit
- Timestamp:
- Apr 10, 2019 12:18:20 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 19 edited
- 6 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/API/JSScript.mm
r242982 r244143 51 51 RetainPtr<NSURL> m_sourceURL; 52 52 RetainPtr<NSURL> m_cachePath; 53 JSC::CachedBytecodem_cachedBytecode;53 RefPtr<JSC::CachedBytecode> m_cachedBytecode; 54 54 } 55 55 … … 170 170 } 171 171 172 - (void)dealloc173 {174 if (m_cachedBytecode.size() && !m_cachedBytecode.owned())175 munmap(const_cast<void*>(m_cachedBytecode.data()), m_cachedBytecode.size());176 177 [super dealloc];178 }179 180 172 - (void)readCache 181 173 { … … 198 190 void* buffer = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0); 199 191 200 JSC::CachedBytecode cachedBytecode { buffer, size };192 Ref<JSC::CachedBytecode> cachedBytecode = JSC::CachedBytecode::create(buffer, size); 201 193 202 194 JSC::VM& vm = m_virtualMachine.vm; 203 195 JSC::SourceCode sourceCode = [self sourceCode]; 204 196 JSC::SourceCodeKey key = m_type == kJSScriptTypeProgram ? sourceCodeKeyForSerializedProgram(vm, sourceCode) : sourceCodeKeyForSerializedModule(vm, sourceCode); 205 if (isCachedBytecodeStillValid(vm, cachedBytecode , key, m_type == kJSScriptTypeProgram ? JSC::SourceCodeType::ProgramType : JSC::SourceCodeType::ModuleType))197 if (isCachedBytecodeStillValid(vm, cachedBytecode.copyRef(), key, m_type == kJSScriptTypeProgram ? JSC::SourceCodeType::ProgramType : JSC::SourceCodeType::ModuleType)) 206 198 m_cachedBytecode = WTFMove(cachedBytecode); 207 199 else … … 223 215 - (BOOL)isUsingBytecodeCache 224 216 { 225 return !!m_cachedBytecode .size();217 return !!m_cachedBytecode->size(); 226 218 } 227 219 … … 246 238 return nil; 247 239 240 self->m_cachedBytecode = JSC::CachedBytecode::create(); 241 248 242 return self; 249 243 } … … 259 253 } 260 254 261 - ( const JSC::CachedBytecode*)cachedBytecode262 { 263 return &m_cachedBytecode;255 - (RefPtr<JSC::CachedBytecode>)cachedBytecode 256 { 257 return m_cachedBytecode; 264 258 } 265 259 … … 287 281 - (BOOL)writeCache:(String&)error 288 282 { 289 if ( m_cachedBytecode.size()) {283 if (self.isUsingBytecodeCache) { 290 284 error = "Cache for JSScript is already non-empty. Can not override it."_s; 291 285 return NO; … … 318 312 319 313 if (parserError.isValid()) { 320 m_cachedBytecode = { };314 m_cachedBytecode = JSC::CachedBytecode::create(); 321 315 error = makeString("Unable to generate bytecode for this JSScript because of a parser error: ", parserError.message()); 322 316 return NO; 323 317 } 324 318 325 ssize_t bytesWritten = write(fd, m_cachedBytecode .data(), m_cachedBytecode.size());319 ssize_t bytesWritten = write(fd, m_cachedBytecode->data(), m_cachedBytecode->size()); 326 320 if (bytesWritten == -1) { 327 321 error = makeString("Could not write cache file to disk: ", strerror(errno)); … … 329 323 } 330 324 331 if (static_cast<size_t>(bytesWritten) != m_cachedBytecode .size()) {325 if (static_cast<size_t>(bytesWritten) != m_cachedBytecode->size()) { 332 326 ftruncate(fd, 0); 333 error = makeString("Could not write the full cache file to disk. Only wrote ", String::number(bytesWritten), " of the expected ", String::number(m_cachedBytecode .size()), " bytes.");327 error = makeString("Could not write the full cache file to disk. Only wrote ", String::number(bytesWritten), " of the expected ", String::number(m_cachedBytecode->size()), " bytes."); 334 328 return NO; 335 329 } -
trunk/Source/JavaScriptCore/API/JSScriptInternal.h
r242980 r244143 28 28 #import "JSScript.h" 29 29 #import "SourceCode.h" 30 #import <wtf/RefPtr.h> 30 31 31 32 #if JSC_OBJC_API_ENABLED … … 48 49 - (unsigned)hash; 49 50 - (const WTF::String&)source; 50 - ( nullable const JSC::CachedBytecode*)cachedBytecode;51 - (RefPtr<JSC::CachedBytecode>)cachedBytecode; 51 52 - (JSC::JSSourceCode*)jsSourceCode; 52 53 - (JSC::SourceCode)sourceCode; -
trunk/Source/JavaScriptCore/API/JSScriptSourceProvider.h
r240511 r244143 40 40 unsigned hash() const override; 41 41 StringView source() const override; 42 const JSC::CachedBytecode*cachedBytecode() const override;42 RefPtr<JSC::CachedBytecode> cachedBytecode() const override; 43 43 44 44 private: -
trunk/Source/JavaScriptCore/API/JSScriptSourceProvider.mm
r240511 r244143 41 41 } 42 42 43 const JSC::CachedBytecode*JSScriptSourceProvider::cachedBytecode() const43 RefPtr<JSC::CachedBytecode> JSScriptSourceProvider::cachedBytecode() const 44 44 { 45 45 return [m_script.get() cachedBytecode]; -
trunk/Source/JavaScriptCore/CMakeLists.txt
r244065 r244143 762 762 runtime/Butterfly.h 763 763 runtime/ButterflyInlines.h 764 runtime/CachePayload.h 765 runtime/CacheUpdate.h 766 runtime/CachedBytecode.h 767 runtime/CachedTypes.h 764 768 runtime/CagedBarrierPtr.h 765 769 runtime/CallData.h … … 897 901 runtime/LazyClassStructure.h 898 902 runtime/LazyProperty.h 903 runtime/LeafExecutable.h 899 904 runtime/Lookup.h 900 905 runtime/MatchResult.h -
trunk/Source/JavaScriptCore/ChangeLog
r244138 r244143 1 2019-04-10 Tadeu Zagallo <tzagallo@apple.com> 2 3 Add support for incremental bytecode cache updates 4 https://bugs.webkit.org/show_bug.cgi?id=195000 5 6 Reviewed by Filip Pizlo. 7 8 Add support for incremental updates to the bytecode cache. The cache 9 is constructed as follows: 10 - When the cache is empty, the initial payload can be added to the BytecodeCache 11 by calling BytecodeCache::addGlobalUpdate. This represents the encoded 12 top-level UnlinkedCodeBlock. 13 - Afterwards, updates can be added by calling BytecodeCache::addFunctionUpdate. 14 The update is applied by appending the encoded UnlinkedFunctionCodeBlock 15 to the existing cache and updating the CachedFunctionExecutableMetadata 16 and the offset of the new CachedFunctionCodeBlock in the owner CachedFunctionExecutable. 17 18 * API/JSScript.mm: 19 (-[JSScript readCache]): 20 (-[JSScript isUsingBytecodeCache]): 21 (-[JSScript init]): 22 (-[JSScript cachedBytecode]): 23 (-[JSScript writeCache:]): 24 * API/JSScriptInternal.h: 25 * API/JSScriptSourceProvider.h: 26 * API/JSScriptSourceProvider.mm: 27 (JSScriptSourceProvider::cachedBytecode const): 28 * CMakeLists.txt: 29 * JavaScriptCore.xcodeproj/project.pbxproj: 30 * Sources.txt: 31 * bytecode/UnlinkedFunctionExecutable.cpp: 32 (JSC::generateUnlinkedFunctionCodeBlock): 33 * jsc.cpp: 34 (ShellSourceProvider::~ShellSourceProvider): 35 (ShellSourceProvider::cachePath const): 36 (ShellSourceProvider::loadBytecode const): 37 (ShellSourceProvider::ShellSourceProvider): 38 (ShellSourceProvider::cacheEnabled): 39 * parser/SourceProvider.h: 40 (JSC::SourceProvider::cachedBytecode const): 41 (JSC::SourceProvider::updateCache const): 42 (JSC::SourceProvider::commitCachedBytecode const): 43 * runtime/CachePayload.cpp: Copied from Source/JavaScriptCore/API/JSScriptInternal.h. 44 (JSC::CachePayload::makeMappedPayload): 45 (JSC::CachePayload::makeMallocPayload): 46 (JSC::CachePayload::makeEmptyPayload): 47 (JSC::CachePayload::CachePayload): 48 (JSC::CachePayload::~CachePayload): 49 (JSC::CachePayload::operator=): 50 (JSC::CachePayload::freeData): 51 * runtime/CachePayload.h: Copied from Source/JavaScriptCore/API/JSScriptInternal.h. 52 (JSC::CachePayload::data const): 53 (JSC::CachePayload::size const): 54 (JSC::CachePayload::CachePayload): 55 * runtime/CacheUpdate.cpp: Copied from Source/JavaScriptCore/API/JSScriptInternal.h. 56 (JSC::CacheUpdate::CacheUpdate): 57 (JSC::CacheUpdate::operator=): 58 (JSC::CacheUpdate::isGlobal const): 59 (JSC::CacheUpdate::asGlobal const): 60 (JSC::CacheUpdate::asFunction const): 61 * runtime/CacheUpdate.h: Copied from Source/JavaScriptCore/API/JSScriptInternal.h. 62 * runtime/CachedBytecode.cpp: Added. 63 (JSC::CachedBytecode::addGlobalUpdate): 64 (JSC::CachedBytecode::addFunctionUpdate): 65 (JSC::CachedBytecode::copyLeafExecutables): 66 (JSC::CachedBytecode::commitUpdates const): 67 * runtime/CachedBytecode.h: Added. 68 (JSC::CachedBytecode::create): 69 (JSC::CachedBytecode::leafExecutables): 70 (JSC::CachedBytecode::data const): 71 (JSC::CachedBytecode::size const): 72 (JSC::CachedBytecode::hasUpdates const): 73 (JSC::CachedBytecode::sizeForUpdate const): 74 (JSC::CachedBytecode::CachedBytecode): 75 * runtime/CachedTypes.cpp: 76 (JSC::Encoder::addLeafExecutable): 77 (JSC::Encoder::release): 78 (JSC::Decoder::Decoder): 79 (JSC::Decoder::create): 80 (JSC::Decoder::size const): 81 (JSC::Decoder::offsetOf): 82 (JSC::Decoder::ptrForOffsetFromBase): 83 (JSC::Decoder::addLeafExecutable): 84 (JSC::VariableLengthObject::VariableLengthObject): 85 (JSC::VariableLengthObject::buffer const): 86 (JSC::CachedPtrOffsets::offsetOffset): 87 (JSC::CachedWriteBarrierOffsets::ptrOffset): 88 (JSC::CachedFunctionExecutable::features const): 89 (JSC::CachedFunctionExecutable::hasCapturedVariables const): 90 (JSC::CachedFunctionExecutableOffsets::codeBlockForCallOffset): 91 (JSC::CachedFunctionExecutableOffsets::codeBlockForConstructOffset): 92 (JSC::CachedFunctionExecutableOffsets::metadataOffset): 93 (JSC::CachedFunctionExecutable::encode): 94 (JSC::CachedFunctionExecutable::decode const): 95 (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): 96 (JSC::encodeCodeBlock): 97 (JSC::encodeFunctionCodeBlock): 98 (JSC::decodeCodeBlockImpl): 99 (JSC::isCachedBytecodeStillValid): 100 * runtime/CachedTypes.h: 101 (JSC::VariableLengthObjectBase::VariableLengthObjectBase): 102 (JSC::decodeCodeBlock): 103 * runtime/CodeCache.cpp: 104 (JSC::CodeCache::getUnlinkedGlobalCodeBlock): 105 (JSC::CodeCache::updateCache): 106 (JSC::CodeCache::write): 107 (JSC::writeCodeBlock): 108 (JSC::serializeBytecode): 109 * runtime/CodeCache.h: 110 (JSC::SourceCodeValue::SourceCodeValue): 111 (JSC::CodeCacheMap::findCacheAndUpdateAge): 112 (JSC::CodeCacheMap::fetchFromDiskImpl): 113 * runtime/Completion.cpp: 114 (JSC::generateProgramBytecode): 115 (JSC::generateModuleBytecode): 116 * runtime/Completion.h: 117 * runtime/LeafExecutable.cpp: Copied from Source/JavaScriptCore/API/JSScriptSourceProvider.mm. 118 (JSC::LeafExecutable::operator+ const): 119 * runtime/LeafExecutable.h: Copied from Source/JavaScriptCore/API/JSScriptSourceProvider.mm. 120 (JSC::LeafExecutable::LeafExecutable): 121 (JSC::LeafExecutable::base const): 122 1 123 2019-04-10 Michael Catanzaro <mcatanzaro@igalia.com> 2 124 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r243925 r244143 751 751 0FFFC95E14EF90B700C72532 /* DFGPredictionPropagationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFFC95214EF909500C72532 /* DFGPredictionPropagationPhase.h */; }; 752 752 0FFFC96014EF90BD00C72532 /* DFGVirtualRegisterAllocationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFFC95414EF909500C72532 /* DFGVirtualRegisterAllocationPhase.h */; }; 753 1409ECBF225E177400BEDD54 /* LeafExecutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 148B1417225DD1D700D6E998 /* LeafExecutable.h */; settings = {ATTRIBUTES = (Private, ); }; }; 754 1409ECC0225E178100BEDD54 /* CacheUpdate.h in Headers */ = {isa = PBXBuildFile; fileRef = 148B1418225DD1D700D6E998 /* CacheUpdate.h */; settings = {ATTRIBUTES = (Private, ); }; }; 755 1409ECC1225E178C00BEDD54 /* CachePayload.h in Headers */ = {isa = PBXBuildFile; fileRef = 148B1416225DD1D700D6E998 /* CachePayload.h */; settings = {ATTRIBUTES = (Private, ); }; }; 753 756 140D17D70E8AD4A9000CD17D /* JSBasePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 140D17D60E8AD4A9000CD17D /* JSBasePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; 754 757 141211310A48794D00480255 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 932F5BD90822A1C700736975 /* JavaScriptCore.framework */; }; … … 784 787 1442566215EDE98D0066A49B /* JSWithScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 1442566015EDE98D0066A49B /* JSWithScope.h */; settings = {ATTRIBUTES = (Private, ); }; }; 785 788 144836E7132DA7BE005BE785 /* ConservativeRoots.h in Headers */ = {isa = PBXBuildFile; fileRef = 149DAAF212EB559D0083B12B /* ConservativeRoots.h */; settings = {ATTRIBUTES = (Private, ); }; }; 789 144CA3502224180100817789 /* CachedBytecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 144CA34F221F037900817789 /* CachedBytecode.h */; settings = {ATTRIBUTES = (Private, ); }; }; 786 790 145722861437E140005FDE26 /* StrongInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 145722851437E140005FDE26 /* StrongInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; 787 791 146C384B2177ACDF0079F6D9 /* UnlinkedMetadataTable.h in Headers */ = {isa = PBXBuildFile; fileRef = 142D52BE21762958002DB086 /* UnlinkedMetadataTable.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 832 836 14E84FA114EE1ACC00D6D5D4 /* WeakSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 14E84F9C14EE1ACC00D6D5D4 /* WeakSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; 833 837 14E84FA214EE1ACC00D6D5D4 /* WeakImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 14E84F9D14EE1ACC00D6D5D4 /* WeakImpl.h */; settings = {ATTRIBUTES = (Private, ); }; }; 838 14F09C2A2231923100CF88EB /* CachedTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 143BE26521C857770020CD17 /* CachedTypes.h */; settings = {ATTRIBUTES = (Private, ); }; }; 834 839 14F7256614EE265E00B1652B /* WeakHandleOwner.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F7256414EE265E00B1652B /* WeakHandleOwner.h */; settings = {ATTRIBUTES = (Private, ); }; }; 835 840 14F79F70216EAFD200046D39 /* Opcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 969A07950ED1D3AE00F1F681 /* Opcode.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 3189 3194 1442565F15EDE98D0066A49B /* JSWithScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWithScope.cpp; sourceTree = "<group>"; }; 3190 3195 1442566015EDE98D0066A49B /* JSWithScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWithScope.h; sourceTree = "<group>"; }; 3196 144CA34F221F037900817789 /* CachedBytecode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedBytecode.h; sourceTree = "<group>"; }; 3191 3197 145722851437E140005FDE26 /* StrongInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StrongInlines.h; sourceTree = "<group>"; }; 3192 3198 145C507F0D9DF63B0088F6B9 /* CallData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallData.h; sourceTree = "<group>"; }; … … 3228 3234 148A7BED1B82975A002D9157 /* InlineCallFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InlineCallFrame.cpp; sourceTree = "<group>"; }; 3229 3235 148A7BEE1B82975A002D9157 /* InlineCallFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineCallFrame.h; sourceTree = "<group>"; }; 3236 148B1416225DD1D700D6E998 /* CachePayload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachePayload.h; sourceTree = "<group>"; }; 3237 148B1417225DD1D700D6E998 /* LeafExecutable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LeafExecutable.h; sourceTree = "<group>"; }; 3238 148B1418225DD1D700D6E998 /* CacheUpdate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CacheUpdate.h; sourceTree = "<group>"; }; 3239 148B1419225DD1E900D6E998 /* CachedBytecode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CachedBytecode.cpp; sourceTree = "<group>"; }; 3240 148B141A225DD1E900D6E998 /* CacheUpdate.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CacheUpdate.cpp; sourceTree = "<group>"; }; 3241 148B141B225DD1EA00D6E998 /* CachePayload.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CachePayload.cpp; sourceTree = "<group>"; }; 3242 148B141C225DD1EA00D6E998 /* LeafExecutable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LeafExecutable.cpp; sourceTree = "<group>"; }; 3230 3243 148CD1D7108CF902008163C6 /* JSContextRefPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSContextRefPrivate.h; sourceTree = "<group>"; }; 3231 3244 149559ED0DDCDDF700648087 /* DebuggerCallFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DebuggerCallFrame.cpp; sourceTree = "<group>"; }; … … 6711 6724 0FB7F38B15ED8E3800F167B2 /* Butterfly.h */, 6712 6725 0FB7F38C15ED8E3800F167B2 /* ButterflyInlines.h */, 6726 148B1419225DD1E900D6E998 /* CachedBytecode.cpp */, 6727 144CA34F221F037900817789 /* CachedBytecode.h */, 6713 6728 14DAFA4521E3B871004B68F7 /* CachedTypes.cpp */, 6714 6729 143BE26521C857770020CD17 /* CachedTypes.h */, 6730 148B141B225DD1EA00D6E998 /* CachePayload.cpp */, 6731 148B1416225DD1D700D6E998 /* CachePayload.h */, 6732 148B141A225DD1E900D6E998 /* CacheUpdate.cpp */, 6733 148B1418225DD1D700D6E998 /* CacheUpdate.h */, 6715 6734 0FEC3C5F1F379F5300F59B6C /* CagedBarrierPtr.h */, 6716 6735 BCA62DFE0E2826230004F30D /* CallData.cpp */, … … 7081 7100 DCF3D5671CD29468003D5C65 /* LazyProperty.h */, 7082 7101 DCF3D5681CD29468003D5C65 /* LazyPropertyInlines.h */, 7102 148B141C225DD1EA00D6E998 /* LeafExecutable.cpp */, 7103 148B1417225DD1D700D6E998 /* LeafExecutable.h */, 7083 7104 A7E2EA6A0FB460CF00601F06 /* LiteralParser.cpp */, 7084 7105 A7E2EA690FB460CF00601F06 /* LiteralParser.h */, … … 8729 8750 0F885E111849A3BE00F1E3FA /* BytecodeUseDef.h in Headers */, 8730 8751 0F8023EA1613832B00A0BA45 /* ByValInfo.h in Headers */, 8752 144CA3502224180100817789 /* CachedBytecode.h in Headers */, 8731 8753 65B8392E1BACAD360044E824 /* CachedRecovery.h in Headers */, 8754 14F09C2A2231923100CF88EB /* CachedTypes.h in Headers */, 8755 1409ECC1225E178C00BEDD54 /* CachePayload.h in Headers */, 8756 1409ECC0225E178100BEDD54 /* CacheUpdate.h in Headers */, 8732 8757 0FEC3C601F379F5300F59B6C /* CagedBarrierPtr.h in Headers */, 8733 8758 BC18C3ED0E16F5CD00B34460 /* CallData.h in Headers */, … … 9514 9539 DCF3D56D1CD29476003D5C65 /* LazyPropertyInlines.h in Headers */, 9515 9540 99DA00B01BD5994E00F4575C /* lazywriter.py in Headers */, 9541 1409ECBF225E177400BEDD54 /* LeafExecutable.h in Headers */, 9516 9542 BC18C4310E16F5CD00B34460 /* Lexer.h in Headers */, 9517 9543 BC18C52E0E16FCE100B34460 /* Lexer.lut.h in Headers */, -
trunk/Source/JavaScriptCore/Sources.txt
r243925 r244143 718 718 runtime/BooleanPrototype.cpp 719 719 runtime/CallData.cpp 720 runtime/CachePayload.cpp 721 runtime/CacheUpdate.cpp 722 runtime/CachedBytecode.cpp 720 723 runtime/CachedTypes.cpp 721 724 runtime/CatchScope.cpp … … 873 876 runtime/JSWrapperObject.cpp 874 877 runtime/LazyClassStructure.cpp 878 runtime/LeafExecutable.cpp 875 879 runtime/LiteralParser.cpp 876 880 runtime/Lookup.cpp -
trunk/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp
r243875 r244143 78 78 if (error.isValid()) 79 79 return nullptr; 80 vm.codeCache()->updateCache(executable, source, kind, result); 80 81 return result; 81 82 } -
trunk/Source/JavaScriptCore/jsc.cpp
r243869 r244143 968 968 ~ShellSourceProvider() 969 969 { 970 commitCachedBytecode(); 971 } 972 973 RefPtr<CachedBytecode> cachedBytecode() const override 974 { 975 if (!m_cachedBytecode->size()) 976 loadBytecode(); 977 return m_cachedBytecode.copyRef(); 978 } 979 980 void updateCache(const UnlinkedFunctionExecutable* executable, const SourceCode&, CodeSpecializationKind kind, const UnlinkedFunctionCodeBlock* codeBlock) const override 981 { 982 if (!cacheEnabled()) 983 return; 984 Ref<CachedBytecode> cachedBytecode = encodeFunctionCodeBlock(*executable->vm(), codeBlock); 985 m_cachedBytecode->addFunctionUpdate(executable, kind, WTFMove(cachedBytecode)); 986 } 987 988 void cacheBytecode(const BytecodeCacheGenerator& generator) const override 989 { 990 if (!cacheEnabled()) 991 return; 992 m_cachedBytecode->addGlobalUpdate(generator()); 993 } 994 995 void commitCachedBytecode() const override 996 { 970 997 #if OS(DARWIN) 971 if (m_cachedBytecode.size()) 972 munmap(const_cast<void*>(m_cachedBytecode.data()), m_cachedBytecode.size()); 973 #endif 974 } 975 976 const CachedBytecode* cachedBytecode() const override 977 { 978 return &m_cachedBytecode; 979 } 980 981 void cacheBytecode(const BytecodeCacheGenerator& generator) const override 982 { 983 #if OS(DARWIN) 998 if (!cacheEnabled() || !m_cachedBytecode->hasUpdates()) 999 return; 1000 1001 auto clearBytecode = makeScopeExit([&] { 1002 m_cachedBytecode = CachedBytecode::create(); 1003 }); 1004 984 1005 String filename = cachePath(); 985 if (filename.isNull())986 return;987 1006 int fd = open(filename.utf8().data(), O_CREAT | O_WRONLY | O_TRUNC | O_EXLOCK | O_NONBLOCK, 0666); 988 1007 if (fd == -1) 989 1008 return; 990 CachedBytecode cachedBytecode = generator(); 991 write(fd, cachedBytecode.data(), cachedBytecode.size()); 992 close(fd); 993 #else 994 UNUSED_PARAM(generator); 1009 1010 auto closeFD = makeScopeExit([&] { 1011 close(fd); 1012 }); 1013 1014 struct stat sb; 1015 int res = fstat(fd, &sb); 1016 size_t size = static_cast<size_t>(sb.st_size); 1017 if (res || size != m_cachedBytecode->size()) { 1018 // The bytecode cache has already been updated 1019 return; 1020 } 1021 1022 if (ftruncate(fd, m_cachedBytecode->sizeForUpdate())) 1023 return; 1024 1025 m_cachedBytecode->commitUpdates([&] (off_t offset, const void* data, size_t size) { 1026 int result = lseek(fd, offset, SEEK_SET); 1027 ASSERT_UNUSED(result, result != -1); 1028 size_t bytesWritten = static_cast<size_t>(write(fd, data, size)); 1029 ASSERT_UNUSED(bytesWritten, bytesWritten == size); 1030 }); 995 1031 #endif 996 1032 } … … 999 1035 String cachePath() const 1000 1036 { 1037 if (!cacheEnabled()) 1038 return static_cast<const char*>(nullptr); 1001 1039 const char* cachePath = Options::diskCachePath(); 1002 if (!cachePath)1003 return static_cast<const char*>(nullptr);1004 1040 String filename = sourceOrigin().string(); 1005 1041 filename.replace('/', '_'); … … 1007 1043 } 1008 1044 1009 void loadBytecode() 1045 void loadBytecode() const 1010 1046 { 1011 1047 #if OS(DARWIN) 1048 if (!cacheEnabled()) 1049 return; 1050 1012 1051 String filename = cachePath(); 1013 1052 if (filename.isNull()) … … 1031 1070 if (buffer == MAP_FAILED) 1032 1071 return; 1033 m_cachedBytecode = CachedBytecode { buffer, size };1072 m_cachedBytecode = CachedBytecode::create(buffer, size); 1034 1073 #endif 1035 1074 } … … 1037 1076 ShellSourceProvider(const String& source, const SourceOrigin& sourceOrigin, URL&& url, const TextPosition& startPosition, SourceProviderSourceType sourceType) 1038 1077 : StringSourceProvider(source, sourceOrigin, WTFMove(url), startPosition, sourceType) 1078 , m_cachedBytecode(CachedBytecode::create()) 1039 1079 { 1040 1080 loadBytecode(); 1041 1081 } 1042 1082 1043 CachedBytecode m_cachedBytecode; 1083 static bool cacheEnabled() 1084 { 1085 static bool enabled = !!Options::diskCachePath(); 1086 return enabled; 1087 } 1088 1089 mutable Ref<CachedBytecode> m_cachedBytecode; 1044 1090 }; 1045 1091 -
trunk/Source/JavaScriptCore/parser/SourceProvider.h
r241758 r244143 29 29 #pragma once 30 30 31 #include "CachedBytecode.h" 32 #include "CodeSpecializationKind.h" 31 33 #include "SourceOrigin.h" 32 34 #include <wtf/RefCounted.h> … … 37 39 namespace JSC { 38 40 41 class SourceCode; 42 class UnlinkedFunctionExecutable; 43 class UnlinkedFunctionCodeBlock; 44 39 45 enum class SourceProviderSourceType : uint8_t { 40 46 Program, … … 43 49 }; 44 50 45 class CachedBytecode { 46 WTF_MAKE_NONCOPYABLE(CachedBytecode); 47 48 public: 49 CachedBytecode() 50 : CachedBytecode(nullptr, 0) 51 { 52 } 53 54 CachedBytecode(const void* data, size_t size) 55 : m_owned(false) 56 , m_size(size) 57 , m_data(data) 58 { 59 } 60 61 CachedBytecode(MallocPtr<uint8_t>&& data, size_t size) 62 : m_owned(true) 63 , m_size(size) 64 , m_data(data.leakPtr()) 65 { 66 } 67 68 CachedBytecode(CachedBytecode&& other) 69 { 70 m_owned = other.m_owned; 71 m_size = other.m_size; 72 m_data = other.m_data; 73 other.m_owned = false; 74 } 75 76 CachedBytecode& operator=(CachedBytecode&& other) 77 { 78 freeDataIfOwned(); 79 m_owned = other.m_owned; 80 m_size = other.m_size; 81 m_data = other.m_data; 82 other.m_owned = false; 83 return *this; 84 } 85 86 const void* data() const { return m_data; } 87 size_t size() const { return m_size; } 88 bool owned() const { return m_owned; } 89 90 ~CachedBytecode() 91 { 92 freeDataIfOwned(); 93 } 94 95 private: 96 void freeDataIfOwned() 97 { 98 if (m_data && m_owned) 99 fastFree(const_cast<void*>(m_data)); 100 } 101 102 bool m_owned; 103 size_t m_size; 104 const void* m_data; 105 }; 106 107 using BytecodeCacheGenerator = Function<CachedBytecode()>; 51 using BytecodeCacheGenerator = Function<Ref<CachedBytecode>()>; 108 52 109 53 class SourceProvider : public RefCounted<SourceProvider> { … … 117 61 virtual unsigned hash() const = 0; 118 62 virtual StringView source() const = 0; 119 virtual const CachedBytecode*cachedBytecode() const { return nullptr; }63 virtual RefPtr<CachedBytecode> cachedBytecode() const { return nullptr; } 120 64 virtual void cacheBytecode(const BytecodeCacheGenerator&) const { } 65 virtual void updateCache(const UnlinkedFunctionExecutable*, const SourceCode&, CodeSpecializationKind, const UnlinkedFunctionCodeBlock*) const { } 66 virtual void commitCachedBytecode() const { } 121 67 122 68 StringView getRange(int start, int end) const -
trunk/Source/JavaScriptCore/runtime/CachePayload.cpp
r244142 r244143 24 24 */ 25 25 26 #pragma once 26 #include "config.h" 27 #include "CachePayload.h" 27 28 28 #import "JSScript.h" 29 #import "SourceCode.h" 30 31 #if JSC_OBJC_API_ENABLED 32 33 NS_ASSUME_NONNULL_BEGIN 29 #if !OS(WINDOWS) 30 #include <sys/mman.h> 31 #endif 34 32 35 33 namespace JSC { 36 class CachedBytecode;37 class Identifier;38 class JSSourceCode;39 };40 34 41 namespace WTF { 42 class String; 43 }; 35 #if !OS(WINDOWS) 36 CachePayload CachePayload::makeMappedPayload(void* data, size_t size) 37 { 38 return CachePayload(true, data, size); 39 } 40 #endif 44 41 45 @interface JSScript(Internal) 42 CachePayload CachePayload::makeMallocPayload(MallocPtr<uint8_t>&& data, size_t size) 43 { 44 return CachePayload(false, data.leakPtr(), size); 45 } 46 46 47 - (instancetype)init; 48 - (unsigned)hash; 49 - (const WTF::String&)source; 50 - (nullable const JSC::CachedBytecode*)cachedBytecode; 51 - (JSC::JSSourceCode*)jsSourceCode; 52 - (JSC::SourceCode)sourceCode; 53 - (BOOL)writeCache:(String&)error; 54 // FIXME: Remove this once we require sourceURL upon creation: https://bugs.webkit.org/show_bug.cgi?id=194909 55 - (void)setSourceURL:(NSURL *)url; 47 CachePayload CachePayload::makeEmptyPayload() 48 { 49 return CachePayload(true, nullptr, 0); 50 } 56 51 57 @end 52 CachePayload::CachePayload(CachePayload&& other) 53 { 54 m_mapped = other.m_mapped; 55 m_size = other.m_size; 56 m_data = other.m_data; 57 other.m_mapped = false; 58 other.m_data = nullptr; 59 other.m_size = 0; 60 } 58 61 59 NS_ASSUME_NONNULL_END 62 CachePayload::~CachePayload() 63 { 64 freeData(); 65 } 60 66 61 #endif // JSC_OBJC_API_ENABLED 67 CachePayload& CachePayload::operator=(CachePayload&& other) 68 { 69 ASSERT(&other != this); 70 freeData(); 71 return *new (this) CachePayload(WTFMove(other)); 72 } 73 74 void CachePayload::freeData() 75 { 76 if (!m_data) 77 return; 78 if (m_mapped) { 79 #if !OS(WINDOWS) 80 munmap(m_data, m_size); 81 #else 82 RELEASE_ASSERT_NOT_REACHED(); 83 #endif 84 } else 85 fastFree(m_data); 86 } 87 88 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/CachePayload.h
r244142 r244143 26 26 #pragma once 27 27 28 #import "JSScript.h" 29 #import "SourceCode.h" 30 31 #if JSC_OBJC_API_ENABLED 32 33 NS_ASSUME_NONNULL_BEGIN 28 #include <wtf/MallocPtr.h> 34 29 35 30 namespace JSC { 36 class CachedBytecode; 37 class Identifier; 38 class JSSourceCode; 31 32 class CachePayload { 33 public: 34 #if !OS(WINDOWS) 35 JS_EXPORT_PRIVATE static CachePayload makeMappedPayload(void*, size_t); 36 #endif 37 JS_EXPORT_PRIVATE static CachePayload makeMallocPayload(MallocPtr<uint8_t>&&, size_t); 38 JS_EXPORT_PRIVATE static CachePayload makeEmptyPayload(); 39 40 JS_EXPORT_PRIVATE CachePayload(CachePayload&&); 41 JS_EXPORT_PRIVATE ~CachePayload(); 42 JS_EXPORT_PRIVATE CachePayload& operator=(CachePayload&& other); 43 44 const uint8_t* data() const { return m_data; } 45 size_t size() const { return m_size; } 46 47 private: 48 CachePayload(bool mapped, void* data, size_t size) 49 : m_mapped(mapped) 50 , m_size(size) 51 , m_data(static_cast<uint8_t*>(data)) 52 { 53 } 54 55 void freeData(); 56 57 bool m_mapped; 58 size_t m_size; 59 uint8_t* m_data; 39 60 }; 40 61 41 namespace WTF { 42 class String; 43 }; 44 45 @interface JSScript(Internal) 46 47 - (instancetype)init; 48 - (unsigned)hash; 49 - (const WTF::String&)source; 50 - (nullable const JSC::CachedBytecode*)cachedBytecode; 51 - (JSC::JSSourceCode*)jsSourceCode; 52 - (JSC::SourceCode)sourceCode; 53 - (BOOL)writeCache:(String&)error; 54 // FIXME: Remove this once we require sourceURL upon creation: https://bugs.webkit.org/show_bug.cgi?id=194909 55 - (void)setSourceURL:(NSURL *)url; 56 57 @end 58 59 NS_ASSUME_NONNULL_END 60 61 #endif // JSC_OBJC_API_ENABLED 62 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/CacheUpdate.cpp
r244142 r244143 24 24 */ 25 25 26 #pragma once 27 28 #import "JSScript.h" 29 #import "SourceCode.h" 30 31 #if JSC_OBJC_API_ENABLED 32 33 NS_ASSUME_NONNULL_BEGIN 26 #include "config.h" 27 #include "CacheUpdate.h" 34 28 35 29 namespace JSC { 36 class CachedBytecode;37 class Identifier;38 class JSSourceCode;39 };40 30 41 namespace WTF { 42 class String; 43 }; 31 CacheUpdate::CacheUpdate(GlobalUpdate&& update) 32 : m_update(WTFMove(update)) 33 { 34 } 44 35 45 @interface JSScript(Internal) 36 CacheUpdate::CacheUpdate(FunctionUpdate&& update) 37 : m_update(WTFMove(update)) 38 { 39 } 46 40 47 - (instancetype)init; 48 - (unsigned)hash; 49 - (const WTF::String&)source; 50 - (nullable const JSC::CachedBytecode*)cachedBytecode; 51 - (JSC::JSSourceCode*)jsSourceCode; 52 - (JSC::SourceCode)sourceCode; 53 - (BOOL)writeCache:(String&)error; 54 // FIXME: Remove this once we require sourceURL upon creation: https://bugs.webkit.org/show_bug.cgi?id=194909 55 - (void)setSourceURL:(NSURL *)url; 41 CacheUpdate::CacheUpdate(CacheUpdate&& other) 42 { 43 if (WTF::holds_alternative<GlobalUpdate>(other.m_update)) 44 new (this) CacheUpdate(WTFMove(WTF::get<GlobalUpdate>(other.m_update))); 45 else 46 new (this) CacheUpdate(WTFMove(WTF::get<FunctionUpdate>(other.m_update))); 47 } 56 48 57 @end 49 CacheUpdate& CacheUpdate::operator=(CacheUpdate&& other) 50 { 51 this->~CacheUpdate(); 52 return *new (this) CacheUpdate(WTFMove(other)); 53 } 58 54 59 NS_ASSUME_NONNULL_END 55 bool CacheUpdate::isGlobal() const 56 { 57 return WTF::holds_alternative<GlobalUpdate>(m_update); 58 } 60 59 61 #endif // JSC_OBJC_API_ENABLED 60 const CacheUpdate::GlobalUpdate& CacheUpdate::asGlobal() const 61 { 62 ASSERT(isGlobal()); 63 return WTF::get<GlobalUpdate>(m_update); 64 } 65 66 const CacheUpdate::FunctionUpdate& CacheUpdate::asFunction() const 67 { 68 ASSERT(!isGlobal()); 69 return WTF::get<FunctionUpdate>(m_update); 70 } 71 72 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/CacheUpdate.h
r244142 r244143 26 26 #pragma once 27 27 28 #import "JSScript.h" 29 #import "SourceCode.h" 30 31 #if JSC_OBJC_API_ENABLED 32 33 NS_ASSUME_NONNULL_BEGIN 28 #include "CachePayload.h" 29 #include "CachedTypes.h" 30 #include "CodeSpecializationKind.h" 31 #include <wtf/Variant.h> 34 32 35 33 namespace JSC { 36 class CachedBytecode; 37 class Identifier; 38 class JSSourceCode; 34 35 class CacheUpdate { 36 public: 37 struct GlobalUpdate { 38 CachePayload m_payload; 39 }; 40 41 struct FunctionUpdate { 42 ptrdiff_t m_base; 43 CodeSpecializationKind m_kind; 44 CachedFunctionExecutableMetadata m_metadata; 45 CachePayload m_payload; 46 }; 47 48 49 CacheUpdate(GlobalUpdate&&); 50 CacheUpdate(FunctionUpdate&&); 51 52 CacheUpdate(CacheUpdate&&); 53 CacheUpdate& operator=(CacheUpdate&&); 54 55 bool isGlobal() const; 56 const GlobalUpdate& asGlobal() const; 57 const FunctionUpdate& asFunction() const; 58 59 private: 60 Variant<GlobalUpdate, FunctionUpdate> m_update; 39 61 }; 40 62 41 namespace WTF { 42 class String; 43 }; 44 45 @interface JSScript(Internal) 46 47 - (instancetype)init; 48 - (unsigned)hash; 49 - (const WTF::String&)source; 50 - (nullable const JSC::CachedBytecode*)cachedBytecode; 51 - (JSC::JSSourceCode*)jsSourceCode; 52 - (JSC::SourceCode)sourceCode; 53 - (BOOL)writeCache:(String&)error; 54 // FIXME: Remove this once we require sourceURL upon creation: https://bugs.webkit.org/show_bug.cgi?id=194909 55 - (void)setSourceURL:(NSURL *)url; 56 57 @end 58 59 NS_ASSUME_NONNULL_END 60 61 #endif // JSC_OBJC_API_ENABLED 63 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/CachedTypes.cpp
r244088 r244143 140 140 } 141 141 142 std::pair<MallocPtr<uint8_t>, size_t> release() 142 void addLeafExecutable(const UnlinkedFunctionExecutable* executable, ptrdiff_t offset) 143 { 144 m_leafExecutables.add(executable, offset); 145 } 146 147 Ref<CachedBytecode> release() 143 148 { 144 149 size_t size = m_baseOffset + m_currentPage->size(); … … 150 155 } 151 156 RELEASE_ASSERT(offset == size); 152 return { WTFMove(buffer), size };157 return CachedBytecode::create(WTFMove(buffer), size, WTFMove(m_leafExecutables)); 153 158 } 154 159 … … 213 218 Vector<Page> m_pages; 214 219 HashMap<const void*, ptrdiff_t> m_ptrToOffsetMap; 215 }; 216 217 Decoder::Decoder(VM& vm, const void* baseAddress, size_t size) 220 LeafExecutableMap m_leafExecutables; 221 }; 222 223 Decoder::Decoder(VM& vm, Ref<CachedBytecode> cachedBytecode) 218 224 : m_vm(vm) 219 , m_baseAddress(reinterpret_cast<const uint8_t*>(baseAddress)) 220 #ifndef NDEBUG 221 , m_size(size) 222 #endif 223 { 224 UNUSED_PARAM(size); 225 , m_cachedBytecode(WTFMove(cachedBytecode)) 226 { 225 227 } 226 228 … … 231 233 } 232 234 233 Ref<Decoder> Decoder::create(VM& vm, const void* baseAddress, size_t size) 234 { 235 return adoptRef(*new Decoder(vm, baseAddress, size)); 235 Ref<Decoder> Decoder::create(VM& vm, Ref<CachedBytecode> cachedBytecode) 236 { 237 return adoptRef(*new Decoder(vm, WTFMove(cachedBytecode))); 238 } 239 240 size_t Decoder::size() const 241 { 242 return m_cachedBytecode->size(); 236 243 } 237 244 … … 239 246 { 240 247 const uint8_t* addr = static_cast<const uint8_t*>(ptr); 241 ASSERT(addr >= m_ baseAddress && addr < m_baseAddress + m_size);242 return addr - m_ baseAddress;248 ASSERT(addr >= m_cachedBytecode->data() && addr < m_cachedBytecode->data() + m_cachedBytecode->size()); 249 return addr - m_cachedBytecode->data(); 243 250 } 244 251 … … 259 266 { 260 267 #ifndef NDEBUG 261 ASSERT(offset > 0 && static_cast<size_t>(offset) < m_ size);268 ASSERT(offset > 0 && static_cast<size_t>(offset) < m_cachedBytecode->size()); 262 269 #endif 263 return m_ baseAddress+ offset;270 return m_cachedBytecode->data() + offset; 264 271 } 265 272 … … 275 282 auto addResult = m_environmentToHandleMap.add(environment, handle); 276 283 ASSERT_UNUSED(addResult, addResult.isNewEntry); 284 } 285 286 void Decoder::addLeafExecutable(const UnlinkedFunctionExecutable* executable, ptrdiff_t offset) 287 { 288 m_cachedBytecode->leafExecutables().add(executable, offset); 277 289 } 278 290 … … 340 352 341 353 template<typename Source> 342 class VariableLengthObject : public CachedObject<Source> {354 class VariableLengthObject : public CachedObject<Source>, VariableLengthObjectBase { 343 355 template<typename, typename> 344 friend struct CachedPtr; 345 346 public: 356 friend class CachedPtr; 357 friend struct CachedPtrOffsets; 358 359 public: 360 VariableLengthObject() 361 : VariableLengthObjectBase(s_invalidOffset) 362 { 363 } 364 347 365 bool isEmpty() const 348 366 { … … 353 371 const uint8_t* buffer() const 354 372 { 355 ASSERT( m_offset != s_invalidOffset);373 ASSERT(!isEmpty()); 356 374 return bitwise_cast<const uint8_t*>(this) + m_offset; 357 375 } … … 380 398 private: 381 399 constexpr static ptrdiff_t s_invalidOffset = std::numeric_limits<ptrdiff_t>::max(); 382 383 ptrdiff_t m_offset { s_invalidOffset };384 385 400 }; 386 401 … … 388 403 class CachedPtr : public VariableLengthObject<Source*> { 389 404 template<typename, typename> 390 friend struct CachedRefPtr; 405 friend class CachedRefPtr; 406 407 friend struct CachedPtrOffsets; 391 408 392 409 public: … … 443 460 } 444 461 }; 462 463 ptrdiff_t CachedPtrOffsets::offsetOffset() 464 { 465 return OBJECT_OFFSETOF(CachedPtr<void>, m_offset); 466 } 445 467 446 468 template<typename T, typename Source = SourceType<T>> … … 483 505 template<typename T, typename Source = SourceType<T>> 484 506 class CachedWriteBarrier : public CachedObject<WriteBarrier<Source>> { 507 friend struct CachedWriteBarrierOffsets; 508 485 509 public: 486 510 bool isEmpty() const { return m_ptr.isEmpty(); } … … 501 525 CachedPtr<T, Source> m_ptr; 502 526 }; 527 528 ptrdiff_t CachedWriteBarrierOffsets::ptrOffset() 529 { 530 return OBJECT_OFFSETOF(CachedWriteBarrier<void>, m_ptr); 531 } 503 532 504 533 template<typename T, size_t InlineCapacity = 0, typename OverflowHandler = CrashOnOverflow> … … 1537 1566 1538 1567 class CachedFunctionExecutable : public CachedObject<UnlinkedFunctionExecutable> { 1568 friend struct CachedFunctionExecutableOffsets; 1569 1539 1570 public: 1540 1571 void encode(Encoder&, const UnlinkedFunctionExecutable&); … … 1553 1584 unsigned parameterCount() const { return m_parameterCount; } 1554 1585 1555 CodeFeatures features() const { return m_ features; }1586 CodeFeatures features() const { return m_mutableMetadata.m_features; } 1556 1587 SourceParseMode sourceParseMode() const { return m_sourceParseMode; } 1557 1588 1558 1589 unsigned isInStrictContext() const { return m_isInStrictContext; } 1559 unsigned hasCapturedVariables() const { return m_ hasCapturedVariables; }1590 unsigned hasCapturedVariables() const { return m_mutableMetadata.m_hasCapturedVariables; } 1560 1591 unsigned isBuiltinFunction() const { return m_isBuiltinFunction; } 1561 1592 unsigned isBuiltinDefaultClassConstructor() const { return m_isBuiltinDefaultClassConstructor; } … … 1577 1608 1578 1609 private: 1610 CachedFunctionExecutableMetadata m_mutableMetadata; 1611 1579 1612 unsigned m_firstLineOffset; 1580 1613 unsigned m_lineCount; … … 1588 1621 unsigned m_typeProfilingEndOffset; 1589 1622 unsigned m_parameterCount; 1590 CodeFeatures m_features;1591 1623 SourceParseMode m_sourceParseMode; 1592 1624 unsigned m_isInStrictContext : 1; 1593 unsigned m_hasCapturedVariables : 1;1594 1625 unsigned m_isBuiltinFunction : 1; 1595 1626 unsigned m_isBuiltinDefaultClassConstructor : 1; … … 1610 1641 CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForConstruct; 1611 1642 }; 1643 1644 ptrdiff_t CachedFunctionExecutableOffsets::codeBlockForCallOffset() 1645 { 1646 return OBJECT_OFFSETOF(CachedFunctionExecutable, m_unlinkedCodeBlockForCall); 1647 } 1648 1649 ptrdiff_t CachedFunctionExecutableOffsets::codeBlockForConstructOffset() 1650 { 1651 return OBJECT_OFFSETOF(CachedFunctionExecutable, m_unlinkedCodeBlockForConstruct); 1652 } 1653 1654 ptrdiff_t CachedFunctionExecutableOffsets::metadataOffset() 1655 { 1656 return OBJECT_OFFSETOF(CachedFunctionExecutable, m_mutableMetadata); 1657 } 1612 1658 1613 1659 template<typename CodeBlockType> … … 1926 1972 ALWAYS_INLINE void CachedFunctionExecutable::encode(Encoder& encoder, const UnlinkedFunctionExecutable& executable) 1927 1973 { 1974 m_mutableMetadata.m_features = executable.m_features; 1975 m_mutableMetadata.m_hasCapturedVariables = executable.m_hasCapturedVariables; 1976 1928 1977 m_firstLineOffset = executable.m_firstLineOffset; 1929 1978 m_lineCount = executable.m_lineCount; … … 1938 1987 m_parameterCount = executable.m_parameterCount; 1939 1988 1940 m_features = executable.m_features;1941 1989 m_sourceParseMode = executable.m_sourceParseMode; 1942 1990 1943 1991 m_isInStrictContext = executable.m_isInStrictContext; 1944 m_hasCapturedVariables = executable.m_hasCapturedVariables;1945 1992 m_isBuiltinFunction = executable.m_isBuiltinFunction; 1946 1993 m_isBuiltinDefaultClassConstructor = executable.m_isBuiltinDefaultClassConstructor; … … 1960 2007 m_unlinkedCodeBlockForCall.encode(encoder, executable.m_unlinkedCodeBlockForCall); 1961 2008 m_unlinkedCodeBlockForConstruct.encode(encoder, executable.m_unlinkedCodeBlockForConstruct); 2009 2010 if (!executable.m_unlinkedCodeBlockForCall || !executable.m_unlinkedCodeBlockForConstruct) 2011 encoder.addLeafExecutable(&executable, encoder.offsetOf(this)); 1962 2012 } 1963 2013 … … 1966 2016 UnlinkedFunctionExecutable* executable = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(decoder.vm().heap)) UnlinkedFunctionExecutable(decoder, *this); 1967 2017 executable->finishCreation(decoder.vm()); 1968 1969 2018 return executable; 1970 2019 } … … 2006 2055 { 2007 2056 2057 uint32_t leafExecutables = 2; 2058 auto checkBounds = [&](int32_t& codeBlockOffset, auto& cachedPtr) { 2059 if (!cachedPtr.isEmpty()) { 2060 ptrdiff_t offset = decoder.offsetOf(&cachedPtr); 2061 if (static_cast<size_t>(offset) < decoder.size()) { 2062 codeBlockOffset = offset; 2063 m_isCached = true; 2064 leafExecutables--; 2065 } 2066 } 2067 }; 2068 2008 2069 if (!cachedExecutable.unlinkedCodeBlockForCall().isEmpty() || !cachedExecutable.unlinkedCodeBlockForConstruct().isEmpty()) { 2009 m_isCached = true; 2010 m_decoder = &decoder; 2011 if (!cachedExecutable.unlinkedCodeBlockForCall().isEmpty()) 2012 m_cachedCodeBlockForCallOffset = decoder.offsetOf(&cachedExecutable.unlinkedCodeBlockForCall()); 2013 else 2014 m_cachedCodeBlockForCallOffset = 0; 2015 if (!cachedExecutable.unlinkedCodeBlockForConstruct().isEmpty()) 2016 m_cachedCodeBlockForConstructOffset = decoder.offsetOf(&cachedExecutable.unlinkedCodeBlockForConstruct()); 2017 else 2018 m_cachedCodeBlockForConstructOffset = 0; 2019 } 2070 checkBounds(m_cachedCodeBlockForCallOffset, cachedExecutable.unlinkedCodeBlockForCall()); 2071 checkBounds(m_cachedCodeBlockForConstructOffset, cachedExecutable.unlinkedCodeBlockForConstruct()); 2072 if (m_isCached) 2073 m_decoder = &decoder; 2074 } 2075 2076 if (leafExecutables) 2077 decoder.addLeafExecutable(this, decoder.offsetOf(&cachedExecutable)); 2020 2078 } 2021 2079 … … 2210 2268 } 2211 2269 2212 std::pair<MallocPtr<uint8_t>, size_t> encodeCodeBlock(VM& vm, const SourceCodeKey& key, const UnlinkedCodeBlock* codeBlock)2270 Ref<CachedBytecode> encodeCodeBlock(VM& vm, const SourceCodeKey& key, const UnlinkedCodeBlock* codeBlock) 2213 2271 { 2214 2272 const ClassInfo* classInfo = codeBlock->classInfo(vm); … … 2225 2283 } 2226 2284 2227 UnlinkedCodeBlock* decodeCodeBlockImpl(VM& vm, const SourceCodeKey& key, const void* buffer, size_t size) 2228 { 2229 const auto* cachedEntry = bitwise_cast<const GenericCacheEntry*>(buffer); 2230 Ref<Decoder> decoder = Decoder::create(vm, buffer, size); 2285 Ref<CachedBytecode> encodeFunctionCodeBlock(VM& vm, const UnlinkedFunctionCodeBlock* codeBlock) 2286 { 2287 Encoder encoder(vm); 2288 encoder.malloc<CachedFunctionCodeBlock>()->encode(encoder, *codeBlock); 2289 return encoder.release(); 2290 } 2291 2292 UnlinkedCodeBlock* decodeCodeBlockImpl(VM& vm, const SourceCodeKey& key, Ref<CachedBytecode> cachedBytecode) 2293 { 2294 const auto* cachedEntry = bitwise_cast<const GenericCacheEntry*>(cachedBytecode->data()); 2295 Ref<Decoder> decoder = Decoder::create(vm, WTFMove(cachedBytecode)); 2231 2296 std::pair<SourceCodeKey, UnlinkedCodeBlock*> entry; 2232 2297 { … … 2241 2306 } 2242 2307 2243 bool isCachedBytecodeStillValid(VM& vm, const CachedBytecode&cachedBytecode, const SourceCodeKey& key, SourceCodeType type)2244 { 2245 const void* buffer = cachedBytecode .data();2246 size_t size = cachedBytecode .size();2308 bool isCachedBytecodeStillValid(VM& vm, Ref<CachedBytecode> cachedBytecode, const SourceCodeKey& key, SourceCodeType type) 2309 { 2310 const void* buffer = cachedBytecode->data(); 2311 size_t size = cachedBytecode->size(); 2247 2312 if (!size) 2248 2313 return false; 2249 2314 const auto* cachedEntry = bitwise_cast<const GenericCacheEntry*>(buffer); 2250 Ref<Decoder> decoder = Decoder::create(vm, buffer, size);2315 Ref<Decoder> decoder = Decoder::create(vm, WTFMove(cachedBytecode)); 2251 2316 return cachedEntry->isStillValid(decoder.get(), key, tagFromSourceCodeType(type)); 2252 2317 } -
trunk/Source/JavaScriptCore/runtime/CachedTypes.h
r242605 r244143 27 27 28 28 #include "JSCast.h" 29 #include "ParserModes.h" 29 30 #include "VariableEnvironment.h" 30 31 #include <wtf/HashMap.h> … … 38 39 class UnlinkedFunctionCodeBlock; 39 40 41 enum class SourceCodeType; 42 43 // This struct has to be updated when incrementally writing to the bytecode 44 // cache, since this will only be filled in when we parse the function 45 struct CachedFunctionExecutableMetadata { 46 CodeFeatures m_features; 47 bool m_hasCapturedVariables; 48 }; 49 50 struct CachedFunctionExecutableOffsets { 51 static ptrdiff_t codeBlockForCallOffset(); 52 static ptrdiff_t codeBlockForConstructOffset(); 53 static ptrdiff_t metadataOffset(); 54 }; 55 56 struct CachedWriteBarrierOffsets { 57 static ptrdiff_t ptrOffset(); 58 }; 59 60 struct CachedPtrOffsets { 61 static ptrdiff_t offsetOffset(); 62 }; 63 64 class VariableLengthObjectBase { 65 friend class CachedBytecode; 66 67 protected: 68 VariableLengthObjectBase(ptrdiff_t offset) 69 : m_offset(offset) 70 { 71 } 72 73 ptrdiff_t m_offset; 74 }; 75 40 76 class Decoder : public RefCounted<Decoder> { 41 77 WTF_MAKE_NONCOPYABLE(Decoder); 42 78 43 79 public: 44 static Ref<Decoder> create(VM&, const void*, size_t);80 static Ref<Decoder> create(VM&, Ref<CachedBytecode>); 45 81 46 82 ~Decoder(); 47 83 48 84 VM& vm() { return m_vm; } 85 size_t size() const; 49 86 50 87 ptrdiff_t offsetOf(const void*); … … 54 91 CompactVariableMap::Handle handleForEnvironment(CompactVariableEnvironment*) const; 55 92 void setHandleForEnvironment(CompactVariableEnvironment*, const CompactVariableMap::Handle&); 93 void addLeafExecutable(const UnlinkedFunctionExecutable*, ptrdiff_t); 56 94 57 95 template<typename Functor> … … 59 97 60 98 private: 61 Decoder(VM&, const void*, size_t);99 Decoder(VM&, Ref<CachedBytecode>); 62 100 63 101 VM& m_vm; 64 const uint8_t* m_baseAddress; 65 #ifndef NDEBUG 66 size_t m_size; 67 #endif 102 Ref<CachedBytecode> m_cachedBytecode; 68 103 HashMap<ptrdiff_t, void*> m_offsetToPtrMap; 69 104 Vector<std::function<void()>> m_finalizers; … … 71 106 }; 72 107 73 enum class SourceCodeType;108 JS_EXPORT_PRIVATE Ref<CachedBytecode> encodeCodeBlock(VM&, const SourceCodeKey&, const UnlinkedCodeBlock*); 74 109 75 std::pair<MallocPtr<uint8_t>, size_t> encodeCodeBlock(VM&, const SourceCodeKey&, const UnlinkedCodeBlock*); 76 77 UnlinkedCodeBlock* decodeCodeBlockImpl(VM&, const SourceCodeKey&, const void*, size_t); 78 79 void decodeFunctionCodeBlock(Decoder&, int32_t cachedFunctionCodeBlockOffset, WriteBarrier<UnlinkedFunctionCodeBlock>&, const JSCell*); 110 UnlinkedCodeBlock* decodeCodeBlockImpl(VM&, const SourceCodeKey&, Ref<CachedBytecode>); 80 111 81 112 template<typename UnlinkedCodeBlockType> 82 UnlinkedCodeBlockType* decodeCodeBlock(VM& vm, const SourceCodeKey& key, const void* buffer, size_t size)113 UnlinkedCodeBlockType* decodeCodeBlock(VM& vm, const SourceCodeKey& key, Ref<CachedBytecode> cachedBytecode) 83 114 { 84 return jsCast<UnlinkedCodeBlockType*>(decodeCodeBlockImpl(vm, key, buffer, size));115 return jsCast<UnlinkedCodeBlockType*>(decodeCodeBlockImpl(vm, key, WTFMove(cachedBytecode))); 85 116 } 86 117 87 bool isCachedBytecodeStillValid(VM&, const CachedBytecode&, const SourceCodeKey&, SourceCodeType); 118 JS_EXPORT_PRIVATE Ref<CachedBytecode> encodeFunctionCodeBlock(VM&, const UnlinkedFunctionCodeBlock*); 119 120 JS_EXPORT_PRIVATE void decodeFunctionCodeBlock(Decoder&, int32_t cachedFunctionCodeBlockOffset, WriteBarrier<UnlinkedFunctionCodeBlock>&, const JSCell*); 121 122 bool isCachedBytecodeStillValid(VM&, Ref<CachedBytecode>, const SourceCodeKey&, SourceCodeType); 88 123 89 124 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/CodeCache.cpp
r243875 r244143 84 84 m_sourceCode.addCache(key, SourceCodeValue(vm, unlinkedCodeBlock, m_sourceCode.age())); 85 85 86 key.source().provider().cacheBytecode([&] { 87 return encodeCodeBlock(vm, key, unlinkedCodeBlock); 88 }); 89 86 90 return unlinkedCodeBlock; 87 91 } … … 163 167 } 164 168 169 void CodeCache::updateCache(const UnlinkedFunctionExecutable* executable, const SourceCode& parentSource, CodeSpecializationKind kind, const UnlinkedFunctionCodeBlock* codeBlock) 170 { 171 parentSource.provider()->updateCache(executable, parentSource, kind, codeBlock); 172 } 173 165 174 void CodeCache::write(VM& vm) 166 175 { 167 for (auto& it : m_sourceCode) { 168 if (it.value.written) 169 continue; 170 it.value.written = true; 176 for (auto& it : m_sourceCode) 171 177 writeCodeBlock(vm, it.key, it.value); 172 }173 178 } 174 179 … … 199 204 return; 200 205 201 key.source().provider().cacheBytecode([&] { 202 std::pair<MallocPtr<uint8_t>, size_t> result = encodeCodeBlock(vm, key, codeBlock); 203 return CachedBytecode { WTFMove(result.first), result.second }; 204 }); 206 key.source().provider().commitCachedBytecode(); 205 207 } 206 208 … … 231 233 } 232 234 233 CachedBytecodeserializeBytecode(VM& vm, UnlinkedCodeBlock* codeBlock, const SourceCode& source, SourceCodeType codeType, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode)234 { 235 std::pair<MallocPtr<uint8_t>, size_t> result =encodeCodeBlock(vm,235 Ref<CachedBytecode> serializeBytecode(VM& vm, UnlinkedCodeBlock* codeBlock, const SourceCode& source, SourceCodeType codeType, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode) 236 { 237 return encodeCodeBlock(vm, 236 238 sourceCodeKeyForSerializedBytecode(vm, source, codeType, strictMode, scriptMode, debuggerMode), codeBlock); 237 return CachedBytecode { WTFMove(result.first), result.second }; 238 } 239 240 } 239 } 240 241 } -
trunk/Source/JavaScriptCore/runtime/CodeCache.h
r242239 r244143 63 63 } // namespace CodeCacheInternal 64 64 65 #define VERBOSE_LOG(...) do { \66 if (CodeCacheInternal::verbose) \67 dataLogLn("(JSC::CodeCache) ", __VA_ARGS__); \68 } while (false)69 70 65 struct SourceCodeValue { 71 66 SourceCodeValue() … … 73 68 } 74 69 75 SourceCodeValue(VM& vm, JSCell* cell, int64_t age , bool written = false)70 SourceCodeValue(VM& vm, JSCell* cell, int64_t age) 76 71 : cell(vm, cell) 77 72 , age(age) 78 , written(written)79 73 { 80 74 } … … 82 76 Strong<JSCell> cell; 83 77 int64_t age; 84 bool written;85 78 }; 86 79 … … 109 102 prune(); 110 103 111 VERBOSE_LOG("Trying to find cached CodeBlock for ", key.source().provider().url().string());112 104 iterator findResult = m_map.find(key); 113 105 if (findResult == m_map.end()) … … 132 124 m_age += key.length(); 133 125 134 VERBOSE_LOG("Found cached CodeBlock in memory");135 126 return jsCast<UnlinkedCodeBlockType*>(findResult->value.cell.get()); 136 127 } … … 167 158 UnlinkedCodeBlockType* fetchFromDiskImpl(VM& vm, const SourceCodeKey& key) 168 159 { 169 const CachedBytecode* cachedBytecode = key.source().provider().cachedBytecode(); 170 if (cachedBytecode && cachedBytecode->size()) { 171 VERBOSE_LOG("Found cached CodeBlock in the SourceProvider"); 172 UnlinkedCodeBlockType* unlinkedCodeBlock = decodeCodeBlock<UnlinkedCodeBlockType>(vm, key, cachedBytecode->data(), cachedBytecode->size()); 173 if (unlinkedCodeBlock) 174 return unlinkedCodeBlock; 175 } 176 return nullptr; 160 RefPtr<CachedBytecode> cachedBytecode = key.source().provider().cachedBytecode(); 161 if (!cachedBytecode || !cachedBytecode->size()) 162 return nullptr; 163 return decodeCodeBlock<UnlinkedCodeBlockType>(vm, key, *cachedBytecode); 177 164 } 178 165 … … 241 228 UnlinkedFunctionExecutable* getUnlinkedGlobalFunctionExecutable(VM&, const Identifier&, const SourceCode&, DebuggerMode, Optional<int> functionConstructorParametersEndPosition, ParserError&); 242 229 230 void updateCache(const UnlinkedFunctionExecutable*, const SourceCode&, CodeSpecializationKind, const UnlinkedFunctionCodeBlock*); 231 243 232 void clear() { m_sourceCode.clear(); } 244 233 JS_EXPORT_PRIVATE void write(VM&); … … 330 319 331 320 void writeCodeBlock(VM&, const SourceCodeKey&, const SourceCodeValue&); 332 CachedBytecodeserializeBytecode(VM&, UnlinkedCodeBlock*, const SourceCode&, SourceCodeType, JSParserStrictMode, JSParserScriptMode, DebuggerMode);321 Ref<CachedBytecode> serializeBytecode(VM&, UnlinkedCodeBlock*, const SourceCode&, SourceCodeType, JSParserStrictMode, JSParserScriptMode, DebuggerMode); 333 322 SourceCodeKey sourceCodeKeyForSerializedProgram(VM&, const SourceCode&); 334 323 SourceCodeKey sourceCodeKeyForSerializedModule(VM&, const SourceCode&); -
trunk/Source/JavaScriptCore/runtime/Completion.cpp
r242239 r244143 92 92 } 93 93 94 CachedBytecodegenerateProgramBytecode(VM& vm, const SourceCode& source, ParserError& error)94 Ref<CachedBytecode> generateProgramBytecode(VM& vm, const SourceCode& source, ParserError& error) 95 95 { 96 96 JSLockHolder lock(vm); … … 105 105 UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlock<UnlinkedProgramCodeBlock>(vm, source, strictMode, scriptMode, debuggerMode, error, evalContextType, &variablesUnderTDZ); 106 106 if (!unlinkedCodeBlock) 107 return { };107 return CachedBytecode::create(); 108 108 return serializeBytecode(vm, unlinkedCodeBlock, source, SourceCodeType::ProgramType, strictMode, scriptMode, debuggerMode); 109 109 } 110 110 111 CachedBytecodegenerateModuleBytecode(VM& vm, const SourceCode& source, ParserError& error)111 Ref<CachedBytecode> generateModuleBytecode(VM& vm, const SourceCode& source, ParserError& error) 112 112 { 113 113 JSLockHolder lock(vm); … … 122 122 UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, source, strictMode, scriptMode, debuggerMode, error, evalContextType, &variablesUnderTDZ); 123 123 if (!unlinkedCodeBlock) 124 return { };124 return CachedBytecode::create(); 125 125 return serializeBytecode(vm, unlinkedCodeBlock, source, SourceCodeType::ModuleType, strictMode, scriptMode, debuggerMode); 126 126 } -
trunk/Source/JavaScriptCore/runtime/Completion.h
r242239 r244143 43 43 JS_EXPORT_PRIVATE bool checkModuleSyntax(ExecState*, const SourceCode&, ParserError&); 44 44 45 JS_EXPORT_PRIVATE CachedBytecodegenerateProgramBytecode(VM&, const SourceCode&, ParserError&);46 JS_EXPORT_PRIVATE CachedBytecodegenerateModuleBytecode(VM&, const SourceCode&, ParserError&);45 JS_EXPORT_PRIVATE Ref<CachedBytecode> generateProgramBytecode(VM&, const SourceCode&, ParserError&); 46 JS_EXPORT_PRIVATE Ref<CachedBytecode> generateModuleBytecode(VM&, const SourceCode&, ParserError&); 47 47 48 48 JS_EXPORT_PRIVATE JSValue evaluate(ExecState*, const SourceCode&, JSValue thisValue, NakedPtr<Exception>& returnedException); -
trunk/Source/JavaScriptCore/runtime/LeafExecutable.cpp
r244142 r244143 24 24 */ 25 25 26 #i mport"config.h"27 #i mport "JSScriptSourceProvider.h"26 #include "config.h" 27 #include "LeafExecutable.h" 28 28 29 #if JSC_OBJC_API_ENABLED 29 namespace JSC { 30 30 31 #import "JSScriptInternal.h" 32 33 unsigned JSScriptSourceProvider::hash() const 31 LeafExecutable LeafExecutable::operator+(size_t offset) const 34 32 { 35 return [m_script.get() hash];33 return LeafExecutable { static_cast<ptrdiff_t>(m_base + offset) }; 36 34 } 37 35 38 StringView JSScriptSourceProvider::source() const 39 { 40 return [m_script.get() source]; 41 } 42 43 const JSC::CachedBytecode* JSScriptSourceProvider::cachedBytecode() const 44 { 45 return [m_script.get() cachedBytecode]; 46 } 47 48 #endif // JSC_OBJC_API_ENABLED 36 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/LeafExecutable.h
r244142 r244143 24 24 */ 25 25 26 #import "config.h" 27 #import "JSScriptSourceProvider.h" 26 #pragma once 28 27 29 #i f JSC_OBJC_API_ENABLED28 #include <wtf/HashMap.h> 30 29 31 #import "JSScriptInternal.h" 30 namespace JSC { 32 31 33 unsigned JSScriptSourceProvider::hash() const 34 { 35 return [m_script.get() hash]; 36 } 32 class LeafExecutable; 33 class UnlinkedFunctionExecutable; 37 34 38 StringView JSScriptSourceProvider::source() const 39 { 40 return [m_script.get() source]; 41 } 35 using LeafExecutableMap = HashMap<const UnlinkedFunctionExecutable*, LeafExecutable>; 42 36 43 const JSC::CachedBytecode* JSScriptSourceProvider::cachedBytecode() const 44 { 45 return [m_script.get() cachedBytecode]; 46 } 37 class LeafExecutable { 38 public: 39 LeafExecutable() = default; 47 40 48 #endif // JSC_OBJC_API_ENABLED 41 LeafExecutable(ptrdiff_t offset) 42 : m_base(offset) 43 { 44 } 45 46 ptrdiff_t base() const { return m_base; } 47 LeafExecutable operator+(size_t) const; 48 49 private: 50 ptrdiff_t m_base; 51 }; 52 53 } // namespace JSC -
trunk/Tools/ChangeLog
r244139 r244143 1 2019-04-10 Tadeu Zagallo <tzagallo@apple.com> 2 3 Add support for incremental bytecode cache updates 4 https://bugs.webkit.org/show_bug.cgi?id=195000 5 6 Reviewed by Filip Pizlo. 7 8 Exit when the initial run to generate bytecode fails. 9 10 * Scripts/jsc-stress-test-helpers/bytecode-cache-test-helper.sh: 11 1 12 2019-04-10 Alex Christensen <achristensen@webkit.org> 2 13 -
trunk/Tools/Scripts/jsc-stress-test-helpers/bytecode-cache-test-helper.sh
r240255 r244143 30 30 if [ $exitCode != 0 ]; then 31 31 echo "Command '$*' failed" 32 return$exitCode32 exit $exitCode 33 33 fi 34 34 }
Note: See TracChangeset
for help on using the changeset viewer.