mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm gc: support resources
This commit is contained in:
parent
e8c939f40b
commit
dd24425de0
|
@ -16,8 +16,8 @@
|
||||||
package org.teavm.classlib.impl.console;
|
package org.teavm.classlib.impl.console;
|
||||||
|
|
||||||
import org.teavm.backend.c.intrinsic.RuntimeInclude;
|
import org.teavm.backend.c.intrinsic.RuntimeInclude;
|
||||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
|
||||||
import org.teavm.backend.wasm.runtime.WasmSupport;
|
import org.teavm.backend.wasm.runtime.WasmSupport;
|
||||||
|
import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
|
||||||
import org.teavm.classlib.PlatformDetector;
|
import org.teavm.classlib.PlatformDetector;
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
import org.teavm.interop.Import;
|
import org.teavm.interop.Import;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.classlib.impl.console;
|
package org.teavm.classlib.impl.console;
|
||||||
|
|
||||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
|
||||||
import org.teavm.classlib.PlatformDetector;
|
import org.teavm.classlib.PlatformDetector;
|
||||||
import org.teavm.jso.JSBody;
|
import org.teavm.jso.JSBody;
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.classlib.impl.console;
|
package org.teavm.classlib.impl.console;
|
||||||
|
|
||||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
|
||||||
import org.teavm.classlib.PlatformDetector;
|
import org.teavm.classlib.PlatformDetector;
|
||||||
import org.teavm.jso.JSBody;
|
import org.teavm.jso.JSBody;
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.classlib.java.lang;
|
package org.teavm.classlib.java.lang;
|
||||||
|
|
||||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
|
||||||
import org.teavm.classlib.PlatformDetector;
|
import org.teavm.classlib.PlatformDetector;
|
||||||
import org.teavm.dependency.PluggableDependency;
|
import org.teavm.dependency.PluggableDependency;
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
|
|
|
@ -29,7 +29,7 @@ import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
|
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
|
||||||
import org.teavm.backend.wasm.runtime.StringInternPool;
|
import org.teavm.backend.wasm.runtime.StringInternPool;
|
||||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ import org.teavm.backend.wasm.render.WasmBinaryVersion;
|
||||||
import org.teavm.backend.wasm.render.WasmBinaryWriter;
|
import org.teavm.backend.wasm.render.WasmBinaryWriter;
|
||||||
import org.teavm.backend.wasm.runtime.StringInternPool;
|
import org.teavm.backend.wasm.runtime.StringInternPool;
|
||||||
import org.teavm.backend.wasm.transformation.gc.BaseClassesTransformation;
|
import org.teavm.backend.wasm.transformation.gc.BaseClassesTransformation;
|
||||||
|
import org.teavm.backend.wasm.transformation.gc.ClassLoaderResourceTransformation;
|
||||||
import org.teavm.dependency.DependencyAnalyzer;
|
import org.teavm.dependency.DependencyAnalyzer;
|
||||||
import org.teavm.dependency.DependencyListener;
|
import org.teavm.dependency.DependencyListener;
|
||||||
import org.teavm.interop.Platforms;
|
import org.teavm.interop.Platforms;
|
||||||
|
@ -119,7 +120,8 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
|
||||||
@Override
|
@Override
|
||||||
public List<ClassHolderTransformer> getTransformers() {
|
public List<ClassHolderTransformer> getTransformers() {
|
||||||
return List.of(
|
return List.of(
|
||||||
new BaseClassesTransformation()
|
new BaseClassesTransformation(),
|
||||||
|
new ClassLoaderResourceTransformation()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +169,8 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
|
||||||
public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName) throws IOException {
|
public void emit(ListableClassHolderSource classes, BuildTarget buildTarget, String outputName) throws IOException {
|
||||||
var module = new WasmModule();
|
var module = new WasmModule();
|
||||||
var customGenerators = new WasmGCCustomGenerators(classes, controller.getServices(),
|
var customGenerators = new WasmGCCustomGenerators(classes, controller.getServices(),
|
||||||
customGeneratorFactories, customCustomGenerators);
|
customGeneratorFactories, customCustomGenerators,
|
||||||
|
controller.getProperties());
|
||||||
var intrinsics = new WasmGCIntrinsics(classes, controller.getServices(), intrinsicFactories, customIntrinsics);
|
var intrinsics = new WasmGCIntrinsics(classes, controller.getServices(), intrinsicFactories, customIntrinsics);
|
||||||
var declarationsGenerator = new WasmGCDeclarationsGenerator(
|
var declarationsGenerator = new WasmGCDeclarationsGenerator(
|
||||||
module,
|
module,
|
||||||
|
@ -218,6 +221,7 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
|
||||||
}
|
}
|
||||||
|
|
||||||
moduleGenerator.generate();
|
moduleGenerator.generate();
|
||||||
|
customGenerators.contributeToModule(module);
|
||||||
adjustModuleMemory(module);
|
adjustModuleMemory(module);
|
||||||
|
|
||||||
emitWasmFile(module, buildTarget, outputName);
|
emitWasmFile(module, buildTarget, outputName);
|
||||||
|
|
|
@ -18,7 +18,7 @@ package org.teavm.backend.wasm.gc;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.teavm.backend.wasm.WasmRuntime;
|
import org.teavm.backend.wasm.WasmRuntime;
|
||||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
|
||||||
import org.teavm.dependency.DependencyAnalyzer;
|
import org.teavm.dependency.DependencyAnalyzer;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ public class WasmGCDependencies {
|
||||||
contributeInitializerUtils();
|
contributeInitializerUtils();
|
||||||
contributeString();
|
contributeString();
|
||||||
analyzer.addDependencyListener(new WasmGCReferenceQueueDependency());
|
analyzer.addDependencyListener(new WasmGCReferenceQueueDependency());
|
||||||
|
analyzer.addDependencyListener(new WasmGCResourceDependency());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void contributeStandardExports() {
|
public void contributeStandardExports() {
|
||||||
|
|
|
@ -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.backend.wasm.gc;
|
||||||
|
|
||||||
|
import org.teavm.backend.wasm.runtime.gc.WasmGCResources;
|
||||||
|
import org.teavm.dependency.AbstractDependencyListener;
|
||||||
|
import org.teavm.dependency.DependencyAgent;
|
||||||
|
import org.teavm.dependency.MethodDependency;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
|
public class WasmGCResourceDependency extends AbstractDependencyListener {
|
||||||
|
private static final MethodReference ACQUIRE_METHOD = new MethodReference(WasmGCResources.class,
|
||||||
|
"acquireResources", WasmGCResources.Resource[].class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void methodReached(DependencyAgent agent, MethodDependency method) {
|
||||||
|
if (method.getMethod().getReference().equals(ACQUIRE_METHOD)) {
|
||||||
|
var create = agent.linkMethod(new MethodReference(WasmGCResources.class,
|
||||||
|
"create", String.class, int.class, int.class, WasmGCResources.Resource.class));
|
||||||
|
create.propagate(1, agent.getType("java.lang.String"));
|
||||||
|
create.use();
|
||||||
|
method.getResult().propagate(agent.getType("[" + WasmGCResources.Resource.class.getName()));
|
||||||
|
method.getResult().getArrayItem().propagate(agent.getType(WasmGCResources.Resource.class.getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -76,7 +76,7 @@ import org.teavm.backend.wasm.model.expression.WasmStructNew;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||||
import org.teavm.backend.wasm.runtime.StringInternPool;
|
import org.teavm.backend.wasm.runtime.StringInternPool;
|
||||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
|
||||||
import org.teavm.dependency.DependencyInfo;
|
import org.teavm.dependency.DependencyInfo;
|
||||||
import org.teavm.model.ClassHierarchy;
|
import org.teavm.model.ClassHierarchy;
|
||||||
import org.teavm.model.ClassReader;
|
import org.teavm.model.ClassReader;
|
||||||
|
|
|
@ -34,7 +34,7 @@ import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringProvider;
|
||||||
import org.teavm.backend.wasm.model.WasmFunction;
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
import org.teavm.backend.wasm.model.WasmModule;
|
import org.teavm.backend.wasm.model.WasmModule;
|
||||||
import org.teavm.backend.wasm.model.WasmTag;
|
import org.teavm.backend.wasm.model.WasmTag;
|
||||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
|
||||||
import org.teavm.model.ClassHierarchy;
|
import org.teavm.model.ClassHierarchy;
|
||||||
import org.teavm.model.ClassReaderSource;
|
import org.teavm.model.ClassReaderSource;
|
||||||
import org.teavm.model.ElementModifier;
|
import org.teavm.model.ElementModifier;
|
||||||
|
|
|
@ -52,6 +52,7 @@ import org.teavm.model.CallLocation;
|
||||||
import org.teavm.model.ClassHierarchy;
|
import org.teavm.model.ClassHierarchy;
|
||||||
import org.teavm.model.ElementModifier;
|
import org.teavm.model.ElementModifier;
|
||||||
import org.teavm.model.ListableClassHolderSource;
|
import org.teavm.model.ListableClassHolderSource;
|
||||||
|
import org.teavm.model.ListableClassReaderSource;
|
||||||
import org.teavm.model.MethodHolder;
|
import org.teavm.model.MethodHolder;
|
||||||
import org.teavm.model.MethodReader;
|
import org.teavm.model.MethodReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
@ -353,6 +354,16 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
private WasmGCCustomGeneratorContext customGeneratorContext = new WasmGCCustomGeneratorContext() {
|
private WasmGCCustomGeneratorContext customGeneratorContext = new WasmGCCustomGeneratorContext() {
|
||||||
|
@Override
|
||||||
|
public ClassLoader classLoader() {
|
||||||
|
return classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListableClassReaderSource classes() {
|
||||||
|
return classes;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WasmModule module() {
|
public WasmModule module() {
|
||||||
return module;
|
return module;
|
||||||
|
@ -387,5 +398,15 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
||||||
public BaseWasmFunctionRepository functions() {
|
public BaseWasmFunctionRepository functions() {
|
||||||
return WasmGCMethodGenerator.this;
|
return WasmGCMethodGenerator.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Diagnostics diagnostics() {
|
||||||
|
return diagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmGCStringProvider strings() {
|
||||||
|
return context.strings();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||||
import org.teavm.backend.wasm.render.WasmBinaryWriter;
|
import org.teavm.backend.wasm.render.WasmBinaryWriter;
|
||||||
import org.teavm.backend.wasm.runtime.StringInternPool;
|
import org.teavm.backend.wasm.runtime.StringInternPool;
|
||||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
|
||||||
import org.teavm.dependency.DependencyInfo;
|
import org.teavm.dependency.DependencyInfo;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIsNull;
|
import org.teavm.backend.wasm.model.expression.WasmIsNull;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
||||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
public class ClassGenerators implements WasmGCCustomGenerator {
|
public class ClassGenerators implements WasmGCCustomGenerator {
|
||||||
|
|
|
@ -20,10 +20,17 @@ import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||||
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
|
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
|
||||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
||||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper;
|
import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper;
|
||||||
|
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringProvider;
|
||||||
import org.teavm.backend.wasm.model.WasmModule;
|
import org.teavm.backend.wasm.model.WasmModule;
|
||||||
import org.teavm.backend.wasm.model.WasmTag;
|
import org.teavm.backend.wasm.model.WasmTag;
|
||||||
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
|
import org.teavm.model.ListableClassReaderSource;
|
||||||
|
|
||||||
public interface WasmGCCustomGeneratorContext {
|
public interface WasmGCCustomGeneratorContext {
|
||||||
|
ClassLoader classLoader();
|
||||||
|
|
||||||
|
ListableClassReaderSource classes();
|
||||||
|
|
||||||
WasmModule module();
|
WasmModule module();
|
||||||
|
|
||||||
WasmFunctionTypes functionTypes();
|
WasmFunctionTypes functionTypes();
|
||||||
|
@ -37,4 +44,8 @@ public interface WasmGCCustomGeneratorContext {
|
||||||
BaseWasmFunctionRepository functions();
|
BaseWasmFunctionRepository functions();
|
||||||
|
|
||||||
WasmTag exceptionTag();
|
WasmTag exceptionTag();
|
||||||
|
|
||||||
|
Diagnostics diagnostics();
|
||||||
|
|
||||||
|
WasmGCStringProvider strings();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,11 @@ import java.lang.reflect.Array;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
import org.teavm.backend.wasm.generate.gc.methods.WasmGCCustomGeneratorProvider;
|
import org.teavm.backend.wasm.generate.gc.methods.WasmGCCustomGeneratorProvider;
|
||||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
import org.teavm.backend.wasm.model.WasmModule;
|
||||||
|
import org.teavm.backend.wasm.runtime.gc.WasmGCResources;
|
||||||
|
import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
|
||||||
import org.teavm.common.ServiceRepository;
|
import org.teavm.common.ServiceRepository;
|
||||||
import org.teavm.model.ClassReaderSource;
|
import org.teavm.model.ClassReaderSource;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
@ -32,24 +35,32 @@ public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider {
|
||||||
private Map<MethodReference, Container> generators = new HashMap<>();
|
private Map<MethodReference, Container> generators = new HashMap<>();
|
||||||
private ClassReaderSource classes;
|
private ClassReaderSource classes;
|
||||||
private ServiceRepository services;
|
private ServiceRepository services;
|
||||||
|
private WasmGCResourcesGenerator resourcesGenerator;
|
||||||
|
|
||||||
public WasmGCCustomGenerators(ClassReaderSource classes, ServiceRepository services,
|
public WasmGCCustomGenerators(ClassReaderSource classes, ServiceRepository services,
|
||||||
List<WasmGCCustomGeneratorFactory> factories,
|
List<WasmGCCustomGeneratorFactory> factories,
|
||||||
Map<MethodReference, WasmGCCustomGenerator> generators) {
|
Map<MethodReference, WasmGCCustomGenerator> generators,
|
||||||
|
Properties properties) {
|
||||||
this.factories = List.copyOf(factories);
|
this.factories = List.copyOf(factories);
|
||||||
this.classes = classes;
|
this.classes = classes;
|
||||||
this.services = services;
|
this.services = services;
|
||||||
|
resourcesGenerator = new WasmGCResourcesGenerator(properties);
|
||||||
fillClass();
|
fillClass();
|
||||||
fillStringPool();
|
fillStringPool();
|
||||||
fillSystem();
|
fillSystem();
|
||||||
fillArray();
|
fillArray();
|
||||||
fillWeakReference();
|
fillWeakReference();
|
||||||
fillString();
|
fillString();
|
||||||
|
fillResources();
|
||||||
for (var entry : generators.entrySet()) {
|
for (var entry : generators.entrySet()) {
|
||||||
add(entry.getKey(), entry.getValue());
|
add(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void contributeToModule(WasmModule module) {
|
||||||
|
resourcesGenerator.writeModule(module);
|
||||||
|
}
|
||||||
|
|
||||||
private void fillClass() {
|
private void fillClass() {
|
||||||
var classGenerators = new ClassGenerators();
|
var classGenerators = new ClassGenerators();
|
||||||
add(new MethodReference(Class.class, "isAssignableFrom", Class.class, boolean.class), classGenerators);
|
add(new MethodReference(Class.class, "isAssignableFrom", Class.class, boolean.class), classGenerators);
|
||||||
|
@ -85,6 +96,11 @@ public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider {
|
||||||
add(new MethodReference(String.class, "intern", String.class), generator);
|
add(new MethodReference(String.class, "intern", String.class), generator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fillResources() {
|
||||||
|
add(new MethodReference(WasmGCResources.class, "acquireResources", WasmGCResources.Resource[].class),
|
||||||
|
resourcesGenerator);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WasmGCCustomGenerator get(MethodReference method) {
|
public WasmGCCustomGenerator get(MethodReference method) {
|
||||||
var result = generators.get(method);
|
var result = generators.get(method);
|
||||||
|
|
|
@ -0,0 +1,174 @@
|
||||||
|
/*
|
||||||
|
* 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.backend.wasm.generators.gc;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
import org.teavm.backend.wasm.generate.TemporaryVariablePool;
|
||||||
|
import org.teavm.backend.wasm.generate.gc.methods.WasmGCGenerationUtil;
|
||||||
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
|
import org.teavm.backend.wasm.model.WasmGlobal;
|
||||||
|
import org.teavm.backend.wasm.model.WasmLocal;
|
||||||
|
import org.teavm.backend.wasm.model.WasmMemorySegment;
|
||||||
|
import org.teavm.backend.wasm.model.WasmModule;
|
||||||
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
|
import org.teavm.backend.wasm.runtime.gc.WasmGCResources;
|
||||||
|
import org.teavm.classlib.ResourceSupplier;
|
||||||
|
import org.teavm.classlib.ResourceSupplierContext;
|
||||||
|
import org.teavm.model.CallLocation;
|
||||||
|
import org.teavm.model.ListableClassReaderSource;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
|
||||||
|
public class WasmGCResourcesGenerator implements WasmGCCustomGenerator {
|
||||||
|
private Properties properties;
|
||||||
|
private ByteArrayOutputStream resources = new ByteArrayOutputStream();
|
||||||
|
private WasmGlobal baseGlobal;
|
||||||
|
|
||||||
|
public WasmGCResourcesGenerator(Properties properties) {
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeModule(WasmModule module) {
|
||||||
|
if (resources.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var segment = new WasmMemorySegment();
|
||||||
|
if (!module.getSegments().isEmpty()) {
|
||||||
|
var lastSegment = module.getSegments().get(module.getSegments().size() - 1);
|
||||||
|
segment.setOffset(lastSegment.getOffset() + lastSegment.getLength());
|
||||||
|
}
|
||||||
|
segment.setData(resources.toByteArray());
|
||||||
|
module.getSegments().add(segment);
|
||||||
|
baseGlobal.setInitialValue(new WasmInt32Constant(segment.getOffset()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(MethodReference method, WasmFunction function, WasmGCCustomGeneratorContext context) {
|
||||||
|
var supplierContext = new SupplierContextImpl(context.classLoader(), context.classes(), properties);
|
||||||
|
var resourceSet = new LinkedHashSet<String>();
|
||||||
|
for (var supplier : ServiceLoader.load(ResourceSupplier.class, context.classLoader())) {
|
||||||
|
var resources = supplier.supplyResources(supplierContext);
|
||||||
|
if (resources != null) {
|
||||||
|
resourceSet.addAll(Arrays.asList(resources));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var descriptors = new ArrayList<ResourceDescriptor>();
|
||||||
|
var location = new CallLocation(new MethodReference(ClassLoader.class,
|
||||||
|
"getResourceAsStream", String.class, InputStream.class));
|
||||||
|
for (var resource : resourceSet) {
|
||||||
|
try (var input = context.classLoader().getResourceAsStream(resource)) {
|
||||||
|
if (input == null) {
|
||||||
|
context.diagnostics().error(location, "Resource not found: " + resource);
|
||||||
|
} else {
|
||||||
|
var start = resources.size();
|
||||||
|
input.transferTo(resources);
|
||||||
|
var end = resources.size();
|
||||||
|
descriptors.add(new ResourceDescriptor(resource, start, end));
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
context.diagnostics().error(location, "Error occurred reading resource '" + resource + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!descriptors.isEmpty()) {
|
||||||
|
baseGlobal = new WasmGlobal(context.names().topLevel("teavm@resourcesBaseAddress"),
|
||||||
|
WasmType.INT32, new WasmInt32Constant(0));
|
||||||
|
context.module().globals.add(baseGlobal);
|
||||||
|
|
||||||
|
var genUtil = new WasmGCGenerationUtil(context.classInfoProvider(), new TemporaryVariablePool(function));
|
||||||
|
var local = new WasmLocal(context.typeMapper().mapType(ValueType.parse(WasmGCResources.Resource[].class)));
|
||||||
|
function.add(local);
|
||||||
|
var constructor = context.functions().forStaticMethod(new MethodReference(WasmGCResources.class,
|
||||||
|
"create", String.class, int.class, int.class, WasmGCResources.Resource.class));
|
||||||
|
|
||||||
|
genUtil.allocateArrayWithElements(
|
||||||
|
ValueType.parse(WasmGCResources.Resource.class),
|
||||||
|
() -> {
|
||||||
|
var items = new ArrayList<WasmExpression>();
|
||||||
|
for (var descriptor : descriptors) {
|
||||||
|
var name = context.strings().getStringConstant(descriptor.name);
|
||||||
|
var offset = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
||||||
|
new WasmGetGlobal(baseGlobal), new WasmInt32Constant(descriptor.address));
|
||||||
|
var end = new WasmInt32Constant(descriptor.end - descriptor.address);
|
||||||
|
items.add(new WasmCall(constructor, new WasmGetGlobal(name.global), offset, end));
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
local,
|
||||||
|
function.getBody()
|
||||||
|
);
|
||||||
|
function.getBody().add(new WasmGetLocal(local));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ResourceDescriptor {
|
||||||
|
String name;
|
||||||
|
int address;
|
||||||
|
int end;
|
||||||
|
|
||||||
|
ResourceDescriptor(String name, int address, int end) {
|
||||||
|
this.name = name;
|
||||||
|
this.address = address;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SupplierContextImpl implements ResourceSupplierContext {
|
||||||
|
private ClassLoader classLoader;
|
||||||
|
private ListableClassReaderSource classSource;
|
||||||
|
private Properties properties;
|
||||||
|
|
||||||
|
SupplierContextImpl(ClassLoader classLoader, ListableClassReaderSource classSource,
|
||||||
|
Properties properties) {
|
||||||
|
this.classLoader = classLoader;
|
||||||
|
this.classSource = classSource;
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClassLoader getClassLoader() {
|
||||||
|
return classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListableClassReaderSource getClassSource() {
|
||||||
|
return classSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Properties getProperties() {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ import org.teavm.backend.wasm.WasmRuntime;
|
||||||
import org.teavm.backend.wasm.generate.gc.methods.WasmGCIntrinsicProvider;
|
import org.teavm.backend.wasm.generate.gc.methods.WasmGCIntrinsicProvider;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
import org.teavm.backend.wasm.runtime.StringInternPool;
|
import org.teavm.backend.wasm.runtime.StringInternPool;
|
||||||
|
import org.teavm.backend.wasm.runtime.gc.WasmGCResources;
|
||||||
import org.teavm.common.ServiceRepository;
|
import org.teavm.common.ServiceRepository;
|
||||||
import org.teavm.model.ClassReaderSource;
|
import org.teavm.model.ClassReaderSource;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
@ -49,6 +50,7 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
||||||
fillDouble();
|
fillDouble();
|
||||||
fillArray();
|
fillArray();
|
||||||
fillString();
|
fillString();
|
||||||
|
fillResources();
|
||||||
for (var entry : customIntrinsics.entrySet()) {
|
for (var entry : customIntrinsics.entrySet()) {
|
||||||
add(entry.getKey(), entry.getValue());
|
add(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
|
@ -156,6 +158,11 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
||||||
add(new MethodReference(className, "setValue", ValueType.parse(String.class), ValueType.VOID), intrinsic);
|
add(new MethodReference(className, "setValue", ValueType.parse(String.class), ValueType.VOID), intrinsic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fillResources() {
|
||||||
|
var intrinsic = new WasmGCResourcesIntrinsic();
|
||||||
|
add(new MethodReference(WasmGCResources.class, "readSingleByte", int.class, int.class), intrinsic);
|
||||||
|
}
|
||||||
|
|
||||||
private void add(MethodReference methodRef, WasmGCIntrinsic intrinsic) {
|
private void add(MethodReference methodRef, WasmGCIntrinsic intrinsic) {
|
||||||
intrinsics.put(methodRef, new IntrinsicContainer(intrinsic));
|
intrinsics.put(methodRef, new IntrinsicContainer(intrinsic));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* 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.intrinsics.gc;
|
||||||
|
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmInt32Subtype;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmLoadInt32;
|
||||||
|
|
||||||
|
public class WasmGCResourcesIntrinsic implements WasmGCIntrinsic {
|
||||||
|
@Override
|
||||||
|
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
||||||
|
return new WasmLoadInt32(1, context.generate(invocation.getArguments().get(0)), WasmInt32Subtype.UINT8);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* 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.backend.wasm.runtime.gc;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public final class WasmGCResources {
|
||||||
|
private static Map<String, Resource> resources = new HashMap<>();
|
||||||
|
|
||||||
|
private WasmGCResources() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (var resource : acquireResources()) {
|
||||||
|
resources.put(resource.name, resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native Resource[] acquireResources();
|
||||||
|
|
||||||
|
private static Resource create(String name, int start, int length) {
|
||||||
|
return new Resource(name, start, start + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InputStream getResource(String name) {
|
||||||
|
var resource = resources.get(name);
|
||||||
|
if (resource == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new ResourceInputStream(resource.start, resource.end);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Resource {
|
||||||
|
public final String name;
|
||||||
|
public final int start;
|
||||||
|
public final int end;
|
||||||
|
|
||||||
|
public Resource(String name, int start, int end) {
|
||||||
|
this.name = name;
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class ResourceInputStream extends InputStream {
|
||||||
|
private int address;
|
||||||
|
private int end;
|
||||||
|
|
||||||
|
private ResourceInputStream(int address, int end) {
|
||||||
|
this.address = address;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
return address < end ? readSingleByte(address++) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] b, int off, int len) throws IOException {
|
||||||
|
if (address >= end) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
var bytesToRead = Math.min(len, end - address);
|
||||||
|
readBytes(b, off, bytesToRead, address);
|
||||||
|
address += bytesToRead;
|
||||||
|
return bytesToRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void readBytes(byte[] bytes, int off, int len, int fromAddress) {
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
bytes[i] = (byte) readSingleByte(fromAddress++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native int readSingleByte(int address);
|
||||||
|
}
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.wasm.runtime;
|
package org.teavm.backend.wasm.runtime.gc;
|
||||||
|
|
||||||
import org.teavm.interop.Import;
|
import org.teavm.interop.Import;
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* 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.backend.wasm.transformation.gc;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import org.teavm.backend.wasm.runtime.gc.WasmGCResources;
|
||||||
|
import org.teavm.model.ClassHolder;
|
||||||
|
import org.teavm.model.ClassHolderTransformer;
|
||||||
|
import org.teavm.model.ClassHolderTransformerContext;
|
||||||
|
import org.teavm.model.MethodDescriptor;
|
||||||
|
import org.teavm.model.MethodHolder;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.Program;
|
||||||
|
import org.teavm.model.instructions.ExitInstruction;
|
||||||
|
import org.teavm.model.instructions.InvocationType;
|
||||||
|
import org.teavm.model.instructions.InvokeInstruction;
|
||||||
|
|
||||||
|
public class ClassLoaderResourceTransformation implements ClassHolderTransformer {
|
||||||
|
@Override
|
||||||
|
public void transformClass(ClassHolder cls, ClassHolderTransformerContext context) {
|
||||||
|
if (cls.getName().equals(ClassLoader.class.getName())) {
|
||||||
|
var method = cls.getMethod(new MethodDescriptor("getResourceAsStream", String.class, InputStream.class));
|
||||||
|
transformGetResourceAsStream(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void transformGetResourceAsStream(MethodHolder method) {
|
||||||
|
var program = new Program();
|
||||||
|
program.createVariable();
|
||||||
|
var nameVar = program.createVariable();
|
||||||
|
var block = program.createBasicBlock();
|
||||||
|
|
||||||
|
var invoke = new InvokeInstruction();
|
||||||
|
invoke.setType(InvocationType.SPECIAL);
|
||||||
|
invoke.setMethod(new MethodReference(WasmGCResources.class, "getResource", String.class,
|
||||||
|
InputStream.class));
|
||||||
|
invoke.setArguments(nameVar);
|
||||||
|
invoke.setReceiver(program.createVariable());
|
||||||
|
block.add(invoke);
|
||||||
|
|
||||||
|
var exit = new ExitInstruction();
|
||||||
|
exit.setValueToReturn(invoke.getReceiver());
|
||||||
|
block.add(exit);
|
||||||
|
|
||||||
|
method.setProgram(program);
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,8 +19,8 @@ import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.teavm.junit.EachTestCompiledSeparately;
|
import org.teavm.junit.EachTestCompiledSeparately;
|
||||||
|
@ -48,14 +48,14 @@ public class ClassLoaderTest {
|
||||||
@Test
|
@Test
|
||||||
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI})
|
@SkipPlatform({TestPlatform.C, TestPlatform.WEBASSEMBLY, TestPlatform.WASI})
|
||||||
public void returnsNullForNonExistentResource() {
|
public void returnsNullForNonExistentResource() {
|
||||||
InputStream input = ClassLoader.getSystemClassLoader().getResourceAsStream("non-existent-resource.txt");
|
var input = ClassLoader.getSystemClassLoader().getResourceAsStream("non-existent-resource.txt");
|
||||||
assertNull(input);
|
assertNull(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String loadResource(String name) {
|
private static String loadResource(String name) {
|
||||||
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
|
var classLoader = ClassLoader.getSystemClassLoader();
|
||||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(classLoader.getResourceAsStream(
|
try (var reader = new BufferedReader(new InputStreamReader(classLoader.getResourceAsStream(
|
||||||
"resources-for-test/" + name), "UTF-8"))) {
|
"resources-for-test/" + name), StandardCharsets.UTF_8))) {
|
||||||
return reader.readLine();
|
return reader.readLine();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return "";
|
return "";
|
||||||
|
|
Loading…
Reference in New Issue
Block a user