Skip to content
This repository was archived by the owner on Jun 24, 2022. It is now read-only.

Commit 9451b45

Browse files
Add API to generate and consume cached bytecode
https://bugs.webkit.org/show_bug.cgi?id=193401 <rdar://problem/47514099> Reviewed by Keith Miller. Add the `generateBytecode` and `generateModuleBytecode` functions to generate serialized bytecode for a given `SourceCode`. These functions will eagerly generate code for all the nested functions. Additionally, update the API methods in JSScript to generate and use the bytecode when the bytecodeCache path is provided. * API/JSAPIGlobalObject.mm: (JSC::JSAPIGlobalObject::moduleLoaderFetch): * API/JSContext.mm: (-[JSContext wrapperMap]): * API/JSContextInternal.h: * API/JSScript.mm: (+[JSScript scriptWithSource:inVirtualMachine:]): (+[JSScript scriptFromASCIIFile:inVirtualMachine:withCodeSigning:andBytecodeCache:]): (-[JSScript dealloc]): (-[JSScript readCache]): (-[JSScript writeCache]): (-[JSScript hash]): (-[JSScript source]): (-[JSScript cachedBytecode]): (-[JSScript jsSourceCode:]): * API/JSScriptInternal.h: * API/JSScriptSourceProvider.h: Copied from Source/JavaScriptCore/API/JSScriptInternal.h. (JSScriptSourceProvider::create): (JSScriptSourceProvider::JSScriptSourceProvider): * API/JSScriptSourceProvider.mm: Copied from Source/JavaScriptCore/API/JSScriptInternal.h. (JSScriptSourceProvider::hash const): (JSScriptSourceProvider::source const): (JSScriptSourceProvider::cachedBytecode const): * API/JSVirtualMachine.mm: (-[JSVirtualMachine vm]): * API/JSVirtualMachineInternal.h: * API/tests/testapi.mm: (testBytecodeCache): (-[JSContextFileLoaderDelegate context:fetchModuleForIdentifier:withResolveHandler:andRejectHandler:]): (testObjectiveCAPI): * JavaScriptCore.xcodeproj/project.pbxproj: * SourcesCocoa.txt: * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::UnlinkedFunctionExecutable::unlinkedCodeBlockFor): * bytecode/UnlinkedFunctionExecutable.h: * parser/SourceCodeKey.h: (JSC::SourceCodeKey::source const): * parser/SourceProvider.h: (JSC::CachedBytecode::CachedBytecode): (JSC::CachedBytecode::operator=): (JSC::CachedBytecode::data const): (JSC::CachedBytecode::size const): (JSC::CachedBytecode::owned const): (JSC::CachedBytecode::~CachedBytecode): (JSC::CachedBytecode::freeDataIfOwned): (JSC::SourceProvider::cachedBytecode const): * parser/UnlinkedSourceCode.h: (JSC::UnlinkedSourceCode::provider const): * runtime/CodeCache.cpp: (JSC::generateUnlinkedCodeBlockForFunctions): (JSC::writeCodeBlock): (JSC::serializeBytecode): * runtime/CodeCache.h: (JSC::CodeCacheMap::fetchFromDiskImpl): (JSC::CodeCacheMap::findCacheAndUpdateAge): (JSC::generateUnlinkedCodeBlockImpl): (JSC::generateUnlinkedCodeBlock): * runtime/Completion.cpp: (JSC::generateBytecode): (JSC::generateModuleBytecode): * runtime/Completion.h: * runtime/Options.cpp: (JSC::recomputeDependentOptions): git-svn-id: http://svn.webkit.org/repository/webkit/trunk@240511 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent 4e05d58 commit 9451b45

23 files changed

+636
-61
lines changed

Source/JavaScriptCore/API/JSAPIGlobalObject.mm

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@
164164
auto deferredPromise = Strong<JSInternalPromiseDeferred>(vm, deferred);
165165
auto strongKey = Strong<JSString>(vm, jsSecureCast<JSString*>(vm, key));
166166
auto* resolve = JSNativeStdFunction::create(vm, globalObject, 1, "resolve", [=] (ExecState* exec) {
167-
VM& vm = exec->vm();
168167
// This captures the globalObject but that's ok because our structure keeps it alive anyway.
169168
JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(globalObject->globalExec())];
170169
id script = valueToObject(context, toRef(exec, exec->argument(0)));
@@ -176,8 +175,7 @@
176175
return encodedJSUndefined();
177176
}
178177

