Skip to content

Commit 24bd1b2

Browse files
committed
Add support for incremental bytecode cache updates
https://bugs.webkit.org/show_bug.cgi?id=195000 Reviewed by Filip Pizlo. Source/JavaScriptCore: Add support for incremental updates to the bytecode cache. The cache is constructed as follows: - When the cache is empty, the initial payload can be added to the BytecodeCache by calling BytecodeCache::addGlobalUpdate. This represents the encoded top-level UnlinkedCodeBlock. - Afterwards, updates can be added by calling BytecodeCache::addFunctionUpdate. The update is applied by appending the encoded UnlinkedFunctionCodeBlock to the existing cache and updating the CachedFunctionExecutableMetadata and the offset of the new CachedFunctionCodeBlock in the owner CachedFunctionExecutable. * API/JSScript.mm: (-[JSScript readCache]): (-[JSScript isUsingBytecodeCache]): (-[JSScript init]): (-[JSScript cachedBytecode]): (-[JSScript writeCache:]): * API/JSScriptInternal.h: * API/JSScriptSourceProvider.h: * API/JSScriptSourceProvider.mm: (JSScriptSourceProvider::cachedBytecode const): * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * Sources.txt: * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::generateUnlinkedFunctionCodeBlock): * jsc.cpp: (ShellSourceProvider::~ShellSourceProvider): (ShellSourceProvider::cachePath const): (ShellSourceProvider::loadBytecode const): (ShellSourceProvider::ShellSourceProvider): (ShellSourceProvider::cacheEnabled): * parser/SourceProvider.h: (JSC::SourceProvider::cachedBytecode const): (JSC::SourceProvider::updateCache const): (JSC::SourceProvider::commitCachedBytecode const): * runtime/CachePayload.cpp: Copied from Source/JavaScriptCore/API/JSScriptInternal.h. (JSC::CachePayload::makeMappedPayload): (JSC::CachePayload::makeMallocPayload): (JSC::CachePayload::makeEmptyPayload): (JSC::CachePayload::CachePayload): (JSC::CachePayload::~CachePayload): (JSC::CachePayload::operator=): (JSC::CachePayload::freeData): * runtime/CachePayload.h: Copied from Source/JavaScriptCore/API/JSScriptInternal.h. (JSC::CachePayload::data const): (JSC::CachePayload::size const): (JSC::CachePayload::CachePayload): * runtime/CacheUpdate.cpp: Copied from Source/JavaScriptCore/API/JSScriptInternal.h. (JSC::CacheUpdate::CacheUpdate): (JSC::CacheUpdate::operator=): (JSC::CacheUpdate::isGlobal const): (JSC::CacheUpdate::asGlobal const): (JSC::CacheUpdate::asFunction const): * runtime/CacheUpdate.h: Copied from Source/JavaScriptCore/API/JSScriptInternal.h. * runtime/CachedBytecode.cpp: Added. (JSC::CachedBytecode::addGlobalUpdate): (JSC::CachedBytecode::addFunctionUpdate): (JSC::CachedBytecode::copyLeafExecutables): (JSC::CachedBytecode::commitUpdates const): * runtime/CachedBytecode.h: Added. (JSC::CachedBytecode::create): (JSC::CachedBytecode::leafExecutables): (JSC::CachedBytecode::data const): (JSC::CachedBytecode::size const): (JSC::CachedBytecode::hasUpdates const): (JSC::CachedBytecode::sizeForUpdate const): (JSC::CachedBytecode::CachedBytecode): * runtime/CachedTypes.cpp: (JSC::Encoder::addLeafExecutable): (JSC::Encoder::release): (JSC::Decoder::Decoder): (JSC::Decoder::create): (JSC::Decoder::size const): (JSC::Decoder::offsetOf): (JSC::Decoder::ptrForOffsetFromBase): (JSC::Decoder::addLeafExecutable): (JSC::VariableLengthObject::VariableLengthObject): (JSC::VariableLengthObject::buffer const): (JSC::CachedPtrOffsets::offsetOffset): (JSC::CachedWriteBarrierOffsets::ptrOffset): (JSC::CachedFunctionExecutable::features const): (JSC::CachedFunctionExecutable::hasCapturedVariables const): (JSC::CachedFunctionExecutableOffsets::codeBlockForCallOffset): (JSC::CachedFunctionExecutableOffsets::codeBlockForConstructOffset): (JSC::CachedFunctionExecutableOffsets::metadataOffset): (JSC::CachedFunctionExecutable::encode): (JSC::CachedFunctionExecutable::decode const): (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): (JSC::encodeCodeBlock): (JSC::encodeFunctionCodeBlock): (JSC::decodeCodeBlockImpl): (JSC::isCachedBytecodeStillValid): * runtime/CachedTypes.h: (JSC::VariableLengthObjectBase::VariableLengthObjectBase): (JSC::decodeCodeBlock): * runtime/CodeCache.cpp: (JSC::CodeCache::getUnlinkedGlobalCodeBlock): (JSC::CodeCache::updateCache): (JSC::CodeCache::write): (JSC::writeCodeBlock): (JSC::serializeBytecode): * runtime/CodeCache.h: (JSC::SourceCodeValue::SourceCodeValue): (JSC::CodeCacheMap::findCacheAndUpdateAge): (JSC::CodeCacheMap::fetchFromDiskImpl): * runtime/Completion.cpp: (JSC::generateProgramBytecode): (JSC::generateModuleBytecode): * runtime/Completion.h: * runtime/LeafExecutable.cpp: Copied from Source/JavaScriptCore/API/JSScriptSourceProvider.mm. (JSC::LeafExecutable::operator+ const): * runtime/LeafExecutable.h: Copied from Source/JavaScriptCore/API/JSScriptSourceProvider.mm. (JSC::LeafExecutable::LeafExecutable): (JSC::LeafExecutable::base const): Tools: Exit when the initial run to generate bytecode fails. * Scripts/jsc-stress-test-helpers/bytecode-cache-test-helper.sh: Canonical link: https://commits.webkit.org/211061@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@244143 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent 0bc146d commit 24bd1b2

