diff --git a/Runtime/src/index.ts b/Runtime/src/index.ts index f0639b09c..2fc71c6c8 100644 --- a/Runtime/src/index.ts +++ b/Runtime/src/index.ts @@ -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; @@ -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 { @@ -386,6 +390,7 @@ export class SwiftRuntime { decodeValue(kind, payload1, payload2) ); }, + swjs_get_prop: ( ref: ref, name: ref, @@ -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, @@ -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, @@ -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( @@ -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, @@ -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, @@ -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, @@ -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 @@ -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); }, diff --git a/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift b/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift index 347d74992..5c8294a89 100644 --- a/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift +++ b/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift @@ -44,11 +44,10 @@ public class JSTypedArray: 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`. diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift b/Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift index a8fcd01e9..f8c2632c9 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSClosure.swift @@ -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. @@ -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 diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift b/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift index d5e819f94..d9d66ff94 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift @@ -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))) } } } diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSThrowingFunction.swift b/Sources/JavaScriptKit/FundamentalObjects/JSThrowingFunction.swift index ffd6f6894..0fe96d318 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSThrowingFunction.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSThrowingFunction.swift @@ -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) diff --git a/Sources/JavaScriptKit/XcodeSupport.swift b/Sources/JavaScriptKit/XcodeSupport.swift index 0777e911a..54b7c7671 100644 --- a/Sources/JavaScriptKit/XcodeSupport.swift +++ b/Sources/JavaScriptKit/XcodeSupport.swift @@ -63,31 +63,25 @@ import _CJavaScriptKit ) { fatalError() } func _call_new( _: JavaScriptObjectRef, - _: UnsafePointer!, _: Int32, - _: UnsafeMutablePointer! - ) { fatalError() } + _: UnsafePointer!, _: Int32 + ) -> JavaScriptObjectRef { fatalError() } func _call_throwing_new( _: JavaScriptObjectRef, _: UnsafePointer!, _: Int32, - _: UnsafeMutablePointer!, _: UnsafeMutablePointer!, _: UnsafeMutablePointer!, _: UnsafeMutablePointer! - ) { fatalError() } + ) -> JavaScriptObjectRef { fatalError() } func _instanceof( _: JavaScriptObjectRef, _: JavaScriptObjectRef ) -> Bool { fatalError() } - func _create_function( - _: JavaScriptHostFuncRef, - _: UnsafePointer! - ) { fatalError() } - func _release(_: JavaScriptObjectRef) { fatalError() } + func _create_function(_: JavaScriptHostFuncRef) -> JavaScriptObjectRef { fatalError() } func _create_typed_array( _: JavaScriptObjectRef, _: UnsafePointer, - _: Int32, - _: UnsafeMutablePointer! - ) { fatalError() } + _: Int32 + ) -> JavaScriptObjectRef { fatalError() } + func _release(_: JavaScriptObjectRef) { fatalError() } #endif diff --git a/Sources/_CJavaScriptKit/_CJavaScriptKit.c b/Sources/_CJavaScriptKit/_CJavaScriptKit.c index 98f444fea..383349a8e 100644 --- a/Sources/_CJavaScriptKit/_CJavaScriptKit.c +++ b/Sources/_CJavaScriptKit/_CJavaScriptKit.c @@ -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); diff --git a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h index 6d383b3ea..acdd7d3fa 100644 --- a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h +++ b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h @@ -193,30 +193,28 @@ extern void _call_function_with_this(const JavaScriptObjectRef _this, /// @param ref The target JavaScript constructor to call. /// @param argv A list of `RawJSValue` arguments to apply. /// @param argc The length of `argv``. -/// @param result_obj A result pointer of the constructed object. +/// @returns A reference to the constructed object. __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_call_new"))) -extern void _call_new(const JavaScriptObjectRef ref, - const RawJSValue *argv, const int argc, - JavaScriptObjectRef *result_obj); +extern JavaScriptObjectRef _call_new(const JavaScriptObjectRef ref, + const RawJSValue *argv, const int argc); /// `_call_throwing_new` calls JavaScript object constructor with given arguments list. /// /// @param ref The target JavaScript constructor to call. /// @param argv A list of `RawJSValue` arguments to apply. /// @param argc The length of `argv``. -/// @param result_obj A result pointer of the constructed object. /// @param exception_kind A result pointer of JavaScript value kind of thrown exception. /// @param exception_payload1 A result pointer of first payload of JavaScript value of thrown exception. /// @param exception_payload2 A result pointer of second payload of JavaScript value of thrown exception. +/// @returns A reference to the constructed object. __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_call_throwing_new"))) -extern void _call_throwing_new(const JavaScriptObjectRef ref, - const RawJSValue *argv, const int argc, - JavaScriptObjectRef *result_obj, - JavaScriptValueKindAndFlags *exception_kind, - JavaScriptPayload1 *exception_payload1, - JavaScriptPayload2 *exception_payload2); +extern JavaScriptObjectRef _call_throwing_new(const JavaScriptObjectRef ref, + const RawJSValue *argv, const int argc, + JavaScriptValueKindAndFlags *exception_kind, + JavaScriptPayload1 *exception_payload1, + JavaScriptPayload2 *exception_payload2); /// `_instanceof` acts like JavaScript `instanceof` operator. /// @@ -232,18 +230,10 @@ extern bool _instanceof(const JavaScriptObjectRef obj, /// See also comments on JSFunction.swift /// /// @param host_func_id The target Swift side function called by the created thunk function. -/// @param func_ref_ptr A result pointer of created thunk function. +/// @returns A reference to the newly-created JavaScript thunk function __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_create_function"))) -extern void _create_function(const JavaScriptHostFuncRef host_func_id, - const JavaScriptObjectRef *func_ref_ptr); - -/// Decrements reference count of `ref` retained by `SwiftRuntimeHeap` in JavaScript side. -/// -/// @param ref The target JavaScript object. -__attribute__((__import_module__("javascript_kit"), - __import_name__("swjs_release"))) -extern void _release(const JavaScriptObjectRef ref); +extern JavaScriptObjectRef _create_function(const JavaScriptHostFuncRef host_func_id); /// Instantiate a new `TypedArray` object with given elements /// This is used to provide an efficient way to create `TypedArray`. @@ -251,12 +241,18 @@ extern void _release(const JavaScriptObjectRef ref); /// @param constructor The `TypedArray` constructor. /// @param elements_ptr The elements pointer to initialize. They are assumed to be the same size of `constructor` elements size. /// @param length The length of `elements_ptr` -/// @param result_obj A result pointer of the constructed object. +/// @returns A reference to the constructed typed array __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_create_typed_array"))) -extern void _create_typed_array(const JavaScriptObjectRef constructor, - const void *elements_ptr, const int length, - JavaScriptObjectRef *result_obj); +extern JavaScriptObjectRef _create_typed_array(const JavaScriptObjectRef constructor, + const void *elements_ptr, const int length); + +/// Decrements reference count of `ref` retained by `SwiftRuntimeHeap` in JavaScript side. +/// +/// @param ref The target JavaScript object. +__attribute__((__import_module__("javascript_kit"), + __import_name__("swjs_release"))) +extern void _release(const JavaScriptObjectRef ref); #endif diff --git a/package-lock.json b/package-lock.json index 524ea4c7f..d6c775156 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,14 +9,14 @@ "version": "0.11.1", "license": "MIT", "devDependencies": { - "prettier": "2.1.2", + "prettier": "2.5.1", "typescript": "^4.4.2" } }, "node_modules/prettier": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz", - "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", + "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -41,9 +41,9 @@ }, "dependencies": { "prettier": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.2.tgz", - "integrity": "sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", + "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", "dev": true }, "typescript": { diff --git a/package.json b/package.json index c1a2e8471..3beae47fa 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "build": "npm run build:clean && npm run build:ts", "build:clean": "rm -rf Runtime/lib", "build:ts": "cd Runtime; tsc -b", - "prepublishOnly": "npm run build" + "prepublishOnly": "npm run build", + "format": "prettier --write Runtime/src" }, "keywords": [ "Swift", @@ -31,7 +32,7 @@ "author": "swiftwasm", "license": "MIT", "devDependencies": { - "prettier": "2.1.2", + "prettier": "2.5.1", "typescript": "^4.4.2" } }