Add support for invoke static method calls

This commit is contained in:
Volker Berlin 2018-03-24 12:33:56 +01:00
parent c548779c76
commit 4836024e4e
6 changed files with 123 additions and 51 deletions

View File

@ -25,6 +25,7 @@ import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import de.inetsoftware.classparser.MethodInfo;
import de.inetsoftware.jwebassembly.WasmException; import de.inetsoftware.jwebassembly.WasmException;
import de.inetsoftware.jwebassembly.module.ModuleWriter; import de.inetsoftware.jwebassembly.module.ModuleWriter;
import de.inetsoftware.jwebassembly.module.NumericOperator; import de.inetsoftware.jwebassembly.module.NumericOperator;
@ -176,19 +177,30 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override protected void prepareMethod( MethodInfo method ) throws WasmException {
protected void writeExport( String methodName, String exportName ) throws IOException { String methodName = method.getName();
exports.put( exportName, methodName ); String className = method.getDeclaringClassFile().getThisClass().getName();
String fullName = className + '.' + methodName;
String signatureName = fullName + method.getDescription();
Function function = new Function();
function.id = functions.size();
functions.put( signatureName, function );
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
protected void writeMethodStart( String name ) throws IOException { protected void writeExport( String signatureName, String methodName, String exportName ) throws IOException {
function = new Function(); exports.put( exportName, signatureName );
function.id = functions.size(); }
functions.put( name, function );
/**
* {@inheritDoc}
*/
@Override
protected void writeMethodStart( String signatureName, String name ) throws IOException {
function = functions.get( signatureName );
functionType = new FunctionType(); functionType = new FunctionType();
codeStream.reset(); codeStream.reset();
} }
@ -458,4 +470,17 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
protected void writeReturn() throws IOException { protected void writeReturn() throws IOException {
codeStream.write( RETURN ); codeStream.write( RETURN );
} }
/**
* {@inheritDoc}
*/
@Override
protected void writeFunctionCall( String name ) throws IOException {
codeStream.write( CALL );
Function func = functions.get( name );
if( func == null ) {
throw new WasmException( "Call to unknown function: " + name, null, -1 );
}
codeStream.writeVaruint32( func.id );
}
} }

View File

