GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Add `JSRemote<T>` for owner-thread `JSObject` access · Issue #704 · swiftwasm/JavaScriptKit

Add JSRemote<T> for owner-thread JSObject access #704

New issue
Copy link
New issue
Copy link
Closed
Closed
Add JSRemote<T> for owner-thread JSObject access#704
Copy link

Description

@kateinoigakukun
kateinoigakukun
opened on Mar 19, 2026
Issue body actions

Motivation

JSObject is intentionally thread-bound in JavaScriptKit. In multi-threaded WebAssembly builds, each worker owns its own JavaScript object space, and JSObject enforces that ownership at runtime via ownerTid.

This is the right default for safety, but it leaves a gap for cases where Swift code wants to keep a stable reference to a JavaScript object while interacting with it from another isolation domain. Today the only public cross-thread escape hatch is JSSending, which transfers or clones the object into the destination thread. That is useful when ownership should move, but it does not help when the caller wants to keep using the original object on its original owner thread.

We need a small, explicit abstraction for that use case: a sendable handle that can be passed across threads, while only exposing the underlying JSObject through an async hop back to the owner thread.

Overview

This proposal introduces JSRemote<T> in JavaScriptEventLoop.

The initial scope is intentionally narrow:

  • The first version is effectively JSRemote<JSObject>.
  • The handle is Sendable.
  • It retains the original owner-side JSObject.
  • It stores the owning thread ID.
  • The wrapped object is only accessible through an async API that executes a closure on the owner thread.

The key design constraints are:

  • JSObject itself should remain non-Sendable
  • the public API should make cross-thread access explicit
  • the wrapped object should not be cloned or transferred just to perform a temporary access
  • the implementation should reuse the existing ITC request-routing mechanism already used by JSSending

API Design (draft)

The first public shape would be:

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
public struct JSRemote<T>: @unchecked Sendable

@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
extension JSRemote where T == JSObject {
    public init(_ object: JSObject)

    public func withJSObject<R: Sendable>(
        _ body: (JSObject) -> R
    ) async -> R
}

Usage:

let remote = JSRemote(document)

let title = await remote.withJSObject { document in
    document.title.string ?? ""
}

Semantics:

  • withJSObject always executes body on the JSObject owner thread
  • the method is async because it may need to hop threads
  • the closure itself is synchronous and cannot suspend while borrowing the object
  • the return type is constrained to Sendable, so raw JS references do not escape back across threads
Reacted by Max Desiatov, Andrew Luey and Adin

Activity

  1. kateinoigakukun
    closed this as completedon Apr 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402520 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.