Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ jobs:
enable_windows_checks: false
swift_flags: --package-path WebGPUDemo

dom-ref-types:
name: Build DOMRefTypes Demo
uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@main
with:
enable_embedded_wasm_sdk_build: true
enable_linux_checks: false
enable_macos_checks: false
enable_windows_checks: false
swift_flags: --package-path DOMRefTypes

soundness:
name: Soundness
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
Expand Down
3 changes: 3 additions & 0 deletions DOMRefTypes/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[*]
indent_style = space
indent_size = 2
5 changes: 5 additions & 0 deletions DOMRefTypes/.sourcekit-lsp/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"swiftPM": {
"swiftSDK": "swift-DEVELOPMENT-SNAPSHOT-2025-08-02-a_wasm-embedded"
}
}
37 changes: 37 additions & 0 deletions DOMRefTypes/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// swift-tools-version: 6.2
// The swift-tools-version declares the minimum version of Swift required to build this package.

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import PackageDescription

let linkerSettings: [LinkerSetting] = [
.unsafeFlags([
"-Xclang-linker", "-mexec-model=reactor",
"-Xlinker", "--export-if-defined=__main_argc_argv",
]),
]

let package = Package(
name: "Guest",
targets: [
.target(
name: "externref",
),
.executableTarget(
name: "RefsTest",
dependencies: ["externref"],
linkerSettings: linkerSettings,
),
]
)
21 changes: 21 additions & 0 deletions DOMRefTypes/Sources/RefsTest/Entrypoint.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2024-2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

@main
struct Entrypoint {
static func main() {
var h1 = Document.global.createElement(name: JSString("h1"))
let body = Document.global.body
body.append(child: h1)
h1.innerHTML = JSString("Hello, world!")
}
}
85 changes: 85 additions & 0 deletions DOMRefTypes/Sources/RefsTest/SwiftBindings.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2024-2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import externref

struct JSObject: ~Copyable {
fileprivate let ref: ExternRefIndex

deinit {
freeExternRef(ref)
}
}

struct JSArray: ~Copyable {
private let ref: ExternRefIndex

init() {
self.ref = emptyArray()
}

func append(_ object: borrowing JSObject) {
arrayPush(ref, object.ref)
}
}

struct JSString: ~Copyable {
fileprivate let ref: ExternRefIndex

deinit {
freeExternRef(self.ref)
}
}

extension JSString {
init(_ string: StaticString) {
self.ref = bridgeString(string.utf8Start, string.utf8CodeUnitCount)
}

}

struct HTMLElement: ~Copyable {
fileprivate let ref: ExternRefIndex

func append(child: borrowing HTMLElement) {
appendChild(self.ref, child.ref)
}

static let innerHTMLName = JSString("innerHTML")

var innerHTML: JSString {

get {
JSString(ref: getProp(self.ref, Self.innerHTMLName.ref))
}

set {
setProp(self.ref, Self.innerHTMLName.ref, newValue.ref)
}
}
}

struct Document: ~Copyable {
fileprivate let object: JSObject

static let global = Document(object: JSObject(ref: getDocument()))

static let bodyName = JSString("body")

func createElement(name: borrowing JSString) -> HTMLElement {
.init(ref: externref.createElement(name.ref))
}

var body: HTMLElement {
HTMLElement(ref: getProp(self.object.ref, Self.bodyName.ref))
}
}
75 changes: 75 additions & 0 deletions DOMRefTypes/Sources/externref/bridge.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2024-2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "dom.h"
#include "refs.h"
#include <stdint.h>

static __externref_t table[0];

typedef __externref_t (*__funcref funcref_t)(__externref_t);
static funcref_t ftable[0];

static int nextAvailableTableIndex = 0;
static const int defaultTableGrowSize = 256;

void freeExternRef(ExternRefIndex ref) {
__builtin_wasm_table_set(table, ref.index, __builtin_wasm_ref_null_extern());
}

ExternRefIndex tableAppend(__externref_t ref) {
ExternRefIndex idx = { .index = nextAvailableTableIndex++ };

if (idx.index >= __builtin_wasm_table_size(table)) {
__builtin_wasm_table_grow(table, __builtin_wasm_ref_null_extern(), defaultTableGrowSize);
}

__builtin_wasm_table_set(table, idx.index, ref);

return idx;
}

ExternRefIndex createElement(ExternRefIndex name) {
return tableAppend(createElementJS(__builtin_wasm_table_get(table, name.index)));
}

