Skip to content

Commit

Permalink
PoC for JSR223 script-engine (#149)
Browse files Browse the repository at this point in the history
Signed-off-by: Thomas Darimont <[email protected]>
  • Loading branch information
thomasdarimont committed May 7, 2024
1 parent fb1f64a commit 4a8f35a
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 0 deletions.
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
<module>wasi</module>
<module>wasm-corpus</module>
<module>cli</module>
<module>scriptengine</module>
</modules>

<scm>
Expand Down
31 changes: 31 additions & 0 deletions scriptengine/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.dylibso.chicory</groupId>
<artifactId>chicory</artifactId>
<version>999-SNAPSHOT</version>
</parent>
<artifactId>scriptengine</artifactId>
<name>Chicory - JSR 223 Script Engine</name>
<description>WebAssembly Script Engine</description>
<dependencies>
<dependency>
<groupId>com.dylibso.chicory</groupId>
<artifactId>runtime</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
</dependency>

<dependency>
<!-- generates meta-inf services file for script engine -->
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
<version>1.1.1</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package com.dylibso.chicory.scriptengine;

import com.dylibso.chicory.runtime.Module;
import com.dylibso.chicory.wasm.types.Value;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Base64;
import java.util.Objects;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
import javax.script.SimpleBindings;

public class ChicoryScriptEngine implements ScriptEngine {

@Override
public Object eval(String script, ScriptContext context) throws ScriptException {
return null;
}

@Override
public Object eval(Reader reader, ScriptContext context) throws ScriptException {
return null;
}

@Override
public Object eval(String script) throws ScriptException {
return eval(script, (ScriptContext) null);
}

@Override
public Object eval(Reader reader) throws ScriptException {
return eval(reader, (ScriptContext) null);
}

@Override
public Object eval(String script, Bindings bindings) throws ScriptException {
return eval(new StringReader(script), bindings);
}

@Override
public Object eval(Reader reader, Bindings bindings) throws ScriptException {

StringWriter sw = new StringWriter();
try {
reader.transferTo(sw);
} catch (IOException e) {
throw new RuntimeException(e);
}

byte[] wasmBytes =
Base64.getDecoder().decode(Objects.requireNonNull(sw.toString(), "script"));

int arg0 = ((Integer) bindings.get("arg0")).intValue();
String func = (String) bindings.get("func");

var module = Module.builder(wasmBytes).build();
var instance = module.instantiate();
var iterFact = instance.export(func);
var result = iterFact.apply(Value.i32(arg0))[0].asInt();

return result;
}

@Override
public void put(String key, Object value) {}

@Override
public Object get(String key) {
return null;
}

@Override
public Bindings getBindings(int scope) {
return null;
}

@Override
public void setBindings(Bindings bindings, int scope) {}

@Override
public Bindings createBindings() {
return new SimpleBindings();
}

@Override
public ScriptContext getContext() {
return null;
}

@Override
public void setContext(ScriptContext context) {}

@Override
public ScriptEngineFactory getFactory() {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.dylibso.chicory.scriptengine;

import com.google.auto.service.AutoService;
import java.util.List;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;

@AutoService(ScriptEngineFactory.class)
public class ChicoryScriptEngineFactory implements ScriptEngineFactory {

@Override
public String getEngineName() {
return "Chicory ScriptEngine";
}

@Override
public String getEngineVersion() {
return getClass().getPackage().getImplementationVersion();
}

@Override
public List<String> getExtensions() {
return List.of("wasm");
}

@Override
public List<String> getMimeTypes() {
return List.of("application/wasm");
}

@Override
public List<String> getNames() {
return List.of("chicory");
}

@Override
public String getLanguageName() {
return "WebAssembly";
}

@Override
public String getLanguageVersion() {
return "1.0";
}

@Override
public Object getParameter(String key) {
return null;
}

@Override
public String getMethodCallSyntax(String obj, String m, String... args) {
return "";
}

@Override
public String getOutputStatement(String toDisplay) {
return "";
}

@Override
public String getProgram(String... statements) {
return "";
}

@Override
public ScriptEngine getScriptEngine() {
return new ChicoryScriptEngine();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.dylibso.chicory.scriptengine;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
import javax.script.Bindings;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class ChicoryScriptEngineTest {

ScriptEngineManager engines;

@BeforeEach
public void init() {
engines = new ScriptEngineManager();
}

@Test
public void scriptEngineLookupByName() {
Assertions.assertNotNull(engines.getEngineByName("chicory"));
}

@Test
public void scriptEngineLookupByExtension() {
Assertions.assertNotNull(engines.getEngineByExtension("wasm"));
}

@Test
public void simpleEval() throws Exception {
ScriptEngine engine = engines.getEngineByExtension("wasm");
byte[] wasmBytes =
Files.readAllBytes(
Path.of("../wasm-corpus/src/test/resources/compiled/iterfact.wat.wasm"));
String wasmBase64 = Base64.getEncoder().encodeToString(wasmBytes);
Bindings bindings = engine.createBindings();
bindings.put("arg0", 5);
bindings.put("func", "iterFact");
Object result = engine.eval(wasmBase64, bindings);
Assertions.assertEquals(120, result);
}
}

0 comments on commit 4a8f35a

Please sign in to comment.