add a prepare phase on compiling

This commit is contained in:
Volker Berlin 2017-04-17 12:10:56 +02:00
parent 5450ccb2ce
commit f2efc5aafd
2 changed files with 87 additions and 44 deletions

View File

@ -157,6 +157,10 @@ public class JWebAssembly {
* if any conversion error occurs * if any conversion error occurs
*/ */
private void compile( ModuleWriter writer ) throws IOException, WasmException { private void compile( ModuleWriter writer ) throws IOException, WasmException {
for( URL url : classFiles ) {
ClassFile classFile = new ClassFile( new BufferedInputStream( url.openStream() ) );
writer.prepare( classFile );
}
for( URL url : classFiles ) { for( URL url : classFiles ) {
ClassFile classFile = new ClassFile( new BufferedInputStream( url.openStream() ) ); ClassFile classFile = new ClassFile( new BufferedInputStream( url.openStream() ) );
writer.write( classFile ); writer.write( classFile );

View File

@ -20,6 +20,7 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer;
import javax.annotation.Nonnegative; import javax.annotation.Nonnegative;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -30,6 +31,7 @@ import de.inetsoftware.classparser.ClassFile;
import de.inetsoftware.classparser.Code; import de.inetsoftware.classparser.Code;
import de.inetsoftware.classparser.CodeInputStream; import de.inetsoftware.classparser.CodeInputStream;
import de.inetsoftware.classparser.ConstantPool; import de.inetsoftware.classparser.ConstantPool;
import de.inetsoftware.classparser.ConstantRef;
import de.inetsoftware.classparser.LineNumberTable; import de.inetsoftware.classparser.LineNumberTable;
import de.inetsoftware.classparser.LocalVariableTable; import de.inetsoftware.classparser.LocalVariableTable;
import de.inetsoftware.classparser.MethodInfo; import de.inetsoftware.classparser.MethodInfo;
@ -51,78 +53,115 @@ public abstract class ModuleWriter implements Closeable {
private String sourceFile; private String sourceFile;
/** /**
* Write the content of the class to the * Prepare the content of the class.
* *
* @param classFile * @param classFile
* the class file * the class file
* @throws IOException
* if any I/O error occur
* @throws WasmException * @throws WasmException
* if some Java code can't converted * if some Java code can't converted
*/ */
public void write( ClassFile classFile ) throws IOException, WasmException { public void prepare( ClassFile classFile ) {
sourceFile = classFile.getSourceFile(); iterateMethods( classFile, m -> prepareMethod( m ) );
if( sourceFile == null ) { }
sourceFile = classFile.getThisClass().getName();
} /**
MethodInfo[] methods = classFile.getMethods(); * Write the content of the class to the writer.
for( MethodInfo method : methods ) { *
Code code = method.getCode(); * @param classFile
if( method.getName().equals( "<init>" ) && method.getDescription().equals( "()V" ) * the class file
&& code.isSuperInitReturn( classFile.getSuperClass() ) ) { * @throws WasmException
continue; //default constructor * if some Java code can't converted
*/
public void write( ClassFile classFile ) throws WasmException {
iterateMethods( classFile, m -> writeMethod( m ) );
}
private void iterateMethods( ClassFile classFile, Consumer<MethodInfo> handler ) throws WasmException {
sourceFile = null; // clear previous value for the case an IO exception occur
try {
sourceFile = classFile.getSourceFile();
if( sourceFile == null ) {
sourceFile = classFile.getThisClass().getName();
} }
writeMethod( method ); MethodInfo[] methods = classFile.getMethods();
for( MethodInfo method : methods ) {
Code code = method.getCode();
if( method.getName().equals( "<init>" ) && method.getDescription().equals( "()V" )
&& code.isSuperInitReturn( classFile.getSuperClass() ) ) {
continue; //default constructor
}
handler.accept( method );
}
} catch( IOException ioex ) {
throw WasmException.create( ioex, sourceFile, -1 );
} }
} }
/**
* Prepare the method.
*
* @param method
* the method
* @throws WasmException
* if some Java code can't converted
*/
private void prepareMethod( MethodInfo method ) throws WasmException {
}
/** /**
* Write the content of a method. * Write the content of a method.
* *
* @param method * @param method
* the method * the method
* @throws IOException
* if any I/O error occur
* @throws WasmException * @throws WasmException
* if some Java code can't converted * if some Java code can't converted
*/ */
private void writeMethod( MethodInfo method ) throws IOException, WasmException { private void writeMethod( MethodInfo method ) throws WasmException {
Code code = method.getCode(); try {
if( code != null ) { // abstract methods and interface methods does not have code Code code = method.getCode();
String methodName = method.getName(); // TODO naming conversion rule if( code != null ) { // abstract methods and interface methods does not have code
writeExport( methodName, method ); String methodName = method.getName(); // TODO naming conversion rule
writeMethodStart( methodName ); writeExport( methodName, method );
writeMethodSignature( method ); writeMethodStart( methodName );
locals.clear(); writeMethodSignature( method );
localTable = code.getLocalVariableTable(); locals.clear();
LineNumberTable lineNumberTable = code.getLineNumberTable(); localTable = code.getLocalVariableTable();
if( lineNumberTable != null ) { LineNumberTable lineNumberTable = code.getLineNumberTable();
int lineNumber; if( lineNumberTable != null ) {
for( int i = 0; i < lineNumberTable.size(); i++ ) { int lineNumber;
lineNumber = lineNumberTable.getLineNumber( i ); for( int i = 0; i < lineNumberTable.size(); i++ ) {
int offset = lineNumberTable.getStartOffset( i ); lineNumber = lineNumberTable.getLineNumber( i );
int nextOffset = int offset = lineNumberTable.getStartOffset( i );
i + 1 == lineNumberTable.size() ? code.getCodeSize() int nextOffset =
: lineNumberTable.getStartOffset( i + 1 ); i + 1 == lineNumberTable.size() ? code.getCodeSize()
CodeInputStream byteCode = code.getByteCode( offset, nextOffset - offset ); : lineNumberTable.getStartOffset( i + 1 );
writeCodeChunk( byteCode, lineNumber, method.getConstantPool() ); CodeInputStream byteCode = code.getByteCode( offset, nextOffset - offset );
writeCodeChunk( byteCode, lineNumber, method.getConstantPool() );
}
} else {
CodeInputStream byteCode = code.getByteCode();
writeCodeChunk( byteCode, -1, method.getConstantPool() );
} }
} else { for( int i = Math.min( paramCount, locals.size() ); i > 0; i-- ) {
CodeInputStream byteCode = code.getByteCode(); locals.remove( 0 );
writeCodeChunk( byteCode, -1, method.getConstantPool() ); }
writeMethodFinish( locals );
} }
for( int i = Math.min( paramCount, locals.size() ); i > 0; i-- ) { } catch( IOException ioex ) {
locals.remove( 0 ); throw WasmException.create( ioex, sourceFile, -1 );
}
writeMethodFinish( locals );
} }
} }
/** /**
* 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 methodName * @param methodName
* the normalized method name
* @param method * @param method
* the moethod
* @throws IOException * @throws IOException
* if any IOException occur
*/ */
private void writeExport( String methodName, MethodInfo method ) throws IOException { private void writeExport( String methodName, MethodInfo method ) throws IOException {
Annotations annotations = method.getRuntimeInvisibleAnnotations(); Annotations annotations = method.getRuntimeInvisibleAnnotations();