From 9fa88a15daa667c6947dbfef17b417d36fef3ada Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 19 Sep 2024 08:24:50 +0200 Subject: [PATCH] wasm gc: add support to Gradle plugin --- samples/pi/build.gradle.kts | 3 + samples/pi/src/main/webapp/index.html | 1 + samples/pi/src/main/webapp/wasm-gc.html | 62 +++++++++++++++++++ .../org/teavm/tooling/TeaVMTargetType.java | 1 + .../java/org/teavm/tooling/TeaVMTool.java | 11 ++++ .../org/teavm/gradle/TeaVMExtensionImpl.java | 31 ++++++++++ .../java/org/teavm/gradle/TeaVMPlugin.java | 24 +++++++ .../org/teavm/gradle/api/TeaVMExtension.java | 6 ++ .../gradle/api/TeaVMWasmGCConfiguration.java | 26 ++++++++ .../gradle/tasks/GenerateWasmGCTask.java | 43 +++++++++++++ 10 files changed, 208 insertions(+) create mode 100644 samples/pi/src/main/webapp/wasm-gc.html create mode 100644 tools/gradle/src/main/java/org/teavm/gradle/api/TeaVMWasmGCConfiguration.java create mode 100644 tools/gradle/src/main/java/org/teavm/gradle/tasks/GenerateWasmGCTask.java diff --git a/samples/pi/build.gradle.kts b/samples/pi/build.gradle.kts index 89c948078..3b6d429c2 100644 --- a/samples/pi/build.gradle.kts +++ b/samples/pi/build.gradle.kts @@ -39,6 +39,9 @@ teavm { outputDir = layout.buildDirectory.dir("libs/wasi").get().asFile relativePathInOutputDir = "" } + wasmGC { + addedToWebApp = true + } all { mainClass = "org.teavm.samples.pi.PiCalculator" } diff --git a/samples/pi/src/main/webapp/index.html b/samples/pi/src/main/webapp/index.html index 4c338da42..4a77689fa 100644 --- a/samples/pi/src/main/webapp/index.html +++ b/samples/pi/src/main/webapp/index.html @@ -24,6 +24,7 @@ \ No newline at end of file diff --git a/samples/pi/src/main/webapp/wasm-gc.html b/samples/pi/src/main/webapp/wasm-gc.html new file mode 100644 index 000000000..b28eb95f4 --- /dev/null +++ b/samples/pi/src/main/webapp/wasm-gc.html @@ -0,0 +1,62 @@ + + + + + PI calculator example + + + + + + + +
+ Digit count: + + +
+
+ + \ No newline at end of file diff --git a/tools/core/src/main/java/org/teavm/tooling/TeaVMTargetType.java b/tools/core/src/main/java/org/teavm/tooling/TeaVMTargetType.java index b7d6ac36b..5ff2cfc7b 100644 --- a/tools/core/src/main/java/org/teavm/tooling/TeaVMTargetType.java +++ b/tools/core/src/main/java/org/teavm/tooling/TeaVMTargetType.java @@ -19,5 +19,6 @@ public enum TeaVMTargetType { JAVASCRIPT, WEBASSEMBLY, WEBASSEMBLY_WASI, + WEBASSEMBLY_GC, C } diff --git a/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java b/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java index ced297b60..2308d7684 100644 --- a/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java +++ b/tools/core/src/main/java/org/teavm/tooling/TeaVMTool.java @@ -38,6 +38,7 @@ import org.teavm.backend.c.generate.ShorteningFileNameProvider; import org.teavm.backend.c.generate.SimpleFileNameProvider; import org.teavm.backend.javascript.JSModuleType; import org.teavm.backend.javascript.JavaScriptTarget; +import org.teavm.backend.wasm.WasmGCTarget; import org.teavm.backend.wasm.WasmRuntimeType; import org.teavm.backend.wasm.WasmTarget; import org.teavm.backend.wasm.render.WasmBinaryVersion; @@ -336,6 +337,8 @@ public class TeaVMTool { return prepareWebAssemblyDefaultTarget(); case WEBASSEMBLY_WASI: return prepareWebAssemblyWasiTarget(); + case WEBASSEMBLY_GC: + return prepareWebAssemblyGCTarget(); case C: return prepareCTarget(); } @@ -381,6 +384,13 @@ public class TeaVMTool { return target; } + private WasmGCTarget prepareWebAssemblyGCTarget() { + var target = new WasmGCTarget(); + target.setObfuscated(obfuscated); + target.setStrict(strict); + return target; + } + private CTarget prepareCTarget() { cTarget = new CTarget(new CNameProvider()); cTarget.setMinHeapSize(minHeapSize); @@ -529,6 +539,7 @@ public class TeaVMTool { return "classes.js"; case WEBASSEMBLY: case WEBASSEMBLY_WASI: + case WEBASSEMBLY_GC: return "classes.wasm"; case C: return "classes.c"; diff --git a/tools/gradle/src/main/java/org/teavm/gradle/TeaVMExtensionImpl.java b/tools/gradle/src/main/java/org/teavm/gradle/TeaVMExtensionImpl.java index 4dd9ea54c..9f4120bcb 100644 --- a/tools/gradle/src/main/java/org/teavm/gradle/TeaVMExtensionImpl.java +++ b/tools/gradle/src/main/java/org/teavm/gradle/TeaVMExtensionImpl.java @@ -30,11 +30,13 @@ import org.teavm.gradle.api.TeaVMExtension; import org.teavm.gradle.api.TeaVMJSConfiguration; import org.teavm.gradle.api.TeaVMWasiConfiguration; import org.teavm.gradle.api.TeaVMWasmConfiguration; +import org.teavm.gradle.api.TeaVMWasmGCConfiguration; class TeaVMExtensionImpl extends TeaVMBaseExtensionImpl implements TeaVMExtension { private TeaVMJSConfiguration js; private TeaVMWasmConfiguration wasm; private TeaVMWasiConfiguration wasi; + private TeaVMWasmGCConfiguration wasmGC; private TeaVMCConfiguration c; private TeaVMCommonConfiguration all; @@ -43,11 +45,13 @@ class TeaVMExtensionImpl extends TeaVMBaseExtensionImpl implements TeaVMExtensio js = objectFactory.newInstance(JsConfigImpl.class); wasm = objectFactory.newInstance(TeaVMWasmConfiguration.class); wasi = objectFactory.newInstance(TeaVMWasiConfiguration.class); + wasmGC = objectFactory.newInstance(TeaVMWasmGCConfiguration.class); c = objectFactory.newInstance(TeaVMCConfiguration.class); all = objectFactory.newInstance(TeaVMCommonConfiguration.class); inherit(js, all); inherit(wasm, all); inherit(wasi, all); + inherit(wasmGC, all); inherit(c, all); setupDefaults(); } @@ -56,6 +60,7 @@ class TeaVMExtensionImpl extends TeaVMBaseExtensionImpl implements TeaVMExtensio setupJsDefaults(); setupWasmDefaults(); setupWasiDefaults(); + setupWasmGCDefaults(); setupCDefaults(); setupAllDefaults(); } @@ -95,6 +100,17 @@ class TeaVMExtensionImpl extends TeaVMBaseExtensionImpl implements TeaVMExtensio wasm.getExceptionsUsed().convention(property("wasm.exceptionsUsed").map(Boolean::parseBoolean).orElse(true)); } + private void setupWasmGCDefaults() { + wasmGC.getRelativePathInOutputDir().convention("wasm-gc"); + wasmGC.getOptimization().convention(property("wasm-gc.optimization").map(OptimizationLevel::valueOf) + .orElse(OptimizationLevel.AGGRESSIVE)); + wasmGC.getTargetFileName().convention(project.provider(() -> project.getName() + ".wasm")); + wasmGC.getAddedToWebApp().convention(property("wasm-gc.addedToWebApp") + .map(Boolean::parseBoolean).orElse(false)); + wasmGC.getStrict().convention(property("wasm-gc.strict").map(Boolean::parseBoolean).orElse(true)); + wasmGC.getObfuscated().convention(property("wasm-gc.obfuscated").map(Boolean::parseBoolean).orElse(true)); + } + private void setupWasiDefaults() { wasi.getRelativePathInOutputDir().convention("wasi"); wasi.getMinHeapSize().convention(1); @@ -170,6 +186,21 @@ class TeaVMExtensionImpl extends TeaVMBaseExtensionImpl implements TeaVMExtensio action.rehydrate(getWasi(), action.getOwner(), action.getThisObject()).call(); } + @Override + public TeaVMWasmGCConfiguration getWasmGC() { + return wasmGC; + } + + @Override + public void wasmGC(Action action) { + action.execute(getWasmGC()); + } + + @Override + public void wasmGC(Closure action) { + action.rehydrate(getWasmGC(), action.getOwner(), action.getThisObject()).call(); + } + @Override public TeaVMCConfiguration getC() { return c; diff --git a/tools/gradle/src/main/java/org/teavm/gradle/TeaVMPlugin.java b/tools/gradle/src/main/java/org/teavm/gradle/TeaVMPlugin.java index e2539783a..e7c8a8762 100644 --- a/tools/gradle/src/main/java/org/teavm/gradle/TeaVMPlugin.java +++ b/tools/gradle/src/main/java/org/teavm/gradle/TeaVMPlugin.java @@ -40,6 +40,7 @@ import org.teavm.gradle.config.ArtifactCoordinates; import org.teavm.gradle.tasks.GenerateCTask; import org.teavm.gradle.tasks.GenerateJavaScriptTask; import org.teavm.gradle.tasks.GenerateWasiTask; +import org.teavm.gradle.tasks.GenerateWasmGCTask; import org.teavm.gradle.tasks.GenerateWasmTask; import org.teavm.gradle.tasks.JavaScriptDevServerTask; import org.teavm.gradle.tasks.StopJavaScriptDevServerTask; @@ -53,6 +54,7 @@ public class TeaVMPlugin implements Plugin { public static final String STOP_JS_DEV_SERVER_TASK_NAME = "stopJavaScriptDevServer"; public static final String WASM_TASK_NAME = "generateWasm"; public static final String WASI_TASK_NAME = "generateWasi"; + public static final String WASM_GC_TASK_NAME = "generateWasmGC"; public static final String C_TASK_NAME = "generateC"; public static final String CONFIGURATION_NAME = "teavm"; public static final String CLASSPATH_CONFIGURATION_NAME = "teavmClasspath"; @@ -118,6 +120,7 @@ public class TeaVMPlugin implements Plugin { registerStopJsDevServerTask(project); registerWasmTask(project, compilerConfig); registerWasiTask(project, compilerConfig); + registerWasmGCTask(project, compilerConfig); registerCTask(project, compilerConfig); } @@ -210,6 +213,17 @@ public class TeaVMPlugin implements Plugin { }); } + private void registerWasmGCTask(Project project, Configuration configuration) { + var extension = project.getExtensions().getByType(TeaVMExtension.class); + project.getTasks().create(WASM_GC_TASK_NAME, GenerateWasmGCTask.class, task -> { + var wasmGC = extension.getWasmGC(); + applyToTask(wasmGC, task, configuration); + task.getTargetFileName().convention(wasmGC.getTargetFileName()); + task.getObfuscated().convention(wasmGC.getObfuscated()); + task.getStrict().convention(wasmGC.getStrict()); + }); + } + private void registerCTask(Project project, Configuration configuration) { var extension = project.getExtensions().getByType(TeaVMExtension.class); project.getTasks().create(C_TASK_NAME, GenerateCTask.class, task -> { @@ -236,6 +250,7 @@ public class TeaVMPlugin implements Plugin { if (task.getName().equals(WarPlugin.WAR_TASK_NAME)) { var jsAddedToWebApp = extension.getJs().getAddedToWebApp().get(); var wasmAddedToWebApp = extension.getWasm().getAddedToWebApp().get(); + var wasmGCAddedToWebApp = extension.getWasmGC().getAddedToWebApp().get(); if (jsAddedToWebApp) { task.dependsOn(project.getTasks().named(JS_TASK_NAME)); var outDir = extension.getJs().getOutputDir(); @@ -255,6 +270,15 @@ public class TeaVMPlugin implements Plugin { spec.from(project.files(outDir.map(dir -> new File(dir.getAsFile(), relPath.get())))); })); } + if (wasmGCAddedToWebApp) { + task.dependsOn(project.getTasks().named(WASM_GC_TASK_NAME)); + var outDir = extension.getWasmGC().getOutputDir(); + var relPath = extension.getWasmGC().getRelativePathInOutputDir(); + task.with(project.copySpec(spec -> { + spec.into(relPath); + spec.from(project.files(outDir.map(dir -> new File(dir.getAsFile(), relPath.get())))); + })); + } } }); } diff --git a/tools/gradle/src/main/java/org/teavm/gradle/api/TeaVMExtension.java b/tools/gradle/src/main/java/org/teavm/gradle/api/TeaVMExtension.java index dc4a13efb..c53b8be69 100644 --- a/tools/gradle/src/main/java/org/teavm/gradle/api/TeaVMExtension.java +++ b/tools/gradle/src/main/java/org/teavm/gradle/api/TeaVMExtension.java @@ -38,6 +38,12 @@ public interface TeaVMExtension extends TeaVMBaseExtension { void wasi(@DelegatesTo(TeaVMWasiConfiguration.class) Closure action); + TeaVMWasmGCConfiguration getWasmGC(); + + void wasmGC(Action action); + + void wasmGC(@DelegatesTo(TeaVMWasmGCConfiguration.class) Closure action); + TeaVMCConfiguration getC(); void c(Action action); diff --git a/tools/gradle/src/main/java/org/teavm/gradle/api/TeaVMWasmGCConfiguration.java b/tools/gradle/src/main/java/org/teavm/gradle/api/TeaVMWasmGCConfiguration.java new file mode 100644 index 000000000..85ccfaf6b --- /dev/null +++ b/tools/gradle/src/main/java/org/teavm/gradle/api/TeaVMWasmGCConfiguration.java @@ -0,0 +1,26 @@ +/* + * Copyright 2024 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.gradle.api; + +import org.gradle.api.provider.Property; + +public interface TeaVMWasmGCConfiguration extends TeaVMCommonConfiguration, TeaVMWebConfiguration { + Property getObfuscated(); + + Property getStrict(); + + Property getTargetFileName(); +} diff --git a/tools/gradle/src/main/java/org/teavm/gradle/tasks/GenerateWasmGCTask.java b/tools/gradle/src/main/java/org/teavm/gradle/tasks/GenerateWasmGCTask.java new file mode 100644 index 000000000..b3cb61223 --- /dev/null +++ b/tools/gradle/src/main/java/org/teavm/gradle/tasks/GenerateWasmGCTask.java @@ -0,0 +1,43 @@ +/* + * Copyright 2023 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.gradle.tasks; + +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.teavm.tooling.TeaVMTargetType; +import org.teavm.tooling.builder.BuildStrategy; + +public abstract class GenerateWasmGCTask extends TeaVMTask { + private static final int MB = 1024 * 1024; + + public GenerateWasmGCTask() { + getStrict().convention(true); + getObfuscated().convention(true); + } + + @Input + public abstract Property getStrict(); + + @Input + public abstract Property getObfuscated(); + + @Override + protected void setupBuilder(BuildStrategy builder) { + builder.setStrict(getStrict().get()); + builder.setObfuscated(getObfuscated().get()); + builder.setTargetType(TeaVMTargetType.WEBASSEMBLY_GC); + } +}