mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2026-04-29 18:31:22 +00:00
Enable TeaVM WASM GC Backend
I'd tried this ages ago, and had some issues I utterly failed to find a minimal reproducer for. Now it Just Works.
This commit is contained in:
9
package-lock.json
generated
9
package-lock.json
generated
@@ -12,7 +12,8 @@
|
||||
"@squid-dev/cc-web-term": "^2.0.0",
|
||||
"preact": "^10.5.5",
|
||||
"setimmediate": "^1.0.5",
|
||||
"tslib": "^2.0.3"
|
||||
"tslib": "^2.0.3",
|
||||
"wasm-feature-detect": "^1.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "^16.0.0",
|
||||
@@ -3262,6 +3263,12 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/wasm-feature-detect": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.8.0.tgz",
|
||||
"integrity": "sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/web-namespaces": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz",
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"@squid-dev/cc-web-term": "^2.0.0",
|
||||
"preact": "^10.5.5",
|
||||
"setimmediate": "^1.0.5",
|
||||
"tslib": "^2.0.3"
|
||||
"tslib": "^2.0.3",
|
||||
"wasm-feature-detect": "^1.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "^16.0.0",
|
||||
|
||||
@@ -88,9 +88,9 @@ const ccTweaked = minify => {
|
||||
}
|
||||
},
|
||||
|
||||
/** @type {import("rollup").ResolveIdHook} */
|
||||
async resolveId(source) {
|
||||
if (source === "cct/classes") return path.resolve("build/teaVM/classes.js");
|
||||
if (source === "cct/resources") return path.resolve("build/teaVM/resources.js");
|
||||
if (source.startsWith("cct/")) return path.resolve("build/teaVM/" + source.substring(4));
|
||||
return null;
|
||||
},
|
||||
|
||||
@@ -124,7 +124,7 @@ export default args => ({
|
||||
resolve({ browser: true }),
|
||||
|
||||
url({
|
||||
include: ["**/*.dfpwm", "**/*.worker.js", "**/*.png"],
|
||||
include: ["**/*.dfpwm", "**/*.worker.js", "**/*.png", "**/*.wasm"],
|
||||
fileName: "[name]-[hash][extname]",
|
||||
publicPath: "/",
|
||||
limit: 0,
|
||||
|
||||
@@ -19,6 +19,7 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -70,14 +71,24 @@ public class Builder {
|
||||
}
|
||||
|
||||
// Then finally start the compiler!
|
||||
run(output, remapper, TeaVMTargetType.JAVASCRIPT, TeaVMOptimizationLevel.ADVANCED, minify);
|
||||
run(output, remapper, TeaVMTargetType.WEBASSEMBLY_GC, TeaVMOptimizationLevel.SIMPLE, minify);
|
||||
|
||||
try (var runtime = Builder.class.getClassLoader().getResourceAsStream("org/teavm/backend/wasm/wasm-gc-module-runtime.js")) {
|
||||
if (runtime == null) throw new IllegalStateException("Cannot find WASM runtime");
|
||||
Files.copy(runtime, output.resolve("wasm-gc-runtime.js"), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
||||
|
||||
private static void run(Path output, ClassLoader classes, TeaVMTargetType target, TeaVMOptimizationLevel optimise, boolean minify) throws Exception {
|
||||
var tool = new TeaVMTool();
|
||||
tool.setTargetType(TeaVMTargetType.JAVASCRIPT);
|
||||
tool.setTargetType(target);
|
||||
tool.setJsModuleType(JSModuleType.ES2015);
|
||||
tool.setTargetDirectory(output.toFile());
|
||||
tool.setClassLoader(remapper);
|
||||
tool.setClassLoader(classes);
|
||||
tool.setMainClass("cc.tweaked.web.Main");
|
||||
|
||||
tool.setOptimizationLevel(TeaVMOptimizationLevel.ADVANCED);
|
||||
tool.setOptimizationLevel(optimise);
|
||||
tool.setObfuscated(minify);
|
||||
|
||||
tool.generate();
|
||||
|
||||
@@ -4,11 +4,31 @@
|
||||
|
||||
import "setimmediate";
|
||||
|
||||
import type { ComputerDisplay, ComputerHandle } from "cct/classes";
|
||||
export type { ComputerDisplay, ComputerHandle, PeripheralKind, Side } from "cct/classes";
|
||||
import type { ComputerDisplay, ComputerHandle } from "cct/classes.js";
|
||||
export type { ComputerDisplay, ComputerHandle, PeripheralKind, Side } from "cct/classes.js";
|
||||
import { load as teaVMLoad } from "cct/wasm-gc-runtime.js";
|
||||
import { exceptions, gc } from "wasm-feature-detect";
|
||||
import wasmClasses from "cct/classes.wasm";
|
||||
|
||||
const loadClasses = async (): Promise<{ main: (args: string[]) => void }> => {
|
||||
if (
|
||||
typeof WebAssembly === "object" && typeof WebAssembly.compileStreaming === "function" &&
|
||||
await exceptions() && await gc()
|
||||
) {
|
||||
try {
|
||||
console.log("Loading WASM runtime");
|
||||
return (await teaVMLoad(wasmClasses)).exports;
|
||||
} catch (e) {
|
||||
console.error("Failed to load WebAssembly runtime", e);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Using JS runtime");
|
||||
return await import("cct/classes.js");
|
||||
}
|
||||
|
||||
const load = async (): Promise<(computer: ComputerDisplay) => ComputerHandle> => {
|
||||
const [classes, { version, resources }] = await Promise.all([import("cct/classes"), import("cct/resources")]);
|
||||
const [classes, { version, resources }] = await Promise.all([loadClasses(), import("cct/resources.js")]);
|
||||
|
||||
let addComputer: ((computer: ComputerDisplay) => ComputerHandle) | null = null;
|
||||
const encoder = new TextEncoder();
|
||||
@@ -18,7 +38,7 @@ const load = async (): Promise<(computer: ComputerDisplay) => ComputerHandle> =>
|
||||
listResources: () => Object.keys(resources),
|
||||
getResource: path => new Int8Array(encoder.encode(resources[path]))
|
||||
};
|
||||
classes.main();
|
||||
classes.main([]);
|
||||
|
||||
if (!addComputer) throw new Error("Callbacks.setup was never called");
|
||||
return addComputer;
|
||||
|
||||
23
projects/web/src/frontend/typings.d.ts
vendored
23
projects/web/src/frontend/typings.d.ts
vendored
@@ -28,16 +28,21 @@ declare module "*.license" {
|
||||
}
|
||||
|
||||
declare module "*.dfpwm" {
|
||||
const contents: string;
|
||||
export default contents;
|
||||
const url: string;
|
||||
export default url;
|
||||
}
|
||||
|
||||
declare module "cct/resources" {
|
||||
declare module "*.wasm" {
|
||||
const url: string;
|
||||
export default url;
|
||||
}
|
||||
|
||||
declare module "cct/resources.js" {
|
||||
export const version: string;
|
||||
export const resources: Record<string, string>;
|
||||
}
|
||||
|
||||
declare module "cct/classes" {
|
||||
declare module "cct/classes.js" {
|
||||
export const main: () => void;
|
||||
|
||||
export type Side = "up" | "down" | "left" | "right" | "front" | "back";
|
||||
@@ -169,10 +174,18 @@ declare module "cct/classes" {
|
||||
}
|
||||
}
|
||||
|
||||
declare module "cct/wasm-gc-runtime.js" {
|
||||
export const load: (url: string, options?: any) => Promise<{
|
||||
exports: { main: (args: string[]) => void },
|
||||
instance: WebAssembly.Instance,
|
||||
module: WebAssembly.Module,
|
||||
}>
|
||||
}
|
||||
|
||||
declare namespace JSX {
|
||||
export type Element = import("preact").JSX.Element;
|
||||
export type IntrinsicElements = import("preact").JSX.IntrinsicElements;
|
||||
export type ElementClass = import("preact").JSX.ElementClass;
|
||||
}
|
||||
|
||||
declare var $javaCallbacks: import("cct/classes").Callbacks; // eslint-disable-line no-var
|
||||
declare var $javaCallbacks: import("cct/classes.js").Callbacks; // eslint-disable-line no-var
|
||||
|
||||
@@ -54,7 +54,7 @@ public class Callbacks {
|
||||
* @param resource The path to the resource to load.
|
||||
* @return The loaded resource.
|
||||
*/
|
||||
@JSByRef
|
||||
@JSByRef(optional = true)
|
||||
@JSBody(params = "name", script = "return $javaCallbacks.getResource(name);")
|
||||
public static native byte[] getResource(String resource);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user