package org.graalvm.wasm;
import com.oracle.truffle.api.TruffleLanguage.Env;
import org.graalvm.wasm.exception.Failure;
import org.graalvm.wasm.exception.WasmException;
import org.graalvm.wasm.predefined.BuiltinModule;
import java.util.LinkedHashMap;
import java.util.Map;
public final class WasmContext {
private final Env env;
private final WasmLanguage language;
private final MemoryRegistry memoryRegistry;
private final GlobalRegistry globals;
private final TableRegistry tableRegistry;
private final Linker linker;
private final Map<String, WasmInstance> moduleInstances;
private int moduleNameCount;
public static WasmContext getCurrent() {
return WasmLanguage.getCurrentContext();
}
public WasmContext(Env env, WasmLanguage language) {
this.env = env;
this.language = language;
this.globals = new GlobalRegistry();
this.tableRegistry = new TableRegistry();
this.memoryRegistry = new MemoryRegistry();
this.moduleInstances = new LinkedHashMap<>();
this.linker = new Linker();
this.moduleNameCount = 0;
instantiateBuiltinInstances();
}
public Env environment() {
return env;
}
public WasmLanguage language() {
return language;
}
public MemoryRegistry memories() {
return memoryRegistry;
}
public GlobalRegistry globals() {
return globals;
}
public TableRegistry tables() {
return tableRegistry;
}
public Linker linker() {
return linker;
}
@SuppressWarnings("unused")
public Object getScope() {
return new WasmScope(moduleInstances);
}
public Map<String, WasmInstance> moduleInstances() {
return moduleInstances;
}
public void register(WasmInstance instance) {
if (moduleInstances.containsKey(instance.name())) {
throw WasmException.create(Failure.UNSPECIFIED_INTERNAL, "Context already contains an instance named '" + instance.name() + "'.");
}
moduleInstances.put(instance.name(), instance);
}
private void instantiateBuiltinInstances() {
final String extraModuleValue = WasmOptions.Builtins.getValue(env.getOptions());
if (extraModuleValue.equals("")) {
return;
}
final String[] moduleSpecs = extraModuleValue.split(",");
for (String moduleSpec : moduleSpecs) {
final String[] parts = moduleSpec.split(":");
if (parts.length > 2) {
throw WasmException.create(Failure.UNSPECIFIED_INVALID, "Module specification '" + moduleSpec + "' is not valid.");
}
final String name = parts[0];
final String key = parts.length == 2 ? parts[1] : parts[0];
final WasmInstance module = BuiltinModule.createBuiltinInstance(language, this, name, key);
moduleInstances.put(name, module);
}
}
private String freshModuleName() {
return "module-" + moduleNameCount++;
}
public WasmModule readModule(byte[] data, ModuleLimits moduleLimits) {
return readModule(freshModuleName(), data, moduleLimits);
}
public WasmModule readModule(String moduleName, byte[] data, ModuleLimits moduleLimits) {
final WasmModule module = new WasmModule(moduleName, data);
final BinaryParser reader = new BinaryParser(language, module, moduleLimits);
reader.readModule();
return module;
}
public WasmInstance readInstance(WasmModule module) {
if (moduleInstances.containsKey(module.name())) {
throw WasmException.create(Failure.UNSPECIFIED_INVALID, null, "Module " + module.name() + " is already instantiated in this context.");
}
final WasmInstance instance = new WasmInstance(module);
final BinaryParser reader = new BinaryParser(language, module);
reader.readInstance(this, instance);
this.register(instance);
return instance;
}
public void reinitInstance(WasmInstance instance, boolean reinitMemory) {
final BinaryParser reader = new BinaryParser(language, instance.module());
reader.resetGlobalState(this, instance);
if (reinitMemory) {
reader.resetMemoryState(this, instance);
final WasmFunction startFunction = instance.symbolTable().startFunction();
if (startFunction != null) {
instance.target(startFunction.index()).call();
}
}
}
}