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 9f4120bcb..5c0300646 100644 --- a/tools/gradle/src/main/java/org/teavm/gradle/TeaVMExtensionImpl.java +++ b/tools/gradle/src/main/java/org/teavm/gradle/TeaVMExtensionImpl.java @@ -108,7 +108,9 @@ class TeaVMExtensionImpl extends TeaVMBaseExtensionImpl implements TeaVMExtensio 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.getCopyRuntime().convention(property("wasm-gc.copyRuntime").map(Boolean::parseBoolean).orElse(true)); wasmGC.getObfuscated().convention(property("wasm-gc.obfuscated").map(Boolean::parseBoolean).orElse(true)); + wasmGC.getDisassembly().convention(property("wasm-gc.disassembly").map(Boolean::parseBoolean).orElse(false)); } private void setupWasiDefaults() { 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 e7c8a8762..5d824a484 100644 --- a/tools/gradle/src/main/java/org/teavm/gradle/TeaVMPlugin.java +++ b/tools/gradle/src/main/java/org/teavm/gradle/TeaVMPlugin.java @@ -37,6 +37,8 @@ import org.gradle.api.tasks.bundling.War; import org.teavm.gradle.api.TeaVMConfiguration; import org.teavm.gradle.api.TeaVMExtension; import org.teavm.gradle.config.ArtifactCoordinates; +import org.teavm.gradle.tasks.CopyWasmGCRuntimeTask; +import org.teavm.gradle.tasks.DisasmWebAssemblyTask; import org.teavm.gradle.tasks.GenerateCTask; import org.teavm.gradle.tasks.GenerateJavaScriptTask; import org.teavm.gradle.tasks.GenerateWasiTask; @@ -55,6 +57,8 @@ public class TeaVMPlugin implements Plugin { 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 WASM_GC_COPY_RUNTIME_TASK_NAME = "copyWasmGCRuntime"; + public static final String WASM_GC_DISASSEMBLY_TASK_NAME = "disasmWasmGC"; public static final String C_TASK_NAME = "generateC"; public static final String CONFIGURATION_NAME = "teavm"; public static final String CLASSPATH_CONFIGURATION_NAME = "teavmClasspath"; @@ -222,6 +226,31 @@ public class TeaVMPlugin implements Plugin { task.getObfuscated().convention(wasmGC.getObfuscated()); task.getStrict().convention(wasmGC.getStrict()); }); + project.getTasks().create(WASM_GC_COPY_RUNTIME_TASK_NAME, CopyWasmGCRuntimeTask.class, task -> { + task.setGroup(TASK_GROUP); + task.onlyIf(t -> extension.getWasmGC().getCopyRuntime().getOrElse(false)); + var fileName = extension.getWasmGC().getTargetFileName().map(x -> x + "-runtime.js"); + task.getOutputFile().convention(extension.getWasmGC().getOutputDir() + .flatMap(d -> d.dir(extension.getWasmGC().getRelativePathInOutputDir())) + .flatMap(d -> d.file(fileName))); + }); + project.getTasks().create(WASM_GC_DISASSEMBLY_TASK_NAME, DisasmWebAssemblyTask.class, task -> { + task.setGroup(TASK_GROUP); + var genTask = (GenerateWasmGCTask) project.getTasks().getByName(WASM_GC_TASK_NAME); + task.dependsOn(genTask); + task.onlyIf(t -> extension.getWasmGC().getDisassembly().getOrElse(false)); + task.getHtml().set(true); + task.getInputFile().convention(project.getLayout().dir(genTask.getOutputDir()) + .flatMap(x -> x.file(genTask.getTargetFileName()))); + var fileName = extension.getWasmGC().getTargetFileName().map(x -> { + if (x.endsWith(".wasm")) { + x = x.substring(0, x.length() - 5); + } + return x + ".wast.html"; + }); + task.getOutputFile().convention(project.getLayout().dir(genTask.getOutputDir()) + .flatMap(d -> d.file(fileName))); + }); } private void registerCTask(Project project, Configuration configuration) { @@ -272,6 +301,8 @@ public class TeaVMPlugin implements Plugin { } if (wasmGCAddedToWebApp) { task.dependsOn(project.getTasks().named(WASM_GC_TASK_NAME)); + task.dependsOn(project.getTasks().named(WASM_GC_COPY_RUNTIME_TASK_NAME)); + task.dependsOn(project.getTasks().named(WASM_GC_DISASSEMBLY_TASK_NAME)); var outDir = extension.getWasmGC().getOutputDir(); var relPath = extension.getWasmGC().getRelativePathInOutputDir(); task.with(project.copySpec(spec -> { 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 index 85ccfaf6b..d2794bc05 100644 --- a/tools/gradle/src/main/java/org/teavm/gradle/api/TeaVMWasmGCConfiguration.java +++ b/tools/gradle/src/main/java/org/teavm/gradle/api/TeaVMWasmGCConfiguration.java @@ -22,5 +22,9 @@ public interface TeaVMWasmGCConfiguration extends TeaVMCommonConfiguration, TeaV Property getStrict(); + Property getCopyRuntime(); + + Property getDisassembly(); + Property getTargetFileName(); } diff --git a/tools/gradle/src/main/java/org/teavm/gradle/tasks/CopyWasmGCRuntimeTask.java b/tools/gradle/src/main/java/org/teavm/gradle/tasks/CopyWasmGCRuntimeTask.java new file mode 100644 index 000000000..3516760ca --- /dev/null +++ b/tools/gradle/src/main/java/org/teavm/gradle/tasks/CopyWasmGCRuntimeTask.java @@ -0,0 +1,39 @@ +/* + * 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.tasks; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import org.gradle.api.DefaultTask; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.TaskAction; + +public abstract class CopyWasmGCRuntimeTask extends DefaultTask { + @OutputFile + public abstract RegularFileProperty getOutputFile(); + + @TaskAction + public void copyRuntime() throws IOException { + var resourceName = "org/teavm/backend/wasm/wasm-gc-runtime.js"; + var classLoader = CopyWasmGCRuntimeTask.class.getClassLoader(); + var output = getOutputFile().get().getAsFile(); + try (var input = classLoader.getResourceAsStream(resourceName)) { + Files.copy(input, output.toPath(), StandardCopyOption.REPLACE_EXISTING); + } + } +} diff --git a/tools/gradle/src/main/java/org/teavm/gradle/tasks/DisasmWebAssemblyTask.java b/tools/gradle/src/main/java/org/teavm/gradle/tasks/DisasmWebAssemblyTask.java new file mode 100644 index 000000000..92f56758e --- /dev/null +++ b/tools/gradle/src/main/java/org/teavm/gradle/tasks/DisasmWebAssemblyTask.java @@ -0,0 +1,67 @@ +/* + * 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.tasks; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import org.gradle.api.DefaultTask; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.TaskAction; +import org.teavm.backend.wasm.disasm.Disassembler; +import org.teavm.backend.wasm.disasm.DisassemblyHTMLWriter; +import org.teavm.backend.wasm.disasm.DisassemblyTextWriter; + +public abstract class DisasmWebAssemblyTask extends DefaultTask { + public DisasmWebAssemblyTask() { + getHtml().convention(false); + } + + @InputFile + public abstract RegularFileProperty getInputFile(); + + @OutputFile + public abstract RegularFileProperty getOutputFile(); + + @Input + public abstract Property getHtml(); + + @TaskAction + public void disassemble() throws IOException { + var file = getInputFile().get().getAsFile(); + var bytes = Files.readAllBytes(file.toPath()); + var output = new FileOutputStream(getOutputFile().get().getAsFile()); + var writer = new PrintWriter(output); + var html = getHtml().get(); + var disassemblyWriter = html + ? new DisassemblyHTMLWriter(writer) + : new DisassemblyTextWriter(writer); + disassemblyWriter.setWithAddress(true); + if (html) { + disassemblyWriter.write("
").eol();
+        }
+        var disassembler = new Disassembler(disassemblyWriter);
+        disassembler.disassemble(bytes);
+        if (html) {
+            disassemblyWriter.write("
").eol(); + } + } +} 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 index b3cb61223..f1e180726 100644 --- a/tools/gradle/src/main/java/org/teavm/gradle/tasks/GenerateWasmGCTask.java +++ b/tools/gradle/src/main/java/org/teavm/gradle/tasks/GenerateWasmGCTask.java @@ -21,8 +21,6 @@ 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);