179-
const String& source = getJSScriptSourceCode(static_cast<JSScript *>(script));
180-
args.append(JSSourceCode::create(vm, makeSource(source, SourceOrigin(moduleKey.string()), URL({ }, moduleKey.string()), TextPosition(), JSC::SourceProviderSourceType::Module)));
178+
args.append([static_cast<JSScript *>(script) jsSourceCode:moduleKey]);
181179
call(exec, deferredPromise->JSPromiseDeferred::resolve(), args, "This should never be seen...");
182180
return encodedJSUndefined();
183181
});

Source/JavaScriptCore/API/JSContext.mm

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
#import "JSGlobalObject.h"
3535
#import "JSInternalPromise.h"
3636
#import "JSModuleLoader.h"
37-
#import "JSScriptInternal.h"
3837
#import "JSValueInternal.h"
3938
#import "JSVirtualMachineInternal.h"
4039
#import "JSWrapperMap.h"
@@ -135,11 +134,6 @@ - (JSValue *)exception
135134
return [JSValue valueWithJSValueRef:toRef(m_exception.get()) inContext:self];
136135
}
137136

138-
- (JSWrapperMap *)wrapperMap
139-
{
140-
return toJS(m_context)->lexicalGlobalObject()->wrapperMap();
141-
}
142-
143137
- (JSValue *)globalObject
144138
{
145139
return [JSValue valueWithJSValueRef:JSContextGetGlobalObject(m_context) inContext:self];
@@ -332,6 +326,11 @@ - (JSValue *)wrapperForObjCObject:(id)object
332326
return [[self wrapperMap] jsWrapperForObject:object inContext:self];
333327
}
334328

