diff --git a/core/src/main/java/io/roastedroot/quickjs4j/core/BasicScriptCache.java b/core/src/main/java/io/roastedroot/quickjs4j/core/BasicScriptCache.java index 9af0196..30b91da 100644 --- a/core/src/main/java/io/roastedroot/quickjs4j/core/BasicScriptCache.java +++ b/core/src/main/java/io/roastedroot/quickjs4j/core/BasicScriptCache.java @@ -1,6 +1,6 @@ package io.roastedroot.quickjs4j.core; -import java.nio.charset.StandardCharsets; +import java.nio.ByteBuffer; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashMap; @@ -8,7 +8,7 @@ public class BasicScriptCache implements ScriptCache, AutoCloseable { private static final String DEFAULT_MESSAGE_DIGEST_ALGORITHM = "SHA-256"; - private final HashMap cache; + private final HashMap cache; private final MessageDigest messageDigest; public BasicScriptCache() { @@ -24,19 +24,20 @@ public BasicScriptCache(String messageDigestAlgorithm) { } } + private ByteBuffer key(byte[] code) { + return ByteBuffer.wrap(messageDigest.digest(code)); + } + public boolean exists(byte[] code) { - var key = messageDigest.digest(code); - return cache.containsKey(new String(key, StandardCharsets.UTF_8)); + return cache.containsKey(key(code)); } public void set(byte[] code, byte[] compiled) { - var key = messageDigest.digest(code); - cache.put(new String(key, StandardCharsets.UTF_8), compiled); + cache.put(key(code), compiled); } public byte[] get(byte[] code) { - var key = messageDigest.digest(code); - return cache.get(new String(key, StandardCharsets.UTF_8)); + return cache.get(key(code)); } public void close() { diff --git a/core/src/main/java/io/roastedroot/quickjs4j/core/Engine.java b/core/src/main/java/io/roastedroot/quickjs4j/core/Engine.java index e91ec1d..c02f606 100644 --- a/core/src/main/java/io/roastedroot/quickjs4j/core/Engine.java +++ b/core/src/main/java/io/roastedroot/quickjs4j/core/Engine.java @@ -29,6 +29,8 @@ @WasmModuleInterface(WasmResource.absoluteFile) public final class Engine implements AutoCloseable { private static final int ALIGNMENT = 1; + + private static final byte[] NULL_BYTES = "null".getBytes(UTF_8); public static final ObjectMapper DEFAULT_OBJECT_MAPPER = new ObjectMapper(); private final ByteArrayOutputStream stdout; @@ -120,11 +122,16 @@ private String readJavyString(int ptr, int len) { public Object invokeGuestFunction( String moduleName, String name, List args, String libraryCode) { + return invokeGuestFunction(moduleName, name, args, libraryCode.getBytes(UTF_8)); + } + + public Object invokeGuestFunction( + String moduleName, String name, List args, byte[] libraryCode) { return invokePrecompiledGuestFunction( moduleName, name, args, compilePortableGuestFunction(libraryCode)); } - public String invokeFunction() { + private String invokeFunction() { var funInvoke = "globalThis[quickjs4j_engine.module_name()][quickjs4j_engine.function_name()](...JSON.parse(quickjs4j_engine.args()))"; Function setResult = @@ -146,24 +153,24 @@ public String invokeFunction() { // we compile a static version of the module and we invoke it parametrically using a basic // protocol // { moduleName: "..", functionName: "..", args: "stringified args" } + public byte[] compilePortableGuestFunction(byte[] libraryCode) { + return compilePortableGuestFunction(new String(libraryCode, UTF_8)); + } + public byte[] compilePortableGuestFunction(String libraryCode) { int codePtr = 0; try { - var invokeFunction = invokeFunction(); - - String jsCode = - new String(jsPrelude(), UTF_8) - + "\n" - + libraryCode - + "\n" - + new String(jsSuffix(), UTF_8) - + "\n" - + invokeFunction - + ";\n"; - - // System.out.println(jsCode); - - codePtr = compileRaw(jsCode.getBytes(UTF_8)); + var buf = new StringBuilder(); + buf.append(jsPrelude()); + buf.append('\n'); + buf.append(libraryCode); + buf.append('\n'); + buf.append(jsSuffix()); + buf.append('\n'); + buf.append(invokeFunction()); + buf.append(";\n"); + + codePtr = compileRaw(buf.toString().getBytes(UTF_8)); return readCompiled(codePtr); } finally { if (codePtr != 0) { @@ -267,11 +274,10 @@ private long[] invokeBuiltin(Instance instance, long[] args) { } } - var returnStr = + var returnBytes = (returnType == Void.class) - ? "null" - : mapper.writerFor(returnType).writeValueAsString(res); - var returnBytes = returnStr.getBytes(); + ? NULL_BYTES + : mapper.writerFor(returnType).writeValueAsBytes(res); var returnPtr = exports.canonicalAbiRealloc( @@ -315,7 +321,7 @@ private long[] invokeBuiltin(Instance instance, long[] args) { this::invokeBuiltin); // This function dynamically generates the global functions defined by the Builtins - private byte[] jsPrelude() { + private String jsPrelude() { var preludeBuilder = new StringBuilder(); for (Map.Entry builtin : builtins.entrySet()) { preludeBuilder.append("globalThis." + builtin.getKey() + " = {};\n"); @@ -332,11 +338,11 @@ private byte[] jsPrelude() { + "\", JSON.stringify(args))) };\n"); } } - return preludeBuilder.toString().getBytes(); + return preludeBuilder.toString(); } // This function dynamically generates the js handlers for Invokables - private byte[] jsSuffix() { + private String jsSuffix() { var suffixBuilder = new StringBuilder(); for (Map.Entry invokable : invokables.entrySet()) { // The object is already defined by the set_result, just add the handlers @@ -352,7 +358,7 @@ private byte[] jsSuffix() { + ";\n"); } } - return suffixBuilder.toString().getBytes(); + return suffixBuilder.toString(); } public int compile(String js) { @@ -360,7 +366,7 @@ public int compile(String js) { } public int compile(byte[] js) { - byte[] prelude = jsPrelude(); + byte[] prelude = jsPrelude().getBytes(UTF_8); byte[] jsCode = new byte[prelude.length + js.length]; System.arraycopy(prelude, 0, jsCode, 0, prelude.length); System.arraycopy(js, 0, jsCode, prelude.length, js.length); diff --git a/core/src/main/java/io/roastedroot/quickjs4j/core/Runner.java b/core/src/main/java/io/roastedroot/quickjs4j/core/Runner.java index 81f0605..b6b2e79 100644 --- a/core/src/main/java/io/roastedroot/quickjs4j/core/Runner.java +++ b/core/src/main/java/io/roastedroot/quickjs4j/core/Runner.java @@ -24,10 +24,13 @@ private Runner(Engine engine, int timeout, int compilationTimeout, ExecutorServi } public byte[] compile(String code) { + return compile(code.getBytes(StandardCharsets.UTF_8)); + } + + public byte[] compile(byte[] code) { return submitWithTimeout( () -> { - byte[] codeBytes = code.getBytes(StandardCharsets.UTF_8); - int codePtr = engine.compile(codeBytes); + int codePtr = engine.compile(code); try { return engine.readCompiled(codePtr); } finally {