Skip to content

Commit 4195ddd

Browse files
committed
[V8] Implement functions
1 parent 4e01bfa commit 4195ddd

File tree

9 files changed

+373
-31
lines changed

9 files changed

+373
-31
lines changed

Package.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ let package = Package(
1919
targets: ["JavaScript"])
2020
],
2121
dependencies: [
22+
.package(
23+
url: "https://github.com/tris-foundation/platform.git",
24+
.branch("master")),
2225
.package(
2326
url: "https://github.com/tris-foundation/test.git",
2427
.branch("master"))
@@ -35,7 +38,7 @@ let package = Package(
3538
dependencies: ["CJavaScriptCore", "JavaScript"]),
3639
.target(
3740
name: "V8",
38-
dependencies: ["CV8", "JavaScript"]),
41+
dependencies: ["CV8", "Platform", "JavaScript"]),
3942
.target(
4043
name: "JavaScript",
4144
dependencies: []),

Sources/CV8/include/wrappers.h

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,29 +18,48 @@
1818
extern "C" {
1919
#endif
2020

21+
// global
22+
void * _Nonnull initialize();
23+
void dispose(void * _Nonnull platform);
24+
// isolate
25+
void * _Nonnull createIsolate();
26+
void disposeIsolate(void * _Nonnull isolate);
27+
// global template
28+
void * _Nonnull createTemplate(void * _Nonnull isolate);
29+
void disposeTemplate(void * _Nonnull context);
30+
// context
31+
void * _Nonnull createContext(void * _Nonnull isolate, void * _Nonnull globalTemplate);
32+
void disposeContext(void * _Nonnull context);
2133

22-
void* initialize();
23-
void dispose(void* platform);
24-
void* createIsolate();
25-
void disposeIsolate(void* isolate);
2634

27-
void* createContext(void* isolate);
28-
void disposeContext(void* context);
35+
// called from JSValue's destructor
36+
void disposeValue(void * _Nonnull pointer);
2937

30-
void* evaluate(void* isolatePtr, void* contextPtr, const char* scriptPtr, void** exception);
31-
void disposeValue(void* pointer);
38+
void * _Nullable evaluate(void * _Nonnull isolatePtr, void * _Nonnull contextPtr, const char* _Nonnull scriptPtr, void * _Nullable* _Nonnull exception);
3239

33-
int getUtf8StringLength(void* isolatePtr, void* valuePtr);
34-
void copyUtf8String(void* isolatePtr, void* valuePtr, void* buffer, int count);
40+
int getUtf8StringLength(void * _Nonnull isolatePtr, void * _Nonnull valuePtr);
41+
void copyUtf8String(void * _Nonnull isolatePtr, void * _Nonnull valuePtr, void * _Nonnull buffer, int count);
3542

36-
int64_t valueToInt(void* isolatePtr, void* valuePtr);
43+
int64_t valueToInt(void * _Nonnull isolatePtr, void * _Nonnull valuePtr);
3744

38-
bool isNull(void* isolatePtr, void* valuePtr);
39-
bool isUndefined(void* isolatePtr, void* valuePtr);
40-
bool isBoolean(void* isolatePtr, void* valuePtr);
41-
bool isNumber(void* isolatePtr, void* valuePtr);
42-
bool isString(void* isolatePtr, void* valuePtr);
43-
bool isObject(void* isolatePtr, void* valuePtr);
45+
46+
bool isNull(void * _Nonnull isolatePtr, void * _Nonnull valuePtr);
47+
bool isUndefined(void * _Nonnull isolatePtr, void * _Nonnull valuePtr);
48+
bool isBoolean(void * _Nonnull isolatePtr, void * _Nonnull valuePtr);
49+
bool isNumber(void * _Nonnull isolatePtr, void * _Nonnull valuePtr);
50+
bool isString(void * _Nonnull isolatePtr, void * _Nonnull valuePtr);
51+
bool isObject(void * _Nonnull isolatePtr, void * _Nonnull valuePtr);
52+
53+
54+
void (* _Nullable swiftCallback)(void * _Nonnull isolate, int32_t id, void * _Nullable * _Nonnull arguments, int32_t count, void * _Nonnull returnValue);
55+
void createFunction(void * _Nonnull isolatePtr, void * _Nonnull contextPtr, void * _Nonnull templatePtr, const char* _Nonnull namePtr, int32_t id);
56+
57+
void setReturnValueUndefined(void * _Nonnull isolatePtr, void * _Nonnull returnValuePtr);
58+
void setReturnValueNull(void * _Nonnull isolatePtr, void * _Nonnull returnValuePtr);
59+
void setReturnValueBoolean(void * _Nonnull isolatePtr, void * _Nonnull returnValuePtr, bool value);
60+
void setReturnValueNumber(void * _Nonnull isolatePtr, void * _Nonnull returnValuePtr, double value);
61+
void setReturnValueString(void * _Nonnull isolatePtr, void * _Nonnull returnValuePtr, const char* _Nonnull utf8);
62+
void setReturnValueEmptyString(void * _Nonnull isolatePtr, void * _Nonnull returnValuePtr);
4463

4564

4665
#ifdef __cplusplus

Sources/CV8/wrappers.cpp

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <string.h> // memset, memcpy
1313
#include <libplatform/libplatform.h>
1414
#include <v8.h>
15+
#include "wrappers.h"
1516

1617
using namespace v8;
1718

@@ -62,7 +63,7 @@ class GlobalValue {
6263
extern "C" {
6364
ArrayBufferAllocator bufferAllocator;
6465

65-
const void* initialize() {
66+
void* initialize() {
6667
V8::InitializeICU();
6768
auto platform = platform::CreateDefaultPlatform();
6869
V8::InitializePlatform(platform);
@@ -76,7 +77,7 @@ extern "C" {
7677
delete reinterpret_cast<Platform*>(platform);;
7778
}
7879

79-
const void* createIsolate() {
80+
void* createIsolate() {
8081
Isolate::CreateParams create_params;
8182
create_params.array_buffer_allocator = &bufferAllocator;
8283
return Isolate::New(create_params);
@@ -86,12 +87,29 @@ extern "C" {
8687
reinterpret_cast<Isolate*>(isolate)->Dispose();
8788
}
8889

89-
void* createContext(void* isolatePtr) {
90+
void* createTemplate(void* isolatePtr) {
9091
auto isolate = reinterpret_cast<Isolate*>(isolatePtr);
9192
Locker isolateLocker(isolate);
9293
Isolate::Scope isolate_scope(isolate);
9394
HandleScope handle_scope(isolate);
94-
Local<Context> context = Context::New(isolate);
95+
Local<ObjectTemplate> globalObject = ObjectTemplate::New(isolate);
96+
return new Global<ObjectTemplate>(isolate, globalObject);
97+
}
98+
99+
void disposeTemplate(void* context) {
100+
delete reinterpret_cast<Global<ObjectTemplate>*>(context);
101+
}
102+
103+
void* createContext(void* isolatePtr, void* templatePtr) {
104+
auto isolate = reinterpret_cast<Isolate*>(isolatePtr);
105+
auto globalGlobalTemplate = reinterpret_cast<Global<ObjectTemplate>*>(templatePtr);
106+
107+
Locker isolateLocker(isolate);
108+
Isolate::Scope isolate_scope(isolate);
109+
HandleScope handle_scope(isolate);
110+
111+
auto globalTemplate = globalGlobalTemplate->Get(isolate);
112+
Local<Context> context = Context::New(isolate, NULL, globalTemplate);
95113
return new Global<Context>(isolate, context);
96114
}
97115

@@ -173,4 +191,77 @@ extern "C" {
173191
GlobalValue scoped(isolate, value);
174192
return scoped->IsObject();
175193
}
194+
195+
// MARK: functions
196+
197+
static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
198+
int32_t id = args.Data()->Int32Value();
199+
200+
Isolate* isolate = args.GetIsolate();
201+
HandleScope scope(isolate);
202+
203+
void* values[args.Length()];
204+
for(int i = 0; i < args.Length(); i++) {
205+
values[i] = new Global<Value>(isolate, args[i]);
206+
}
207+
auto returnValue = args.GetReturnValue();
208+
swiftCallback(isolate, id, values, args.Length(), &returnValue);
209+
}
210+
211+
void createFunction(void* isolatePtr, void* contextPtr, void* templatePtr, const char* namePtr, int32_t id) {
212+
auto isolate = reinterpret_cast<Isolate*>(isolatePtr);
213+
auto globalContext = reinterpret_cast<Global<Context>*>(contextPtr);
214+
auto globalGlobalTemplate = reinterpret_cast<Global<ObjectTemplate>*>(templatePtr);
215+
216+
Locker isolateLocker(isolate);
217+
Isolate::Scope isolate_scope(isolate);
218+
HandleScope handle_scope(isolate);
219+
220+
auto data = Integer::New(isolate, id);
221+
auto globalTemplate = globalGlobalTemplate->Get(isolate);
222+
globalTemplate->Set(
223+
String::NewFromUtf8(isolate, namePtr),
224+
FunctionTemplate::New(isolate, callback, data));
225+
226+
auto context = globalContext->Get(isolate);
227+
auto globalObject = context->Global();
228+
context->DetachGlobal();
229+
230+
auto newContext = Context::New(isolate, NULL, globalTemplate, globalObject);
231+
232+
globalContext->Reset(isolate, newContext);
233+
}
234+
235+
void setReturnValueUndefined(void* isolatePtr, void* returnValuePtr) {
236+
auto returnValue = reinterpret_cast<ReturnValue<Value>*>(returnValuePtr);
237+
returnValue->SetUndefined();
238+
}
239+
240+
void setReturnValueNull(void* isolatePtr, void* returnValuePtr) {
241+
auto returnValue = reinterpret_cast<ReturnValue<Value>*>(returnValuePtr);
242+
returnValue->SetNull();
243+
}
244+
245+
void setReturnValueBoolean(void* isolatePtr, void* returnValuePtr, bool value) {
246+
auto returnValue = reinterpret_cast<ReturnValue<Value>*>(returnValuePtr);
247+
returnValue->Set(value);
248+
}
249+
250+
void setReturnValueNumber(void* isolatePtr, void* returnValuePtr, double value) {
251+
auto returnValue = reinterpret_cast<ReturnValue<Value>*>(returnValuePtr);
252+
returnValue->Set(value);
253+
}
254+
255+
void setReturnValueString(void* isolatePtr, void* returnValuePtr, const char* utf8) {
256+
auto isolate = reinterpret_cast<Isolate*>(isolatePtr);
257+
auto returnValue = reinterpret_cast<ReturnValue<Value>*>(returnValuePtr);
258+
259+
auto string = String::NewFromUtf8(isolate, utf8);
260+
returnValue->Set(string);
261+
}
262+
263+
void setReturnValueEmptyString(void* isolatePtr, void* returnValuePtr) {
264+
auto returnValue = reinterpret_cast<ReturnValue<Value>*>(returnValuePtr);
265+
returnValue->SetEmptyString();
266+
}
176267
}

Sources/V8/JSContext+closure.swift

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright 2017 Tris Foundation and the project authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License
6+
*
7+
* See LICENSE.txt in the project root for license information
8+
* See CONTRIBUTORS.txt for the list of the project authors
9+
*/
10+
11+
import CV8
12+
import Platform
13+
@_exported import JavaScript
14+
15+
private var functions: [Int32: ([JSValue]) throws -> Value] = [:]
16+
17+
extension JSContext {
18+
func generateId() -> Int32 {
19+
var id: Int32 = 0
20+
repeat {
21+
id = Int32(bitPattern: arc4random())
22+
} while functions[id] != nil
23+
return id
24+
}
25+
26+
public func createFunction(
27+
name: String,
28+
_ body: @escaping ([JSValue]) throws -> Value) throws
29+
{
30+
let id = generateId()
31+
CV8.createFunction(isolate, context, template, name, id)
32+
functions[id] = body
33+
}
34+
35+
public func createFunction(
36+
name: String,
37+
_ body: @escaping ([JSValue]) throws -> Void) throws
38+
{
39+
let id = generateId()
40+
CV8.createFunction(isolate, context, template, name, id)
41+
functions[id] = { arguments in
42+
try body(arguments)
43+
return .undefined
44+
}
45+
}
46+
47+
public func createFunction(
48+
name: String,
49+
_ body: @escaping () throws -> Value) throws
50+
{
51+
return try createFunction(name: name) { _ in
52+
return try body()
53+
}
54+
}
55+
56+
public func createFunction(
57+
name: String,
58+
_ body: @escaping () throws -> Void) throws
59+
{
60+
try createFunction(name: name) { _ in
61+
try body()
62+
}
63+
}
64+
}
65+
66+
extension Array where Element == JSValue {
67+
init(
68+
isolate: UnsafeMutableRawPointer,
69+
pointer: UnsafeMutablePointer<UnsafeMutableRawPointer?>?,
70+
count: Int
71+
) {
72+
var arguments = [JSValue]()
73+
for i in 0..<count {
74+
let next = pointer!.advanced(by: i).pointee!
75+
arguments.append(JSValue(isolate: isolate, pointer: next))
76+
}
77+
self = arguments
78+
}
79+
}
80+
81+
func functionWrapper(
82+
isolate: UnsafeMutableRawPointer,
83+
functionId: Int32,
84+
arguments: UnsafeMutablePointer<UnsafeMutableRawPointer?>,
85+
argumentsCount: Int32,
86+
returnValue: UnsafeMutableRawPointer)
87+
{
88+
guard let body = functions[functionId] else {
89+
fatalError("swift error: unregistered function")
90+
}
91+
do {
92+
let arguments = [JSValue](
93+
isolate: isolate,
94+
pointer: arguments,
95+
count: Int(argumentsCount))
96+
let result = try body(arguments)
97+
switch result {
98+
case .undefined: setReturnValueUndefined(isolate, returnValue)
99+
case .null: setReturnValueNull(isolate, returnValue)
100+
case .bool(let value): setReturnValueBoolean(isolate, returnValue, value)
101+
case .number(let value): setReturnValueNumber(isolate, returnValue, value)
102+
case .string(let value) where value.isEmpty: setReturnValueEmptyString(isolate, returnValue)
103+
case .string(let value): setReturnValueString(isolate, returnValue, value)
104+
}
105+
} catch {
106+
fatalError("\(error)")
107+
}
108+
}

Sources/V8/JSContext.swift

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,19 @@ import CV8
1212
import JavaScript
1313

1414
public class JSContext {
15-
let runtime: JSRuntime
16-
let context: UnsafeMutableRawPointer?
15+
let isolate: UnsafeMutableRawPointer
16+
let context: UnsafeMutableRawPointer
17+
var template: UnsafeMutableRawPointer
1718

1819
public init(_ runtime: JSRuntime = JSRuntime.global) {
19-
self.runtime = runtime
20-
self.context = CV8.createContext(runtime.isolate)
20+
self.isolate = runtime.isolate
21+
let template = CV8.createTemplate(runtime.isolate)
22+
self.context = CV8.createContext(runtime.isolate, template)
23+
self.template = template
2124
}
2225

2326
deinit {
27+
CV8.disposeTemplate(template)
2428
CV8.disposeContext(context)
2529
}
2630
}
@@ -30,15 +34,16 @@ struct JSError: Error, CustomStringConvertible {
3034
}
3135

3236
extension JSContext: JavaScript.JSContext {
37+
@discardableResult
3338
public func evaluate(_ script: String) throws -> JSValue {
3439
var exception: UnsafeMutableRawPointer?
35-
guard let pointer = CV8.evaluate(runtime.isolate, context, script, &exception) else {
40+
guard let pointer = CV8.evaluate(isolate, context, script, &exception) else {
3641
guard let exception = exception else {
3742
fatalError("exception pointer is nil")
3843
}
39-
let value = JSValue(pointer: exception, isolate: runtime.isolate)
44+
let value = JSValue(isolate: isolate, pointer: exception)
4045
throw JSError(description: value.description)
4146
}
42-
return JSValue(pointer: pointer, isolate: runtime.isolate)
47+
return JSValue(isolate: isolate, pointer: pointer)
4348
}
4449
}

Sources/V8/JSRuntime.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class JSRuntime {
2222
public required init() {
2323
self.platform = initialize()
2424
self.isolate = createIsolate()
25+
CV8.swiftCallback = functionWrapper
2526
}
2627

2728
deinit {

Sources/V8/JSValue.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ public class JSValue {
1515
let isolate: UnsafeMutableRawPointer
1616
let pointer: UnsafeMutableRawPointer
1717

18-
init(pointer: UnsafeMutableRawPointer, isolate: UnsafeMutableRawPointer) {
19-
self.pointer = pointer
18+
init(isolate: UnsafeMutableRawPointer, pointer: UnsafeMutableRawPointer) {
2019
self.isolate = isolate
20+
self.pointer = pointer
2121
}
2222

2323
deinit {

0 commit comments

Comments
 (0)