ExternRefIndex getDocument() {
return tableAppend(getDocumentJS());
}

ExternRefIndex getProp(ExternRefIndex self, ExternRefIndex name) {
return tableAppend(getPropJS(__builtin_wasm_table_get(table, self.index), __builtin_wasm_table_get(table, name.index)));
}

int getIntProp(ExternRefIndex self, ExternRefIndex name) {
return getIntPropJS(__builtin_wasm_table_get(table, self.index), __builtin_wasm_table_get(table, name.index));
}

void setProp(ExternRefIndex self, ExternRefIndex name, ExternRefIndex val) {
setPropJS(__builtin_wasm_table_get(table, self.index), __builtin_wasm_table_get(table, name.index), __builtin_wasm_table_get(table, val.index));
}

void appendChild(ExternRefIndex self, ExternRefIndex child) {
appendChildJS(__builtin_wasm_table_get(table, self.index), __builtin_wasm_table_get(table, child.index));
}

ExternRefIndex bridgeString(const uint8_t *str, size_t bytes) {
return tableAppend(bridgeStringJS(str, bytes));
}

ExternRefIndex emptyArray() {
return tableAppend(emptyArrayJS());
}

void arrayPush(ExternRefIndex self, ExternRefIndex element) {
arrayPushJS(__builtin_wasm_table_get(table, self.index), __builtin_wasm_table_get(table, element.index));
}
56 changes: 56 additions & 0 deletions DOMRefTypes/Sources/externref/dom.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2024-2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#pragma once

#include <stdint.h>

__attribute__((import_module("js")))
__attribute__((import_name("getDocument"))) __externref_t
getDocumentJS(void);

__attribute__((import_module("js")))
__attribute__((import_name("emptyDictionary"))) __externref_t
emptyDictionaryJS(void);

__attribute__((import_module("js")))
__attribute__((import_name("emptyArray"))) __externref_t
emptyArrayJS(void);

__attribute__((import_module("js")))
__attribute__((import_name("arrayPush"))) void
arrayPushJS(__externref_t self, __externref_t element);

__attribute__((import_module("js")))
__attribute__((import_name("bridgeString"))) __externref_t
bridgeStringJS(const uint8_t *str, uint32_t bytes);

__attribute__((import_module("js")))
__attribute__((import_name("setProp"))) void
setPropJS(__externref_t self, __externref_t name, __externref_t val);

__attribute__((import_module("js")))
__attribute__((import_name("getProp"))) __externref_t
getPropJS(__externref_t self, __externref_t name);


__attribute__((import_module("js")))
__attribute__((import_name("getIntProp"))) int
getIntPropJS(__externref_t self, __externref_t name);

__attribute__((import_module("document")))
__attribute__((import_name("createElement"))) __externref_t
createElementJS(__externref_t name);

__attribute__((import_module("document")))
__attribute__((import_name("appendChild"))) void
appendChildJS(__externref_t self, __externref_t child);
40 changes: 40 additions & 0 deletions DOMRefTypes/Sources/externref/include/refs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2024-2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#pragma once

#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

typedef struct ExternRefIndex {
int index;
} ExternRefIndex;

void freeExternRef(ExternRefIndex);

ExternRefIndex createElement(ExternRefIndex name);
ExternRefIndex getDocument(void);
ExternRefIndex getProp(ExternRefIndex self, ExternRefIndex name);
int getIntProp(ExternRefIndex self, ExternRefIndex name);
void setProp(ExternRefIndex self, ExternRefIndex name, ExternRefIndex val);
void appendChild(ExternRefIndex self, ExternRefIndex child);
ExternRefIndex bridgeString(const uint8_t *str, size_t bytes);
ExternRefIndex emptyArray(void);
void arrayPush(ExternRefIndex self, ExternRefIndex element);

#ifdef __cplusplus
}
#endif /* __cplusplus */
29 changes: 29 additions & 0 deletions DOMRefTypes/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!-- This source file is part of the Swift open source project

Copyright (c) 2024 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -->

<html>
<head>
<meta charset="utf-8">
<title>Swift for WebAssembly Examples</title>
<script type="module" src="index.js">
</script>
<style>
body {
background-color: black;
padding: 1rem;
}
h1 {
font-family: sans-serif;
color: white;
}
</style>
</head>
<body>
<h1 id="wasm-logger">Wasm Reference Types Demo</h1>
</body>
</html>
Loading