use of de.mirkosertic.bytecoder.core.BytecodeMethodSignature in project Bytecoder by mirkosertic.
the class BytecoderUnitTestRunner method testWASMBackendFrameworkMethod.
private void testWASMBackendFrameworkMethod(FrameworkMethod aFrameworkMethod, RunNotifier aRunNotifier) {
Description theDescription = Description.createTestDescription(testClass.getJavaClass(), aFrameworkMethod.getName() + " WASM Backend ");
aRunNotifier.fireTestStarted(theDescription);
WebDriver theDriver = null;
try {
CompileTarget theCompileTarget = new CompileTarget(testClass.getJavaClass().getClassLoader(), CompileTarget.BackendType.wasm);
BytecodeMethodSignature theSignature = theCompileTarget.toMethodSignature(aFrameworkMethod.getMethod());
BytecodeObjectTypeRef theTypeRef = new BytecodeObjectTypeRef(testClass.getName());
CompileOptions theOptions = new CompileOptions(LOGGER, true, KnownOptimizer.ALL);
WASMCompileResult theResult = (WASMCompileResult) theCompileTarget.compileToJS(theOptions, testClass.getJavaClass(), aFrameworkMethod.getName(), theSignature);
String theFileName = theCompileTarget.toClassName(theTypeRef) + "." + theCompileTarget.toMethodName(aFrameworkMethod.getName(), theSignature) + ".html";
File theWorkingDirectory = new File(".");
initializeSeleniumDriver();
File theMavenTargetDir = new File(theWorkingDirectory, "target");
File theGeneratedFilesDir = new File(theMavenTargetDir, "bytecoderwat");
theGeneratedFilesDir.mkdirs();
File theGeneratedFile = new File(theGeneratedFilesDir, theFileName);
// Copy WABT Tools
File theWABTFile = new File(theGeneratedFilesDir, "libwabt.js");
try (FileOutputStream theOS = new FileOutputStream(theWABTFile)) {
IOUtils.copy(getClass().getResourceAsStream("/libwabt.js"), theOS);
}
PrintWriter theWriter = new PrintWriter(theGeneratedFile);
theWriter.println("<html>");
theWriter.println(" <body>");
theWriter.println(" <h1>Module code</h1>");
theWriter.println(" <pre id=\"modulecode\">");
theWriter.println(theResult.getData());
theWriter.println(" </pre>");
theWriter.println(" <h1>Compilation result</h1>");
theWriter.println(" <pre id=\"compileresult\">");
theWriter.println(" </pre>");
theWriter.println(" <script src=\"libwabt.js\">");
theWriter.println(" </script>");
theWriter.println(" <script>");
theWriter.println(" var runningInstance;");
theWriter.println(" var runningInstanceMemory;");
theWriter.println();
theWriter.println(" function bytecoder_IntInMemory(value) {");
theWriter.println(" return runningInstanceMemory[value]");
theWriter.println(" + (runningInstanceMemory[value + 1] * 256)");
theWriter.println(" + (runningInstanceMemory[value + 2] * 256 * 256)");
theWriter.println(" + (runningInstanceMemory[value + 3] * 256 * 256 * 256);");
theWriter.println(" }");
theWriter.println();
theWriter.println(" function bytecoder_logByteArrayAsString(acaller, value) {");
theWriter.println(" var theLength = bytecoder_IntInMemory(value + 16);");
theWriter.println(" var theData = '';");
theWriter.println(" value = value + 20;");
theWriter.println(" for (var i=0;i<theLength;i++) {");
theWriter.println(" var theCharCode = bytecoder_IntInMemory(value);");
theWriter.println(" value = value + 4;");
theWriter.println(" theData+= String.fromCharCode(theCharCode);");
theWriter.println(" }");
theWriter.println(" console.log(theData);");
theWriter.println(" }");
theWriter.println();
theWriter.println(" function bytecoder_logDebug(caller,value) {");
theWriter.println(" console.log(value);");
theWriter.println(" }");
theWriter.println();
theWriter.println(" function compile() {");
theWriter.println(" console.log('Test started');");
theWriter.println(" try {");
theWriter.println(" var module = wabt.parseWat('test.wast', document.getElementById(\"modulecode\").innerText);");
theWriter.println(" module.resolveNames();");
theWriter.println(" module.validate();");
theWriter.println(" var binaryOutput = module.toBinary({log: true, write_debug_names:true});");
theWriter.println(" document.getElementById(\"compileresult\").innerText = binaryOutput.log;");
theWriter.println(" var binaryBuffer = binaryOutput.buffer;");
theWriter.println(" console.log('Size of compiled WASM binary is ' + binaryBuffer.length);");
theWriter.println();
theWriter.println(" var theInstantiatePromise = WebAssembly.instantiate(binaryBuffer, {");
theWriter.println(" system: {");
theWriter.println(" currentTimeMillis: function() {return Date.now();},");
theWriter.println(" nanoTime: function() {return Date.now() * 1000000;},");
theWriter.println(" logDebug: bytecoder_logDebug,");
theWriter.println(" writeByteArrayToConsole: bytecoder_logByteArrayAsString,");
theWriter.println(" },");
theWriter.println(" printstream: {");
theWriter.println(" logDebug: bytecoder_logDebug,");
theWriter.println(" },");
theWriter.println(" math: {");
theWriter.println(" floor: function (thisref, p1) {return Math.floor(p1);},");
theWriter.println(" ceil: function (thisref, p1) {return Math.ceil(p1);},");
theWriter.println(" sin: function (thisref, p1) {return Math.sin(p1);},");
theWriter.println(" cos: function (thisref, p1) {return Math.cos(p1);},");
theWriter.println(" round: function (thisref, p1) {return Math.round(p1);},");
theWriter.println(" float_rem: function(a, b) {return a % b;},");
theWriter.println(" sqrt: function(thisref, p1) {return Math.sqrt(p1);},");
theWriter.println(" add: function(thisref, p1, p2) {return p1 + p2;},");
theWriter.println(" float_rem: function(a, b) {return a % b;},");
theWriter.println(" max: function(p1, p2) { return Math.max(p1, p2);},");
theWriter.println(" min: function(p1, p2) { return Math.min(p1, p2);},");
theWriter.println(" },");
theWriter.println(" strictmath: {");
theWriter.println(" floor: function (thisref, p1) {return Math.floor(p1);},");
theWriter.println(" ceil: function (thisref, p1) {return Math.ceil(p1);},");
theWriter.println(" sin: function (thisref, p1) {return Math.sin(p1);},");
theWriter.println(" cos: function (thisref, p1) {return Math.cos(p1);},");
theWriter.println(" round: function (thisref, p1) {return Math.round(p1);},");
theWriter.println(" float_rem: function(a, b) {return a % b;},");
theWriter.println(" sqrt: function(thisref, p1) {return Math.sqrt(p1);},");
theWriter.println(" add: function(thisref, p1, p2) {return p1 + p2;},");
theWriter.println(" },");
theWriter.println(" profiler: {");
theWriter.println(" logMemoryLayoutBlock: function(aCaller, aStart, aUsed, aNext) {");
theWriter.println(" if (aUsed == 1) return;");
theWriter.println(" console.log(' Block at ' + aStart + ' status is ' + aUsed + ' points to ' + aNext);");
theWriter.println(" console.log(' Block size is ' + bytecoder_IntInMemory(aStart));");
theWriter.println(" console.log(' Object type ' + bytecoder_IntInMemory(aStart + 12));");
theWriter.println(" }");
theWriter.println(" }");
theWriter.println(" });");
theWriter.println(" theInstantiatePromise.then(");
theWriter.println(" function (resolved) {");
theWriter.println(" var wasmModule = resolved.module;");
theWriter.println(" runningInstance = resolved.instance;");
theWriter.println(" runningInstanceMemory = new Uint8Array(runningInstance.exports.memory.buffer);");
theWriter.println(" runningInstance.exports.initMemory(0);");
theWriter.println(" console.log(\"Memory initialized\")");
theWriter.println(" runningInstance.exports.logMemoryLayout(0);");
theWriter.println(" console.log(\"Used memory in bytes \" + runningInstance.exports.usedMem());");
theWriter.println(" console.log(\"Free memory in bytes \" + runningInstance.exports.freeMem());");
theWriter.println(" runningInstance.exports.bootstrap(0);");
theWriter.println(" console.log(\"Used memory after bootstrap in bytes \" + runningInstance.exports.usedMem());");
theWriter.println(" console.log(\"Free memory after bootstrap in bytes \" + runningInstance.exports.freeMem());");
theWriter.println(" runningInstance.exports.logMemoryLayout(0);");
theWriter.println(" console.log(\"Creating test instance\")");
theWriter.print(" var theTest = runningInstance.exports.newObject(0,");
theWriter.print(theResult.getSizeOf(theTypeRef));
theWriter.print(",");
theWriter.print(theResult.getTypeIDFor(theTypeRef));
theWriter.print(",");
theWriter.print(theResult.getVTableIndexOf(theTypeRef));
theWriter.println(", 0);");
theWriter.println(" runningInstance.exports.logMemoryLayout(0);");
theWriter.println(" console.log(\"Bootstrapped\")");
theWriter.println(" try {");
theWriter.println(" runningInstance.exports.logMemoryLayout(0);");
theWriter.println(" console.log(\"Starting main method\")");
theWriter.println(" runningInstance.exports.main(theTest);");
theWriter.println(" console.log(\"Main finished\")");
theWriter.println(" runningInstance.exports.logMemoryLayout(0);");
theWriter.println(" wasmHexDump(runningInstanceMemory);");
theWriter.println(" console.log(\"Test finished OK\")");
theWriter.println(" } catch (e) {");
theWriter.println(" console.log(\"Test threw error\")");
theWriter.println(" runningInstance.exports.logMemoryLayout(0);");
theWriter.println(" wasmHexDump(runningInstanceMemory);");
theWriter.println(" throw e;");
theWriter.println(" }");
theWriter.println(" },");
theWriter.println(" function (rejected) {");
theWriter.println(" console.log(\"Error instantiating webassembly\");");
theWriter.println(" console.log(rejected);");
theWriter.println(" }");
theWriter.println(" );");
theWriter.println(" } catch (e) {");
theWriter.println(" document.getElementById(\"compileresult\").innerText = e.toString();");
theWriter.println(" console.log(e.toString());");
theWriter.println(" console.log(e.stack);");
theWriter.println(" if (runningInstance) {");
theWriter.println(" runningInstance.exports.logMemoryLayout(0);");
theWriter.println(" wasmHexDump(runningInstanceMemory);");
theWriter.println(" }");
theWriter.println(" }");
theWriter.println(" }");
theWriter.println();
theWriter.println(" function wasmHexDump(memory) {");
theWriter.println(" var theStart = 0;");
theWriter.println(" console.log('HEX DUMP');");
theWriter.println(" console.log('=================================================================================');");
theWriter.println(" for (var i=0;i<200;i++) {");
theWriter.println(" var theLine = '' + theStart;");
theWriter.println(" while(theLine.length < 15) {");
theWriter.println(" theLine+= ' ';");
theWriter.println(" }");
theWriter.println(" theLine+= ' : ';");
theWriter.println(" for (var j=0;j<32;j++) {");
theWriter.println(" var theByte = memory[theStart++];");
theWriter.println(" var theData = '' + theByte;");
theWriter.println(" while(theData.length < 3) {");
theWriter.println(" theData = ' ' + theData;");
theWriter.println(" }");
theWriter.println(" theLine += theData;");
theWriter.println(" theLine += ' ';");
theWriter.println(" }");
theWriter.println(" console.log(theLine);");
theWriter.println(" }");
theWriter.println(" console.log('DONE');");
theWriter.println(" }");
theWriter.println();
theWriter.println(" compile();");
theWriter.println(" </script>");
theWriter.println(" </body>");
theWriter.println("</html>");
theWriter.flush();
theWriter.close();
try (PrintWriter theWATWriter = new PrintWriter(new FileWriter(new File(theGeneratedFilesDir, theCompileTarget.toClassName(theTypeRef) + "." + theCompileTarget.toMethodName(aFrameworkMethod.getName(), theSignature) + ".wat")))) {
theWATWriter.println(theResult.getData());
}
// Invoke test in browser
theDriver = newDriverForTest();
theDriver.get(theGeneratedFile.toURI().toURL().toString());
long theStart = System.currentTimeMillis();
boolean theTestSuccedded = false;
while (!theTestSuccedded && System.currentTimeMillis() - theStart < 10 * 1000) {
List<LogEntry> theAll = theDriver.manage().logs().get(LogType.BROWSER).getAll();
for (LogEntry theEntry : theAll) {
String theMessage = theEntry.getMessage();
System.out.println(theMessage);
if (theMessage.contains("Test finished OK")) {
theTestSuccedded = true;
}
}
if (!theTestSuccedded) {
Thread.sleep(100);
}
}
if (!theTestSuccedded) {
aRunNotifier.fireTestFailure(new Failure(theDescription, new RuntimeException("Test did not succeed!")));
}
} catch (ControlFlowProcessingException e) {
System.out.println(e.getGraph().toDOT());
aRunNotifier.fireTestFailure(new Failure(theDescription, e));
} catch (Exception e) {
aRunNotifier.fireTestFailure(new Failure(theDescription, e));
} finally {
if (theDriver != null) {
theDriver.close();
}
aRunNotifier.fireTestFinished(theDescription);
}
}
use of de.mirkosertic.bytecoder.core.BytecodeMethodSignature in project Bytecoder by mirkosertic.
the class BytecoderUnitTestRunner method testJSBackendFrameworkMethod.
private void testJSBackendFrameworkMethod(FrameworkMethod aFrameworkMethod, RunNotifier aRunNotifier) {
Description theDescription = Description.createTestDescription(testClass.getJavaClass(), aFrameworkMethod.getName() + " JS Backend ");
aRunNotifier.fireTestStarted(theDescription);
WebDriver theDriver = null;
try {
CompileTarget theCompileTarget = new CompileTarget(testClass.getJavaClass().getClassLoader(), CompileTarget.BackendType.js);
BytecodeMethodSignature theSignature = theCompileTarget.toMethodSignature(aFrameworkMethod.getMethod());
BytecodeMethodSignature theGetLastExceptionSignature = new BytecodeMethodSignature(BytecodeObjectTypeRef.fromRuntimeClass(Throwable.class), new BytecodeTypeRef[0]);
BytecodeObjectTypeRef theTypeRef = new BytecodeObjectTypeRef(testClass.getName());
StringWriter theStrWriter = new StringWriter();
PrintWriter theCodeWriter = new PrintWriter(theStrWriter);
CompileOptions theOptions = new CompileOptions(LOGGER, true, KnownOptimizer.ALL);
theCodeWriter.println(theCompileTarget.compileToJS(theOptions, testClass.getJavaClass(), aFrameworkMethod.getName(), theSignature).getData());
String theFilename = theCompileTarget.toClassName(theTypeRef) + "." + theCompileTarget.toMethodName(aFrameworkMethod.getName(), theSignature) + "_js.html";
theCodeWriter.println();
theCodeWriter.println("bytecoder.imports.system = {");
theCodeWriter.println(" currentTimeMillis: function() {");
theCodeWriter.println(" return Date.now();");
theCodeWriter.println(" },");
theCodeWriter.println(" nanoTime: function() {");
theCodeWriter.println(" return Date.now() * 1000000;");
theCodeWriter.println(" },");
theCodeWriter.println(" writeByteArrayToConsole: function(thisRef, p1) {");
theCodeWriter.println(" bytecoder.logByteArrayAsString(p1);");
theCodeWriter.println(" },");
theCodeWriter.println(" logDebug: function(p1) {");
theCodeWriter.println(" bytecoder.logDebug(p1);");
theCodeWriter.println(" },");
theCodeWriter.println(" arraycopy: function(src, srcPos, dest, destPos, length) {");
theCodeWriter.println(" for (i=0;i<length;i++) {");
theCodeWriter.println(" dest.data[destPos++] = src.data[srcPos++];");
theCodeWriter.println(" }");
theCodeWriter.println(" }");
theCodeWriter.println("};");
theCodeWriter.println("bytecoder.imports.printstream = {");
theCodeWriter.println(" logDebug: function(thisref, p1) {");
theCodeWriter.println(" bytecoder.logDebug(p1);");
theCodeWriter.println(" },");
theCodeWriter.println("};");
theCodeWriter.println("bytecoder.imports.math = {");
theCodeWriter.println(" ceil: function(p1) {");
theCodeWriter.println(" return Math.ceil(p1);");
theCodeWriter.println(" },");
theCodeWriter.println(" floor: function(p1) {");
theCodeWriter.println(" return Math.floor(p1);");
theCodeWriter.println(" },");
theCodeWriter.println(" sin: function(p1) {");
theCodeWriter.println(" return Math.sin(p1);");
theCodeWriter.println(" },");
theCodeWriter.println(" cos: function(p1) {");
theCodeWriter.println(" return Math.cos(p1);");
theCodeWriter.println(" },");
theCodeWriter.println(" sqrt: function(p1) {");
theCodeWriter.println(" return Math.sqrt(p1);");
theCodeWriter.println(" },");
theCodeWriter.println(" round: function(p1) {");
theCodeWriter.println(" return Math.round(p1);");
theCodeWriter.println(" },");
theCodeWriter.println(" NaN: function(p1) {");
theCodeWriter.println(" return NaN;");
theCodeWriter.println(" },");
theCodeWriter.println(" atan2: function(p1, p2) {");
theCodeWriter.println(" return Math.atan2(p1, p2);");
theCodeWriter.println(" },");
theCodeWriter.println(" max: function(p1, p2) {");
theCodeWriter.println(" return Math.max(p1, p2);");
theCodeWriter.println(" },");
theCodeWriter.println(" random: function() {");
theCodeWriter.println(" return Math.random();");
theCodeWriter.println(" },");
theCodeWriter.println(" tan: function(p1) {");
theCodeWriter.println(" return Math.tan(p1);");
theCodeWriter.println(" },");
theCodeWriter.println(" toRadians: function(p1) {");
theCodeWriter.println(" return Math.toRadians(p1);");
theCodeWriter.println(" },");
theCodeWriter.println(" toDegrees: function(p1) {");
theCodeWriter.println(" return Math.toDegrees(p1);");
theCodeWriter.println(" },");
theCodeWriter.println(" min: function (p1, p2) {");
theCodeWriter.println(" return Math.min(p1, p2);");
theCodeWriter.println(" },");
theCodeWriter.println(" add: function(p1, p2) {");
theCodeWriter.println(" return p1 + p2;");
theCodeWriter.println(" }");
theCodeWriter.println("};");
theCodeWriter.println("bytecoder.imports.strictmath = {");
theCodeWriter.println(" sin: function(p1) {");
theCodeWriter.println(" return Math.sin(p1);");
theCodeWriter.println(" },");
theCodeWriter.println(" cos: function(p1) {");
theCodeWriter.println(" return Math.cos(p1);");
theCodeWriter.println(" },");
theCodeWriter.println(" sqrt: function(p1) {");
theCodeWriter.println(" return Math.sqrt(p1);");
theCodeWriter.println(" },");
theCodeWriter.println(" round: function(p1) {");
theCodeWriter.println(" return Math.round(p1);");
theCodeWriter.println(" },");
theCodeWriter.println(" atan2: function(p1, p2) {");
theCodeWriter.println(" return Math.atan2(p1, p2);");
theCodeWriter.println(" },");
theCodeWriter.println("};");
theCodeWriter.println();
theCodeWriter.println("console.log(\"Starting test\");");
theCodeWriter.println("bytecoder.bootstrap();");
theCodeWriter.println("var theTestInstance = new " + theCompileTarget.toClassName(theTypeRef) + ".Create();");
theCodeWriter.println("theTestInstance." + theCompileTarget.toMethodName(aFrameworkMethod.getName(), theSignature) + "(theTestInstance);");
theCodeWriter.println("var theLastException = " + theCompileTarget.toClassName(BytecodeObjectTypeRef.fromRuntimeClass(ExceptionRethrower.class)) + "." + theCompileTarget.toMethodName("getLastOutcomeOrNullAndReset", theGetLastExceptionSignature) + "();");
theCodeWriter.println("if (theLastException) {");
theCodeWriter.println("var theStringData = theLastException.message.data.data;");
theCodeWriter.println(" var theMessage = \"\";");
theCodeWriter.println(" for (var i=0;i<theStringData.length;i++) {");
theCodeWriter.println(" theMessage += String.fromCharCode(theStringData[i]);");
theCodeWriter.println(" }");
theCodeWriter.println(" console.log(\"Test finished with exception. Message = \" + theMessage);");
theCodeWriter.println(" throw theLastException;");
theCodeWriter.println("}");
theCodeWriter.println("console.log(\"Test finished OK\");");
theCodeWriter.flush();
File theWorkingDirectory = new File(".");
initializeSeleniumDriver();
File theMavenTargetDir = new File(theWorkingDirectory, "target");
File theGeneratedFilesDir = new File(theMavenTargetDir, "bytecoderjs");
theGeneratedFilesDir.mkdirs();
File theGeneratedFile = new File(theGeneratedFilesDir, theFilename);
PrintWriter theWriter = new PrintWriter(theGeneratedFile);
theWriter.println("<html><body><script>");
theWriter.println(theStrWriter.toString());
theWriter.println("</script></body></html>");
theWriter.flush();
theWriter.close();
theDriver = newDriverForTest();
theDriver.get(theGeneratedFile.toURI().toURL().toString());
List<LogEntry> theAll = theDriver.manage().logs().get(LogType.BROWSER).getAll();
if (theAll.size() < 1) {
aRunNotifier.fireTestFailure(new Failure(theDescription, new RuntimeException("No console output from browser")));
}
for (LogEntry theEntry : theAll) {
System.out.println(theEntry.getMessage());
}
LogEntry theLast = theAll.get(theAll.size() - 1);
if (!theLast.getMessage().contains("Test finished OK")) {
aRunNotifier.fireTestFailure(new Failure(theDescription, new RuntimeException("Test did not succeed! Got : " + theLast.getMessage())));
}
} catch (ControlFlowProcessingException e) {
System.out.println(e.getGraph().toDOT());
aRunNotifier.fireTestFailure(new Failure(theDescription, e));
} catch (Exception e) {
aRunNotifier.fireTestFailure(new Failure(theDescription, e));
} finally {
if (theDriver != null) {
theDriver.close();
}
aRunNotifier.fireTestFinished(theDescription);
}
}
use of de.mirkosertic.bytecoder.core.BytecodeMethodSignature in project Bytecoder by mirkosertic.
the class OpenCLWriter method printReloopedInline.
public void printReloopedInline(BytecodeMethod aMethod, Program aProgram, Relooper.Block aBlock) {
BytecodeMethodSignature theSignature = aMethod.getSignature();
print("__inline ");
print(toType(TypeRef.toType(theSignature.getReturnType())));
print(" ");
print(aMethod.getName().stringValue());
print("(");
boolean theFirst = true;
List<OpenCLInputOutputs.KernelArgument> theArguments = inputOutputs.arguments();
for (OpenCLInputOutputs.KernelArgument theArgument1 : theArguments) {
if (theFirst) {
theFirst = false;
} else {
print(", ");
}
TypeRef theTypeRef = TypeRef.toType(theArgument1.getField().getValue().getTypeRef());
switch(theArgument1.getType()) {
case INPUT:
print("const ");
print(toType(theTypeRef));
print(" ");
print(theArgument1.getField().getValue().getName().stringValue());
break;
case OUTPUT:
case INPUTOUTPUT:
print(toType(theTypeRef));
print(" ");
print(theArgument1.getField().getValue().getName().stringValue());
break;
}
}
List<Program.Argument> theProgramArguments = aProgram.getArguments();
for (int i = 1; i < theProgramArguments.size(); i++) {
Program.Argument theArgument = theProgramArguments.get(i);
if (theFirst) {
theFirst = false;
} else {
print(", ");
}
print(toType(theArgument.getVariable().resolveType()));
print(" ");
print(theArgument.getVariable().getName());
}
println(") {");
OpenCLWriter theDeeper = withDeeperIndent();
theDeeper.println("int $__label__ = 0;");
for (Variable theVariable : aProgram.getVariables()) {
if (!theVariable.isSynthetic()) {
theDeeper.print(toType(theVariable.resolveType(), false));
theDeeper.print(" ");
theDeeper.print(theVariable.getName());
theDeeper.println(";");
}
}
theDeeper.print(aBlock);
println("}");
}
use of de.mirkosertic.bytecoder.core.BytecodeMethodSignature in project Bytecoder by mirkosertic.
the class WASMSSACompilerBackend method generateCodeFor.
@Override
public WASMCompileResult generateCodeFor(CompileOptions aOptions, BytecodeLinkerContext aLinkerContext, Class aEntryPointClass, String aEntryPointMethodName, BytecodeMethodSignature aEntryPointSignatue) {
// Link required mamory management code
BytecodeLinkedClass theArrayClass = aLinkerContext.resolveClass(BytecodeObjectTypeRef.fromRuntimeClass(Array.class));
BytecodeLinkedClass theManagerClass = aLinkerContext.resolveClass(BytecodeObjectTypeRef.fromRuntimeClass(MemoryManager.class));
theManagerClass.resolveStaticMethod("freeMem", new BytecodeMethodSignature(BytecodePrimitiveTypeRef.LONG, new BytecodeTypeRef[0]));
theManagerClass.resolveStaticMethod("usedMem", new BytecodeMethodSignature(BytecodePrimitiveTypeRef.LONG, new BytecodeTypeRef[0]));
theManagerClass.resolveStaticMethod("free", new BytecodeMethodSignature(BytecodePrimitiveTypeRef.VOID, new BytecodeTypeRef[] { BytecodeObjectTypeRef.fromRuntimeClass(Address.class) }));
theManagerClass.resolveStaticMethod("malloc", new BytecodeMethodSignature(BytecodeObjectTypeRef.fromRuntimeClass(Address.class), new BytecodeTypeRef[] { BytecodePrimitiveTypeRef.INT }));
theManagerClass.resolveStaticMethod("newObject", new BytecodeMethodSignature(BytecodeObjectTypeRef.fromRuntimeClass(Address.class), new BytecodeTypeRef[] { BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT }));
theManagerClass.resolveStaticMethod("newArray", new BytecodeMethodSignature(BytecodeObjectTypeRef.fromRuntimeClass(Address.class), new BytecodeTypeRef[] { BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT }));
theManagerClass.resolveStaticMethod("newArray", new BytecodeMethodSignature(BytecodeObjectTypeRef.fromRuntimeClass(Address.class), new BytecodeTypeRef[] { BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT }));
BytecodeLinkedClass theStringClass = aLinkerContext.resolveClass(BytecodeObjectTypeRef.fromRuntimeClass(String.class));
if (!theStringClass.resolveConstructorInvocation(new BytecodeMethodSignature(BytecodePrimitiveTypeRef.VOID, new BytecodeTypeRef[] { new BytecodeArrayTypeRef(BytecodePrimitiveTypeRef.BYTE, 1) }))) {
throw new IllegalStateException("No matching constructor!");
}
StringWriter theStringWriter = new StringWriter();
PrintWriter theWriter = new PrintWriter(theStringWriter);
theWriter.println("(module");
theWriter.println(" (func $float_remainder (import \"math\" \"float_rem\") (param $p1 f32) (param $p2 f32) (result f32))\n");
// Print imported functions first
aLinkerContext.linkedClasses().forEach(aEntry -> {
if (aEntry.targetNode().getBytecodeClass().getAccessFlags().isInterface()) {
return;
}
if (Objects.equals(aEntry.edgeType().objectTypeRef(), BytecodeObjectTypeRef.fromRuntimeClass(Address.class))) {
return;
}
BytecodeResolvedMethods theMethodMap = aEntry.targetNode().resolvedMethods();
theMethodMap.stream().forEach(aMethodMapEntry -> {
// Only add implementation methods
if (!(aMethodMapEntry.getProvidingClass() == aEntry.targetNode())) {
return;
}
BytecodeMethod t = aMethodMapEntry.getValue();
BytecodeMethodSignature theSignature = t.getSignature();
if (t.getAccessFlags().isNative()) {
if (aMethodMapEntry.getProvidingClass().getBytecodeClass().getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
return;
}
BytecodeImportedLink theLink = aMethodMapEntry.getProvidingClass().linkfor(t);
// Imported function
theWriter.print(" (func ");
theWriter.print("$");
theWriter.print(WASMWriterUtils.toMethodName(aMethodMapEntry.getProvidingClass().getClassName(), t.getName(), theSignature));
theWriter.print(" (import \"");
theWriter.print(theLink.getModuleName());
theWriter.print("\" \"");
theWriter.print(theLink.getLinkName());
theWriter.print("\") ");
theWriter.print("(param $thisRef");
theWriter.print(" ");
theWriter.print(WASMWriterUtils.toType(TypeRef.Native.REFERENCE));
theWriter.print(") ");
for (int i = 0; i < theSignature.getArguments().length; i++) {
BytecodeTypeRef theParamType = theSignature.getArguments()[i];
theWriter.print("(param $p");
theWriter.print((i + 1));
theWriter.print(" ");
theWriter.print(WASMWriterUtils.toType(TypeRef.toType(theParamType)));
theWriter.print(") ");
}
if (!theSignature.getReturnType().isVoid()) {
// result
theWriter.print("(result ");
theWriter.print(WASMWriterUtils.toType(TypeRef.toType(theSignature.getReturnType())));
theWriter.print(")");
}
theWriter.println(")");
}
});
});
Map<String, String> theGlobalTypes = new HashMap<>();
theGlobalTypes.put("RESOLVEMETHOD", "(func (param i32) (param i32) (result i32))");
theGlobalTypes.put("INSTANCEOF", "(func (param i32) (param i32) (result i32))");
theWriter.println();
List<String> theGeneratedFunctions = new ArrayList<>();
theGeneratedFunctions.add("LAMBDA__resolvevtableindex");
theGeneratedFunctions.add("RUNTIMECLASS__resolvevtableindex");
theGeneratedFunctions.add("jlClass_A1jlObjectgetEnumConstants");
theGeneratedFunctions.add("jlClass_BOOLEANdesiredAssertionStatus");
List<BytecodeLinkedClass> theLinkedClasses = new ArrayList<>();
ConstantPool theConstantPool = new ConstantPool();
Map<String, CallSite> theCallsites = new HashMap<>();
WASMSSAWriter.IDResolver theResolver = new WASMSSAWriter.IDResolver() {
@Override
public int resolveVTableMethodByType(BytecodeObjectTypeRef aObjectType) {
String theClassName = WASMWriterUtils.toClassName(aObjectType);
String theMethodName = theClassName + "__resolvevtableindex";
int theIndex = theGeneratedFunctions.indexOf(theMethodName);
if (theIndex < 0) {
throw new IllegalStateException("Cannot resolve vtable method for " + theClassName);
}
return theIndex;
}
@Override
public String resolveStringPoolFunctionName(StringValue aValue) {
return "stringPool" + theConstantPool.register(aValue);
}
@Override
public String resolveCallsiteBootstrapFor(BytecodeClass aOwningClass, String aCallsiteId, Program aProgram, RegionNode aBootstrapMethod) {
String theID = "callsite_" + aCallsiteId.replace("/", "_");
CallSite theCallsite = theCallsites.computeIfAbsent(theID, k -> new CallSite(aProgram, aBootstrapMethod));
return theID;
}
@Override
public int resolveMethodIDByName(String aMethodName) {
int theIndex = theGeneratedFunctions.indexOf(aMethodName);
if (theIndex < 0) {
throw new IllegalStateException("Cannot resolve method " + aMethodName);
}
return theIndex;
}
@Override
public void registerGlobalType(BytecodeMethodSignature aSignature, boolean aStatic) {
String theMethodSignature = WASMWriterUtils.toMethodSignature(aSignature, aStatic);
if (!theGlobalTypes.containsKey(theMethodSignature)) {
String theTypeDefinition = WASMWriterUtils.toWASMMethodSignature(aSignature);
theGlobalTypes.put(theMethodSignature, theTypeDefinition);
}
}
};
aLinkerContext.linkedClasses().forEach(aEntry -> {
if (Objects.equals(aEntry.edgeType().objectTypeRef(), BytecodeObjectTypeRef.fromRuntimeClass(Address.class))) {
return;
}
theLinkedClasses.add(aEntry.targetNode());
String theClassName = WASMWriterUtils.toClassName(aEntry.edgeType().objectTypeRef());
if (!aEntry.targetNode().getBytecodeClass().getAccessFlags().isInterface()) {
theGeneratedFunctions.add(theClassName + "__resolvevtableindex");
theGeneratedFunctions.add(theClassName + "__instanceof");
}
BytecodeResolvedMethods theMethodMap = aEntry.targetNode().resolvedMethods();
theMethodMap.stream().forEach(aMapEntry -> {
BytecodeMethod t = aMapEntry.getValue();
// If the method is provided by the runtime, we do not need to generate the implementation
if (t.getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
return;
}
// Do not generate code for abstract methods
if (t.getAccessFlags().isAbstract()) {
return;
}
// Constructors for the same reason
if (t.isConstructor()) {
return;
}
// Class initializer also
if (t.isClassInitializer()) {
return;
}
// Only write real methods
if (!(aMapEntry.getProvidingClass() == aEntry.targetNode())) {
return;
}
BytecodeMethodSignature theSignature = t.getSignature();
theResolver.registerGlobalType(theSignature, t.getAccessFlags().isStatic());
if (aEntry.targetNode().getBytecodeClass().getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
return;
}
String theMethodName = WASMWriterUtils.toMethodName(aEntry.edgeType().objectTypeRef(), t.getName(), theSignature);
if (!theGeneratedFunctions.contains(theMethodName)) {
theGeneratedFunctions.add(theMethodName);
}
});
});
theWriter.println(" (memory (export \"memory\") 512 512)");
// Write virtual method table
if (!theGeneratedFunctions.isEmpty()) {
theWriter.println();
theWriter.print(" (table ");
theWriter.print(theGeneratedFunctions.size());
theWriter.println(" anyfunc)");
for (int i = 0; i < theGeneratedFunctions.size(); i++) {
theWriter.print(" (elem (i32.const ");
theWriter.print(i);
theWriter.print(") $");
theWriter.print(theGeneratedFunctions.get(i));
theWriter.println(")");
}
theWriter.println();
}
// Initialize memory layout for classes and instances
WASMMemoryLayouter theMemoryLayout = new WASMMemoryLayouter(aLinkerContext);
// Now everything else
aLinkerContext.linkedClasses().forEach(aEntry -> {
BytecodeLinkedClass theLinkedClass = aEntry.targetNode();
if (Objects.equals(aEntry.edgeType().objectTypeRef(), BytecodeObjectTypeRef.fromRuntimeClass(Address.class))) {
return;
}
if (theLinkedClass.getBytecodeClass().getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
return;
}
Set<BytecodeObjectTypeRef> theStaticReferences = new HashSet<>();
BytecodeResolvedMethods theMethodMap = theLinkedClass.resolvedMethods();
theMethodMap.stream().forEach(aMethodMapEntry -> {
BytecodeMethod theMethod = aMethodMapEntry.getValue();
BytecodeMethodSignature theSignature = theMethod.getSignature();
// If the method is provided by the runtime, we do not need to generate the implementation
if (theMethod.getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
return;
}
// Do not generate code for abstract methods
if (theMethod.getAccessFlags().isAbstract()) {
return;
}
if (theMethod.getAccessFlags().isNative()) {
// Already written
return;
}
if (!(aMethodMapEntry.getProvidingClass() == theLinkedClass)) {
// But include static methods, as they are inherited from the base classes
if (aMethodMapEntry.getValue().getAccessFlags().isStatic() && !aMethodMapEntry.getValue().isClassInitializer()) {
// We need to create a delegate function here
if (!theMethodMap.isImplementedBy(aMethodMapEntry.getValue(), theLinkedClass)) {
theWriter.print(" (func ");
theWriter.print("$");
theWriter.print(WASMWriterUtils.toMethodName(theLinkedClass.getClassName(), theMethod.getName(), theSignature));
theWriter.print(" ");
theWriter.print("(param $UNUSED");
theWriter.print(" ");
theWriter.print(WASMWriterUtils.toType(TypeRef.Native.REFERENCE));
theWriter.print(") ");
StringBuilder theArguments = new StringBuilder();
theArguments.append("(get_local $UNUSED)");
for (int i = 0; i < theSignature.getArguments().length; i++) {
theWriter.print("(param $p");
theWriter.print(i);
theWriter.print(" ");
theWriter.print(WASMWriterUtils.toType(TypeRef.toType(theSignature.getArguments()[i])));
theWriter.print(") ");
theArguments.append(" (get_local $p");
theArguments.append(i);
theArguments.append(")");
}
if (!theSignature.getReturnType().isVoid()) {
// result
theWriter.print("(result ");
theWriter.print(WASMWriterUtils.toType(TypeRef.toType(theSignature.getReturnType())));
theWriter.print(")");
}
theWriter.println();
// Static methods will just delegate to the implementation in the class
theWriter.println();
if (!theSignature.getReturnType().isVoid()) {
theWriter.print(" (return ");
theWriter.print("(call $");
theWriter.print(WASMWriterUtils.toMethodName(aMethodMapEntry.getProvidingClass().getClassName(), theMethod.getName(), theSignature));
theWriter.print(" ");
theWriter.print(theArguments);
theWriter.println(")))");
} else {
theWriter.print(" (call $");
theWriter.print(WASMWriterUtils.toMethodName(aMethodMapEntry.getProvidingClass().getClassName(), theMethod.getName(), theSignature));
theWriter.print(" ");
theWriter.print(theArguments);
theWriter.println("))");
}
}
}
return;
}
ProgramGenerator theGenerator = programGeneratorFactory.createFor(aLinkerContext);
Program theSSAProgram = theGenerator.generateFrom(aMethodMapEntry.getProvidingClass().getBytecodeClass(), theMethod);
// Run optimizer
aOptions.getOptimizer().optimize(theSSAProgram.getControlFlowGraph(), aLinkerContext);
theWriter.print(" (func ");
theWriter.print("$");
theWriter.print(WASMWriterUtils.toMethodName(theLinkedClass.getClassName(), theMethod.getName(), theSignature));
theWriter.print(" ");
if (theMethod.getAccessFlags().isStatic()) {
theWriter.print("(param $UNUSED");
theWriter.print(" ");
theWriter.print(WASMWriterUtils.toType(TypeRef.Native.REFERENCE));
theWriter.print(") ");
}
for (Program.Argument theArgument : theSSAProgram.getArguments()) {
Variable theVariable = theArgument.getVariable();
theWriter.print("(param $");
theWriter.print(theVariable.getName());
theWriter.print(" ");
theWriter.print(WASMWriterUtils.toType(theVariable.resolveType()));
theWriter.print(") ");
}
if (!theSignature.getReturnType().isVoid()) {
// result
theWriter.print("(result ");
theWriter.print(WASMWriterUtils.toType(TypeRef.toType(theSignature.getReturnType())));
theWriter.print(")");
}
theWriter.println();
theStaticReferences.addAll(theSSAProgram.getStaticReferences());
WASMSSAWriter theSSAWriter = new WASMSSAWriter(aOptions, theSSAProgram, " ", theWriter, aLinkerContext, theResolver, theMemoryLayout);
for (Variable theVariable : theSSAProgram.getVariables()) {
if (!(theVariable.isSynthetic()) && !theSSAWriter.isStackVariable(theVariable)) {
theSSAWriter.print("(local $");
theSSAWriter.print(theVariable.getName());
theSSAWriter.print(" ");
theSSAWriter.print(WASMWriterUtils.toType(theVariable.resolveType()));
theSSAWriter.print(") ;; ");
theSSAWriter.println(theVariable.resolveType().resolve().name());
}
}
// Try to reloop it!
try {
Relooper theRelooper = new Relooper();
Relooper.Block theReloopedBlock = theRelooper.reloop(theSSAProgram.getControlFlowGraph());
theSSAWriter.writeRelooped(theReloopedBlock);
} catch (Exception e) {
throw new IllegalStateException("Error relooping cfg", e);
}
theWriter.println(" )");
theWriter.println();
});
String theClassName = WASMWriterUtils.toClassName(aEntry.edgeType().objectTypeRef());
if (!theLinkedClass.getBytecodeClass().getAccessFlags().isInterface()) {
theWriter.print(" (func ");
theWriter.print("$");
theWriter.print(theClassName);
theWriter.println("__resolvevtableindex (param $thisRef i32) (param $p1 i32) (result i32)");
List<BytecodeResolvedMethods.MethodEntry> theEntries = theMethodMap.stream().collect(Collectors.toList());
Set<BytecodeVirtualMethodIdentifier> theVisitedMethods = new HashSet<>();
for (int i = theEntries.size() - 1; i >= 0; i--) {
BytecodeResolvedMethods.MethodEntry aMethodMapEntry = theEntries.get(i);
BytecodeMethod theMethod = aMethodMapEntry.getValue();
if (!theMethod.getAccessFlags().isStatic() && !theMethod.getAccessFlags().isPrivate() && !theMethod.isConstructor() && !theMethod.getAccessFlags().isAbstract() && (theMethod != BytecodeLinkedClass.GET_CLASS_PLACEHOLDER)) {
BytecodeVirtualMethodIdentifier theMethodIdentifier = aLinkerContext.getMethodCollection().identifierFor(theMethod);
if (theVisitedMethods.add(theMethodIdentifier)) {
theWriter.println(" (block $b");
theWriter.print(" (br_if $b (i32.ne (get_local $p1) (i32.const ");
theWriter.print(theMethodIdentifier.getIdentifier());
theWriter.println(")))");
String theFullMethodName = WASMWriterUtils.toMethodName(aMethodMapEntry.getProvidingClass().getClassName(), theMethod.getName(), theMethod.getSignature());
int theIndex = theGeneratedFunctions.indexOf(theFullMethodName);
if (theIndex < 0) {
throw new IllegalStateException("Unknown index : " + theFullMethodName);
}
theWriter.print(" (return (i32.const ");
theWriter.print(theIndex);
theWriter.println("))");
theWriter.println(" )");
}
}
}
;
theWriter.println(" (block $b");
theWriter.print(" (br_if $b (i32.ne (get_local $p1) (i32.const ");
theWriter.print(WASMSSAWriter.GENERATED_INSTANCEOF_METHOD_ID);
theWriter.println(")))");
String theFullMethodName = theClassName + "__instanceof";
int theIndex = theGeneratedFunctions.indexOf(theFullMethodName);
if (theIndex < 0) {
throw new IllegalStateException("Unknown index : " + theFullMethodName);
}
theWriter.print(" (return (i32.const ");
theWriter.print(theIndex);
theWriter.println("))");
theWriter.println(" )");
theWriter.println(" (unreachable)");
theWriter.println(" )");
theWriter.println();
// Instanceof method
theWriter.print(" (func ");
theWriter.print("$");
theWriter.print(theClassName);
theWriter.println("__instanceof (param $thisRef i32) (param $p1 i32) (result i32)");
for (BytecodeLinkedClass theType : theLinkedClass.getImplementingTypes()) {
theWriter.print(" (block $block");
theWriter.print(theType.getUniqueId());
theWriter.println();
theWriter.print(" (br_if $block");
theWriter.print(theType.getUniqueId());
theWriter.print(" (i32.ne (get_local $p1) (i32.const ");
theWriter.print(theType.getUniqueId());
theWriter.println(")))");
theWriter.println(" (return (i32.const 1))");
theWriter.println(" )");
}
theWriter.println(" (return (i32.const 0))");
theWriter.println(" )");
theWriter.println();
}
theWriter.print(" (func ");
theWriter.print("$");
theWriter.print(theClassName);
theWriter.println("__classinitcheck");
theWriter.println(" (block $check");
theWriter.print(" (br_if $check (i32.eq (i32.load offset=8 (get_global $");
theWriter.print(theClassName);
theWriter.println("__runtimeClass)) (i32.const 1)))");
theWriter.print(" (i32.store offset=8 (get_global $");
theWriter.print(theClassName);
theWriter.println("__runtimeClass) (i32.const 1))");
for (BytecodeObjectTypeRef theRef : theStaticReferences) {
if (!Objects.equals(theRef, aEntry.edgeType().objectTypeRef())) {
theWriter.print(" (call $");
theWriter.print(WASMWriterUtils.toClassName(theRef));
theWriter.println("__classinitcheck)");
}
}
if (theLinkedClass.hasClassInitializer()) {
theWriter.print(" (call $");
theWriter.print(theClassName);
theWriter.println("_VOIDclinit (i32.const 0))");
}
theWriter.println(" )");
theWriter.println(" )");
theWriter.println();
});
// Render callsites
for (Map.Entry<String, CallSite> theEntry : theCallsites.entrySet()) {
theWriter.print(" (func ");
theWriter.print("$");
theWriter.print(theEntry.getKey());
theWriter.print(" ");
// result
theWriter.print("(result ");
theWriter.print(WASMWriterUtils.toType(TypeRef.Native.REFERENCE));
theWriter.print(")");
theWriter.println();
Program theSSAProgram = theEntry.getValue().program;
WASMSSAWriter theSSAWriter = new WASMSSAWriter(aOptions, theSSAProgram, " ", theWriter, aLinkerContext, theResolver, theMemoryLayout);
for (Variable theVariable : theSSAProgram.getVariables()) {
if (!(theVariable.isSynthetic()) && !(theSSAWriter.isStackVariable(theVariable))) {
theSSAWriter.print("(local $");
theSSAWriter.print(theVariable.getName());
theSSAWriter.print(" ");
theSSAWriter.print(WASMWriterUtils.toType(theVariable.resolveType()));
theSSAWriter.print(") ;; ");
theSSAWriter.println(theVariable.resolveType().resolve().name());
}
}
theSSAWriter.printStackEnter();
theSSAWriter.writeExpressionList(theEntry.getValue().bootstrapMethod.getExpressions());
theWriter.println(" )");
theWriter.println();
}
theWriter.println(" (func $newRuntimeClass (param $type i32) (param $staticSize i32) (param $enumValuesOffset i32) (result i32)");
theWriter.println(" (local $newRef i32)");
theWriter.println(" (set_local $newRef");
theWriter.print(" (call $");
theWriter.print(WASMWriterUtils.toClassName(theManagerClass.getClassName()));
theWriter.print("_dmbcAddressnewObjectINTINTINT (i32.const 0) (get_local $staticSize) (i32.const -1) (i32.const ");
theWriter.print(theGeneratedFunctions.indexOf("RUNTIMECLASS__resolvevtableindex"));
theWriter.println("))");
theWriter.println(" )");
theWriter.println(" (i32.store offset=12 (get_local $newRef) (i32.add (get_local $newRef) (get_local $enumValuesOffset)))");
theWriter.println(" (return (get_local $newRef))");
theWriter.println(" )");
theWriter.println();
theWriter.println(" (func $LAMBDA__resolvevtableindex (param $thisRef i32) (param $methodId i32) (result i32)");
theWriter.println(" (return (i32.load offset=8 (get_local $thisRef)))");
theWriter.println(" )");
theWriter.println();
int theLambdaVTableResolveIndex = theGeneratedFunctions.indexOf("LAMBDA__resolvevtableindex");
if (theLambdaVTableResolveIndex < 0) {
throw new IllegalStateException("Cannot resolve LAMBDA__resolvevtableindex");
}
theWriter.println(" (func $newLambda (param $type i32) (param $implMethodNumber i32) (result i32)");
theWriter.println(" (local $newRef i32)");
theWriter.println(" (set_local $newRef");
theWriter.print(" (call $");
theWriter.print(WASMWriterUtils.toClassName(theManagerClass.getClassName()));
theWriter.print("_dmbcAddressnewObjectINTINTINT (i32.const 0) (i32.const 12) (get_local $type) (i32.const ");
theWriter.print(theLambdaVTableResolveIndex);
theWriter.println("))");
theWriter.println(" )");
theWriter.println(" (i32.store offset=8 (get_local $newRef) (get_local $implMethodNumber))");
theWriter.println(" (return (get_local $newRef))");
theWriter.println(" )");
theWriter.println();
theWriter.println(" (func $compareValueI32 (param $p1 i32) (param $p2 i32) (result i32)");
theWriter.println(" (block $b1");
theWriter.println(" (br_if $b1");
theWriter.println(" (i32.ne (get_local $p1) (get_local $p2))");
theWriter.println(" )");
theWriter.println(" (return (i32.const 0))");
theWriter.println(" )");
theWriter.println(" (block $b2");
theWriter.println(" (br_if $b2");
theWriter.println(" (i32.ge_s (get_local $p1) (get_local $p2))");
theWriter.println(" )");
theWriter.println(" (return (i32.const -1))");
theWriter.println(" )");
theWriter.println(" (return (i32.const 1))");
theWriter.println(" )");
theWriter.println();
theWriter.println(" (func $compareValueF32 (param $p1 f32) (param $p2 f32) (result i32)");
theWriter.println(" (block $b1");
theWriter.println(" (br_if $b1");
theWriter.println(" (f32.ne (get_local $p1) (get_local $p2))");
theWriter.println(" )");
theWriter.println(" (return (i32.const 0))");
theWriter.println(" )");
theWriter.println(" (block $b2");
theWriter.println(" (br_if $b2");
theWriter.println(" (f32.ge (get_local $p1) (get_local $p2))");
theWriter.println(" )");
theWriter.println(" (return (i32.const -1))");
theWriter.println(" )");
theWriter.println(" (return (i32.const 1))");
theWriter.println(" )");
theWriter.println();
theWriter.println(" (func $INSTANCEOF_CHECK (param $thisRef i32) (param $type i32) (result i32)");
theWriter.println(" (block $nullcheck");
theWriter.println(" (br_if $nullcheck");
theWriter.println(" (i32.ne (get_local $thisRef) (i32.const 0))");
theWriter.println(" )");
theWriter.println(" (return (i32.const 0))");
theWriter.println(" )");
theWriter.println(" (call_indirect $t_INSTANCEOF");
theWriter.println(" (get_local $thisRef)");
theWriter.println(" (get_local $type)");
theWriter.println(" (call_indirect $t_RESOLVEMETHOD");
theWriter.println(" (get_local $thisRef)");
theWriter.print(" (i32.const ");
theWriter.print(WASMSSAWriter.GENERATED_INSTANCEOF_METHOD_ID);
theWriter.println(")");
theWriter.println(" (i32.load offset=4 (get_local $thisRef))");
theWriter.println(" )");
theWriter.println(" )");
theWriter.println(" )");
theWriter.println();
theWriter.println(" (func $jlClass_A1jlObjectgetEnumConstants (param $thisRef i32) (result i32)");
theWriter.println(" (return (i32.load (i32.load offset=12 (get_local $thisRef))))");
theWriter.println(" )");
theWriter.println();
theWriter.println(" (func $jlClass_BOOLEANdesiredAssertionStatus (param $thisRef i32) (result i32)");
theWriter.println(" (return (i32.const 0))");
theWriter.println(" )");
theWriter.println();
theWriter.println(" (func $RUNTIMECLASS__resolvevtableindex (param $thisRef i32) (param $methodId i32) (result i32)");
BytecodeLinkedClass theClassLinkedCass = aLinkerContext.resolveClass(BytecodeObjectTypeRef.fromRuntimeClass(Class.class));
BytecodeResolvedMethods theRuntimeMethodMap = theClassLinkedCass.resolvedMethods();
theRuntimeMethodMap.stream().forEach(aMethodMapEntry -> {
BytecodeMethod theMethod = aMethodMapEntry.getValue();
if (!theMethod.getAccessFlags().isStatic()) {
BytecodeVirtualMethodIdentifier theMethodIdentifier = aLinkerContext.getMethodCollection().identifierFor(theMethod);
theWriter.println(" (block $m" + theMethodIdentifier.getIdentifier());
theWriter.println(" (br_if $m" + theMethodIdentifier.getIdentifier() + " (i32.ne (get_local $methodId) (i32.const " + theMethodIdentifier.getIdentifier() + ")))");
if (Objects.equals("getClass", theMethod.getName().stringValue())) {
theWriter.println(" (unreachable)");
} else if (Objects.equals("toString", theMethod.getName().stringValue())) {
theWriter.println(" (unreachable)");
} else if (Objects.equals("equals", theMethod.getName().stringValue())) {
theWriter.println(" (unreachable)");
} else if (Objects.equals("hashCode", theMethod.getName().stringValue())) {
theWriter.println(" (unreachable)");
} else if (Objects.equals("desiredAssertionStatus", theMethod.getName().stringValue())) {
theWriter.println(" (return (i32.const " + theGeneratedFunctions.indexOf("Class_BOOLEANdesiredAssertionStatus") + "))");
} else if (Objects.equals("getEnumConstants", theMethod.getName().stringValue())) {
theWriter.println(" (return (i32.const " + theGeneratedFunctions.indexOf("Class_A1TObjectgetEnumConstants") + "))");
} else {
theWriter.println(" (unreachable)");
}
theWriter.println(" )");
}
});
theWriter.println(" (unreachable)");
theWriter.println(" )");
theWriter.println();
List<String> theGlobalVariables = new ArrayList<>();
theWriter.println(" (func $bootstrap");
theWriter.println(" (set_global $STACKTOP (i32.sub (i32.mul (current_memory) (i32.const 65536)) (i32.const 1)))");
// Globals for static class data
aLinkerContext.linkedClasses().forEach(aEntry -> {
BytecodeLinkedClass theLinkedClass = aEntry.targetNode();
if (Objects.equals(aEntry.edgeType().objectTypeRef(), BytecodeObjectTypeRef.fromRuntimeClass(Address.class))) {
return;
}
if (theLinkedClass.getBytecodeClass().getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
return;
}
theGlobalVariables.add(WASMWriterUtils.toClassName(aEntry.edgeType().objectTypeRef()) + "__runtimeClass");
theWriter.print(" (set_global $");
theWriter.print(WASMWriterUtils.toClassName(aEntry.edgeType().objectTypeRef()));
theWriter.print("__runtimeClass (call $newRuntimeClass");
theWriter.print(" (i32.const ");
theWriter.print(theLinkedClass.getUniqueId());
theWriter.print(")");
WASMMemoryLayouter.MemoryLayout theLayout = theMemoryLayout.layoutFor(aEntry.edgeType().objectTypeRef());
theWriter.print(" (i32.const ");
theWriter.print(theLayout.classSize());
theWriter.print(")");
BytecodeResolvedFields theStaticFields = theLinkedClass.resolvedFields();
if (theStaticFields.fieldByName("$VALUES") != null) {
theWriter.print(" (i32.const ");
theWriter.print(theLayout.offsetForClassMember("$VALUES"));
theWriter.println(")");
} else {
theWriter.print(" (i32.const -1)");
}
theWriter.println("))");
});
WASMMemoryLayouter.MemoryLayout theStringMemoryLayout = theMemoryLayout.layoutFor(theStringClass.getClassName());
aLinkerContext.linkedClasses().forEach(aEntry -> {
if (aEntry.targetNode().getBytecodeClass().getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
return;
}
if (!Objects.equals(aEntry.edgeType().objectTypeRef(), BytecodeObjectTypeRef.fromRuntimeClass(Address.class))) {
theWriter.print(" (call $");
theWriter.print(WASMWriterUtils.toClassName(aEntry.edgeType().objectTypeRef()));
theWriter.println("__classinitcheck)");
}
});
List<StringValue> thePoolValues = theConstantPool.stringValues();
for (int i = 0; i < thePoolValues.size(); i++) {
StringValue theConstantInPool = thePoolValues.get(i);
String theData = theConstantInPool.getStringValue();
byte[] theDataBytes = theData.getBytes();
theGlobalVariables.add("stringPool" + i);
theGlobalVariables.add("stringPool" + i + "__array");
theWriter.print(" (set_global $stringPool");
theWriter.print(i);
theWriter.print("__array ");
String theMethodName = WASMWriterUtils.toMethodName(BytecodeObjectTypeRef.fromRuntimeClass(MemoryManager.class), "newArray", new BytecodeMethodSignature(BytecodeObjectTypeRef.fromRuntimeClass(Address.class), new BytecodeTypeRef[] { BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT }));
theWriter.print("(call $");
theWriter.print(theMethodName);
// UNUSED argument
theWriter.print(" (i32.const 0) ");
// Length
theWriter.print(" (i32.const ");
theWriter.print(theDataBytes.length);
theWriter.print(")");
// We also need the runtime class
theWriter.print(" (get_global $");
theWriter.print(WASMWriterUtils.toClassName(theArrayClass.getClassName()));
theWriter.print("__runtimeClass");
theWriter.print(")");
// Plus the vtable index
theWriter.print(" (i32.const ");
theWriter.print(theResolver.resolveVTableMethodByType(BytecodeObjectTypeRef.fromRuntimeClass(Array.class)));
theWriter.println(")))");
// Set array value
for (int j = 0; j < theDataBytes.length; j++) {
//
int offset = 20 + j * 4;
theWriter.print(" (i32.store ");
theWriter.print("offset=" + offset + " ");
theWriter.print("(get_global $stringPool");
theWriter.print(i);
theWriter.print("__array) ");
theWriter.print("(i32.const ");
theWriter.print(theDataBytes[j]);
theWriter.println("))");
}
theWriter.print(" (set_global $stringPool");
theWriter.print(i);
theWriter.print(" (call $");
theWriter.print(WASMWriterUtils.toClassName(theManagerClass.getClassName()));
theWriter.print("_dmbcAddressnewObjectINTINTINT");
// Unused argument
theWriter.print(" (i32.const 0)");
theWriter.print(" (i32.const ");
theWriter.print(theStringMemoryLayout.instanceSize());
theWriter.print(")");
theWriter.print(" (i32.const ");
theWriter.print(theStringClass.getUniqueId());
theWriter.print(")");
theWriter.print(" (i32.const ");
theWriter.print(theResolver.resolveVTableMethodByType(theStringClass.getClassName()));
theWriter.print(")");
theWriter.println("))");
theWriter.print(" (call $");
theWriter.print(WASMWriterUtils.toClassName(theStringClass.getClassName()));
theWriter.print("_VOIDinitA1BYTE ");
theWriter.print(" (get_global $stringPool");
theWriter.print(i);
theWriter.print(")");
theWriter.print(" (get_global $stringPool");
theWriter.print(i);
theWriter.println("__array))");
}
// After the Bootstrap, we need to all the static stuff on the stack, so it is not garbage collected
theWriter.print(" (set_global $STACKTOP (i32.sub (get_global $STACKTOP) (i32.const ");
theWriter.print(theGlobalVariables.size() * 4);
theWriter.println(")))");
for (int i = 0; i < theGlobalVariables.size(); i++) {
theWriter.print(" (i32.store offset=");
theWriter.print(i * 4);
theWriter.print(" (get_global $STACKTOP) (get_global $");
theWriter.print(theGlobalVariables.get(i));
theWriter.println("))");
}
theWriter.println(" )");
theWriter.println();
for (int i = 0; i < thePoolValues.size(); i++) {
theWriter.print(" (global $stringPool");
theWriter.print(i);
theWriter.println(" (mut i32) (i32.const 0))");
theWriter.print(" (global $stringPool");
theWriter.print(i);
theWriter.println("__array (mut i32) (i32.const 0))");
}
theWriter.println(" (global $STACKTOP (mut i32) (i32.const 0))");
// Globals for static class data
aLinkerContext.linkedClasses().forEach(aEntry -> {
if (Objects.equals(aEntry.edgeType().objectTypeRef(), BytecodeObjectTypeRef.fromRuntimeClass(Address.class))) {
return;
}
if (aEntry.targetNode().getBytecodeClass().getAttributes().getAnnotationByType(EmulatedByRuntime.class.getName()) != null) {
return;
}
theWriter.print(" (global $");
theWriter.print(WASMWriterUtils.toClassName(aEntry.edgeType().objectTypeRef()));
theWriter.println("__runtimeClass (mut i32) (i32.const 0))");
});
theWriter.println();
theWriter.println(" (export \"bootstrap\" (func $bootstrap))");
// Write exports
aLinkerContext.linkedClasses().forEach(aEntry -> {
BytecodeLinkedClass theLinkedClass = aEntry.targetNode();
if (theLinkedClass.getBytecodeClass().getAccessFlags().isInterface()) {
return;
}
BytecodeResolvedMethods theMethodMap = theLinkedClass.resolvedMethods();
theMethodMap.stream().forEach(aMethodMapEntry -> {
BytecodeMethod t = aMethodMapEntry.getValue();
BytecodeAnnotation theExport = t.getAttributes().getAnnotationByType(Export.class.getName());
if (theExport != null) {
theWriter.print(" (export \"");
theWriter.print(theExport.getElementValueByName("value").stringValue());
theWriter.print("\" (func $");
theWriter.print(WASMWriterUtils.toMethodName(aEntry.edgeType().objectTypeRef(), t.getName(), t.getSignature()));
theWriter.println("))");
}
});
});
theWriter.print(" (export \"main\" (func $");
theWriter.print(WASMWriterUtils.toMethodName(BytecodeObjectTypeRef.fromRuntimeClass(aEntryPointClass), aEntryPointMethodName, aEntryPointSignatue));
theWriter.println("))");
theWriter.println();
for (Map.Entry<String, String> theEntry : theGlobalTypes.entrySet()) {
theWriter.print(" (type $t_");
theWriter.print(theEntry.getKey());
theWriter.print(" ");
theWriter.print(theEntry.getValue());
theWriter.println(")");
}
theWriter.println(")");
theWriter.flush();
return new WASMCompileResult(aLinkerContext, theGeneratedFunctions, theStringWriter.toString(), theMemoryLayout);
}
use of de.mirkosertic.bytecoder.core.BytecodeMethodSignature in project Bytecoder by mirkosertic.
the class WASMSSAWriter method writeNewObjectValue.
private void writeNewObjectValue(NewObjectExpression aValue) {
BytecodeObjectTypeRef theType = BytecodeObjectTypeRef.fromUtf8Constant(aValue.getType().getConstant());
WASMMemoryLayouter.MemoryLayout theLayout = memoryLayouter.layoutFor(theType);
String theMethodName = WASMWriterUtils.toMethodName(BytecodeObjectTypeRef.fromRuntimeClass(MemoryManager.class), "newObject", new BytecodeMethodSignature(BytecodeObjectTypeRef.fromRuntimeClass(Address.class), new BytecodeTypeRef[] { BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT, BytecodePrimitiveTypeRef.INT }));
BytecodeLinkedClass theLinkedClass = linkerContext.resolveClass(theType);
print("(call $");
print(theMethodName);
// UNUSED argument
print(" (i32.const 0) ");
print(" (i32.const ");
print(theLayout.instanceSize());
print(") (get_global $");
print(WASMWriterUtils.toClassName(theLinkedClass.getClassName()));
print("__runtimeClass) (i32.const ");
print(idResolver.resolveVTableMethodByType(theType));
print("))");
}
Aggregations