From fa93b9165b909f5e3409e9b91347cd1c02f2aa78 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 09:30:29 -0400 Subject: [PATCH 01/35] Initial BigInt support --- Runtime/src/index.ts | 20 ++++++++++++++ Runtime/src/js-value.ts | 24 +++++++++++------ Runtime/src/memory.ts | 9 ++++++- Runtime/src/types.ts | 3 +++ Runtime/tsconfig.json | 4 +-- .../JavaScriptKit/ConvertibleToJSValue.swift | 5 ++++ .../FundamentalObjects/JSBigInt.swift | 27 +++++++++++++++++++ .../FundamentalObjects/JSSymbol.swift | 8 ++++++ Sources/JavaScriptKit/JSValue.swift | 16 +++++++++-- Sources/JavaScriptKit/XcodeSupport.swift | 2 ++ .../_CJavaScriptKit/include/_CJavaScriptKit.h | 20 +++++++++++++- 11 files changed, 124 insertions(+), 14 deletions(-) create mode 100644 Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift diff --git a/Runtime/src/index.ts b/Runtime/src/index.ts index 15fc570e..b1f81669 100644 --- a/Runtime/src/index.ts +++ b/Runtime/src/index.ts @@ -409,5 +409,25 @@ export class SwiftRuntime { swjs_release: (ref: ref) => { this.memory.release(ref); }, + + swjs_i64_to_bigint: (value: bigint, signed: number) => { + return this.memory.retain( + signed ? value : BigInt.asUintN(64, value) + ); + }, + swjs_bigint_to_i64: (ref: ref, signed: number) => { + const object = this.memory.getObject(ref); + if (typeof object !== "bigint") { + throw new Error(`Expected a BigInt, but got ${typeof object}`); + } + if (signed) { + return object; + } else { + if (object < 0n) { + return 0n; + } + return BigInt.asIntN(64, object); + } + }, }; } diff --git a/Runtime/src/js-value.ts b/Runtime/src/js-value.ts index 67ac5d46..25baba05 100644 --- a/Runtime/src/js-value.ts +++ b/Runtime/src/js-value.ts @@ -11,6 +11,7 @@ export enum Kind { Undefined = 5, Function = 6, Symbol = 7, + BigInt = 8, } export const decode = ( @@ -33,6 +34,7 @@ export const decode = ( case Kind.String: case Kind.Object: case Kind.Function: + case Kind.BigInt: return memory.getObject(payload1); case Kind.Null: @@ -73,6 +75,12 @@ export const write = ( memory.writeUint32(kind_ptr, exceptionBit | Kind.Null); return; } + + const writeRef = (type: Kind) => { + memory.writeUint32(kind_ptr, exceptionBit | type); + memory.writeUint32(payload1_ptr, memory.retain(value)); + }; + switch (typeof value) { case "boolean": { memory.writeUint32(kind_ptr, exceptionBit | Kind.Boolean); @@ -85,8 +93,7 @@ export const write = ( break; } case "string": { - memory.writeUint32(kind_ptr, exceptionBit | Kind.String); - memory.writeUint32(payload1_ptr, memory.retain(value)); + writeRef(Kind.String); break; } case "undefined": { @@ -94,18 +101,19 @@ export const write = ( break; } case "object": { - memory.writeUint32(kind_ptr, exceptionBit | Kind.Object); - memory.writeUint32(payload1_ptr, memory.retain(value)); + writeRef(Kind.Object); break; } case "function": { - memory.writeUint32(kind_ptr, exceptionBit | Kind.Function); - memory.writeUint32(payload1_ptr, memory.retain(value)); + writeRef(Kind.Function); break; } case "symbol": { - memory.writeUint32(kind_ptr, exceptionBit | Kind.Symbol); - memory.writeUint32(payload1_ptr, memory.retain(value)); + writeRef(Kind.Symbol); + break; + } + case "bigint": { + writeRef(Kind.BigInt); break; } default: diff --git a/Runtime/src/memory.ts b/Runtime/src/memory.ts index 3c010a5f..29f82762 100644 --- a/Runtime/src/memory.ts +++ b/Runtime/src/memory.ts @@ -17,13 +17,20 @@ export class Memory { bytes = () => new Uint8Array(this.rawMemory.buffer); dataView = () => new DataView(this.rawMemory.buffer); - writeBytes = (ptr: pointer, bytes: Uint8Array) => this.bytes().set(bytes, ptr); + writeBytes = (ptr: pointer, bytes: Uint8Array) => + this.bytes().set(bytes, ptr); readUint32 = (ptr: pointer) => this.dataView().getUint32(ptr, true); + readUint64 = (ptr: pointer) => this.dataView().getBigUint64(ptr, true); + readInt64 = (ptr: pointer) => this.dataView().getBigInt64(ptr, true); readFloat64 = (ptr: pointer) => this.dataView().getFloat64(ptr, true); writeUint32 = (ptr: pointer, value: number) => this.dataView().setUint32(ptr, value, true); + writeUint64 = (ptr: pointer, value: bigint) => + this.dataView().setBigUint64(ptr, value, true); + writeInt64 = (ptr: pointer, value: bigint) => + this.dataView().setBigInt64(ptr, value, true); writeFloat64 = (ptr: pointer, value: number) => this.dataView().setFloat64(ptr, value, true); } diff --git a/Runtime/src/types.ts b/Runtime/src/types.ts index b291cd91..c19c43e2 100644 --- a/Runtime/src/types.ts +++ b/Runtime/src/types.ts @@ -2,6 +2,7 @@ import * as JSValue from "./js-value"; export type ref = number; export type pointer = number; +export type bool = number; export interface ExportedFunctions { swjs_library_version(): number; @@ -102,6 +103,8 @@ export interface ImportedFunctions { ): number; swjs_load_typed_array(ref: ref, buffer: pointer): void; swjs_release(ref: number): void; + swjs_i64_to_bigint(value: bigint, signed: bool): ref; + swjs_bigint_to_i64(ref: ref, signed: bool): bigint; } export enum LibraryFeatures { diff --git a/Runtime/tsconfig.json b/Runtime/tsconfig.json index 8fa8e650..73479185 100644 --- a/Runtime/tsconfig.json +++ b/Runtime/tsconfig.json @@ -7,8 +7,8 @@ "noEmit": true, "rootDir": "src", "strict": true, - "target": "es2017", - "lib": ["es2017", "DOM", "ESNext.WeakRef"], + "target": "es2020", + "lib": ["es2020", "DOM", "ESNext.WeakRef"], "skipLibCheck": true }, "include": ["src/**/*"], diff --git a/Sources/JavaScriptKit/ConvertibleToJSValue.swift b/Sources/JavaScriptKit/ConvertibleToJSValue.swift index 83680ad0..f024fb0d 100644 --- a/Sources/JavaScriptKit/ConvertibleToJSValue.swift +++ b/Sources/JavaScriptKit/ConvertibleToJSValue.swift @@ -209,6 +209,8 @@ extension RawJSValue: ConvertibleToJSValue { return .function(JSFunction(id: UInt32(payload1))) case .symbol: return .symbol(JSSymbol(id: UInt32(payload1))) + case .bigInt: + return .bigInt(JSBigInt(id: UInt32(payload1))) } } } @@ -243,6 +245,9 @@ extension JSValue { case let .symbol(symbolRef): kind = .symbol payload1 = JavaScriptPayload1(symbolRef.id) + case let .bigInt(bigIntRef): + kind = .bigInt + payload1 = JavaScriptPayload1(bigIntRef.id) } let rawValue = RawJSValue(kind: kind, payload1: payload1, payload2: payload2) return body(rawValue) diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift new file mode 100644 index 00000000..c48e032d --- /dev/null +++ b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift @@ -0,0 +1,27 @@ +import _CJavaScriptKit + +public class JSBigInt: JSObject { + var int64Value: Int64 { _bigint_to_i64(id, true) } + var uInt64Value: UInt64 { + UInt64(bitPattern: _bigint_to_i64(id, false)) + } + + public convenience init(_ value: Int64) { + self.init(id: _i64_to_bigint(value, true)) + } + public convenience init(_ value: UInt64) { + self.init(id: _i64_to_bigint(Int64(bitPattern: value), false)) + } + + public override init(id: JavaScriptObjectRef) { + super.init(id: id) + } + + override public class func construct(from value: JSValue) -> Self? { + return value.bigInt as? Self + } + + override public var jsValue: JSValue { + .bigInt(self) + } +} diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSSymbol.swift b/Sources/JavaScriptKit/FundamentalObjects/JSSymbol.swift index 3ec1b290..a0dea393 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSSymbol.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSSymbol.swift @@ -37,6 +37,14 @@ public class JSSymbol: JSObject { public static func key(for symbol: JSSymbol) -> String? { Symbol.keyFor!(symbol).string } + + override public class func construct(from value: JSValue) -> Self? { + return value.symbol as? Self + } + + override public var jsValue: JSValue { + .symbol(self) + } } extension JSSymbol { diff --git a/Sources/JavaScriptKit/JSValue.swift b/Sources/JavaScriptKit/JSValue.swift index b001dc7a..8fdd2cd3 100644 --- a/Sources/JavaScriptKit/JSValue.swift +++ b/Sources/JavaScriptKit/JSValue.swift @@ -11,6 +11,7 @@ public enum JSValue: Equatable { case undefined case function(JSFunction) case symbol(JSSymbol) + case bigInt(JSBigInt) /// Returns the `Bool` value of this JS value if its type is boolean. /// If not, returns `nil`. @@ -68,6 +69,8 @@ public enum JSValue: Equatable { } } + /// Returns the `JSSymbol` of this JS value if its type is function. + /// If not, returns `nil`. public var symbol: JSSymbol? { switch self { case let .symbol(symbol): return symbol @@ -75,6 +78,15 @@ public enum JSValue: Equatable { } } + /// Returns the `JSBigInt` of this JS value if its type is function. + /// If not, returns `nil`. + public var bigInt: JSBigInt? { + switch self { + case let .bigInt(bigInt): return bigInt + default: return nil + } + } + /// Returns the `true` if this JS value is null. /// If not, returns `false`. public var isNull: Bool { @@ -233,7 +245,7 @@ public extension JSValue { /// - Returns: The result of `instanceof` in the JavaScript environment. func isInstanceOf(_ constructor: JSFunction) -> Bool { switch self { - case .boolean, .string, .number, .null, .undefined, .symbol: + case .boolean, .string, .number, .null, .undefined, .symbol, .bigInt: return false case let .object(ref): return ref.isInstanceOf(constructor) @@ -253,7 +265,7 @@ extension JSValue: CustomStringConvertible { case let .number(number): return number.description case let .object(object), let .function(object as JSObject), - .symbol(let object as JSObject): + let .symbol(object as JSObject), let .bigInt(object as JSObject): return object.toString!().fromJSValue()! case .null: return "null" diff --git a/Sources/JavaScriptKit/XcodeSupport.swift b/Sources/JavaScriptKit/XcodeSupport.swift index 013c49e2..fd8a58be 100644 --- a/Sources/JavaScriptKit/XcodeSupport.swift +++ b/Sources/JavaScriptKit/XcodeSupport.swift @@ -102,5 +102,7 @@ import _CJavaScriptKit _: UnsafeMutablePointer! ) { fatalError() } func _release(_: JavaScriptObjectRef) { fatalError() } + func _i64_to_bigint(_: Int64, _: Bool) -> JavaScriptObjectRef { fatalError() } + func _bigint_to_i64(_: JavaScriptObjectRef, _: Bool) -> Int64 { fatalError() } #endif diff --git a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h index daf40514..c490d313 100644 --- a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h +++ b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h @@ -22,6 +22,7 @@ typedef enum __attribute__((enum_extensibility(closed))) { JavaScriptValueKindUndefined = 5, JavaScriptValueKindFunction = 6, JavaScriptValueKindSymbol = 7, + JavaScriptValueKindBigInt = 8, } JavaScriptValueKind; typedef struct { @@ -61,7 +62,7 @@ typedef double JavaScriptPayload2; /// payload1: the target `JavaScriptHostFuncRef` /// payload2: 0 /// -/// For symbol value: +/// For symbol and bigint values: /// payload1: `JavaScriptObjectRef` /// payload2: 0 /// @@ -300,6 +301,23 @@ __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_release"))) extern void _release(const JavaScriptObjectRef ref); + +/// Converts the provided Int64 or UInt64 to a BigInt. +/// +/// @param value The value to convert. +/// @param is_signed Whether to treat the value as a signed integer or not. +__attribute__((__import_module__("javascript_kit"), + __import_name__("swjs_i64_to_bigint"))) +extern JavaScriptObjectRef _i64_to_bigint(const int64_t value, bool is_signed); + +/// Converts the provided BigInt to an Int64 or UInt64. +/// +/// @param ref The target JavaScript object. +/// @param is_signed Whether to treat the return value as a signed integer or not. +__attribute__((__import_module__("javascript_kit"), + __import_name__("swjs_bigint_to_i64"))) +extern int64_t _bigint_to_i64(const JavaScriptObjectRef ref, bool is_signed); + #endif #endif /* _CJavaScriptKit_h */ From 3ca153909fa89b06ffa7fc851f8ae267d2f97776 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 09:32:26 -0400 Subject: [PATCH 02/35] Switch to const enums --- Runtime/src/js-value.ts | 2 +- Runtime/src/types.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Runtime/src/js-value.ts b/Runtime/src/js-value.ts index 25baba05..9e7b4573 100644 --- a/Runtime/src/js-value.ts +++ b/Runtime/src/js-value.ts @@ -1,7 +1,7 @@ import { Memory } from "./memory"; import { pointer } from "./types"; -export enum Kind { +export const enum Kind { Invalid = -1, Boolean = 0, String = 1, diff --git a/Runtime/src/types.ts b/Runtime/src/types.ts index c19c43e2..3a132bdd 100644 --- a/Runtime/src/types.ts +++ b/Runtime/src/types.ts @@ -107,7 +107,7 @@ export interface ImportedFunctions { swjs_bigint_to_i64(ref: ref, signed: bool): bigint; } -export enum LibraryFeatures { +export const enum LibraryFeatures { WeakRefs = 1 << 0, } From bf3bac3e1d25560cad02ec828a1ab15b4e61ec0d Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 10:01:36 -0400 Subject: [PATCH 03/35] Add JSBigInt/clamped method, fix overload --- .../FundamentalObjects/JSBigInt.swift | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift index c48e032d..0e7d42c3 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift @@ -1,15 +1,19 @@ import _CJavaScriptKit -public class JSBigInt: JSObject { - var int64Value: Int64 { _bigint_to_i64(id, true) } - var uInt64Value: UInt64 { +private let constructor = JSObject.global.BigInt.function! + +public final class JSBigInt: JSObject { + public var int64Value: Int64 { + _bigint_to_i64(id, true) + } + public var uInt64Value: UInt64 { UInt64(bitPattern: _bigint_to_i64(id, false)) } public convenience init(_ value: Int64) { self.init(id: _i64_to_bigint(value, true)) } - public convenience init(_ value: UInt64) { + public convenience init(unsigned value: UInt64) { self.init(id: _i64_to_bigint(Int64(bitPattern: value), false)) } @@ -24,4 +28,12 @@ public class JSBigInt: JSObject { override public var jsValue: JSValue { .bigInt(self) } + + public func clamped(bitSize: Int, signed: Bool) -> JSBigInt { + if signed { + return constructor.asIntN!(bitSize, self).bigInt! + } else { + return constructor.asUintN!(bitSize, self).bigInt! + } + } } From 8c02c79f3da19f6c3c3d79ef01473899ecc5e593 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 10:10:06 -0400 Subject: [PATCH 04/35] Convert BigInts into Swift ints automatically --- .../ConstructibleFromJSValue.swift | 84 ++++++------------- 1 file changed, 24 insertions(+), 60 deletions(-) diff --git a/Sources/JavaScriptKit/ConstructibleFromJSValue.swift b/Sources/JavaScriptKit/ConstructibleFromJSValue.swift index 063597a9..b5151b37 100644 --- a/Sources/JavaScriptKit/ConstructibleFromJSValue.swift +++ b/Sources/JavaScriptKit/ConstructibleFromJSValue.swift @@ -20,80 +20,44 @@ extension String: ConstructibleFromJSValue { } } -extension Double: ConstructibleFromJSValue { - public static func construct(from value: JSValue) -> Double? { - return value.number - } -} - -extension Float: ConstructibleFromJSValue { - public static func construct(from value: JSValue) -> Float? { - return value.number.map(Float.init) - } -} - -extension Int: ConstructibleFromJSValue { - public static func construct(from value: JSValue) -> Self? { - value.number.map(Self.init) - } -} - -extension Int8: ConstructibleFromJSValue { - public static func construct(from value: JSValue) -> Self? { - value.number.map(Self.init) - } -} - -extension Int16: ConstructibleFromJSValue { - public static func construct(from value: JSValue) -> Self? { - value.number.map(Self.init) - } -} - -extension Int32: ConstructibleFromJSValue { - public static func construct(from value: JSValue) -> Self? { - value.number.map(Self.init) - } -} - -extension Int64: ConstructibleFromJSValue { - public static func construct(from value: JSValue) -> Self? { - value.number.map(Self.init) +extension JSString: ConstructibleFromJSValue { + public static func construct(from value: JSValue) -> JSString? { + value.jsString } } -extension UInt: ConstructibleFromJSValue { +extension BinaryFloatingPoint where Self: ConstructibleFromJSValue { public static func construct(from value: JSValue) -> Self? { value.number.map(Self.init) } } +extension Double: ConstructibleFromJSValue {} +extension Float: ConstructibleFromJSValue {} -extension UInt8: ConstructibleFromJSValue { - public static func construct(from value: JSValue) -> Self? { - value.number.map(Self.init) +extension SignedInteger where Self: ConstructibleFromJSValue { + public init(_ bigInt: JSBigInt) { + self.init(bigInt.int64Value) } -} - -extension UInt16: ConstructibleFromJSValue { public static func construct(from value: JSValue) -> Self? { - value.number.map(Self.init) + value.bigInt.map(Self.init) ?? value.number.map(Self.init) } } +extension Int: ConstructibleFromJSValue {} +extension Int8: ConstructibleFromJSValue {} +extension Int16: ConstructibleFromJSValue {} +extension Int32: ConstructibleFromJSValue {} +extension Int64: ConstructibleFromJSValue {} -extension UInt32: ConstructibleFromJSValue { - public static func construct(from value: JSValue) -> Self? { - value.number.map(Self.init) +extension UnsignedInteger where Self: ConstructibleFromJSValue { + public init(_ bigInt: JSBigInt) { + self.init(bigInt.uInt64Value) } -} - -extension UInt64: ConstructibleFromJSValue { public static func construct(from value: JSValue) -> Self? { - value.number.map(Self.init) - } -} - -extension JSString: ConstructibleFromJSValue { - public static func construct(from value: JSValue) -> JSString? { - value.jsString + value.bigInt.map(Self.init) ?? value.number.map(Self.init) } } +extension UInt: ConstructibleFromJSValue {} +extension UInt8: ConstructibleFromJSValue {} +extension UInt16: ConstructibleFromJSValue {} +extension UInt32: ConstructibleFromJSValue {} +extension UInt64: ConstructibleFromJSValue {} From 814774bc94eb04828b0cdaaf037efcdfbe5a7bf9 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 10:19:09 -0400 Subject: [PATCH 05/35] Add support for JAVASCRIPTKIT_WITHOUT_BIGINTS --- Runtime/src/index.ts | 11 +++++++++++ Runtime/src/types.ts | 1 + .../JavaScriptKit/ConstructibleFromJSValue.swift | 12 ++++++++++++ Sources/JavaScriptKit/ConvertibleToJSValue.swift | 14 ++++++++++++++ Sources/JavaScriptKit/Features.swift | 4 ++++ .../FundamentalObjects/JSBigInt.swift | 2 ++ Sources/JavaScriptKit/JSValue.swift | 16 ++++++++++++++-- Sources/JavaScriptKit/XcodeSupport.swift | 2 ++ .../_CJavaScriptKit/include/_CJavaScriptKit.h | 2 ++ 9 files changed, 62 insertions(+), 2 deletions(-) diff --git a/Runtime/src/index.ts b/Runtime/src/index.ts index b1f81669..29230f3c 100644 --- a/Runtime/src/index.ts +++ b/Runtime/src/index.ts @@ -35,6 +35,17 @@ export class SwiftRuntime { }` ); } + + if (this.exports.swjs_library_features() & LibraryFeatures.BigInts) { + if (typeof BigInt === "undefined") { + throw new Error( + "The Swift part of JavaScriptKit was configured to require " + + "the availability of JavaScript BigInts. Please build " + + "with `-Xswiftc -DJAVASCRIPTKIT_WITHOUT_BIGINTS` to " + + "disable features that use BigInts." + ); + } + } } private get instance() { diff --git a/Runtime/src/types.ts b/Runtime/src/types.ts index 3a132bdd..8af43b0c 100644 --- a/Runtime/src/types.ts +++ b/Runtime/src/types.ts @@ -109,6 +109,7 @@ export interface ImportedFunctions { export const enum LibraryFeatures { WeakRefs = 1 << 0, + BigInts = 1 << 1, } export type TypedArray = diff --git a/Sources/JavaScriptKit/ConstructibleFromJSValue.swift b/Sources/JavaScriptKit/ConstructibleFromJSValue.swift index b5151b37..9ad2b738 100644 --- a/Sources/JavaScriptKit/ConstructibleFromJSValue.swift +++ b/Sources/JavaScriptKit/ConstructibleFromJSValue.swift @@ -35,12 +35,18 @@ extension Double: ConstructibleFromJSValue {} extension Float: ConstructibleFromJSValue {} extension SignedInteger where Self: ConstructibleFromJSValue { +#if JAVASCRIPTKIT_WITHOUT_BIGINTS + public static func construct(from value: JSValue) -> Self? { + value.number.map(Self.init) + } +#else public init(_ bigInt: JSBigInt) { self.init(bigInt.int64Value) } public static func construct(from value: JSValue) -> Self? { value.bigInt.map(Self.init) ?? value.number.map(Self.init) } +#endif } extension Int: ConstructibleFromJSValue {} extension Int8: ConstructibleFromJSValue {} @@ -49,12 +55,18 @@ extension Int32: ConstructibleFromJSValue {} extension Int64: ConstructibleFromJSValue {} extension UnsignedInteger where Self: ConstructibleFromJSValue { +#if JAVASCRIPTKIT_WITHOUT_BIGINTS + public static func construct(from value: JSValue) -> Self? { + value.number.map(Self.init) + } +#else public init(_ bigInt: JSBigInt) { self.init(bigInt.uInt64Value) } public static func construct(from value: JSValue) -> Self? { value.bigInt.map(Self.init) ?? value.number.map(Self.init) } +#endif } extension UInt: ConstructibleFromJSValue {} extension UInt8: ConstructibleFromJSValue {} diff --git a/Sources/JavaScriptKit/ConvertibleToJSValue.swift b/Sources/JavaScriptKit/ConvertibleToJSValue.swift index f024fb0d..17824a60 100644 --- a/Sources/JavaScriptKit/ConvertibleToJSValue.swift +++ b/Sources/JavaScriptKit/ConvertibleToJSValue.swift @@ -58,7 +58,11 @@ extension UInt32: ConvertibleToJSValue { } extension UInt64: ConvertibleToJSValue { +#if JAVASCRIPTKIT_WITHOUT_BIGINTS public var jsValue: JSValue { .number(Double(self)) } +#else + public var jsValue: JSValue { .bigInt(JSBigInt(unsigned: self)) } +#endif } extension Int8: ConvertibleToJSValue { @@ -74,7 +78,11 @@ extension Int32: ConvertibleToJSValue { } extension Int64: ConvertibleToJSValue { +#if JAVASCRIPTKIT_WITHOUT_BIGINTS public var jsValue: JSValue { .number(Double(self)) } +#else + public var jsValue: JSValue { .bigInt(JSBigInt(self)) } +#endif } extension JSString: ConvertibleToJSValue { @@ -210,7 +218,11 @@ extension RawJSValue: ConvertibleToJSValue { case .symbol: return .symbol(JSSymbol(id: UInt32(payload1))) case .bigInt: +#if JAVASCRIPTKIT_WITHOUT_BIGINTS + fatalError("Received unsupported BigInt value") +#else return .bigInt(JSBigInt(id: UInt32(payload1))) +#endif } } } @@ -245,9 +257,11 @@ extension JSValue { case let .symbol(symbolRef): kind = .symbol payload1 = JavaScriptPayload1(symbolRef.id) +#if !JAVASCRIPTKIT_WITHOUT_BIGINTS case let .bigInt(bigIntRef): kind = .bigInt payload1 = JavaScriptPayload1(bigIntRef.id) +#endif } let rawValue = RawJSValue(kind: kind, payload1: payload1, payload2: payload2) return body(rawValue) diff --git a/Sources/JavaScriptKit/Features.swift b/Sources/JavaScriptKit/Features.swift index e479003c..94084421 100644 --- a/Sources/JavaScriptKit/Features.swift +++ b/Sources/JavaScriptKit/Features.swift @@ -1,5 +1,6 @@ enum LibraryFeatures { static let weakRefs: Int32 = 1 << 0 + static let bigInts: Int32 = 1 << 1 } @_cdecl("_library_features") @@ -7,6 +8,9 @@ func _library_features() -> Int32 { var features: Int32 = 0 #if !JAVASCRIPTKIT_WITHOUT_WEAKREFS features |= LibraryFeatures.weakRefs +#endif +#if !JAVASCRIPTKIT_WITHOUT_BIGINTS + features |= LibraryFeatures.bigInts #endif return features } diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift index 0e7d42c3..1b4b9f4f 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift @@ -1,5 +1,6 @@ import _CJavaScriptKit +#if !JAVASCRIPTKIT_WITHOUT_BIGINTS private let constructor = JSObject.global.BigInt.function! public final class JSBigInt: JSObject { @@ -37,3 +38,4 @@ public final class JSBigInt: JSObject { } } } +#endif diff --git a/Sources/JavaScriptKit/JSValue.swift b/Sources/JavaScriptKit/JSValue.swift index 8fdd2cd3..aad8e9c0 100644 --- a/Sources/JavaScriptKit/JSValue.swift +++ b/Sources/JavaScriptKit/JSValue.swift @@ -11,7 +11,9 @@ public enum JSValue: Equatable { case undefined case function(JSFunction) case symbol(JSSymbol) +#if !JAVASCRIPTKIT_WITHOUT_BIGINTS case bigInt(JSBigInt) +#endif /// Returns the `Bool` value of this JS value if its type is boolean. /// If not, returns `nil`. @@ -78,6 +80,7 @@ public enum JSValue: Equatable { } } +#if !JAVASCRIPTKIT_WITHOUT_BIGINTS /// Returns the `JSBigInt` of this JS value if its type is function. /// If not, returns `nil`. public var bigInt: JSBigInt? { @@ -86,6 +89,7 @@ public enum JSValue: Equatable { default: return nil } } +#endif /// Returns the `true` if this JS value is null. /// If not, returns `false`. @@ -245,8 +249,12 @@ public extension JSValue { /// - Returns: The result of `instanceof` in the JavaScript environment. func isInstanceOf(_ constructor: JSFunction) -> Bool { switch self { - case .boolean, .string, .number, .null, .undefined, .symbol, .bigInt: + case .boolean, .string, .number, .null, .undefined, .symbol: return false +#if !JAVASCRIPTKIT_WITHOUT_BIGINTS + case .bigInt: + return false +#endif case let .object(ref): return ref.isInstanceOf(constructor) case let .function(ref): @@ -265,8 +273,12 @@ extension JSValue: CustomStringConvertible { case let .number(number): return number.description case let .object(object), let .function(object as JSObject), - let .symbol(object as JSObject), let .bigInt(object as JSObject): + let .symbol(object as JSObject): + return object.toString!().fromJSValue()! +#if !JAVASCRIPTKIT_WITHOUT_BIGINTS + case let .bigInt(object as JSObject): return object.toString!().fromJSValue()! +#endif case .null: return "null" case .undefined: diff --git a/Sources/JavaScriptKit/XcodeSupport.swift b/Sources/JavaScriptKit/XcodeSupport.swift index fd8a58be..d38a0a08 100644 --- a/Sources/JavaScriptKit/XcodeSupport.swift +++ b/Sources/JavaScriptKit/XcodeSupport.swift @@ -102,7 +102,9 @@ import _CJavaScriptKit _: UnsafeMutablePointer! ) { fatalError() } func _release(_: JavaScriptObjectRef) { fatalError() } +#if !JAVASCRIPTKIT_WITHOUT_BIGINTS func _i64_to_bigint(_: Int64, _: Bool) -> JavaScriptObjectRef { fatalError() } func _bigint_to_i64(_: JavaScriptObjectRef, _: Bool) -> Int64 { fatalError() } +#endif #endif diff --git a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h index c490d313..571cb13c 100644 --- a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h +++ b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h @@ -302,6 +302,7 @@ __attribute__((__import_module__("javascript_kit"), extern void _release(const JavaScriptObjectRef ref); +#if !JAVASCRIPTKIT_WITHOUT_BIGINTS /// Converts the provided Int64 or UInt64 to a BigInt. /// /// @param value The value to convert. @@ -317,6 +318,7 @@ extern JavaScriptObjectRef _i64_to_bigint(const int64_t value, bool is_signed); __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_bigint_to_i64"))) extern int64_t _bigint_to_i64(const JavaScriptObjectRef ref, bool is_signed); +#endif #endif From 0bcb359c4791961272735f86ce2958c8b251316c Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 10:19:25 -0400 Subject: [PATCH 06/35] Allow Int64/UInt64-based arrays --- .../BasicObjects/JSTypedArray.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift b/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift index ebcf3595..19a6868c 100644 --- a/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift +++ b/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift @@ -135,14 +135,14 @@ extension UInt32: TypedArrayElement { public static var typedArrayClass = JSObject.global.Uint32Array.function! } -// FIXME: Support passing BigInts across the bridge -// See https://github.com/swiftwasm/JavaScriptKit/issues/56 -//extension Int64: TypedArrayElement { -// public static var typedArrayClass = JSObject.global.BigInt64Array.function! -//} -//extension UInt64: TypedArrayElement { -// public static var typedArrayClass = JSObject.global.BigUint64Array.function! -//} +#if !JAVASCRIPTKIT_WITHOUT_BIGINTS +extension Int64: TypedArrayElement { + public static var typedArrayClass = JSObject.global.BigInt64Array.function! +} +extension UInt64: TypedArrayElement { + public static var typedArrayClass = JSObject.global.BigUint64Array.function! +} +#endif extension Float32: TypedArrayElement { public static var typedArrayClass = JSObject.global.Float32Array.function! From d1543fc95d837b541e51de97f47bc563aa35252d Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 10:25:40 -0400 Subject: [PATCH 07/35] =?UTF-8?q?Don=E2=80=99t=20use=20BigInt=20literal=20?= =?UTF-8?q?for=20backwards=20compat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Runtime/src/index.ts | 4 ++-- Runtime/tsconfig.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Runtime/src/index.ts b/Runtime/src/index.ts index 29230f3c..d20bd344 100644 --- a/Runtime/src/index.ts +++ b/Runtime/src/index.ts @@ -434,8 +434,8 @@ export class SwiftRuntime { if (signed) { return object; } else { - if (object < 0n) { - return 0n; + if (object < BigInt(0)) { + return BigInt(0); } return BigInt.asIntN(64, object); } diff --git a/Runtime/tsconfig.json b/Runtime/tsconfig.json index 73479185..8a53ba2c 100644 --- a/Runtime/tsconfig.json +++ b/Runtime/tsconfig.json @@ -7,7 +7,7 @@ "noEmit": true, "rootDir": "src", "strict": true, - "target": "es2020", + "target": "es2017", "lib": ["es2020", "DOM", "ESNext.WeakRef"], "skipLibCheck": true }, From f8838eb33820ef66b6bac2b01e3db60b2d724d1c Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 10:31:00 -0400 Subject: [PATCH 08/35] bump lib version --- Runtime/src/index.ts | 2 +- Sources/_CJavaScriptKit/_CJavaScriptKit.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Runtime/src/index.ts b/Runtime/src/index.ts index d20bd344..e4c2ffe9 100644 --- a/Runtime/src/index.ts +++ b/Runtime/src/index.ts @@ -14,7 +14,7 @@ export class SwiftRuntime { private _instance: WebAssembly.Instance | null; private _memory: Memory | null; private _closureDeallocator: SwiftClosureDeallocator | null; - private version: number = 706; + private version: number = 707; private textDecoder = new TextDecoder("utf-8"); private textEncoder = new TextEncoder(); // Only support utf-8 diff --git a/Sources/_CJavaScriptKit/_CJavaScriptKit.c b/Sources/_CJavaScriptKit/_CJavaScriptKit.c index c263b8f7..f2f03b82 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 706; + return 707; } int _library_features(void); From 26b51c7c70067a2036865dc384775b1a3de31071 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 10:50:22 -0400 Subject: [PATCH 09/35] long long? --- Sources/_CJavaScriptKit/include/_CJavaScriptKit.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h index 571cb13c..36b8d628 100644 --- a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h +++ b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h @@ -309,7 +309,7 @@ extern void _release(const JavaScriptObjectRef ref); /// @param is_signed Whether to treat the value as a signed integer or not. __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_i64_to_bigint"))) -extern JavaScriptObjectRef _i64_to_bigint(const int64_t value, bool is_signed); +extern JavaScriptObjectRef _i64_to_bigint(const long long value, bool is_signed); /// Converts the provided BigInt to an Int64 or UInt64. /// @@ -317,7 +317,7 @@ extern JavaScriptObjectRef _i64_to_bigint(const int64_t value, bool is_signed); /// @param is_signed Whether to treat the return value as a signed integer or not. __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_bigint_to_i64"))) -extern int64_t _bigint_to_i64(const JavaScriptObjectRef ref, bool is_signed); +extern long long _bigint_to_i64(const JavaScriptObjectRef ref, bool is_signed); #endif #endif From 4dd4aae3ebcf215812d3e6ea8c21fdd1e4517f83 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 10:53:01 -0400 Subject: [PATCH 10/35] document JAVASCRIPTKIT_WITHOUT_BIGINTS flag --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 46dc963a..310f6210 100644 --- a/README.md +++ b/README.md @@ -71,15 +71,15 @@ a few additional steps though (you can skip these steps if your app depends on ) ``` -2. Add an explicit import in the code that executes **before* you start using `await` and/or `Task` -APIs (most likely in `main.swift`): +1. Add an explicit import in the code that executes **before** you start using `await` and/or `Task` + APIs (most likely in `main.swift`): ```swift import JavaScriptEventLoop ``` -3. Run this function **before* you start using `await` and/or `Task` APIs (again, most likely in -`main.swift`): +3. Run this function **before** you start using `await` and/or `Task` APIs (again, most likely in + `main.swift`): ```swift JavaScriptEventLoop.installGlobalExecutor() @@ -125,21 +125,21 @@ asyncButtonElement.onclick = .object(JSClosure { _ in _ = document.body.appendChild(asyncButtonElement) ``` -## Requirements +## Requirements ### For developers -- macOS 11 and Xcode 13.2 or later versions, which support Swift Concurrency back-deployment. -To use earlier versions of Xcode on macOS 11 you'll have to -add `.unsafeFlags(["-Xfrontend", "-disable-availability-checking"])` in `Package.swift` manifest of -your package that depends on JavaScriptKit. You can also use Xcode 13.0 and 13.1 on macOS Monterey, -since this OS does not need back-deployment. +- macOS 11 and Xcode 13.2 or later versions, which support Swift Concurrency back-deployment. + To use earlier versions of Xcode on macOS 11 you'll have to + add `.unsafeFlags(["-Xfrontend", "-disable-availability-checking"])` in `Package.swift` manifest of + your package that depends on JavaScriptKit. You can also use Xcode 13.0 and 13.1 on macOS Monterey, + since this OS does not need back-deployment. - [Swift 5.5 or later](https://swift.org/download/) and Ubuntu 18.04 if you'd like to use Linux. Other Linux distributions are currently not supported. ### For users of apps depending on JavaScriptKit -Any recent browser that [supports WebAssembly](https://caniuse.com/#feat=wasm) and required +Any recent browser that [supports WebAssembly](https://caniuse.com/#feat=wasm) and required JavaScript features should work, which currently includes: - Edge 84+ @@ -149,7 +149,7 @@ JavaScript features should work, which currently includes: - Mobile Safari 14.8+ If you need to support older browser versions, you'll have to build with -`JAVASCRIPTKIT_WITHOUT_WEAKREFS` flag, passing `-Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS` flags +`JAVASCRIPTKIT_WITHOUT_WEAKREFS` and `JAVASCRIPTKIT_WITHOUT_BIGINTS` flags, passing `-Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS -Xswiftc -DJAVASCRIPTKIT_WITHOUT_BIGINTS` flags when compiling. This should lower browser requirements to these versions: - Edge 16+ From cd3c076cb501ec0b39ff99a6ed58c582e3ecb414 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 10:54:09 -0400 Subject: [PATCH 11/35] check compatibility workflow builds all variants --- .github/workflows/compatibility.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/compatibility.yml b/.github/workflows/compatibility.yml index e4534507..781463dd 100644 --- a/.github/workflows/compatibility.yml +++ b/.github/workflows/compatibility.yml @@ -22,3 +22,6 @@ jobs: make bootstrap cd Example/JavaScriptKitExample swift build --triple wasm32-unknown-wasi + swift build --triple wasm32-unknown-wasi -Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS + swift build --triple wasm32-unknown-wasi -Xswiftc -DJAVASCRIPTKIT_WITHOUT_BIGINTS + swift build --triple wasm32-unknown-wasi -Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS -Xswiftc -DJAVASCRIPTKIT_WITHOUT_BIGINTS From 76303b93dca4f85c2bcb76b2a086f725a4be1b54 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 10:56:03 -0400 Subject: [PATCH 12/35] Increase error stack trace limit --- IntegrationTests/lib.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/IntegrationTests/lib.js b/IntegrationTests/lib.js index c55ed3b4..76d8b2c2 100644 --- a/IntegrationTests/lib.js +++ b/IntegrationTests/lib.js @@ -6,6 +6,8 @@ const promisify = require("util").promisify; const fs = require("fs"); const readFile = promisify(fs.readFile); +Error.stackTraceLimit = Infinity; + const startWasiTask = async (wasmPath) => { // Instantiate a new WASI Instance const wasmFs = new WasmFs(); From c356abac68b7649d7dacaceac019da74a120cffb Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 10:59:18 -0400 Subject: [PATCH 13/35] Use correct type for setTimeout in JavaScriptEventLoop --- Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift b/Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift index 8ff30c8a..53008c5e 100644 --- a/Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift +++ b/Sources/JavaScriptEventLoop/JavaScriptEventLoop.swift @@ -12,7 +12,7 @@ public final class JavaScriptEventLoop: SerialExecutor, @unchecked Sendable { /// See also: https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide let queueMicrotask: @Sendable (@escaping () -> Void) -> Void /// A function that invokes a given closure after a specified number of milliseconds. - let setTimeout: @Sendable (UInt64, @escaping () -> Void) -> Void + let setTimeout: @Sendable (Double, @escaping () -> Void) -> Void /// A mutable state to manage internal job queue /// Note that this should be guarded atomically when supporting multi-threaded environment. @@ -20,7 +20,7 @@ public final class JavaScriptEventLoop: SerialExecutor, @unchecked Sendable { private init( queueTask: @Sendable @escaping (@escaping () -> Void) -> Void, - setTimeout: @Sendable @escaping (UInt64, @escaping () -> Void) -> Void + setTimeout: @Sendable @escaping (Double, @escaping () -> Void) -> Void ) { self.queueMicrotask = queueTask self.setTimeout = setTimeout @@ -83,7 +83,7 @@ public final class JavaScriptEventLoop: SerialExecutor, @unchecked Sendable { private func enqueue(_ job: UnownedJob, withDelay nanoseconds: UInt64) { let milliseconds = nanoseconds / 1_000_000 - setTimeout(milliseconds, { + setTimeout(Double(milliseconds), { job._runSynchronously(on: self.asUnownedSerialExecutor()) }) } From 6f150ad474644db32ef2ee5de2a8acdf4068d8c4 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 11:05:08 -0400 Subject: [PATCH 14/35] =?UTF-8?q?Add=20symbol=20support=20to=20runtime?= =?UTF-8?q?=E2=80=99s=20JSValue.decode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Runtime/src/js-value.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/Runtime/src/js-value.ts b/Runtime/src/js-value.ts index 9e7b4573..bf0819df 100644 --- a/Runtime/src/js-value.ts +++ b/Runtime/src/js-value.ts @@ -34,6 +34,7 @@ export const decode = ( case Kind.String: case Kind.Object: case Kind.Function: + case Kind.Symbol: case Kind.BigInt: return memory.getObject(payload1); From 6257d35bc83d1bb56e396a5004ec159cbf322387 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 11:07:58 -0400 Subject: [PATCH 15/35] remove JavaScriptValueKindInvalid since neither side produces it --- Runtime/src/js-value.ts | 1 - Sources/JavaScriptKit/ConvertibleToJSValue.swift | 2 -- Sources/_CJavaScriptKit/include/_CJavaScriptKit.h | 1 - 3 files changed, 4 deletions(-) diff --git a/Runtime/src/js-value.ts b/Runtime/src/js-value.ts index bf0819df..6d72d708 100644 --- a/Runtime/src/js-value.ts +++ b/Runtime/src/js-value.ts @@ -2,7 +2,6 @@ import { Memory } from "./memory"; import { pointer } from "./types"; export const enum Kind { - Invalid = -1, Boolean = 0, String = 1, Number = 2, diff --git a/Sources/JavaScriptKit/ConvertibleToJSValue.swift b/Sources/JavaScriptKit/ConvertibleToJSValue.swift index 17824a60..2304d1d4 100644 --- a/Sources/JavaScriptKit/ConvertibleToJSValue.swift +++ b/Sources/JavaScriptKit/ConvertibleToJSValue.swift @@ -199,8 +199,6 @@ extension Array: ConstructibleFromJSValue where Element: ConstructibleFromJSValu extension RawJSValue: ConvertibleToJSValue { public var jsValue: JSValue { switch kind { - case .invalid: - fatalError() case .boolean: return .boolean(payload1 != 0) case .number: diff --git a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h index 36b8d628..3e98e4eb 100644 --- a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h +++ b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h @@ -13,7 +13,6 @@ typedef unsigned int JavaScriptHostFuncRef; /// `JavaScriptValueKind` represents the kind of JavaScript primitive value. typedef enum __attribute__((enum_extensibility(closed))) { - JavaScriptValueKindInvalid = -1, JavaScriptValueKindBoolean = 0, JavaScriptValueKindString = 1, JavaScriptValueKindNumber = 2, From 203844f7fd123d9f9e0a11adacbab701d6a4ecd7 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 11:08:28 -0400 Subject: [PATCH 16/35] use assertNever to ensure runtime switch statements are kept up to date --- Runtime/src/js-value.ts | 9 +++++---- Runtime/src/types.ts | 4 ++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Runtime/src/js-value.ts b/Runtime/src/js-value.ts index 6d72d708..553780b7 100644 --- a/Runtime/src/js-value.ts +++ b/Runtime/src/js-value.ts @@ -1,5 +1,5 @@ import { Memory } from "./memory"; -import { pointer } from "./types"; +import { assertNever, pointer } from "./types"; export const enum Kind { Boolean = 0, @@ -44,7 +44,7 @@ export const decode = ( return undefined; default: - throw new Error(`JSValue Type kind "${kind}" is not supported`); + assertNever(kind, `JSValue Type kind "${kind}" is not supported`); } }; @@ -81,7 +81,8 @@ export const write = ( memory.writeUint32(payload1_ptr, memory.retain(value)); }; - switch (typeof value) { + const type = typeof value; + switch (type) { case "boolean": { memory.writeUint32(kind_ptr, exceptionBit | Kind.Boolean); memory.writeUint32(payload1_ptr, value ? 1 : 0); @@ -117,6 +118,6 @@ export const write = ( break; } default: - throw new Error(`Type "${typeof value}" is not supported yet`); + assertNever(type, `Type "${type}" is not supported yet`); } }; diff --git a/Runtime/src/types.ts b/Runtime/src/types.ts index 8af43b0c..95e3f9fe 100644 --- a/Runtime/src/types.ts +++ b/Runtime/src/types.ts @@ -124,3 +124,7 @@ export type TypedArray = // | BigUint64ArrayConstructor | Float32ArrayConstructor | Float64ArrayConstructor; + +export function assertNever(x: never, message: string) { + throw new Error(message); +} From 9d066f94a7ec16efb23c790ee54e349392bafe3d Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 9 Apr 2022 12:50:06 -0400 Subject: [PATCH 17/35] BigInt tests --- .../Sources/PrimaryTests/main.swift | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift b/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift index 6a9ff54c..42aa649e 100644 --- a/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift +++ b/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift @@ -853,4 +853,35 @@ try test("JSValueDecoder") { } +try test("BigInt") { + func expectPassesThrough(signed value: Int64) throws { + let bigInt = JSBigInt(value) + try expectEqual(bigInt.description, value.description) + } + + func expectPassesThrough(unsigned value: UInt64) throws { + let bigInt = JSBigInt(unsigned: value) + try expectEqual(bigInt.description, value.description) + } + + try expectPassesThrough(signed: 0) + try expectPassesThrough(signed: 1 << 62) + try expectPassesThrough(signed: -2305) + for _ in 0 ..< 100 { + try expectPassesThrough(signed: .random(in: .min ... .max)) + } + try expectPassesThrough(signed: .min) + try expectPassesThrough(signed: .max) + + try expectPassesThrough(unsigned: 0) + try expectPassesThrough(unsigned: 1 << 62) + try expectPassesThrough(unsigned: 1 << 63) + try expectPassesThrough(unsigned: .min) + try expectPassesThrough(unsigned: .max) + try expectPassesThrough(unsigned: ~0) + for _ in 0 ..< 100 { + try expectPassesThrough(unsigned: .random(in: .min ... .max)) + } +} + Expectation.wait(expectations) From 1fdcd26e07436248639f131760ef022bc69643d8 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sun, 10 Apr 2022 08:11:11 -0400 Subject: [PATCH 18/35] Revert changes to README --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 310f6210..6a04c5d8 100644 --- a/README.md +++ b/README.md @@ -71,15 +71,15 @@ a few additional steps though (you can skip these steps if your app depends on ) ``` -1. Add an explicit import in the code that executes **before** you start using `await` and/or `Task` - APIs (most likely in `main.swift`): +2. Add an explicit import in the code that executes **before* you start using `await` and/or `Task` +APIs (most likely in `main.swift`): ```swift import JavaScriptEventLoop ``` -3. Run this function **before** you start using `await` and/or `Task` APIs (again, most likely in - `main.swift`): +3. Run this function **before* you start using `await` and/or `Task` APIs (again, most likely in +`main.swift`): ```swift JavaScriptEventLoop.installGlobalExecutor() @@ -125,21 +125,21 @@ asyncButtonElement.onclick = .object(JSClosure { _ in _ = document.body.appendChild(asyncButtonElement) ``` -## Requirements +## Requirements ### For developers -- macOS 11 and Xcode 13.2 or later versions, which support Swift Concurrency back-deployment. - To use earlier versions of Xcode on macOS 11 you'll have to - add `.unsafeFlags(["-Xfrontend", "-disable-availability-checking"])` in `Package.swift` manifest of - your package that depends on JavaScriptKit. You can also use Xcode 13.0 and 13.1 on macOS Monterey, - since this OS does not need back-deployment. +- macOS 11 and Xcode 13.2 or later versions, which support Swift Concurrency back-deployment. +To use earlier versions of Xcode on macOS 11 you'll have to +add `.unsafeFlags(["-Xfrontend", "-disable-availability-checking"])` in `Package.swift` manifest of +your package that depends on JavaScriptKit. You can also use Xcode 13.0 and 13.1 on macOS Monterey, +since this OS does not need back-deployment. - [Swift 5.5 or later](https://swift.org/download/) and Ubuntu 18.04 if you'd like to use Linux. Other Linux distributions are currently not supported. ### For users of apps depending on JavaScriptKit -Any recent browser that [supports WebAssembly](https://caniuse.com/#feat=wasm) and required +Any recent browser that [supports WebAssembly](https://caniuse.com/#feat=wasm) and required JavaScript features should work, which currently includes: - Edge 84+ From 14541b8d7c0d66f4b8ab4d58495a31e3b0a75e04 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sun, 10 Apr 2022 08:13:05 -0400 Subject: [PATCH 19/35] consistent whitespace (by semantic grouping) in index.ts --- Runtime/src/index.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Runtime/src/index.ts b/Runtime/src/index.ts index e4c2ffe9..4a316bff 100644 --- a/Runtime/src/index.ts +++ b/Runtime/src/index.ts @@ -125,7 +125,6 @@ export class SwiftRuntime { const value = JSValue.decode(kind, payload1, payload2, this.memory); obj[key] = value; }, - swjs_get_prop: ( ref: ref, name: ref, @@ -157,7 +156,6 @@ export class SwiftRuntime { const value = JSValue.decode(kind, payload1, payload2, this.memory); obj[index] = value; }, - swjs_get_subscript: ( ref: ref, index: number, @@ -183,7 +181,6 @@ export class SwiftRuntime { this.memory.writeUint32(bytes_ptr_result, bytes_ptr); return bytes.length; }, - swjs_decode_string: (bytes_ptr: pointer, length: number) => { const bytes = this.memory .bytes() @@ -191,7 +188,6 @@ export class SwiftRuntime { const string = this.textDecoder.decode(bytes); return this.memory.retain(string); }, - swjs_load_string: (ref: ref, buffer: pointer) => { const bytes = this.memory.getObject(ref); this.memory.writeBytes(buffer, bytes); @@ -301,7 +297,6 @@ export class SwiftRuntime { this.memory ); }, - swjs_call_function_with_this_no_catch: ( obj_ref: ref, func_ref: ref, @@ -339,13 +334,13 @@ export class SwiftRuntime { } } }, + swjs_call_new: (ref: ref, argv: pointer, argc: number) => { const constructor = this.memory.getObject(ref); const args = JSValue.decodeArray(argv, argc, this.memory); const instance = new constructor(...args); return this.memory.retain(instance); }, - swjs_call_throwing_new: ( ref: ref, argv: pointer, From dcd38c7adf041f8ca9dc7b3fefa9551dca787296 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sun, 10 Apr 2022 08:13:55 -0400 Subject: [PATCH 20/35] =?UTF-8?q?Rename:=20type=E2=86=92kind?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Runtime/src/js-value.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Runtime/src/js-value.ts b/Runtime/src/js-value.ts index 553780b7..c8896900 100644 --- a/Runtime/src/js-value.ts +++ b/Runtime/src/js-value.ts @@ -76,8 +76,8 @@ export const write = ( return; } - const writeRef = (type: Kind) => { - memory.writeUint32(kind_ptr, exceptionBit | type); + const writeRef = (kind: Kind) => { + memory.writeUint32(kind_ptr, exceptionBit | kind); memory.writeUint32(payload1_ptr, memory.retain(value)); }; From 63f33d0fd772abccfb3656725c6f080bd250e28e Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sun, 10 Apr 2022 08:16:20 -0400 Subject: [PATCH 21/35] drop implicit return --- Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift index 1b4b9f4f..f3abfce7 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift @@ -23,7 +23,7 @@ public final class JSBigInt: JSObject { } override public class func construct(from value: JSValue) -> Self? { - return value.bigInt as? Self + value.bigInt as? Self } override public var jsValue: JSValue { From 30a3e66602881c38588bbade741ea3f10dab03d1 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sun, 10 Apr 2022 09:45:08 -0400 Subject: [PATCH 22/35] assert Int/UInt types are 32-bit for now --- Sources/JavaScriptKit/ConvertibleToJSValue.swift | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Sources/JavaScriptKit/ConvertibleToJSValue.swift b/Sources/JavaScriptKit/ConvertibleToJSValue.swift index 2304d1d4..ad7b5d07 100644 --- a/Sources/JavaScriptKit/ConvertibleToJSValue.swift +++ b/Sources/JavaScriptKit/ConvertibleToJSValue.swift @@ -26,11 +26,17 @@ extension Bool: ConvertibleToJSValue { } extension Int: ConvertibleToJSValue { - public var jsValue: JSValue { .number(Double(self)) } + public var jsValue: JSValue { + assert(Self.bitWidth == 32) + return .number(Double(self)) + } } extension UInt: ConvertibleToJSValue { - public var jsValue: JSValue { .number(Double(self)) } + public var jsValue: JSValue { + assert(Self.bitWidth == 32) + return .number(Double(self)) + } } extension Float: ConvertibleToJSValue { From 68cb6897aee6251ca84b96e305a45ffc52448b6c Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sun, 10 Apr 2022 09:45:44 -0400 Subject: [PATCH 23/35] Require BigInts for ConvertibleToJSValue conformance on Int64/UInt64 --- Sources/JavaScriptKit/ConvertibleToJSValue.swift | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Sources/JavaScriptKit/ConvertibleToJSValue.swift b/Sources/JavaScriptKit/ConvertibleToJSValue.swift index ad7b5d07..6311935d 100644 --- a/Sources/JavaScriptKit/ConvertibleToJSValue.swift +++ b/Sources/JavaScriptKit/ConvertibleToJSValue.swift @@ -63,13 +63,11 @@ extension UInt32: ConvertibleToJSValue { public var jsValue: JSValue { .number(Double(self)) } } +#if !JAVASCRIPTKIT_WITHOUT_BIGINTS extension UInt64: ConvertibleToJSValue { -#if JAVASCRIPTKIT_WITHOUT_BIGINTS - public var jsValue: JSValue { .number(Double(self)) } -#else public var jsValue: JSValue { .bigInt(JSBigInt(unsigned: self)) } -#endif } +#endif extension Int8: ConvertibleToJSValue { public var jsValue: JSValue { .number(Double(self)) } @@ -83,13 +81,11 @@ extension Int32: ConvertibleToJSValue { public var jsValue: JSValue { .number(Double(self)) } } +#if !JAVASCRIPTKIT_WITHOUT_BIGINTS extension Int64: ConvertibleToJSValue { -#if JAVASCRIPTKIT_WITHOUT_BIGINTS - public var jsValue: JSValue { .number(Double(self)) } -#else public var jsValue: JSValue { .bigInt(JSBigInt(self)) } -#endif } +#endif extension JSString: ConvertibleToJSValue { public var jsValue: JSValue { .string(self) } From 01ae32d0fc24418114d470296cd4fe47381268bc Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sun, 10 Apr 2022 09:46:47 -0400 Subject: [PATCH 24/35] run Prettier on primary-tests.js --- IntegrationTests/bin/primary-tests.js | 33 +++++++++++++++------------ 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/IntegrationTests/bin/primary-tests.js b/IntegrationTests/bin/primary-tests.js index 597590bd..7632ef58 100644 --- a/IntegrationTests/bin/primary-tests.js +++ b/IntegrationTests/bin/primary-tests.js @@ -44,23 +44,26 @@ global.globalObject1 = { throw "String Error"; }, func3: function () { - throw 3.0 + throw 3.0; }, }, eval_closure: function (fn) { - return fn(arguments[1]) + return fn(arguments[1]); }, observable_obj: { set_called: false, - target: new Proxy({ - nested: {} - }, { - set(target, key, value) { - global.globalObject1.observable_obj.set_called = true; - target[key] = value; - return true; + target: new Proxy( + { + nested: {}, + }, + { + set(target, key, value) { + global.globalObject1.observable_obj.set_called = true; + target[key] = value; + return true; + }, } - }) + ), }, }; @@ -79,16 +82,16 @@ global.Animal = function (name, age, isCat) { }; this.setName = function (name) { this.name = name; - } + }; }; -global.callThrowingClosure = (c) => { +global.callThrowingClosure = (c) => { try { - c() + c(); } catch (error) { - return error + return error; } -} +}; const { startWasiTask } = require("../lib"); From a44de1a3c8d5166ba32244d9fde45e9c8f42ded4 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sun, 10 Apr 2022 09:46:57 -0400 Subject: [PATCH 25/35] move stackTraceLimit change to non-benchmark tests only --- IntegrationTests/bin/concurrency-tests.js | 2 ++ IntegrationTests/bin/primary-tests.js | 2 ++ IntegrationTests/lib.js | 2 -- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/IntegrationTests/bin/concurrency-tests.js b/IntegrationTests/bin/concurrency-tests.js index 2d705761..47ef4abd 100644 --- a/IntegrationTests/bin/concurrency-tests.js +++ b/IntegrationTests/bin/concurrency-tests.js @@ -1,5 +1,7 @@ const { startWasiTask } = require("../lib"); +Error.stackTraceLimit = Infinity; + startWasiTask("./dist/ConcurrencyTests.wasm").catch((err) => { console.log(err); process.exit(1); diff --git a/IntegrationTests/bin/primary-tests.js b/IntegrationTests/bin/primary-tests.js index 7632ef58..94bcf7da 100644 --- a/IntegrationTests/bin/primary-tests.js +++ b/IntegrationTests/bin/primary-tests.js @@ -1,3 +1,5 @@ +Error.stackTraceLimit = Infinity; + global.globalObject1 = { prop_1: { nested_prop: 1, diff --git a/IntegrationTests/lib.js b/IntegrationTests/lib.js index 76d8b2c2..c55ed3b4 100644 --- a/IntegrationTests/lib.js +++ b/IntegrationTests/lib.js @@ -6,8 +6,6 @@ const promisify = require("util").promisify; const fs = require("fs"); const readFile = promisify(fs.readFile); -Error.stackTraceLimit = Infinity; - const startWasiTask = async (wasmPath) => { // Instantiate a new WASI Instance const wasmFs = new WasmFs(); From 6517b7e4da51a472e81c41d12e1b68904bc770d8 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 16 Apr 2022 08:45:55 -0400 Subject: [PATCH 26/35] remove JAVASCRIPTKIT_WITHOUT_BIGINTS --- .github/workflows/compatibility.yml | 2 -- README.md | 2 +- Runtime/src/index.ts | 11 ----------- .../JavaScriptKit/ConstructibleFromJSValue.swift | 12 ------------ Sources/JavaScriptKit/ConvertibleToJSValue.swift | 6 ------ Sources/JavaScriptKit/Features.swift | 4 ---- .../FundamentalObjects/JSBigInt.swift | 6 +++--- Sources/JavaScriptKit/JSValue.swift | 16 ++-------------- 8 files changed, 6 insertions(+), 53 deletions(-) diff --git a/.github/workflows/compatibility.yml b/.github/workflows/compatibility.yml index 781463dd..422e08c4 100644 --- a/.github/workflows/compatibility.yml +++ b/.github/workflows/compatibility.yml @@ -23,5 +23,3 @@ jobs: cd Example/JavaScriptKitExample swift build --triple wasm32-unknown-wasi swift build --triple wasm32-unknown-wasi -Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS - swift build --triple wasm32-unknown-wasi -Xswiftc -DJAVASCRIPTKIT_WITHOUT_BIGINTS - swift build --triple wasm32-unknown-wasi -Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS -Xswiftc -DJAVASCRIPTKIT_WITHOUT_BIGINTS diff --git a/README.md b/README.md index 6a04c5d8..b5c64539 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ JavaScript features should work, which currently includes: - Mobile Safari 14.8+ If you need to support older browser versions, you'll have to build with -`JAVASCRIPTKIT_WITHOUT_WEAKREFS` and `JAVASCRIPTKIT_WITHOUT_BIGINTS` flags, passing `-Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS -Xswiftc -DJAVASCRIPTKIT_WITHOUT_BIGINTS` flags +the `JAVASCRIPTKIT_WITHOUT_WEAKREFS` flag, passing `-Xswiftc -DJAVASCRIPTKIT_WITHOUT_WEAKREFS` flags when compiling. This should lower browser requirements to these versions: - Edge 16+ diff --git a/Runtime/src/index.ts b/Runtime/src/index.ts index 4a316bff..dcd817a7 100644 --- a/Runtime/src/index.ts +++ b/Runtime/src/index.ts @@ -35,17 +35,6 @@ export class SwiftRuntime { }` ); } - - if (this.exports.swjs_library_features() & LibraryFeatures.BigInts) { - if (typeof BigInt === "undefined") { - throw new Error( - "The Swift part of JavaScriptKit was configured to require " + - "the availability of JavaScript BigInts. Please build " + - "with `-Xswiftc -DJAVASCRIPTKIT_WITHOUT_BIGINTS` to " + - "disable features that use BigInts." - ); - } - } } private get instance() { diff --git a/Sources/JavaScriptKit/ConstructibleFromJSValue.swift b/Sources/JavaScriptKit/ConstructibleFromJSValue.swift index 9ad2b738..b5151b37 100644 --- a/Sources/JavaScriptKit/ConstructibleFromJSValue.swift +++ b/Sources/JavaScriptKit/ConstructibleFromJSValue.swift @@ -35,18 +35,12 @@ extension Double: ConstructibleFromJSValue {} extension Float: ConstructibleFromJSValue {} extension SignedInteger where Self: ConstructibleFromJSValue { -#if JAVASCRIPTKIT_WITHOUT_BIGINTS - public static func construct(from value: JSValue) -> Self? { - value.number.map(Self.init) - } -#else public init(_ bigInt: JSBigInt) { self.init(bigInt.int64Value) } public static func construct(from value: JSValue) -> Self? { value.bigInt.map(Self.init) ?? value.number.map(Self.init) } -#endif } extension Int: ConstructibleFromJSValue {} extension Int8: ConstructibleFromJSValue {} @@ -55,18 +49,12 @@ extension Int32: ConstructibleFromJSValue {} extension Int64: ConstructibleFromJSValue {} extension UnsignedInteger where Self: ConstructibleFromJSValue { -#if JAVASCRIPTKIT_WITHOUT_BIGINTS - public static func construct(from value: JSValue) -> Self? { - value.number.map(Self.init) - } -#else public init(_ bigInt: JSBigInt) { self.init(bigInt.uInt64Value) } public static func construct(from value: JSValue) -> Self? { value.bigInt.map(Self.init) ?? value.number.map(Self.init) } -#endif } extension UInt: ConstructibleFromJSValue {} extension UInt8: ConstructibleFromJSValue {} diff --git a/Sources/JavaScriptKit/ConvertibleToJSValue.swift b/Sources/JavaScriptKit/ConvertibleToJSValue.swift index 6311935d..0b2cb589 100644 --- a/Sources/JavaScriptKit/ConvertibleToJSValue.swift +++ b/Sources/JavaScriptKit/ConvertibleToJSValue.swift @@ -218,11 +218,7 @@ extension RawJSValue: ConvertibleToJSValue { case .symbol: return .symbol(JSSymbol(id: UInt32(payload1))) case .bigInt: -#if JAVASCRIPTKIT_WITHOUT_BIGINTS - fatalError("Received unsupported BigInt value") -#else return .bigInt(JSBigInt(id: UInt32(payload1))) -#endif } } } @@ -257,11 +253,9 @@ extension JSValue { case let .symbol(symbolRef): kind = .symbol payload1 = JavaScriptPayload1(symbolRef.id) -#if !JAVASCRIPTKIT_WITHOUT_BIGINTS case let .bigInt(bigIntRef): kind = .bigInt payload1 = JavaScriptPayload1(bigIntRef.id) -#endif } let rawValue = RawJSValue(kind: kind, payload1: payload1, payload2: payload2) return body(rawValue) diff --git a/Sources/JavaScriptKit/Features.swift b/Sources/JavaScriptKit/Features.swift index 94084421..e479003c 100644 --- a/Sources/JavaScriptKit/Features.swift +++ b/Sources/JavaScriptKit/Features.swift @@ -1,6 +1,5 @@ enum LibraryFeatures { static let weakRefs: Int32 = 1 << 0 - static let bigInts: Int32 = 1 << 1 } @_cdecl("_library_features") @@ -8,9 +7,6 @@ func _library_features() -> Int32 { var features: Int32 = 0 #if !JAVASCRIPTKIT_WITHOUT_WEAKREFS features |= LibraryFeatures.weakRefs -#endif -#if !JAVASCRIPTKIT_WITHOUT_BIGINTS - features |= LibraryFeatures.bigInts #endif return features } diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift index f3abfce7..c005790a 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift @@ -1,12 +1,12 @@ import _CJavaScriptKit -#if !JAVASCRIPTKIT_WITHOUT_BIGINTS private let constructor = JSObject.global.BigInt.function! public final class JSBigInt: JSObject { public var int64Value: Int64 { _bigint_to_i64(id, true) } + public var uInt64Value: UInt64 { UInt64(bitPattern: _bigint_to_i64(id, false)) } @@ -14,11 +14,12 @@ public final class JSBigInt: JSObject { public convenience init(_ value: Int64) { self.init(id: _i64_to_bigint(value, true)) } + public convenience init(unsigned value: UInt64) { self.init(id: _i64_to_bigint(Int64(bitPattern: value), false)) } - public override init(id: JavaScriptObjectRef) { + override public init(id: JavaScriptObjectRef) { super.init(id: id) } @@ -38,4 +39,3 @@ public final class JSBigInt: JSObject { } } } -#endif diff --git a/Sources/JavaScriptKit/JSValue.swift b/Sources/JavaScriptKit/JSValue.swift index aad8e9c0..8fdd2cd3 100644 --- a/Sources/JavaScriptKit/JSValue.swift +++ b/Sources/JavaScriptKit/JSValue.swift @@ -11,9 +11,7 @@ public enum JSValue: Equatable { case undefined case function(JSFunction) case symbol(JSSymbol) -#if !JAVASCRIPTKIT_WITHOUT_BIGINTS case bigInt(JSBigInt) -#endif /// Returns the `Bool` value of this JS value if its type is boolean. /// If not, returns `nil`. @@ -80,7 +78,6 @@ public enum JSValue: Equatable { } } -#if !JAVASCRIPTKIT_WITHOUT_BIGINTS /// Returns the `JSBigInt` of this JS value if its type is function. /// If not, returns `nil`. public var bigInt: JSBigInt? { @@ -89,7 +86,6 @@ public enum JSValue: Equatable { default: return nil } } -#endif /// Returns the `true` if this JS value is null. /// If not, returns `false`. @@ -249,12 +245,8 @@ public extension JSValue { /// - Returns: The result of `instanceof` in the JavaScript environment. func isInstanceOf(_ constructor: JSFunction) -> Bool { switch self { - case .boolean, .string, .number, .null, .undefined, .symbol: + case .boolean, .string, .number, .null, .undefined, .symbol, .bigInt: return false -#if !JAVASCRIPTKIT_WITHOUT_BIGINTS - case .bigInt: - return false -#endif case let .object(ref): return ref.isInstanceOf(constructor) case let .function(ref): @@ -273,12 +265,8 @@ extension JSValue: CustomStringConvertible { case let .number(number): return number.description case let .object(object), let .function(object as JSObject), - let .symbol(object as JSObject): - return object.toString!().fromJSValue()! -#if !JAVASCRIPTKIT_WITHOUT_BIGINTS - case let .bigInt(object as JSObject): + let .symbol(object as JSObject), let .bigInt(object as JSObject): return object.toString!().fromJSValue()! -#endif case .null: return "null" case .undefined: From c54bd10ff350da32adca67bb5cab1a83290c7560 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 16 Apr 2022 09:00:29 -0400 Subject: [PATCH 27/35] SPI for JSObject_id --- Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift | 2 +- Sources/JavaScriptKit/FundamentalObjects/JSObject.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift index c005790a..b86b1a9b 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift @@ -19,7 +19,7 @@ public final class JSBigInt: JSObject { self.init(id: _i64_to_bigint(Int64(bitPattern: value), false)) } - override public init(id: JavaScriptObjectRef) { + @_spi(JSObject_id) override public init(id: JavaScriptObjectRef) { super.init(id: id) } diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift b/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift index 427648bc..f7544533 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift @@ -16,8 +16,8 @@ import _CJavaScriptKit /// reference counting system. @dynamicMemberLookup public class JSObject: Equatable { - internal var id: JavaScriptObjectRef - init(id: JavaScriptObjectRef) { + @_spi(JSObject_id) public var id: JavaScriptObjectRef + @_spi(JSObject_id) public init(id: JavaScriptObjectRef) { self.id = id } From 7af59171842b6e7a7b6a12a3dda44a28a1551c6b Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 16 Apr 2022 09:02:37 -0400 Subject: [PATCH 28/35] Move i64 stuff to a separate module --- Package.swift | 6 +++++ .../BasicObjects/JSTypedArray.swift | 9 -------- .../JavaScriptKit/ConvertibleToJSValue.swift | 11 --------- .../FundamentalObjects/JSBigInt.swift | 16 ------------- Sources/JavaScriptKit_I64/Int64+I64.swift | 13 +++++++++++ Sources/JavaScriptKit_I64/JSBigInt+I64.swift | 20 ++++++++++++++++ .../_CJavaScriptKit/include/_CJavaScriptKit.h | 18 --------------- .../_CJavaScriptKit_I64/_CJavaScriptKit+I64.c | 1 + .../include/_CJavaScriptKit+I64.h | 23 +++++++++++++++++++ .../include/module.modulemap | 4 ++++ 10 files changed, 67 insertions(+), 54 deletions(-) create mode 100644 Sources/JavaScriptKit_I64/Int64+I64.swift create mode 100644 Sources/JavaScriptKit_I64/JSBigInt+I64.swift create mode 100644 Sources/_CJavaScriptKit_I64/_CJavaScriptKit+I64.c create mode 100644 Sources/_CJavaScriptKit_I64/include/_CJavaScriptKit+I64.h create mode 100644 Sources/_CJavaScriptKit_I64/include/module.modulemap diff --git a/Package.swift b/Package.swift index 8a75bed3..4f50d5fb 100644 --- a/Package.swift +++ b/Package.swift @@ -7,6 +7,7 @@ let package = Package( products: [ .library(name: "JavaScriptKit", targets: ["JavaScriptKit"]), .library(name: "JavaScriptEventLoop", targets: ["JavaScriptEventLoop"]), + .library(name: "JavaScriptKit_I64", targets: ["JavaScriptKit_I64"]), ], targets: [ .target( @@ -14,6 +15,11 @@ let package = Package( dependencies: ["_CJavaScriptKit"] ), .target(name: "_CJavaScriptKit"), + .target( + name: "JavaScriptKit_I64", + dependencies: ["_CJavaScriptKit_I64", "JavaScriptKit"] + ), + .target(name: "_CJavaScriptKit_I64", dependencies: ["_CJavaScriptKit"]), .target( name: "JavaScriptEventLoop", dependencies: ["JavaScriptKit", "_CJavaScriptEventLoop"] diff --git a/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift b/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift index 19a6868c..04c1710d 100644 --- a/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift +++ b/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift @@ -135,15 +135,6 @@ extension UInt32: TypedArrayElement { public static var typedArrayClass = JSObject.global.Uint32Array.function! } -#if !JAVASCRIPTKIT_WITHOUT_BIGINTS -extension Int64: TypedArrayElement { - public static var typedArrayClass = JSObject.global.BigInt64Array.function! -} -extension UInt64: TypedArrayElement { - public static var typedArrayClass = JSObject.global.BigUint64Array.function! -} -#endif - extension Float32: TypedArrayElement { public static var typedArrayClass = JSObject.global.Float32Array.function! } diff --git a/Sources/JavaScriptKit/ConvertibleToJSValue.swift b/Sources/JavaScriptKit/ConvertibleToJSValue.swift index 0b2cb589..572e867b 100644 --- a/Sources/JavaScriptKit/ConvertibleToJSValue.swift +++ b/Sources/JavaScriptKit/ConvertibleToJSValue.swift @@ -63,11 +63,6 @@ extension UInt32: ConvertibleToJSValue { public var jsValue: JSValue { .number(Double(self)) } } -#if !JAVASCRIPTKIT_WITHOUT_BIGINTS -extension UInt64: ConvertibleToJSValue { - public var jsValue: JSValue { .bigInt(JSBigInt(unsigned: self)) } -} -#endif extension Int8: ConvertibleToJSValue { public var jsValue: JSValue { .number(Double(self)) } @@ -81,12 +76,6 @@ extension Int32: ConvertibleToJSValue { public var jsValue: JSValue { .number(Double(self)) } } -#if !JAVASCRIPTKIT_WITHOUT_BIGINTS -extension Int64: ConvertibleToJSValue { - public var jsValue: JSValue { .bigInt(JSBigInt(self)) } -} -#endif - extension JSString: ConvertibleToJSValue { public var jsValue: JSValue { .string(self) } } diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift index b86b1a9b..c04979cf 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift @@ -3,22 +3,6 @@ import _CJavaScriptKit private let constructor = JSObject.global.BigInt.function! public final class JSBigInt: JSObject { - public var int64Value: Int64 { - _bigint_to_i64(id, true) - } - - public var uInt64Value: UInt64 { - UInt64(bitPattern: _bigint_to_i64(id, false)) - } - - public convenience init(_ value: Int64) { - self.init(id: _i64_to_bigint(value, true)) - } - - public convenience init(unsigned value: UInt64) { - self.init(id: _i64_to_bigint(Int64(bitPattern: value), false)) - } - @_spi(JSObject_id) override public init(id: JavaScriptObjectRef) { super.init(id: id) } diff --git a/Sources/JavaScriptKit_I64/Int64+I64.swift b/Sources/JavaScriptKit_I64/Int64+I64.swift new file mode 100644 index 00000000..cce10a1b --- /dev/null +++ b/Sources/JavaScriptKit_I64/Int64+I64.swift @@ -0,0 +1,13 @@ +import JavaScriptKit + +extension UInt64: ConvertibleToJSValue, TypedArrayElement { + public static var typedArrayClass = JSObject.global.BigUint64Array.function! + + public var jsValue: JSValue { .bigInt(JSBigInt(unsigned: self)) } +} + +extension Int64: ConvertibleToJSValue, TypedArrayElement { + public static var typedArrayClass = JSObject.global.BigInt64Array.function! + + public var jsValue: JSValue { .bigInt(JSBigInt(self)) } +} diff --git a/Sources/JavaScriptKit_I64/JSBigInt+I64.swift b/Sources/JavaScriptKit_I64/JSBigInt+I64.swift new file mode 100644 index 00000000..592569dd --- /dev/null +++ b/Sources/JavaScriptKit_I64/JSBigInt+I64.swift @@ -0,0 +1,20 @@ +@_spi(JSObject_id) import JavaScriptKit +import _CJavaScriptKit_I64 + +public extension JSBigInt { + var int64Value: Int64 { + _bigint_to_i64(id, true) + } + + var uInt64Value: UInt64 { + UInt64(bitPattern: _bigint_to_i64(id, false)) + } + + convenience init(_ value: Int64) { + self.init(id: _i64_to_bigint(value, true)) + } + + convenience init(unsigned value: UInt64) { + self.init(id: _i64_to_bigint(Int64(bitPattern: value), false)) + } +} diff --git a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h index 3e98e4eb..c3b56c14 100644 --- a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h +++ b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h @@ -301,24 +301,6 @@ __attribute__((__import_module__("javascript_kit"), extern void _release(const JavaScriptObjectRef ref); -#if !JAVASCRIPTKIT_WITHOUT_BIGINTS -/// Converts the provided Int64 or UInt64 to a BigInt. -/// -/// @param value The value to convert. -/// @param is_signed Whether to treat the value as a signed integer or not. -__attribute__((__import_module__("javascript_kit"), - __import_name__("swjs_i64_to_bigint"))) -extern JavaScriptObjectRef _i64_to_bigint(const long long value, bool is_signed); - -/// Converts the provided BigInt to an Int64 or UInt64. -/// -/// @param ref The target JavaScript object. -/// @param is_signed Whether to treat the return value as a signed integer or not. -__attribute__((__import_module__("javascript_kit"), - __import_name__("swjs_bigint_to_i64"))) -extern long long _bigint_to_i64(const JavaScriptObjectRef ref, bool is_signed); -#endif - #endif #endif /* _CJavaScriptKit_h */ diff --git a/Sources/_CJavaScriptKit_I64/_CJavaScriptKit+I64.c b/Sources/_CJavaScriptKit_I64/_CJavaScriptKit+I64.c new file mode 100644 index 00000000..e6b1f456 --- /dev/null +++ b/Sources/_CJavaScriptKit_I64/_CJavaScriptKit+I64.c @@ -0,0 +1 @@ +// empty file to appease build process diff --git a/Sources/_CJavaScriptKit_I64/include/_CJavaScriptKit+I64.h b/Sources/_CJavaScriptKit_I64/include/_CJavaScriptKit+I64.h new file mode 100644 index 00000000..465d2288 --- /dev/null +++ b/Sources/_CJavaScriptKit_I64/include/_CJavaScriptKit+I64.h @@ -0,0 +1,23 @@ + +#ifndef _CJavaScriptKit_I64_h +#define _CJavaScriptKit_I64_h + +#include <_CJavaScriptKit.h> + +/// Converts the provided Int64 or UInt64 to a BigInt. +/// +/// @param value The value to convert. +/// @param is_signed Whether to treat the value as a signed integer or not. +__attribute__((__import_module__("javascript_kit"), + __import_name__("swjs_i64_to_bigint"))) +extern JavaScriptObjectRef _i64_to_bigint(const long long value, bool is_signed); + +/// Converts the provided BigInt to an Int64 or UInt64. +/// +/// @param ref The target JavaScript object. +/// @param is_signed Whether to treat the return value as a signed integer or not. +__attribute__((__import_module__("javascript_kit"), + __import_name__("swjs_bigint_to_i64"))) +extern long long _bigint_to_i64(const JavaScriptObjectRef ref, bool is_signed); + +#endif /* _CJavaScriptKit_I64_h */ diff --git a/Sources/_CJavaScriptKit_I64/include/module.modulemap b/Sources/_CJavaScriptKit_I64/include/module.modulemap new file mode 100644 index 00000000..fb2bdefa --- /dev/null +++ b/Sources/_CJavaScriptKit_I64/include/module.modulemap @@ -0,0 +1,4 @@ +module _CJavaScriptKit_I64 { + header "_CJavaScriptKit+I64.h" + export * +} From b7a6a7d74ef4b355979b73862df4b22048501e50 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 16 Apr 2022 09:15:11 -0400 Subject: [PATCH 29/35] fix Signed/UnsignedInteger ConstructibleFromJSValue --- .../ConstructibleFromJSValue.swift | 20 +++++++++++++++---- .../FundamentalObjects/JSBigInt.swift | 8 ++++++++ Sources/JavaScriptKit_I64/JSBigInt+I64.swift | 10 +++++----- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/Sources/JavaScriptKit/ConstructibleFromJSValue.swift b/Sources/JavaScriptKit/ConstructibleFromJSValue.swift index b5151b37..1f43658f 100644 --- a/Sources/JavaScriptKit/ConstructibleFromJSValue.swift +++ b/Sources/JavaScriptKit/ConstructibleFromJSValue.swift @@ -35,11 +35,17 @@ extension Double: ConstructibleFromJSValue {} extension Float: ConstructibleFromJSValue {} extension SignedInteger where Self: ConstructibleFromJSValue { - public init(_ bigInt: JSBigInt) { + public init(_ bigInt: JSBigIntExtended) { self.init(bigInt.int64Value) } public static func construct(from value: JSValue) -> Self? { - value.bigInt.map(Self.init) ?? value.number.map(Self.init) + if let number = value.number { + return Self(number) + } + if let bigInt = value.bigInt as? JSBigIntExtended { + return Self(bigInt) + } + return nil } } extension Int: ConstructibleFromJSValue {} @@ -49,11 +55,17 @@ extension Int32: ConstructibleFromJSValue {} extension Int64: ConstructibleFromJSValue {} extension UnsignedInteger where Self: ConstructibleFromJSValue { - public init(_ bigInt: JSBigInt) { + public init(_ bigInt: JSBigIntExtended) { self.init(bigInt.uInt64Value) } public static func construct(from value: JSValue) -> Self? { - value.bigInt.map(Self.init) ?? value.number.map(Self.init) + if let number = value.number { + return Self(number) + } + if let bigInt = value.bigInt as? JSBigIntExtended { + return Self(bigInt) + } + return nil } } extension UInt: ConstructibleFromJSValue {} diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift index c04979cf..e5495110 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift @@ -23,3 +23,11 @@ public final class JSBigInt: JSObject { } } } + +public protocol JSBigIntExtended: JSBigInt { + var int64Value: Int64 { get } + var uInt64Value: UInt64 { get } + + init(_ value: Int64) + init(unsigned value: UInt64) +} diff --git a/Sources/JavaScriptKit_I64/JSBigInt+I64.swift b/Sources/JavaScriptKit_I64/JSBigInt+I64.swift index 592569dd..c2b88f86 100644 --- a/Sources/JavaScriptKit_I64/JSBigInt+I64.swift +++ b/Sources/JavaScriptKit_I64/JSBigInt+I64.swift @@ -1,20 +1,20 @@ @_spi(JSObject_id) import JavaScriptKit import _CJavaScriptKit_I64 -public extension JSBigInt { - var int64Value: Int64 { +extension JSBigInt: JSBigIntExtended { + public var int64Value: Int64 { _bigint_to_i64(id, true) } - var uInt64Value: UInt64 { + public var uInt64Value: UInt64 { UInt64(bitPattern: _bigint_to_i64(id, false)) } - convenience init(_ value: Int64) { + convenience public init(_ value: Int64) { self.init(id: _i64_to_bigint(value, true)) } - convenience init(unsigned value: UInt64) { + convenience public init(unsigned value: UInt64) { self.init(id: _i64_to_bigint(Int64(bitPattern: value), false)) } } From b83611f6537ea85f89d71b5002cc3bfc5f30248b Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 16 Apr 2022 09:30:29 -0400 Subject: [PATCH 30/35] fix tests? --- IntegrationTests/TestSuites/Package.swift | 1 + .../TestSuites/Sources/PrimaryTests/I64.swift | 35 +++++++++++++++++++ .../Sources/PrimaryTests/main.swift | 33 +---------------- 3 files changed, 37 insertions(+), 32 deletions(-) create mode 100644 IntegrationTests/TestSuites/Sources/PrimaryTests/I64.swift diff --git a/IntegrationTests/TestSuites/Package.swift b/IntegrationTests/TestSuites/Package.swift index 0344d049..0a0bdf66 100644 --- a/IntegrationTests/TestSuites/Package.swift +++ b/IntegrationTests/TestSuites/Package.swift @@ -25,6 +25,7 @@ let package = Package( targets: [ .target(name: "CHelpers"), .target(name: "PrimaryTests", dependencies: [ + .product(name: "JavaScriptKit_I64", package: "JavaScriptKit"), "JavaScriptKit", "CHelpers", ]), diff --git a/IntegrationTests/TestSuites/Sources/PrimaryTests/I64.swift b/IntegrationTests/TestSuites/Sources/PrimaryTests/I64.swift new file mode 100644 index 00000000..82913481 --- /dev/null +++ b/IntegrationTests/TestSuites/Sources/PrimaryTests/I64.swift @@ -0,0 +1,35 @@ +import JavaScriptKit +import JavaScriptKit_I64 + +func testI64() throws { + try test("BigInt") { + func expectPassesThrough(signed value: Int64) throws { + let bigInt = JSBigInt(value) + try expectEqual(bigInt.description, value.description) + } + + func expectPassesThrough(unsigned value: UInt64) throws { + let bigInt = JSBigInt(unsigned: value) + try expectEqual(bigInt.description, value.description) + } + + try expectPassesThrough(signed: 0) + try expectPassesThrough(signed: 1 << 62) + try expectPassesThrough(signed: -2305) + for _ in 0 ..< 100 { + try expectPassesThrough(signed: .random(in: .min ... .max)) + } + try expectPassesThrough(signed: .min) + try expectPassesThrough(signed: .max) + + try expectPassesThrough(unsigned: 0) + try expectPassesThrough(unsigned: 1 << 62) + try expectPassesThrough(unsigned: 1 << 63) + try expectPassesThrough(unsigned: .min) + try expectPassesThrough(unsigned: .max) + try expectPassesThrough(unsigned: ~0) + for _ in 0 ..< 100 { + try expectPassesThrough(unsigned: .random(in: .min ... .max)) + } + } +} diff --git a/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift b/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift index 42aa649e..a48c6fb0 100644 --- a/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift +++ b/IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift @@ -852,36 +852,5 @@ try test("JSValueDecoder") { try expectEqual(decodedTama.isCat, true) } - -try test("BigInt") { - func expectPassesThrough(signed value: Int64) throws { - let bigInt = JSBigInt(value) - try expectEqual(bigInt.description, value.description) - } - - func expectPassesThrough(unsigned value: UInt64) throws { - let bigInt = JSBigInt(unsigned: value) - try expectEqual(bigInt.description, value.description) - } - - try expectPassesThrough(signed: 0) - try expectPassesThrough(signed: 1 << 62) - try expectPassesThrough(signed: -2305) - for _ in 0 ..< 100 { - try expectPassesThrough(signed: .random(in: .min ... .max)) - } - try expectPassesThrough(signed: .min) - try expectPassesThrough(signed: .max) - - try expectPassesThrough(unsigned: 0) - try expectPassesThrough(unsigned: 1 << 62) - try expectPassesThrough(unsigned: 1 << 63) - try expectPassesThrough(unsigned: .min) - try expectPassesThrough(unsigned: .max) - try expectPassesThrough(unsigned: ~0) - for _ in 0 ..< 100 { - try expectPassesThrough(unsigned: .random(in: .min ... .max)) - } -} - +try testI64() Expectation.wait(expectations) From 4ca7705d5237d5529b4fd386afcab2fb7be2f8e0 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 16 Apr 2022 18:52:41 -0400 Subject: [PATCH 31/35] Address review comments --- Runtime/src/types.ts | 6 ++---- Sources/JavaScriptKit/XcodeSupport.swift | 5 ----- Sources/JavaScriptKit_I64/XcodeSupport.swift | 11 +++++++++++ 3 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 Sources/JavaScriptKit_I64/XcodeSupport.swift diff --git a/Runtime/src/types.ts b/Runtime/src/types.ts index 95e3f9fe..bc670087 100644 --- a/Runtime/src/types.ts +++ b/Runtime/src/types.ts @@ -109,7 +109,6 @@ export interface ImportedFunctions { export const enum LibraryFeatures { WeakRefs = 1 << 0, - BigInts = 1 << 1, } export type TypedArray = @@ -119,9 +118,8 @@ export type TypedArray = | Uint16ArrayConstructor | Int32ArrayConstructor | Uint32ArrayConstructor - // BigInt is not yet supported, see https://github.com/swiftwasm/JavaScriptKit/issues/56 - // | BigInt64ArrayConstructor - // | BigUint64ArrayConstructor + | BigInt64ArrayConstructor + | BigUint64ArrayConstructor | Float32ArrayConstructor | Float64ArrayConstructor; diff --git a/Sources/JavaScriptKit/XcodeSupport.swift b/Sources/JavaScriptKit/XcodeSupport.swift index d38a0a08..7048bcfd 100644 --- a/Sources/JavaScriptKit/XcodeSupport.swift +++ b/Sources/JavaScriptKit/XcodeSupport.swift @@ -102,9 +102,4 @@ import _CJavaScriptKit _: UnsafeMutablePointer! ) { fatalError() } func _release(_: JavaScriptObjectRef) { fatalError() } -#if !JAVASCRIPTKIT_WITHOUT_BIGINTS - func _i64_to_bigint(_: Int64, _: Bool) -> JavaScriptObjectRef { fatalError() } - func _bigint_to_i64(_: JavaScriptObjectRef, _: Bool) -> Int64 { fatalError() } -#endif - #endif diff --git a/Sources/JavaScriptKit_I64/XcodeSupport.swift b/Sources/JavaScriptKit_I64/XcodeSupport.swift new file mode 100644 index 00000000..85170c1a --- /dev/null +++ b/Sources/JavaScriptKit_I64/XcodeSupport.swift @@ -0,0 +1,11 @@ +import _CJavaScriptKit + +/// Note: +/// Define all runtime functions stub which are imported from JavaScript environment. +/// SwiftPM doesn't support WebAssembly target yet, so we need to define them to +/// avoid link failure. +/// When running with JavaScript runtime library, they are ignored completely. +#if !arch(wasm32) + func _i64_to_bigint(_: Int64, _: Bool) -> JavaScriptObjectRef { fatalError() } + func _bigint_to_i64(_: JavaScriptObjectRef, _: Bool) -> Int64 { fatalError() } +#endif From 35dd9f7f958d9f9b4ca3823378642aa171453139 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Sat, 16 Apr 2022 19:00:01 -0400 Subject: [PATCH 32/35] Simplify JSValue: CustomStringConvertible conformance --- Sources/JavaScriptKit/JSValue.swift | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/Sources/JavaScriptKit/JSValue.swift b/Sources/JavaScriptKit/JSValue.swift index 8fdd2cd3..973dfcb5 100644 --- a/Sources/JavaScriptKit/JSValue.swift +++ b/Sources/JavaScriptKit/JSValue.swift @@ -257,20 +257,8 @@ public extension JSValue { extension JSValue: CustomStringConvertible { public var description: String { - switch self { - case let .boolean(boolean): - return boolean.description - case let .string(string): - return string.description - case let .number(number): - return number.description - case let .object(object), let .function(object as JSObject), - let .symbol(object as JSObject), let .bigInt(object as JSObject): - return object.toString!().fromJSValue()! - case .null: - return "null" - case .undefined: - return "undefined" - } + // per https://tc39.es/ecma262/multipage/text-processing.html#sec-string-constructor-string-value + // this always returns a string + JSObject.global.String.function!(self).string! } } From 0ec8fc3aefdd32776624890045b85017f13200be Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Fri, 22 Apr 2022 09:50:45 -0400 Subject: [PATCH 33/35] rename to JavaScriptBigIntSupport --- IntegrationTests/TestSuites/Package.swift | 4 ++-- .../TestSuites/Sources/PrimaryTests/I64.swift | 2 +- Package.swift | 8 ++++---- .../Int64+I64.swift | 0 .../JSBigInt+I64.swift | 6 +++--- .../XcodeSupport.swift | 0 .../_CJavaScriptKit+I64.c | 0 .../include/_CJavaScriptKit+I64.h | 6 +++--- .../include/module.modulemap | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) rename Sources/{JavaScriptKit_I64 => JavaScriptBigIntSupport}/Int64+I64.swift (100%) rename Sources/{JavaScriptKit_I64 => JavaScriptBigIntSupport}/JSBigInt+I64.swift (74%) rename Sources/{JavaScriptKit_I64 => JavaScriptBigIntSupport}/XcodeSupport.swift (100%) rename Sources/{_CJavaScriptKit_I64 => _CJavaScriptBigIntSupport}/_CJavaScriptKit+I64.c (100%) rename Sources/{_CJavaScriptKit_I64 => _CJavaScriptBigIntSupport}/include/_CJavaScriptKit+I64.h (87%) rename Sources/{_CJavaScriptKit_I64 => _CJavaScriptBigIntSupport}/include/module.modulemap (58%) diff --git a/IntegrationTests/TestSuites/Package.swift b/IntegrationTests/TestSuites/Package.swift index 0a0bdf66..297fa838 100644 --- a/IntegrationTests/TestSuites/Package.swift +++ b/IntegrationTests/TestSuites/Package.swift @@ -8,7 +8,7 @@ let package = Package( // This package doesn't work on macOS host, but should be able to be built for it // for developing on Xcode. This minimum version requirement is to prevent availability // errors for Concurrency API, whose runtime support is shipped from macOS 12.0 - .macOS("12.0") + .macOS("12.0"), ], products: [ .executable( @@ -25,7 +25,7 @@ let package = Package( targets: [ .target(name: "CHelpers"), .target(name: "PrimaryTests", dependencies: [ - .product(name: "JavaScriptKit_I64", package: "JavaScriptKit"), + .product(name: "JavaScriptBigIntSupport", package: "JavaScriptKit"), "JavaScriptKit", "CHelpers", ]), diff --git a/IntegrationTests/TestSuites/Sources/PrimaryTests/I64.swift b/IntegrationTests/TestSuites/Sources/PrimaryTests/I64.swift index 82913481..bd0831e7 100644 --- a/IntegrationTests/TestSuites/Sources/PrimaryTests/I64.swift +++ b/IntegrationTests/TestSuites/Sources/PrimaryTests/I64.swift @@ -1,5 +1,5 @@ +import JavaScriptBigIntSupport import JavaScriptKit -import JavaScriptKit_I64 func testI64() throws { try test("BigInt") { diff --git a/Package.swift b/Package.swift index 4f50d5fb..3d07321a 100644 --- a/Package.swift +++ b/Package.swift @@ -7,7 +7,7 @@ let package = Package( products: [ .library(name: "JavaScriptKit", targets: ["JavaScriptKit"]), .library(name: "JavaScriptEventLoop", targets: ["JavaScriptEventLoop"]), - .library(name: "JavaScriptKit_I64", targets: ["JavaScriptKit_I64"]), + .library(name: "JavaScriptBigIntSupport", targets: ["JavaScriptBigIntSupport"]), ], targets: [ .target( @@ -16,10 +16,10 @@ let package = Package( ), .target(name: "_CJavaScriptKit"), .target( - name: "JavaScriptKit_I64", - dependencies: ["_CJavaScriptKit_I64", "JavaScriptKit"] + name: "JavaScriptBigIntSupport", + dependencies: ["_CJavaScriptBigIntSupport", "JavaScriptKit"] ), - .target(name: "_CJavaScriptKit_I64", dependencies: ["_CJavaScriptKit"]), + .target(name: "_CJavaScriptBigIntSupport", dependencies: ["_CJavaScriptKit"]), .target( name: "JavaScriptEventLoop", dependencies: ["JavaScriptKit", "_CJavaScriptEventLoop"] diff --git a/Sources/JavaScriptKit_I64/Int64+I64.swift b/Sources/JavaScriptBigIntSupport/Int64+I64.swift similarity index 100% rename from Sources/JavaScriptKit_I64/Int64+I64.swift rename to Sources/JavaScriptBigIntSupport/Int64+I64.swift diff --git a/Sources/JavaScriptKit_I64/JSBigInt+I64.swift b/Sources/JavaScriptBigIntSupport/JSBigInt+I64.swift similarity index 74% rename from Sources/JavaScriptKit_I64/JSBigInt+I64.swift rename to Sources/JavaScriptBigIntSupport/JSBigInt+I64.swift index c2b88f86..4c8b9bca 100644 --- a/Sources/JavaScriptKit_I64/JSBigInt+I64.swift +++ b/Sources/JavaScriptBigIntSupport/JSBigInt+I64.swift @@ -1,5 +1,5 @@ +import _CJavaScriptBigIntSupport @_spi(JSObject_id) import JavaScriptKit -import _CJavaScriptKit_I64 extension JSBigInt: JSBigIntExtended { public var int64Value: Int64 { @@ -10,11 +10,11 @@ extension JSBigInt: JSBigIntExtended { UInt64(bitPattern: _bigint_to_i64(id, false)) } - convenience public init(_ value: Int64) { + public convenience init(_ value: Int64) { self.init(id: _i64_to_bigint(value, true)) } - convenience public init(unsigned value: UInt64) { + public convenience init(unsigned value: UInt64) { self.init(id: _i64_to_bigint(Int64(bitPattern: value), false)) } } diff --git a/Sources/JavaScriptKit_I64/XcodeSupport.swift b/Sources/JavaScriptBigIntSupport/XcodeSupport.swift similarity index 100% rename from Sources/JavaScriptKit_I64/XcodeSupport.swift rename to Sources/JavaScriptBigIntSupport/XcodeSupport.swift diff --git a/Sources/_CJavaScriptKit_I64/_CJavaScriptKit+I64.c b/Sources/_CJavaScriptBigIntSupport/_CJavaScriptKit+I64.c similarity index 100% rename from Sources/_CJavaScriptKit_I64/_CJavaScriptKit+I64.c rename to Sources/_CJavaScriptBigIntSupport/_CJavaScriptKit+I64.c diff --git a/Sources/_CJavaScriptKit_I64/include/_CJavaScriptKit+I64.h b/Sources/_CJavaScriptBigIntSupport/include/_CJavaScriptKit+I64.h similarity index 87% rename from Sources/_CJavaScriptKit_I64/include/_CJavaScriptKit+I64.h rename to Sources/_CJavaScriptBigIntSupport/include/_CJavaScriptKit+I64.h index 465d2288..dc898c43 100644 --- a/Sources/_CJavaScriptKit_I64/include/_CJavaScriptKit+I64.h +++ b/Sources/_CJavaScriptBigIntSupport/include/_CJavaScriptKit+I64.h @@ -1,6 +1,6 @@ -#ifndef _CJavaScriptKit_I64_h -#define _CJavaScriptKit_I64_h +#ifndef _CJavaScriptBigIntSupport_h +#define _CJavaScriptBigIntSupport_h #include <_CJavaScriptKit.h> @@ -20,4 +20,4 @@ __attribute__((__import_module__("javascript_kit"), __import_name__("swjs_bigint_to_i64"))) extern long long _bigint_to_i64(const JavaScriptObjectRef ref, bool is_signed); -#endif /* _CJavaScriptKit_I64_h */ +#endif /* _CJavaScriptBigIntSupport_h */ diff --git a/Sources/_CJavaScriptKit_I64/include/module.modulemap b/Sources/_CJavaScriptBigIntSupport/include/module.modulemap similarity index 58% rename from Sources/_CJavaScriptKit_I64/include/module.modulemap rename to Sources/_CJavaScriptBigIntSupport/include/module.modulemap index fb2bdefa..944871cd 100644 --- a/Sources/_CJavaScriptKit_I64/include/module.modulemap +++ b/Sources/_CJavaScriptBigIntSupport/include/module.modulemap @@ -1,4 +1,4 @@ -module _CJavaScriptKit_I64 { +module _CJavaScriptBigIntSupport { header "_CJavaScriptKit+I64.h" export * } From 796019863ed255654d6113cdf0d2965df9c52fa8 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Fri, 22 Apr 2022 09:51:50 -0400 Subject: [PATCH 34/35] Formatting tweak Co-Authored-By: Max Desiatov --- Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift | 3 ++- Sources/JavaScriptKit/FundamentalObjects/JSObject.swift | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift index e5495110..4513c14a 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSBigInt.swift @@ -3,7 +3,8 @@ import _CJavaScriptKit private let constructor = JSObject.global.BigInt.function! public final class JSBigInt: JSObject { - @_spi(JSObject_id) override public init(id: JavaScriptObjectRef) { + @_spi(JSObject_id) + override public init(id: JavaScriptObjectRef) { super.init(id: id) } diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift b/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift index f7544533..4e93853e 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSObject.swift @@ -16,8 +16,10 @@ import _CJavaScriptKit /// reference counting system. @dynamicMemberLookup public class JSObject: Equatable { - @_spi(JSObject_id) public var id: JavaScriptObjectRef - @_spi(JSObject_id) public init(id: JavaScriptObjectRef) { + @_spi(JSObject_id) + public var id: JavaScriptObjectRef + @_spi(JSObject_id) + public init(id: JavaScriptObjectRef) { self.id = id } @@ -120,7 +122,7 @@ public class JSObject: Equatable { /// let animal = JSObject.global.animal.object! /// try animal.throwing.validateAge!() /// ``` - public var `throwing`: JSThrowingObject { + public var throwing: JSThrowingObject { JSThrowingObject(self) } From 5cff1425369819c7b61e234e93b2cd441af96848 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Fri, 22 Apr 2022 09:52:15 -0400 Subject: [PATCH 35/35] fix typo Co-Authored-By: Max Desiatov --- Sources/JavaScriptBigIntSupport/XcodeSupport.swift | 2 +- Sources/JavaScriptKit/XcodeSupport.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/JavaScriptBigIntSupport/XcodeSupport.swift b/Sources/JavaScriptBigIntSupport/XcodeSupport.swift index 85170c1a..54912cec 100644 --- a/Sources/JavaScriptBigIntSupport/XcodeSupport.swift +++ b/Sources/JavaScriptBigIntSupport/XcodeSupport.swift @@ -1,7 +1,7 @@ import _CJavaScriptKit /// Note: -/// Define all runtime functions stub which are imported from JavaScript environment. +/// Define all runtime function stubs which are imported from JavaScript environment. /// SwiftPM doesn't support WebAssembly target yet, so we need to define them to /// avoid link failure. /// When running with JavaScript runtime library, they are ignored completely. diff --git a/Sources/JavaScriptKit/XcodeSupport.swift b/Sources/JavaScriptKit/XcodeSupport.swift index 7048bcfd..4cde273f 100644 --- a/Sources/JavaScriptKit/XcodeSupport.swift +++ b/Sources/JavaScriptKit/XcodeSupport.swift @@ -1,7 +1,7 @@ import _CJavaScriptKit /// Note: -/// Define all runtime functions stub which are imported from JavaScript environment. +/// Define all runtime function stubs which are imported from JavaScript environment. /// SwiftPM doesn't support WebAssembly target yet, so we need to define them to /// avoid link failure. /// When running with JavaScript runtime library, they are ignored completely.