329+
- (JSWrapperMap *)wrapperMap
330+
{
331+
return toJS(m_context)->lexicalGlobalObject()->wrapperMap();
332+
}
333+
335334
- (JSValue *)wrapperForJSObject:(JSValueRef)value
336335
{
337336
JSC::JSLockHolder locker(toJS(m_context));

Source/JavaScriptCore/API/JSContextInternal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ struct CallbackData {
5151
- (void)beginCallbackWithData:(CallbackData *)callbackData calleeValue:(JSValueRef)calleeValue thisValue:(JSValueRef)thisValue argumentCount:(size_t)argumentCount arguments:(const JSValueRef *)arguments;
5252
- (void)endCallbackWithData:(CallbackData *)callbackData;
5353

54+
- (JSWrapperMap *)wrapperMap;
5455
- (JSValue *)wrapperForObjCObject:(id)object;
5556
- (JSValue *)wrapperForJSObject:(JSValueRef)value;
5657

Source/JavaScriptCore/API/JSScript.mm

Lines changed: 106 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,32 @@
2727
#import "JSScriptInternal.h"
2828

2929
#import "APICast.h"
30+
#import "Identifier.h"
3031
#import "JSContextInternal.h"
32+
#import "JSScriptSourceProvider.h"
33+
#import "JSSourceCode.h"
3134
#import "JSValuePrivate.h"
35+
#import "JSVirtualMachineInternal.h"
36+
#import "ParserError.h"
3237
#import "Symbol.h"
38+
#include <sys/stat.h>
3339

3440
#if JSC_OBJC_API_ENABLED
3541

3642
@implementation JSScript {
43+
__weak JSVirtualMachine* m_virtualMachine;
3744
String m_source;
45+
NSURL* m_cachePath;
46+
JSC::CachedBytecode m_cachedBytecode;
47+
JSC::Strong<JSC::JSSourceCode> m_jsSourceCode;
48+
UniquedStringImpl* m_moduleKey;
3849
}
3950

4051
+ (instancetype)scriptWithSource:(NSString *)source inVirtualMachine:(JSVirtualMachine *)vm
4152
{
42-
UNUSED_PARAM(vm);
43-
JSScript *result = [[JSScript alloc] init];
53+
JSScript *result = [[[JSScript alloc] init] autorelease];
4454
result->m_source = source;
55+
result->m_virtualMachine = vm;
4556
return result;
4657
}
4758

@@ -81,9 +92,6 @@ + (instancetype)scriptFromASCIIFile:(NSURL *)filePath inVirtualMachine:(JSVirtua
8192
{
8293
// FIXME: This should check codeSigning.
8394
UNUSED_PARAM(codeSigningPath);
84-
// FIXME: This should actually cache bytecode.
85-
UNUSED_PARAM(cachePath);
86-
UNUSED_PARAM(vm);
8795
URL filePathURL([filePath absoluteURL]);
8896
if (!filePathURL.isLocalFile())
8997
return nil;
@@ -95,8 +103,11 @@ + (instancetype)scriptFromASCIIFile:(NSURL *)filePath inVirtualMachine:(JSVirtua
95103
if (!charactersAreAllASCII(buffer.data(), buffer.size()))
96104
return nil;
97105

98-
JSScript *result = [[JSScript alloc] init];
106+
JSScript *result = [[[JSScript alloc] init] autorelease];
107+
result->m_virtualMachine = vm;
99108
result->m_source = String::fromUTF8WithLatin1Fallback(buffer.data(), buffer.size());
109+
result->m_cachePath = cachePath;
110+
[result readCache];
100111
return result;
101112
}
102113

@@ -105,7 +116,95 @@ + (instancetype)scriptFromUTF8File:(NSURL *)filePath inVirtualMachine:(JSVirtual
105116
return [JSScript scriptFromASCIIFile:filePath inVirtualMachine:vm withCodeSigning:codeSigningPath andBytecodeCache:cachePath];
106117
}
107118

108-
const String& getJSScriptSourceCode(JSScript *module) { return module->m_source; }
119+
- (void)dealloc
120+
{
121+
if (m_cachedBytecode.size() && !m_cachedBytecode.owned())
122+
munmap(const_cast<void*>(m_cachedBytecode.data()), m_cachedBytecode.size());
123+
[super dealloc];
124+
}
125+
126+
- (void)readCache
127+
{
128+
if (!m_cachePath)
129+
return;
130+
131+
int fd = open(m_cachePath.path.UTF8String, O_RDONLY);
132+
if (fd == -1)
133+
return;
134+
135+
int rc = flock(fd, LOCK_SH | LOCK_NB);
136+
if (rc) {
137+
close(fd);
138+
return;
139+
}
140+
141+
struct stat sb;
142+
int res = fstat(fd, &sb);
143+
size_t size = static_cast<size_t>(sb.st_size);
144+
if (res || !size) {
145+
close(fd);
146+
return;
147+
}
148+
149+
void* buffer = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
150+
close(fd);
151+
152+
m_cachedBytecode = JSC::CachedBytecode { buffer, size };
153+
}
154+
155+
- (void)writeCache
156+
{
157+
if (m_cachedBytecode.size() || !m_cachePath)
158+
return;
159+
160+
JSC::ParserError error;
161+
m_cachedBytecode = JSC::generateModuleBytecode(m_virtualMachine.vm, m_jsSourceCode->sourceCode(), error);
162+
if (error.isValid())
163+
return;
164+
int fd = open(m_cachePath.path.UTF8String, O_CREAT | O_WRONLY, 0666);
165+
if (fd == -1)
166+
return;
167+
int rc = flock(fd, LOCK_EX | LOCK_NB);
168+
if (!rc)
169+
write(fd, m_cachedBytecode.data(), m_cachedBytecode.size());
170+
close(fd);
171+
}
172+
173+
@end
174+
175+
@implementation JSScript(Internal)
176+
177+
- (unsigned)hash
178+
{
179+
return m_source.hash();
180+
}
181+
182+
- (const String&)source
183+
{
184+
return m_source;
185+
}
186+
187+
- (const JSC::CachedBytecode*)cachedBytecode
188+
{
189+
return &m_cachedBytecode;
190+
}
191+
192+
- (JSC::JSSourceCode*)jsSourceCode:(const JSC::Identifier&)moduleKey
193+
{
194+
if (m_jsSourceCode) {
195+
ASSERT(moduleKey.impl() == m_moduleKey);
196+
return m_jsSourceCode.get();
197+
}
198+
199+
JSC::VM& vm = m_virtualMachine.vm;
200+
TextPosition startPosition { };
201+
Ref<JSScriptSourceProvider> sourceProvider = JSScriptSourceProvider::create(self, JSC::SourceOrigin(moduleKey.string()), URL({ }, moduleKey.string()), TextPosition(), JSC::SourceProviderSourceType::Module);
202+
JSC::SourceCode sourceCode(WTFMove(sourceProvider), startPosition.m_line.oneBasedInt(), startPosition.m_column.oneBasedInt());
203+
JSC::JSSourceCode* jsSourceCode = JSC::JSSourceCode::create(vm, WTFMove(sourceCode));
204+
m_jsSourceCode.set(vm, jsSourceCode);
205+
[self writeCache];
206+
return jsSourceCode;
207+
}
109208

110209
@end
111210

Source/JavaScriptCore/API/JSScriptInternal.h

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,29 @@
2828
#import "JSScript.h"
2929
#import "SourceCode.h"
3030

31-
OBJC_CLASS JSScript;
31+
#if JSC_OBJC_API_ENABLED
3232

33-
const String& getJSScriptSourceCode(JSScript *);
33+
NS_ASSUME_NONNULL_BEGIN
34+
35+
namespace JSC {
36+
class CachedBytecode;
37+
class Identifier;
38+
class JSSourceCode;
39+
};
40+
41+
namespace WTF {
42+
class String;
43+
};
44+
45+
@interface JSScript(Internal)
46+
47+
- (unsigned)hash;
48+
- (const WTF::String&)source;
49+
- (const JSC::CachedBytecode*)cachedBytecode;
50+
- (JSC::JSSourceCode*)jsSourceCode:(const JSC::Identifier&)moduleKey;
51+
52+
@end
53+
54+
NS_ASSUME_NONNULL_END
55+
56+
#endif // JSC_OBJC_API_ENABLED
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (C) 2019 Apple Inc. All rights reserved.
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions
6+
* are met:
7+
* 1. Redistributions of source code must retain the above copyright
8+
* notice, this list of conditions and the following disclaimer.
9+
* 2. Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
*
13+
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14+
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21+
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24+
*/
25+
26+
#if JSC_OBJC_API_ENABLED
27+
28+
#import "SourceProvider.h"
29+
30+
@class JSScript;
31+
32+
class JSScriptSourceProvider : public JSC::SourceProvider {
33+
public:
34+
template<typename... Args>
35+
static Ref<JSScriptSourceProvider> create(JSScript *script, Args&&... args)
36+
{
37+
return adoptRef(*new JSScriptSourceProvider(script, std::forward<Args>(args)...));
38+
}
39+
40+
unsigned hash() const override;
41+
StringView source() const override;
42+
const JSC::CachedBytecode* cachedBytecode() const override;
43+
44+
private:
45+
template<typename... Args>
46+
JSScriptSourceProvider(JSScript *script, Args&&... args)
47+
: SourceProvider(std::forward<Args>(args)...)
48+
, m_script(script)
49+
{ }
50+
51+
RetainPtr<JSScript> m_script;
52+
};
53+
54+
#endif // JSC_OBJC_API_ENABLED
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (C) 2019 Apple Inc. All rights reserved.
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions
6+
* are met:
7+
* 1. Redistributions of source code must retain the above copyright
8+
* notice, this list of conditions and the following disclaimer.
9+
* 2. Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
*
13+
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14+
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21+
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24+
*/
25+
26+
#import "config.h"
27+
#import "JSScriptSourceProvider.h"
28+
29+
#if JSC_OBJC_API_ENABLED
30+
31+
#import "JSScriptInternal.h"
32+
33+
unsigned JSScriptSourceProvider::hash() const
34+
{
35+
return [m_script.get() hash];
36+
}
37+
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

Source/JavaScriptCore/API/JSVirtualMachine.mm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,11 @@ + (NSUInteger)setNumberOfFTLCompilerThreads:(NSUInteger)numberOfThreads
297297

298298
#endif // ENABLE(DFG_JIT)
299299

300+
- (JSC::VM&)vm
301+
{
302+
return *toJS(m_group);
303+
}
304+
300305
@end
301306

302307
static void scanExternalObjectGraph(JSC::VM& vm, JSC::SlotVisitor& visitor, void* root, bool lockAcquired)

Source/JavaScriptCore/API/JSVirtualMachineInternal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *);
4646

4747
- (JSContext *)contextForGlobalContextRef:(JSGlobalContextRef)globalContext;
4848
- (void)addContext:(JSContext *)wrapper forGlobalContextRef:(JSGlobalContextRef)globalContext;
49+
- (JSC::VM&)vm;
50+
4951
@end
5052

5153
#endif // defined(__OBJC__)

0 commit comments

Comments
 (0)