Skip to content

Commit

Permalink
wasm gc: support exporting declarations as JS entities from module
Browse files Browse the repository at this point in the history
  • Loading branch information
konsoletyper committed Oct 8, 2024
1 parent 73dda91 commit 0dcc25d
Show file tree
Hide file tree
Showing 42 changed files with 1,062 additions and 325 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
import org.teavm.interop.Platforms;
import org.teavm.interop.Unmanaged;
import org.teavm.interop.UnsupportedOn;
import org.teavm.jso.JSObject;
import org.teavm.jso.core.JSDate;
import org.teavm.jso.impl.JS;

public class TDate implements TComparable<TDate> {
private long value;
Expand Down Expand Up @@ -420,7 +422,7 @@ public String toString() {
} else if (PlatformDetector.isWebAssembly()) {
return toStringWebAssembly(value);
} else if (PlatformDetector.isWebAssemblyGC()) {
return toStringWebAssemblyGC(value);
return JS.unwrapString(toStringWebAssemblyGC(value));
} else {
return JSDate.create(value).stringValue();
}
Expand All @@ -435,7 +437,7 @@ public String toString() {
private static native String toStringWebAssembly(double date);

@Import(module = "teavmDate", name = "dateToString")
private static native String toStringWebAssemblyGC(double date);
private static native JSObject toStringWebAssemblyGC(double date);

@Deprecated
public String toLocaleString() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import org.teavm.backend.wasm.generate.gc.WasmGCDeclarationsGenerator;
import org.teavm.backend.wasm.model.WasmFunction;
import org.teavm.backend.wasm.runtime.StringInternPool;
import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;

Expand All @@ -34,47 +33,6 @@ public void generate() {
createInitializer();
}


public WasmFunction generateMainFunction(String entryPoint) {
return declarationsGenerator.functions().forStaticMethod(new MethodReference(entryPoint,
"main", ValueType.parse(String[].class), ValueType.VOID));
}

public WasmFunction generateCreateStringBuilderFunction() {
return declarationsGenerator.functions().forStaticMethod(new MethodReference(
WasmGCSupport.class, "createStringBuilder", StringBuilder.class));
}

public WasmFunction generateCreateStringArrayFunction() {
return declarationsGenerator.functions().forStaticMethod(new MethodReference(
WasmGCSupport.class, "createStringArray", int.class, String[].class));
}

public WasmFunction generateAppendCharFunction() {
return declarationsGenerator.functions().forInstanceMethod(new MethodReference(
StringBuilder.class, "append", char.class, StringBuilder.class));
}

public WasmFunction generateBuildStringFunction() {
return declarationsGenerator.functions().forInstanceMethod(new MethodReference(
StringBuilder.class, "toString", String.class));
}

public WasmFunction generateSetToStringArrayFunction() {
return declarationsGenerator.functions().forStaticMethod(new MethodReference(
WasmGCSupport.class, "setToStringArray", String[].class, int.class, String.class, void.class));
}

public WasmFunction generateStringLengthFunction() {
return declarationsGenerator.functions().forInstanceMethod(new MethodReference(
String.class, "length", int.class));
}

public WasmFunction generateCharAtFunction() {
return declarationsGenerator.functions().forInstanceMethod(new MethodReference(
String.class, "charAt", int.class, char.class));
}

public WasmFunction generateReportGarbageCollectedStringFunction() {
var entryType = ValueType.object(StringInternPool.class.getName() + "$Entry");
return declarationsGenerator.functions().forStaticMethod(new MethodReference(
Expand Down
121 changes: 93 additions & 28 deletions core/src/main/java/org/teavm/backend/wasm/WasmGCTarget.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,28 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import org.teavm.backend.wasm.debug.DebugLines;
import org.teavm.backend.wasm.debug.ExternalDebugFile;
import org.teavm.backend.wasm.debug.GCDebugInfoBuilder;
import org.teavm.backend.wasm.gc.TeaVMWasmGCHost;
import org.teavm.backend.wasm.gc.WasmGCClassConsumer;
import org.teavm.backend.wasm.gc.WasmGCClassConsumerContext;
import org.teavm.backend.wasm.gc.WasmGCDependencies;
import org.teavm.backend.wasm.generate.gc.WasmGCDeclarationsGenerator;
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCCustomTypeMapperFactory;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper;
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringProvider;
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGenerator;
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGeneratorFactory;
import org.teavm.backend.wasm.generators.gc.WasmGCCustomGenerators;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsic;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsicFactory;
import org.teavm.backend.wasm.intrinsics.gc.WasmGCIntrinsics;
import org.teavm.backend.wasm.model.WasmFunction;
import org.teavm.backend.wasm.model.WasmModule;
import org.teavm.backend.wasm.model.WasmTag;
import org.teavm.backend.wasm.optimization.WasmUsageCounter;
import org.teavm.backend.wasm.render.WasmBinaryRenderer;
import org.teavm.backend.wasm.render.WasmBinaryStatsCollector;
Expand All @@ -43,10 +51,12 @@
import org.teavm.backend.wasm.runtime.StringInternPool;
import org.teavm.backend.wasm.transformation.gc.BaseClassesTransformation;
import org.teavm.backend.wasm.transformation.gc.ClassLoaderResourceTransformation;
import org.teavm.backend.wasm.transformation.gc.EntryPointTransformation;
import org.teavm.dependency.DependencyAnalyzer;
import org.teavm.dependency.DependencyListener;
import org.teavm.interop.Platforms;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ListableClassHolderSource;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
Expand All @@ -73,6 +83,8 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
private List<WasmGCCustomTypeMapperFactory> customTypeMapperFactories = new ArrayList<>();
private Map<MethodReference, WasmGCCustomGenerator> customCustomGenerators = new HashMap<>();
private List<WasmGCCustomGeneratorFactory> customGeneratorFactories = new ArrayList<>();
private EntryPointTransformation entryPointTransformation = new EntryPointTransformation();
private List<WasmGCClassConsumer> classConsumers = new ArrayList<>();

public void setObfuscated(boolean obfuscated) {
this.obfuscated = obfuscated;
Expand Down Expand Up @@ -115,11 +127,22 @@ public void addCustomTypeMapperFactory(WasmGCCustomTypeMapperFactory customTypeM
customTypeMapperFactories.add(customTypeMapperFactory);
}

@Override
public void addClassConsumer(WasmGCClassConsumer consumer) {
classConsumers.add(consumer);
}

@Override
public void setController(TeaVMTargetController controller) {
this.controller = controller;
}

@Override
public void setEntryPoint(String entryPoint, String name) {
entryPointTransformation.setEntryPoint(entryPoint);
entryPointTransformation.setEntryPointName(name);
}

@Override
public VariableCategoryProvider variableCategoryProvider() {
return null;
Expand All @@ -134,7 +157,8 @@ public List<DependencyListener> getDependencyListeners() {
public List<ClassHolderTransformer> getTransformers() {
return List.of(
new BaseClassesTransformation(),
new ClassLoaderResourceTransformation()
new ClassLoaderResourceTransformation(),
entryPointTransformation
);
}

Expand Down Expand Up @@ -181,6 +205,7 @@ public boolean isAsyncSupported() {
@Override
public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName) throws IOException {
var module = new WasmModule();
module.memoryExportName = "teavm.memory";
var customGenerators = new WasmGCCustomGenerators(classes, controller.getServices(),
customGeneratorFactories, customCustomGenerators,
controller.getProperties());
Expand All @@ -198,47 +223,30 @@ public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, Str
intrinsics,
customTypeMapperFactories,
controller::isVirtual,
strict
strict,
controller.getEntryPoint()
);
declarationsGenerator.setFriendlyToDebugger(controller.isFriendlyToDebugger());
var moduleGenerator = new WasmGCModuleGenerator(declarationsGenerator);

var mainFunction = moduleGenerator.generateMainFunction(controller.getEntryPoint());
mainFunction.setExportName(controller.getEntryPointName());
mainFunction.setName(controller.getEntryPointName());

var stringBuilderFunction = moduleGenerator.generateCreateStringBuilderFunction();
stringBuilderFunction.setExportName("createStringBuilder");

var createStringArrayFunction = moduleGenerator.generateCreateStringArrayFunction();
createStringArrayFunction.setExportName("createStringArray");

var appendCharFunction = moduleGenerator.generateAppendCharFunction();
appendCharFunction.setExportName("appendChar");

var buildStringFunction = moduleGenerator.generateBuildStringFunction();
buildStringFunction.setExportName("buildString");

var setArrayFunction = moduleGenerator.generateSetToStringArrayFunction();
setArrayFunction.setExportName("setToStringArray");

var stringLengthFunction = moduleGenerator.generateStringLengthFunction();
stringLengthFunction.setExportName("stringLength");

var charAtFunction = moduleGenerator.generateCharAtFunction();
charAtFunction.setExportName("charAt");
var classConsumerContext = createClassConsumerContext(classes, declarationsGenerator);
for (var cls : classes.getClassNames()) {
for (var consumer : classConsumers) {
consumer.accept(classConsumerContext, cls);
}
}

var internMethod = controller.getDependencyInfo().getMethod(new MethodReference(String.class,
"intern", String.class));
if (internMethod != null && internMethod.isUsed()) {
var removeStringEntryFunction = moduleGenerator.generateReportGarbageCollectedStringFunction();
removeStringEntryFunction.setExportName("reportGarbageCollectedString");
removeStringEntryFunction.setExportName("teavm.reportGarbageCollectedString");
}

var exceptionMessageRef = new MethodReference(Throwable.class, "getMessage", Throwable.class);
if (controller.getDependencyInfo().getMethod(exceptionMessageRef) != null) {
var exceptionMessageFunction = declarationsGenerator.functions().forInstanceMethod(exceptionMessageRef);
exceptionMessageFunction.setExportName("exceptionMessage");
exceptionMessageFunction.setExportName("teavm.exceptionMessage");
}

moduleGenerator.generate();
Expand All @@ -248,6 +256,63 @@ public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, Str
emitWasmFile(module, buildTarget, outputName, debugInfoBuilder);
}

private WasmGCClassConsumerContext createClassConsumerContext(
ClassReaderSource classes,
WasmGCDeclarationsGenerator generator
) {
return new WasmGCClassConsumerContext() {
@Override
public ClassReaderSource classes() {
return classes;
}

@Override
public WasmModule module() {
return generator.module;
}

@Override
public WasmFunctionTypes functionTypes() {
return generator.functionTypes;
}

@Override
public BaseWasmFunctionRepository functions() {
return generator.functions();
}

@Override
public WasmGCNameProvider names() {
return generator.names();
}

@Override
public WasmGCStringProvider strings() {
return generator.strings();
}

@Override
public WasmGCTypeMapper typeMapper() {
return generator.typeMapper();
}

@Override
public WasmTag exceptionTag() {
return generator.exceptionTag();
}

@Override
public String entryPoint() {
return controller.getEntryPoint();
}

@Override
public void addToInitializer(Consumer<WasmFunction> initializerContributor) {
generator.addToInitializer(initializerContributor);
}
};
}

private void adjustModuleMemory(WasmModule module) {
var memorySize = 0;
for (var segment : module.getSegments()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@ public interface TeaVMWasmGCHost extends TeaVMHostExtension {
void addGenerator(MethodReference method, WasmGCCustomGenerator generator);

void addCustomTypeMapperFactory(WasmGCCustomTypeMapperFactory customTypeMapperFactory);

void addClassConsumer(WasmGCClassConsumer consumer);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright 2024 konsoletyper.
*
* 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.gc;

public interface WasmGCClassConsumer {
void accept(WasmGCClassConsumerContext context, String className);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2024 konsoletyper.
*
* 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.gc;

import java.util.function.Consumer;
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
import org.teavm.backend.wasm.WasmFunctionTypes;
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper;
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringProvider;
import org.teavm.backend.wasm.model.WasmFunction;
import org.teavm.backend.wasm.model.WasmModule;
import org.teavm.backend.wasm.model.WasmTag;
import org.teavm.model.ClassReaderSource;

public interface WasmGCClassConsumerContext {
ClassReaderSource classes();

WasmModule module();

WasmFunctionTypes functionTypes();

BaseWasmFunctionRepository functions();

WasmGCNameProvider names();

WasmGCStringProvider strings();

WasmGCTypeMapper typeMapper();

WasmTag exceptionTag();

String entryPoint();

void addToInitializer(Consumer<WasmFunction> initializerContributor);
}
Loading

0 comments on commit 0dcc25d

Please sign in to comment.