27 files changed

+1007
-203
lines changed

Source/JavaScriptCore/API/JSScript.mm

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ @implementation JSScript {
5050
String m_source;
5151
RetainPtr<NSURL> m_sourceURL;
5252
RetainPtr<NSURL> m_cachePath;
53-
JSC::CachedBytecode m_cachedBytecode;
53+
RefPtr<JSC::CachedBytecode> m_cachedBytecode;
5454
}
5555

5656
+ (instancetype)scriptWithSource:(NSString *)source inVirtualMachine:(JSVirtualMachine *)vm
@@ -169,14 +169,6 @@ + (instancetype)scriptOfType:(JSScriptType)type memoryMappedFromASCIIFile:(NSURL
169169
return result;
170170
}
171171

172-
- (void)dealloc
173-
{
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-
180172
- (void)readCache
181173
{
182174
if (!m_cachePath)
@@ -197,12 +189,12 @@ - (void)readCache
197189

198190
void* buffer = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
199191

200-
JSC::CachedBytecode cachedBytecode { buffer, size };
192+
Ref<JSC::CachedBytecode> cachedBytecode = JSC::CachedBytecode::create(buffer, size);
201193

202194
JSC::VM& vm = m_virtualMachine.vm;
203195
JSC::SourceCode sourceCode = [self sourceCode];
204196
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))
206198
m_cachedBytecode = WTFMove(cachedBytecode);
207199
else
208200
ftruncate(fd, 0);
@@ -222,7 +214,7 @@ - (BOOL)cacheBytecodeWithError:(NSError **)error
222214

223215
- (BOOL)isUsingBytecodeCache
224216
{
225-
return !!m_cachedBytecode.size();
217+
return !!m_cachedBytecode->size();
226218
}
227219

228220
- (NSURL *)sourceURL
@@ -245,6 +237,8 @@ - (instancetype)init
245237
if (!self)
246238
return nil;
247239

240+
self->m_cachedBytecode = JSC::CachedBytecode::create();
241+
248242
return self;
249243
}
250244

@@ -258,9 +252,9 @@ - (unsigned)hash
258252
return m_source;
259253
}
260254

