diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java index 891b499ea..dfe21978f 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java @@ -24,6 +24,7 @@ import java.io.Writer; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; @@ -381,12 +382,16 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost { dependencyAnalyzer.linkMethod(new MethodReference(Fiber.class, "isResuming", boolean.class)).use(); dependencyAnalyzer.linkMethod(new MethodReference(Fiber.class, "isSuspending", boolean.class)).use(); dependencyAnalyzer.linkMethod(new MethodReference(Fiber.class, "current", Fiber.class)).use(); - dependencyAnalyzer.linkMethod(new MethodReference(Fiber.class, "startMain", String[].class, void.class)).use(); + var withArgs = dependencyAnalyzer.linkMethod(new MethodReference(WasmSupport.class, "runWithArgs", + String[].class, void.class)); + withArgs.getVariable(1).propagate(dependencyAnalyzer.getType("[java/lang/String;")); + withArgs.getVariable(1).getArrayItem().propagate(dependencyAnalyzer.getType("java/lang/String")); + withArgs.use(); + dependencyAnalyzer.linkMethod(new MethodReference(WasmSupport.class, "runWithoutArgs", void.class)).use(); dependencyAnalyzer.linkMethod(new MethodReference(EventQueue.class, "processSingle", void.class)).use(); dependencyAnalyzer.linkMethod(new MethodReference(EventQueue.class, "isStopped", boolean.class)).use(); dependencyAnalyzer.linkMethod(new MethodReference(Thread.class, "setCurrentThread", Thread.class, void.class)).use(); - dependencyAnalyzer.linkMethod(new MethodReference(WasmSupport.class, "getArgs", String[].class)).use(); var fiberClass = dependencyAnalyzer.getClassSource().get(Fiber.class.getName()); for (MethodReader method : fiberClass.getMethods()) { @@ -561,8 +566,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost { var local = new WasmLocal(WasmType.INT32, "args"); function.add(local); - var call = new WasmCall(names.forMethod(new MethodReference(Fiber.class, "startMain", String[].class, - void.class))); + var call = new WasmCall(names.forMethod(new MethodReference(WasmSupport.class, "runWithArgs", + String[].class, void.class))); call.getArguments().add(new WasmGetLocal(local)); function.getBody().add(call); @@ -570,13 +575,10 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost { } private WasmFunction createStartCallerFunction(NameProvider names) { - WasmFunction function = new WasmFunction("teavm_call_start"); + var function = new WasmFunction("teavm_call_start"); function.setExportName("_start"); - WasmCall argsCall = new WasmCall(names.forMethod(new MethodReference(WasmSupport.class, - "getArgs", String[].class))); - WasmCall call = new WasmCall("teavm_start"); - call.getArguments().add(argsCall); + var call = new WasmCall(names.forMethod(new MethodReference(WasmSupport.class, "runWithoutArgs", void.class))); function.getBody().add(call); return function; @@ -1107,4 +1109,9 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost { } } } + + @Override + public Collection getInitializerMethods() { + return Collections.singleton(new MethodReference(WasmSupport.class, "initClasses", void.class)); + } } \ No newline at end of file diff --git a/core/src/main/java/org/teavm/backend/wasm/runtime/WasiEntryPointer.java b/core/src/main/java/org/teavm/backend/wasm/runtime/WasiEntryPointer.java new file mode 100644 index 000000000..b6188b5d0 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/runtime/WasiEntryPointer.java @@ -0,0 +1,19 @@ +/* + * Copyright 2022 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.backend.wasm.runtime; + +public class WasiEntryPointer { +} diff --git a/core/src/main/java/org/teavm/backend/wasm/runtime/WasiSupport.java b/core/src/main/java/org/teavm/backend/wasm/runtime/WasiSupport.java index 21cb6970a..25118bbd9 100644 --- a/core/src/main/java/org/teavm/backend/wasm/runtime/WasiSupport.java +++ b/core/src/main/java/org/teavm/backend/wasm/runtime/WasiSupport.java @@ -27,7 +27,6 @@ import org.teavm.interop.Address; import org.teavm.interop.Structure; import org.teavm.interop.Unmanaged; -@Unmanaged public class WasiSupport { private static long nextRandom; private static boolean randomInitialized; @@ -59,7 +58,7 @@ public class WasiSupport { public static long currentTimeMillis() { LongResult result = WasiBuffer.getBuffer().toStructure(); Wasi.clockTimeGet(Wasi.CLOCKID_REALTIME, 10, result); - return result.value; + return result.value / 1000000; } @Unmanaged diff --git a/core/src/main/java/org/teavm/backend/wasm/runtime/WasmSupport.java b/core/src/main/java/org/teavm/backend/wasm/runtime/WasmSupport.java index d432e377a..ef1c0dacb 100644 --- a/core/src/main/java/org/teavm/backend/wasm/runtime/WasmSupport.java +++ b/core/src/main/java/org/teavm/backend/wasm/runtime/WasmSupport.java @@ -17,6 +17,7 @@ package org.teavm.backend.wasm.runtime; import org.teavm.interop.Address; import org.teavm.interop.Import; +import org.teavm.runtime.Fiber; public class WasmSupport { private WasmSupport() { @@ -59,4 +60,17 @@ public class WasmSupport { @Import(module = "teavmMath", name = "pow") public static native double pow(double x, double y); + + private static void initClasses() { + } + + public static void runWithoutArgs() { + initClasses(); + Fiber.start(() -> Fiber.runMain(getArgs()), false); + } + + public static void runWithArgs(String[] args) { + initClasses(); + Fiber.start(() -> Fiber.runMain(args), false); + } } diff --git a/core/src/main/java/org/teavm/model/text/ListingBuilder.java b/core/src/main/java/org/teavm/model/text/ListingBuilder.java index deccea182..8a4ba9f00 100644 --- a/core/src/main/java/org/teavm/model/text/ListingBuilder.java +++ b/core/src/main/java/org/teavm/model/text/ListingBuilder.java @@ -89,9 +89,11 @@ public class ListingBuilder { while (inliningInfo != null) { sb.append(" at "); InstructionStringifier.escapeIdentifierIfNeeded(sb, inliningInfo.getMethod().toString()); - sb.append(" '"); - InstructionStringifier.escapeStringLiteral(inliningInfo.getFileName(), sb); - sb.append("' " + inliningInfo.getLine()); + if (inliningInfo.getFileName() != null) { + sb.append(" '"); + InstructionStringifier.escapeStringLiteral(inliningInfo.getFileName(), sb); + sb.append("' " + inliningInfo.getLine()); + } inliningInfo = inliningInfo.getParent(); } } diff --git a/core/src/main/java/org/teavm/runtime/Fiber.java b/core/src/main/java/org/teavm/runtime/Fiber.java index a36024ece..2da76ec98 100644 --- a/core/src/main/java/org/teavm/runtime/Fiber.java +++ b/core/src/main/java/org/teavm/runtime/Fiber.java @@ -257,7 +257,7 @@ public class Fiber { start(() -> runMain(args), false); } - static native void runMain(String[] args); + public static native void runMain(String[] args); private void start() { Fiber former = current; diff --git a/core/src/main/java/org/teavm/vm/TeaVM.java b/core/src/main/java/org/teavm/vm/TeaVM.java index 6e951ccee..99b944793 100644 --- a/core/src/main/java/org/teavm/vm/TeaVM.java +++ b/core/src/main/java/org/teavm/vm/TeaVM.java @@ -534,8 +534,12 @@ public class TeaVM implements TeaVMHost, ServiceRepository { } } - for (TeaVMEntryPoint entryPoint : entryPoints.values()) { - addInitializersToEntryPoint(classes, entryPoint.getMethod()); + var initializers = target.getInitializerMethods(); + if (initializers == null) { + initializers = entryPoints.values().stream().map(ep -> ep.getMethod()).collect(Collectors.toList()); + } + for (var initMethod : initializers) { + addInitializersToEntryPoint(classes, initMethod); } } diff --git a/core/src/main/java/org/teavm/vm/TeaVMTarget.java b/core/src/main/java/org/teavm/vm/TeaVMTarget.java index 2271cbb53..28486ac57 100644 --- a/core/src/main/java/org/teavm/vm/TeaVMTarget.java +++ b/core/src/main/java/org/teavm/vm/TeaVMTarget.java @@ -16,6 +16,7 @@ package org.teavm.vm; import java.io.IOException; +import java.util.Collection; import java.util.List; import org.teavm.dependency.DependencyAnalyzer; import org.teavm.dependency.DependencyListener; @@ -23,6 +24,7 @@ import org.teavm.model.ClassHolderTransformer; import org.teavm.model.ListableClassHolderSource; import org.teavm.model.ListableClassReaderSource; import org.teavm.model.MethodReader; +import org.teavm.model.MethodReference; import org.teavm.model.Program; import org.teavm.model.optimization.InliningFilterFactory; import org.teavm.vm.spi.TeaVMHostExtension; @@ -59,4 +61,8 @@ public interface TeaVMTarget { default InliningFilterFactory getInliningFilter() { return InliningFilterFactory.DEFAULT; } + + default Collection getInitializerMethods() { + return null; + } } diff --git a/core/src/main/java/org/teavm/vm/TeaVMTargetController.java b/core/src/main/java/org/teavm/vm/TeaVMTargetController.java index 9306abf57..e2a530aae 100644 --- a/core/src/main/java/org/teavm/vm/TeaVMTargetController.java +++ b/core/src/main/java/org/teavm/vm/TeaVMTargetController.java @@ -59,4 +59,5 @@ public interface TeaVMTargetController { void addVirtualMethods(Predicate methods); ClassInitializerInfo getClassInitializerInfo(); + } diff --git a/core/src/main/resources/org/teavm/backend/wasm/wasm-runtime.c b/core/src/main/resources/org/teavm/backend/wasm/wasm-runtime.c index acc980de3..4226fc4c9 100644 --- a/core/src/main/resources/org/teavm/backend/wasm/wasm-runtime.c +++ b/core/src/main/resources/org/teavm/backend/wasm/wasm-runtime.c @@ -81,7 +81,9 @@ void teavm_logInt(int32_t v) { int32_t wasi_snapshot_preview1_clock_time_get(int32_t clock_id, int64_t precision, int32_t result_ptr) { int64_t* resultAddr = (int64_t*) (wasm_heap + result_ptr); - *resultAddr = teavm_currentTimeMillis(); + struct timespec time; + clock_gettime(CLOCK_REALTIME, &time); + *resultAddr = time.tv_sec * 1000000000 + (int64_t) round(time.tv_nsec); return 0; } diff --git a/tools/junit/src/main/java/org/teavm/junit/TeaVMTestRunner.java b/tools/junit/src/main/java/org/teavm/junit/TeaVMTestRunner.java index 4a6ca2c86..18c01a42c 100644 --- a/tools/junit/src/main/java/org/teavm/junit/TeaVMTestRunner.java +++ b/tools/junit/src/main/java/org/teavm/junit/TeaVMTestRunner.java @@ -207,6 +207,7 @@ public class TeaVMTestRunner extends Runner implements Filterable { case "browser": wasmRunStrategy = new BrowserRunStrategy(outputDir, "WASM", this::customBrowser); break; + case "chrome": case "browser-chrome": wasmRunStrategy = new BrowserRunStrategy(outputDir, "WASM", this::chromeBrowser); break;