@ -37,6 +37,8 @@ interface InstructionOpcodes {
static final int RETURN = 0x0F; static final int RETURN = 0x0F;
static final int CALL = 0x10;
// === Variable access =========== // === Variable access ===========
static final int GET_LOCAL = 0x20; static final int GET_LOCAL = 0x20;

View File

@ -105,8 +105,8 @@ public abstract class ModuleWriter implements Closeable {
* @throws WasmException * @throws WasmException
* if some Java code can't converted * if some Java code can't converted
*/ */
private void prepareMethod( MethodInfo method ) throws WasmException { protected void prepareMethod( MethodInfo method ) throws WasmException {
// Nothing
} }
/** /**
@ -121,9 +121,12 @@ public abstract class ModuleWriter implements Closeable {
try { try {
Code code = method.getCode(); Code code = method.getCode();
if( code != null ) { // abstract methods and interface methods does not have code if( code != null ) { // abstract methods and interface methods does not have code
String methodName = method.getName(); // TODO naming conversion rule String methodName = method.getName();
writeExport( methodName, method ); String className = method.getDeclaringClassFile().getThisClass().getName();
writeMethodStart( methodName ); String fullName = className + '.' + methodName;
String signatureName = fullName + method.getDescription();
writeExport( signatureName, fullName, method );
writeMethodStart( signatureName, fullName );
writeMethodSignature( method ); writeMethodSignature( method );
locals.clear(); locals.clear();
localTable = code.getLocalVariableTable(); localTable = code.getLocalVariableTable();
@ -156,48 +159,55 @@ public abstract class ModuleWriter implements Closeable {
/** /**
* Look for a Export annotation and if there write an export directive. * Look for a Export annotation and if there write an export directive.
* *
* @param signatureName
* the full name with signature
* @param methodName * @param methodName
* the normalized method name * the normalized method name
* @param method * @param method
* the moethod * the moethod
*
* @throws IOException * @throws IOException
* if any IOException occur * if any IOException occur
*/ */
private void writeExport( String methodName, MethodInfo method ) throws IOException { private void writeExport( String signatureName, String methodName, MethodInfo method ) throws IOException {
Annotations annotations = method.getRuntimeInvisibleAnnotations(); Annotations annotations = method.getRuntimeInvisibleAnnotations();
if( annotations != null ) { if( annotations != null ) {
Map<String,Object> export = annotations.get( "org.webassembly.annotation.Export" ); Map<String,Object> export = annotations.get( "org.webassembly.annotation.Export" );
if( export != null ) { if( export != null ) {
String exportName = (String)export.get( "name" ); String exportName = (String)export.get( "name" );
if( exportName == null ) { if( exportName == null ) {
exportName = methodName; exportName = method.getName(); // TODO naming conversion rule if no name was set
} }
writeExport( methodName, exportName ); writeExport( signatureName, methodName, exportName );
} }
} }
} }
/** /**
* Write an export directive * Write an export directive
* * @param signatureName
* the full name with signature
* @param methodName * @param methodName
* the method name * the method name
* @param exportName * @param exportName
* the export name, if null then the same like the method name * the export name, if null then the same like the method name
*
* @throws IOException * @throws IOException
* if any I/O error occur * if any I/O error occur
*/ */
protected abstract void writeExport( String methodName, String exportName ) throws IOException; protected abstract void writeExport( String signatureName, String methodName, String exportName ) throws IOException;
/** /**
* Write the method header. * Write the method header.
* * @param signatureName
* the full name with signature
* @param name * @param name
* the method name * the method name
*
* @throws IOException * @throws IOException
* if any I/O error occur * if any I/O error occur
*/ */
protected abstract void writeMethodStart( String name ) throws IOException; protected abstract void writeMethodStart( String signatureName, String name ) throws IOException;
/** /**
* Write the parameter and return signatures * Write the parameter and return signatures
@ -490,6 +500,11 @@ public abstract class ModuleWriter implements Closeable {
case 177: // return void case 177: // return void
writeReturn(); writeReturn();
break; break;
case 184: // invokestatic
idx = byteCode.readUnsignedShort();
ConstantRef method = (ConstantRef)constantPool.get( idx );
writeFunctionCall( method.getConstantClass().getName() + '.' + method.getName() + method.getType() );
break;
default: default:
throw new WasmException( "Unimplemented byte code operation: " + op, sourceFile, lineNumber ); throw new WasmException( "Unimplemented byte code operation: " + op, sourceFile, lineNumber );
} }
@ -617,7 +632,9 @@ public abstract class ModuleWriter implements Closeable {
/** /**
* Write a add operator * Write a add operator
* @param numOp TODO *
* @param numOp
* the numeric operation
* @param valueType * @param valueType
* the type of the parameters * the type of the parameters
* *
@ -643,4 +660,14 @@ public abstract class ModuleWriter implements Closeable {
* if any I/O error occur * if any I/O error occur
*/ */
protected abstract void writeReturn() throws IOException; protected abstract void writeReturn() throws IOException;
/**
* Write a call to a function.
*
* @param name
* the full qualified method name
* @throws IOException
* if any I/O error occur
*/
protected abstract void writeFunctionCall( String name ) throws IOException;
} }

View File

@ -67,7 +67,7 @@ public class TextModuleWriter extends ModuleWriter {
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
protected void writeExport( String methodName, String exportName ) throws IOException { protected void writeExport( String signatureName, String methodName, String exportName ) throws IOException {
newline( output ); newline( output );
output.append( "(export \"" ).append( exportName ).append( "\" (func $" ).append( methodName ).append( "))" ); output.append( "(export \"" ).append( exportName ).append( "\" (func $" ).append( methodName ).append( "))" );
} }
@ -76,7 +76,7 @@ public class TextModuleWriter extends ModuleWriter {
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
protected void writeMethodStart( String name ) throws IOException { protected void writeMethodStart( String signatureName, String name ) throws IOException {
newline( output ); newline( output );
output.append( "(func $" ); output.append( "(func $" );
output.append( name ); output.append( name );
@ -211,4 +211,14 @@ public class TextModuleWriter extends ModuleWriter {
output.append( ' ' ); output.append( ' ' );
} }
} }
/**
* {@inheritDoc}
*/
@Override
protected void writeFunctionCall( String name ) throws IOException {
newline( methodOutput );
name = name.substring( 0, name.indexOf( '(' ) );
methodOutput.append( "call $" ).append( name );
}
} }

View File

@ -15,6 +15,8 @@
*/ */
package de.inetsoftware.jwebassembly.samples; package de.inetsoftware.jwebassembly.samples;
import org.webassembly.annotation.Export;
/** /**
* *
* @author Volker Berlin * @author Volker Berlin
@ -22,7 +24,8 @@ package de.inetsoftware.jwebassembly.samples;
*/ */
public class FunctionParameters { public class FunctionParameters {
void singleInt( int a ) { @Export(name="abc")
static void singleInt( int a ) {
int b = a + 1;
} }
} }

View File

@ -1,5 +1,10 @@
(module (module
(func $singleInt (param i32) (export "abc" (func $de/inetsoftware/jwebassembly/samples/FunctionParameters.singleInt))
(func $de/inetsoftware/jwebassembly/samples/FunctionParameters.singleInt (param i32) (local i32)
get_local 0
i32.const 1
i32.add
set_local 1
return return
) )
) )