261-
- (const JSC::CachedBytecode*)cachedBytecode
255+
- (RefPtr<JSC::CachedBytecode>)cachedBytecode
262256
{
263-
return &m_cachedBytecode;
257+
return m_cachedBytecode;
264258
}
265259

266260
- (JSC::SourceCode)sourceCode
@@ -286,7 +280,7 @@ - (unsigned)hash
286280

287281
- (BOOL)writeCache:(String&)error
288282
{
289-
if (m_cachedBytecode.size()) {
283+
if (self.isUsingBytecodeCache) {
290284
error = "Cache for JSScript is already non-empty. Can not override it."_s;
291285
return NO;
292286
}
@@ -317,20 +311,20 @@ - (BOOL)writeCache:(String&)error
317311
}
318312

319313
if (parserError.isValid()) {
320-
m_cachedBytecode = { };
314+
m_cachedBytecode = JSC::CachedBytecode::create();
321315
error = makeString("Unable to generate bytecode for this JSScript because of a parser error: ", parserError.message());
322316
return NO;
323317
}
324318

325-
ssize_t bytesWritten = write(fd, m_cachedBytecode.data(), m_cachedBytecode.size());
319+
ssize_t bytesWritten = write(fd, m_cachedBytecode->data(), m_cachedBytecode->size());
326320
if (bytesWritten == -1) {
327321
error = makeString("Could not write cache file to disk: ", strerror(errno));
328322
return NO;
329323
}
330324

331-
if (static_cast<size_t>(bytesWritten) != m_cachedBytecode.size()) {
325+
if (static_cast<size_t>(bytesWritten) != m_cachedBytecode->size()) {
332326
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.");
334328
return NO;
335329
}
336330

Source/JavaScriptCore/API/JSScriptInternal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#import "JSScript.h"
2929
#import "SourceCode.h"
30+
#import <wtf/RefPtr.h>
3031

3132
#if JSC_OBJC_API_ENABLED
3233

@@ -47,7 +48,7 @@ class String;
4748
- (instancetype)init;
4849
- (unsigned)hash;
4950
- (const WTF::String&)source;
50-
- (nullable const JSC::CachedBytecode*)cachedBytecode;
51+
- (RefPtr<JSC::CachedBytecode>)cachedBytecode;
5152
- (JSC::JSSourceCode*)jsSourceCode;
5253
- (JSC::SourceCode)sourceCode;
5354
- (BOOL)writeCache:(String&)error;

Source/JavaScriptCore/API/JSScriptSourceProvider.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class JSScriptSourceProvider : public JSC::SourceProvider {
3939

4040
unsigned hash() const override;
4141
StringView source() const override;
42-
const JSC::CachedBytecode* cachedBytecode() const override;
42+
RefPtr<JSC::CachedBytecode> cachedBytecode() const override;
4343

4444
private:
4545
template<typename... Args>

Source/JavaScriptCore/API/JSScriptSourceProvider.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
return [m_script.get() source];
4141
}
4242

43-
const JSC::CachedBytecode* JSScriptSourceProvider::cachedBytecode() const
43+
RefPtr<JSC::CachedBytecode> JSScriptSourceProvider::cachedBytecode() const
4444
{
4545
return [m_script.get() cachedBytecode];
4646
}

Source/JavaScriptCore/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,10 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS
761761
runtime/BooleanPrototype.h
762762
runtime/Butterfly.h
763763
runtime/ButterflyInlines.h
764+
runtime/CachePayload.h
765+
runtime/CacheUpdate.h
766+
runtime/CachedBytecode.h
767+
runtime/CachedTypes.h
764768
runtime/CagedBarrierPtr.h
765769
runtime/CallData.h
766770
runtime/CatchScope.h
@@ -896,6 +900,7 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS
896900
runtime/JSWrapperObject.h
897901
runtime/LazyClassStructure.h
898902
runtime/LazyProperty.h
903+
runtime/LeafExecutable.h
899904
runtime/Lookup.h
900905
runtime/MatchResult.h
901906
runtime/MathCommon.h

Source/JavaScriptCore/ChangeLog

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,125 @@
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+
1123
2019-04-10 Michael Catanzaro <mcatanzaro@igalia.com>
2124

3125
Unreviewed, rolling out r243989.

0 commit comments

Comments
 (0)