From 0dbd39a79770c9b9ca4d952b074f188bd26fee21 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 15 Oct 2024 07:28:40 +0900 Subject: [PATCH 1/4] Fix build for embedded platforms around JSBigIntExtended existential --- Sources/JavaScriptKit/ConstructibleFromJSValue.swift | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Sources/JavaScriptKit/ConstructibleFromJSValue.swift b/Sources/JavaScriptKit/ConstructibleFromJSValue.swift index ce1e1c25f..f0e0ad431 100644 --- a/Sources/JavaScriptKit/ConstructibleFromJSValue.swift +++ b/Sources/JavaScriptKit/ConstructibleFromJSValue.swift @@ -40,7 +40,7 @@ extension SignedInteger where Self: ConstructibleFromJSValue { /// If the value is too large to fit in the `Self` type, `nil` is returned. /// /// - Parameter bigInt: The `JSBigIntExtended` to decode - public init?(exactly bigInt: JSBigIntExtended) { + public init?(exactly bigInt: some JSBigIntExtended) { self.init(exactly: bigInt.int64Value) } @@ -49,7 +49,7 @@ extension SignedInteger where Self: ConstructibleFromJSValue { /// Crash if the value is too large to fit in the `Self` type. /// /// - Parameter bigInt: The `JSBigIntExtended` to decode - public init(_ bigInt: JSBigIntExtended) { + public init(_ bigInt: some JSBigIntExtended) { self.init(bigInt.int64Value) } @@ -68,9 +68,11 @@ extension SignedInteger where Self: ConstructibleFromJSValue { if let number = value.number { return Self(exactly: number.rounded(.towardZero)) } +#if !hasFeature(Embedded) if let bigInt = value.bigInt as? JSBigIntExtended { return Self(exactly: bigInt) } +#endif return nil } } @@ -87,7 +89,7 @@ extension UnsignedInteger where Self: ConstructibleFromJSValue { /// Returns `nil` if the value is negative or too large to fit in the `Self` type. /// /// - Parameter bigInt: The `JSBigIntExtended` to decode - public init?(exactly bigInt: JSBigIntExtended) { + public init?(exactly bigInt: some JSBigIntExtended) { self.init(exactly: bigInt.uInt64Value) } @@ -96,7 +98,7 @@ extension UnsignedInteger where Self: ConstructibleFromJSValue { /// Crash if the value is negative or too large to fit in the `Self` type. /// /// - Parameter bigInt: The `JSBigIntExtended` to decode - public init(_ bigInt: JSBigIntExtended) { + public init(_ bigInt: some JSBigIntExtended) { self.init(bigInt.uInt64Value) } @@ -114,9 +116,11 @@ extension UnsignedInteger where Self: ConstructibleFromJSValue { if let number = value.number { return Self(exactly: number.rounded(.towardZero)) } +#if !hasFeature(Embedded) if let bigInt = value.bigInt as? JSBigIntExtended { return Self(exactly: bigInt) } +#endif return nil } } From a4636bbc5537216d59246b7c6de07edb6b0752c0 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 15 Oct 2024 11:12:07 +0900 Subject: [PATCH 2/4] Simplify the embedded example * Remove EmbeddedFoundation dependency * Prefix the experimental feature flags with `JAVASCRIPTKIT_` * Remove the unnecessary C shim for `memmove`, which is now provided by `swift-dlmalloc` * Add the `arc4random_buf` shim for the latest Hashable support --- Examples/Embedded/Package.swift | 21 +++++++++++++++++-- .../_thingsThatShouldNotBeNeeded.swift | 14 +++++-------- Examples/Embedded/build.sh | 8 ++----- Package.swift | 2 +- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/Examples/Embedded/Package.swift b/Examples/Embedded/Package.swift index f0c03bd87..4ebc6e841 100644 --- a/Examples/Embedded/Package.swift +++ b/Examples/Embedded/Package.swift @@ -6,14 +6,31 @@ let package = Package( name: "Embedded", dependencies: [ .package(name: "JavaScriptKit", path: "../../"), - .package(url: "https://github.com/swifweb/EmbeddedFoundation", branch: "0.1.0") + .package(url: "https://github.com/swiftwasm/swift-dlmalloc", branch: "0.1.0") ], targets: [ .executableTarget( name: "EmbeddedApp", dependencies: [ "JavaScriptKit", - .product(name: "Foundation", package: "EmbeddedFoundation") + .product(name: "dlmalloc", package: "swift-dlmalloc") + ], + cSettings: [ + .unsafeFlags(["-fdeclspec"]) + ], + swiftSettings: [ + .enableExperimentalFeature("Embedded"), + .enableExperimentalFeature("Extern"), + .unsafeFlags([ + "-Xfrontend", "-gnone", + "-Xfrontend", "-disable-stack-protector", + ]), + ], + linkerSettings: [ + .unsafeFlags([ + "-Xclang-linker", "-nostdlib", + "-Xlinker", "--no-entry" + ]) ] ) ] diff --git a/Examples/Embedded/Sources/EmbeddedApp/_thingsThatShouldNotBeNeeded.swift b/Examples/Embedded/Sources/EmbeddedApp/_thingsThatShouldNotBeNeeded.swift index 20a26e085..773f928d8 100644 --- a/Examples/Embedded/Sources/EmbeddedApp/_thingsThatShouldNotBeNeeded.swift +++ b/Examples/Embedded/Sources/EmbeddedApp/_thingsThatShouldNotBeNeeded.swift @@ -17,13 +17,9 @@ func strlen(_ s: UnsafePointer) -> Int { return p - s } -// TODO: why do I need this? and surely this is not ideal... figure this out, or at least have this come from a C lib -@_cdecl("memmove") -func memmove(_ dest: UnsafeMutableRawPointer, _ src: UnsafeRawPointer, _ n: Int) -> UnsafeMutableRawPointer { - let d = dest.assumingMemoryBound(to: UInt8.self) - let s = src.assumingMemoryBound(to: UInt8.self) - for i in 0.. Date: Tue, 15 Oct 2024 11:46:49 +0900 Subject: [PATCH 3/4] Unify `JavaScriptValueKindAndFlags` type across non-/Embedded builds --- .../FundamentalObjects/JSFunction.swift | 24 ++++++------------- .../JSThrowingFunction.swift | 13 +++++----- .../_CJavaScriptKit/include/_CJavaScriptKit.h | 12 ++-------- 3 files changed, 16 insertions(+), 33 deletions(-) diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift b/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift index 443063981..4620a3aa7 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSFunction.swift @@ -136,7 +136,7 @@ public class JSFunction: JSObject, _JSFunctionProtocol { id, argv, Int32(argc), &payload1, &payload2 ) - let kindAndFlags = valueKindAndFlagsFromBits(resultBitPattern) + let kindAndFlags = JavaScriptValueKindAndFlags(bitPattern: resultBitPattern) assert(!kindAndFlags.isException) let result = RawJSValue(kind: kindAndFlags.kind, payload1: payload1, payload2: payload2) return result @@ -153,7 +153,7 @@ public class JSFunction: JSObject, _JSFunctionProtocol { id, argv, Int32(argc), &payload1, &payload2 ) - let kindAndFlags = valueKindAndFlagsFromBits(resultBitPattern) + let kindAndFlags = JavaScriptValueKindAndFlags(bitPattern: resultBitPattern) #if !hasFeature(Embedded) assert(!kindAndFlags.isException) #endif @@ -241,25 +241,15 @@ public extension _JSFunctionProtocol { new(arguments: [arg0.jsValue, arg1.jsValue, arg2.jsValue, arg3.jsValue, arg4.jsValue, arg5.jsValue, arg6.jsValue]) } } +#endif -// C bit fields seem to not work with Embedded -// in "normal mode" this is defined as a C struct -private struct JavaScriptValueKindAndFlags { - let errorBit: UInt32 = 1 << 32 +internal struct JavaScriptValueKindAndFlags { + static var errorBit: UInt32 { 1 << 31 } let kind: JavaScriptValueKind let isException: Bool init(bitPattern: UInt32) { - self.kind = JavaScriptValueKind(rawValue: bitPattern & ~errorBit)! - self.isException = (bitPattern & errorBit) != 0 + self.kind = JavaScriptValueKind(rawValue: bitPattern & ~Self.errorBit)! + self.isException = (bitPattern & Self.errorBit) != 0 } } -#endif - -private func valueKindAndFlagsFromBits(_ bits: UInt32) -> JavaScriptValueKindAndFlags { - #if hasFeature(Embedded) - JavaScriptValueKindAndFlags(bitPattern: bits) - #else - unsafeBitCast(bits, to: JavaScriptValueKindAndFlags.self) - #endif -} \ No newline at end of file diff --git a/Sources/JavaScriptKit/FundamentalObjects/JSThrowingFunction.swift b/Sources/JavaScriptKit/FundamentalObjects/JSThrowingFunction.swift index 95bc2bd9c..8b4fc7cde 100644 --- a/Sources/JavaScriptKit/FundamentalObjects/JSThrowingFunction.swift +++ b/Sources/JavaScriptKit/FundamentalObjects/JSThrowingFunction.swift @@ -42,13 +42,14 @@ public class JSThrowingFunction { let argv = bufferPointer.baseAddress let argc = bufferPointer.count - var exceptionKind = JavaScriptValueKindAndFlags() + var exceptionRawKind = JavaScriptRawValueKindAndFlags() var exceptionPayload1 = JavaScriptPayload1() var exceptionPayload2 = JavaScriptPayload2() let resultObj = swjs_call_throwing_new( self.base.id, argv, Int32(argc), - &exceptionKind, &exceptionPayload1, &exceptionPayload2 + &exceptionRawKind, &exceptionPayload1, &exceptionPayload2 ) + let exceptionKind = JavaScriptValueKindAndFlags(bitPattern: exceptionRawKind) if exceptionKind.isException { let exception = RawJSValue(kind: exceptionKind.kind, payload1: exceptionPayload1, payload2: exceptionPayload2) return .failure(exception.jsValue) @@ -70,7 +71,7 @@ private func invokeJSFunction(_ jsFunc: JSFunction, arguments: [ConvertibleToJSV rawValues.withUnsafeBufferPointer { bufferPointer -> (JSValue, Bool) in let argv = bufferPointer.baseAddress let argc = bufferPointer.count - var kindAndFlags = JavaScriptValueKindAndFlags() + let kindAndFlags: JavaScriptValueKindAndFlags var payload1 = JavaScriptPayload1() var payload2 = JavaScriptPayload2() if let thisId = this?.id { @@ -78,13 +79,13 @@ private func invokeJSFunction(_ jsFunc: JSFunction, arguments: [ConvertibleToJSV thisId, id, argv, Int32(argc), &payload1, &payload2 ) - kindAndFlags = unsafeBitCast(resultBitPattern, to: JavaScriptValueKindAndFlags.self) + kindAndFlags = JavaScriptValueKindAndFlags(bitPattern: resultBitPattern) } else { let resultBitPattern = swjs_call_function( id, argv, Int32(argc), &payload1, &payload2 ) - kindAndFlags = unsafeBitCast(resultBitPattern, to: JavaScriptValueKindAndFlags.self) + kindAndFlags = JavaScriptValueKindAndFlags(bitPattern: resultBitPattern) } let result = RawJSValue(kind: kindAndFlags.kind, payload1: payload1, payload2: payload2) return (result.jsValue, kindAndFlags.isException) @@ -95,4 +96,4 @@ private func invokeJSFunction(_ jsFunc: JSFunction, arguments: [ConvertibleToJSV } return result } -#endif \ No newline at end of file +#endif diff --git a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h index 8daf7cdc6..cac103c3f 100644 --- a/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h +++ b/Sources/_CJavaScriptKit/include/_CJavaScriptKit.h @@ -29,15 +29,7 @@ typedef enum __attribute__((enum_extensibility(closed))) { JavaScriptValueKindBigInt = 8, } JavaScriptValueKind; -#if __Embedded -// something about the bit field widths is not working with embedded -typedef unsigned short JavaScriptValueKindAndFlags; -#else -typedef struct { - JavaScriptValueKind kind: 31; - bool isException: 1; -} JavaScriptValueKindAndFlags; -#endif +typedef uint32_t JavaScriptRawValueKindAndFlags; typedef unsigned JavaScriptPayload1; typedef double JavaScriptPayload2; @@ -253,7 +245,7 @@ IMPORT_JS_FUNCTION(swjs_call_new, JavaScriptObjectRef, (const JavaScriptObjectRe IMPORT_JS_FUNCTION(swjs_call_throwing_new, JavaScriptObjectRef, (const JavaScriptObjectRef ref, const RawJSValue *argv, const int argc, - JavaScriptValueKindAndFlags *exception_kind, + JavaScriptRawValueKindAndFlags *exception_kind, JavaScriptPayload1 *exception_payload1, JavaScriptPayload2 *exception_payload2)) From c326ebff6bf97bc608d5cfb68b8be7ec07cee053 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Tue, 15 Oct 2024 11:53:41 +0900 Subject: [PATCH 4/4] Add Embedded build to CI --- .github/workflows/test.yml | 16 ++++++++++++++++ Examples/Embedded/build.sh | 4 +++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bc07e6a56..8ba892e06 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -86,3 +86,19 @@ jobs: - run: swift build env: DEVELOPER_DIR: /Applications/${{ matrix.xcode }}.app/Contents/Developer/ + + embedded-build: + name: Build for embedded target + runs-on: ubuntu-22.04 + strategy: + matrix: + entry: + - os: ubuntu-22.04 + toolchain: DEVELOPMENT-SNAPSHOT-2024-09-25-a + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/install-swift + with: + swift-dir: development/ubuntu2204 + swift-version: swift-${{ matrix.entry.toolchain }} + - run: ./Examples/Embedded/build.sh diff --git a/Examples/Embedded/build.sh b/Examples/Embedded/build.sh index d219136b3..e1c3e3c4e 100755 --- a/Examples/Embedded/build.sh +++ b/Examples/Embedded/build.sh @@ -1,4 +1,6 @@ -JAVASCRIPTKIT_EXPERIMENTAL_EMBEDDED_WASM=true swift build -c release --product EmbeddedApp \ +#!/bin/bash +package_dir="$(cd "$(dirname "$0")" && pwd)" +JAVASCRIPTKIT_EXPERIMENTAL_EMBEDDED_WASM=true swift build --package-path "$package_dir" -c release --product EmbeddedApp \ --triple wasm32-unknown-none-wasm \ -Xswiftc -enable-experimental-feature -Xswiftc Embedded \ -Xswiftc -enable-experimental-feature -Xswiftc Extern \