Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return from runtime functions instead of taking a pointer where possible #147

Merged
merged 6 commits into from
Jan 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 53 additions & 33 deletions Runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export class SwiftRuntime {
private instance: WebAssembly.Instance | null;
private heap: SwiftRuntimeHeap;
private _closureHeap: SwiftClosureHeap | null;
private version: number = 702;
private version: number = 703;

constructor() {
this.instance = null;
Expand All @@ -154,7 +154,11 @@ export class SwiftRuntime {
const exports = (this.instance
.exports as any) as SwiftRuntimeExportedFunctions;
if (exports.swjs_library_version() != this.version) {
throw new Error(`The versions of JavaScriptKit are incompatible. ${exports.swjs_library_version()} != ${this.version}`);
throw new Error(
`The versions of JavaScriptKit are incompatible. ${exports.swjs_library_version()} != ${
this.version
}`
);
}
}
get closureHeap(): SwiftClosureHeap | null {
Expand Down Expand Up @@ -386,6 +390,7 @@ export class SwiftRuntime {
decodeValue(kind, payload1, payload2)
);
},

swjs_get_prop: (
ref: ref,
name: ref,
Expand All @@ -397,6 +402,7 @@ export class SwiftRuntime {
const result = Reflect.get(obj, readString(name));
writeValue(result, kind_ptr, payload1_ptr, payload2_ptr, false);
},

swjs_set_subscript: (
ref: ref,
index: number,
Expand All @@ -407,6 +413,7 @@ export class SwiftRuntime {
const obj = this.heap.referenceHeap(ref);
Reflect.set(obj, index, decodeValue(kind, payload1, payload2));
},

swjs_get_subscript: (
ref: ref,
index: number,
Expand All @@ -418,12 +425,14 @@ export class SwiftRuntime {
const result = Reflect.get(obj, index);
writeValue(result, kind_ptr, payload1_ptr, payload2_ptr, false);
},

swjs_encode_string: (ref: ref, bytes_ptr_result: pointer) => {
const bytes = textEncoder.encode(this.heap.referenceHeap(ref));
const bytes_ptr = this.heap.retain(bytes);
writeUint32(bytes_ptr_result, bytes_ptr);
return bytes.length;
},

swjs_decode_string: (bytes_ptr: pointer, length: number) => {
const uint8Memory = new Uint8Array(memory().buffer);
const bytes = uint8Memory.subarray(
Expand All @@ -433,10 +442,12 @@ export class SwiftRuntime {
const string = textDecoder.decode(bytes);
return this.heap.retain(string);
},

swjs_load_string: (ref: ref, buffer: pointer) => {
const bytes = this.heap.referenceHeap(ref);
writeString(buffer, bytes);
},

swjs_call_function: (
ref: ref,
argv: pointer,
Expand Down Expand Up @@ -465,6 +476,7 @@ export class SwiftRuntime {
}
writeValue(result, kind_ptr, payload1_ptr, payload2_ptr, false);
},

swjs_call_function_with_this: (
obj_ref: ref,
func_ref: ref,
Expand All @@ -491,33 +503,30 @@ export class SwiftRuntime {
}
writeValue(result, kind_ptr, payload1_ptr, payload2_ptr, false);
},
swjs_create_function: (
host_func_id: number,
func_ref_ptr: pointer
) => {
const func = function () {
return callHostFunction(
host_func_id,
Array.prototype.slice.call(arguments)
);
};
const func_ref = this.heap.retain(func);
this.closureHeap?.alloc(func, func_ref);
writeUint32(func_ref_ptr, func_ref);
swjs_call_new: (ref: ref, argv: pointer, argc: number) => {
const constructor = this.heap.referenceHeap(ref);
const instance = Reflect.construct(
constructor,
decodeValues(argv, argc)
);
return this.heap.retain(instance);
},

swjs_call_throwing_new: (
ref: ref,
argv: pointer,
argc: number,
result_obj: pointer,
exception_kind_ptr: pointer,
exception_payload1_ptr: pointer,
exception_payload2_ptr: pointer
) => {
const obj = this.heap.referenceHeap(ref);
const constructor = this.heap.referenceHeap(ref);
let result: any;
try {
result = Reflect.construct(obj, decodeValues(argv, argc));
result = Reflect.construct(
constructor,
decodeValues(argv, argc)
);
} catch (error) {
writeValue(
error,
Expand All @@ -526,30 +535,40 @@ export class SwiftRuntime {
exception_payload2_ptr,
true
);
return;
return -1;
}
writeUint32(result_obj, this.heap.retain(result));
},
swjs_call_new: (
ref: ref,
argv: pointer,
argc: number,
result_obj: pointer
) => {
const obj = this.heap.referenceHeap(ref);
const result = Reflect.construct(obj, decodeValues(argv, argc));
writeUint32(result_obj, this.heap.retain(result));
writeValue(
null,
exception_kind_ptr,
exception_payload1_ptr,
exception_payload2_ptr,
false
);
return this.heap.retain(result);
},

swjs_instanceof: (obj_ref: ref, constructor_ref: ref) => {
const obj = this.heap.referenceHeap(obj_ref);
const constructor = this.heap.referenceHeap(constructor_ref);
return obj instanceof constructor;
},

swjs_create_function: (host_func_id: number) => {
const func = function () {
return callHostFunction(
host_func_id,
Array.prototype.slice.call(arguments)
);
};
const func_ref = this.heap.retain(func);
this.closureHeap?.alloc(func, func_ref);
return func_ref;
},

swjs_create_typed_array: (
constructor_ref: ref,
elementsPtr: pointer,
length: number,
result_obj: pointer
length: number
) => {
const ArrayType: TypedArray = this.heap.referenceHeap(
constructor_ref
Expand All @@ -560,8 +579,9 @@ export class SwiftRuntime {
length
);
// Call `.slice()` to copy the memory
writeUint32(result_obj, this.heap.retain(array.slice()));
return this.heap.retain(array.slice());
},

swjs_release: (ref: ref) => {
this.heap.release(ref);
},
Expand Down
7 changes: 3 additions & 4 deletions Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,10 @@ public class JSTypedArray<Element>: JSBridgedClass, ExpressibleByArrayLiteral wh
///
/// - Parameter array: The array that will be copied to create a new instance of TypedArray
public convenience init(_ array: [Element]) {
var resultObj = JavaScriptObjectRef()
array.withUnsafeBufferPointer { ptr in
_create_typed_array(Element.typedArrayClass.id, ptr.baseAddress!, Int32(array.count), &resultObj)
let jsArrayRef = array.withUnsafeBufferPointer { ptr in
_create_typed_array(Element.typedArrayClass.id, ptr.baseAddress!, Int32(array.count))
}
self.init(unsafelyWrapping: JSObject(id: resultObj))
self.init(unsafelyWrapping: JSObject(id: jsArrayRef))
}

/// Convenience initializer for `Sequence`.
Expand Down
34 changes: 14 additions & 20 deletions Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,16 @@ public class JSOneshotClosure: JSObject, JSClosureProtocol {
public init(_ body: @escaping ([JSValue]) -> JSValue) {
// 1. Fill `id` as zero at first to access `self` to get `ObjectIdentifier`.
super.init(id: 0)
let objectId = ObjectIdentifier(self)
let funcRef = JavaScriptHostFuncRef(bitPattern: Int32(objectId.hashValue))
// 2. Retain the given body in static storage by `funcRef`.
JSClosure.sharedClosures[funcRef] = (self, {

// 2. Create a new JavaScript function which calls the given Swift function.
hostFuncRef = JavaScriptHostFuncRef(bitPattern: Int32(ObjectIdentifier(self).hashValue))
id = _create_function(hostFuncRef)

// 3. Retain the given body in static storage by `funcRef`.
JSClosure.sharedClosures[hostFuncRef] = (self, {
defer { self.release() }
return body($0)
})
// 3. Create a new JavaScript function which calls the given Swift function.
var objectRef: JavaScriptObjectRef = 0
_create_function(funcRef, &objectRef)

hostFuncRef = funcRef
id = objectRef
}

/// Release this function resource.
Expand Down Expand Up @@ -78,16 +75,13 @@ public class JSClosure: JSObject, JSClosureProtocol {
public init(_ body: @escaping ([JSValue]) -> JSValue) {
// 1. Fill `id` as zero at first to access `self` to get `ObjectIdentifier`.
super.init(id: 0)
let objectId = ObjectIdentifier(self)
let funcRef = JavaScriptHostFuncRef(bitPattern: Int32(objectId.hashValue))
// 2. Retain the given body in static storage by `funcRef`.
Self.sharedClosures[funcRef] = (self, body)
// 3. Create a new JavaScript function which calls the given Swift function.
var objectRef: JavaScriptObjectRef = 0
_create_function(funcRef, &objectRef)

hostFuncRef = funcRef
id = objectRef

// 2. Create a new JavaScript function which calls the given Swift function.
hostFuncRef = JavaScriptHostFuncRef(bitPattern: Int32(ObjectIdentifier(self).hashValue))
id = _create_function(hostFuncRef)

// 3. Retain the given body in static storage by `funcRef`.
Self.sharedClosures[hostFuncRef] = (self, body)
}

#if JAVASCRIPTKIT_WITHOUT_WEAKREFS
Expand Down
6 changes: 1 addition & 5 deletions Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,7 @@ public class JSFunction: JSObject {
public func new(arguments: [ConvertibleToJSValue]) -> JSObject {
arguments.withRawJSValues { rawValues in
rawValues.withUnsafeBufferPointer { bufferPointer in
let argv = bufferPointer.baseAddress
let argc = bufferPointer.count
var resultObj = JavaScriptObjectRef()
_call_new(self.id, argv, Int32(argc), &resultObj)
return JSObject(id: resultObj)
return JSObject(id: _call_new(self.id, bufferPointer.baseAddress!, Int32(bufferPointer.count)))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,9 @@ public class JSThrowingFunction {
var exceptionKind = JavaScriptValueKindAndFlags()
var exceptionPayload1 = JavaScriptPayload1()
var exceptionPayload2 = JavaScriptPayload2()
var resultObj = JavaScriptObjectRef()
_call_throwing_new(
let resultObj = _call_throwing_new(
self.base.id, argv, Int32(argc),
&resultObj, &exceptionKind, &exceptionPayload1, &exceptionPayload2
&exceptionKind, &exceptionPayload1, &exceptionPayload2
)
if exceptionKind.isException {
let exception = RawJSValue(kind: exceptionKind.kind, payload1: exceptionPayload1, payload2: exceptionPayload2)
Expand Down
20 changes: 7 additions & 13 deletions Sources/JavaScriptKit/XcodeSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,31 +63,25 @@ import _CJavaScriptKit
) { fatalError() }
func _call_new(
_: JavaScriptObjectRef,
_: UnsafePointer<RawJSValue>!, _: Int32,
_: UnsafeMutablePointer<JavaScriptObjectRef>!
) { fatalError() }
_: UnsafePointer<RawJSValue>!, _: Int32
) -> JavaScriptObjectRef { fatalError() }
func _call_throwing_new(
_: JavaScriptObjectRef,
_: UnsafePointer<RawJSValue>!, _: Int32,
_: UnsafeMutablePointer<JavaScriptObjectRef>!,
_: UnsafeMutablePointer<JavaScriptValueKindAndFlags>!,
_: UnsafeMutablePointer<JavaScriptPayload1>!,
_: UnsafeMutablePointer<JavaScriptPayload2>!
) { fatalError() }
) -> JavaScriptObjectRef { fatalError() }
func _instanceof(
_: JavaScriptObjectRef,
_: JavaScriptObjectRef
) -> Bool { fatalError() }
func _create_function(
_: JavaScriptHostFuncRef,
_: UnsafePointer<JavaScriptObjectRef>!
) { fatalError() }
func _release(_: JavaScriptObjectRef) { fatalError() }
func _create_function(_: JavaScriptHostFuncRef) -> JavaScriptObjectRef { fatalError() }
func _create_typed_array<T: TypedArrayElement>(
_: JavaScriptObjectRef,
_: UnsafePointer<T>,
_: Int32,
_: UnsafeMutablePointer<JavaScriptObjectRef>!
) { fatalError() }
_: Int32
) -> JavaScriptObjectRef { fatalError() }
func _release(_: JavaScriptObjectRef) { fatalError() }

#endif
2 changes: 1 addition & 1 deletion Sources/_CJavaScriptKit/_CJavaScriptKit.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void swjs_cleanup_host_function_call(void *argv_buffer) {
/// this and `SwiftRuntime.version` in `./Runtime/src/index.ts`.
__attribute__((export_name("swjs_library_version")))
int swjs_library_version(void) {
return 702;
return 703;
}

int _library_features(void);
Expand Down
Loading