First step to support imports.

This commit is contained in:
Volker Berlin 2018-05-30 18:57:36 +02:00
parent 3e207615ac
commit 88a584cd63
5 changed files with 152 additions and 32 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2017 Volker Berlin (i-net software) * Copyright 2017 - 2018 Volker Berlin (i-net software)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -161,6 +161,7 @@ public class JWebAssembly {
ClassFile classFile = new ClassFile( new BufferedInputStream( url.openStream() ) ); ClassFile classFile = new ClassFile( new BufferedInputStream( url.openStream() ) );
writer.prepare( classFile ); writer.prepare( classFile );
} }
writer.prepareFinish();
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

@ -42,25 +42,27 @@ import de.inetsoftware.jwebassembly.module.ValueTypeConvertion;
*/ */
public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcodes { public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcodes {
private static final byte[] WASM_BINARY_MAGIC = { 0, 'a', 's', 'm' }; private static final byte[] WASM_BINARY_MAGIC = { 0, 'a', 's', 'm' };
private static final int WASM_BINARY_VERSION = 1; private static final int WASM_BINARY_VERSION = 1;
private WasmOutputStream wasm; private WasmOutputStream wasm;
private WasmOutputStream codeStream = new WasmOutputStream(); private WasmOutputStream codeStream = new WasmOutputStream();
private WasmOutputStream functionsStream = new WasmOutputStream(); private WasmOutputStream functionsStream = new WasmOutputStream();
private List<FunctionType> functionTypes = new ArrayList<>(); private List<FunctionType> functionTypes = new ArrayList<>();
private Map<String, Function> functions = new LinkedHashMap<>(); private Map<String, Function> functions = new LinkedHashMap<>();
private Map<String, String> exports = new LinkedHashMap<>(); private Map<String, String> exports = new LinkedHashMap<>();
private Function function; private Map<String, ImportEntry> imports = new LinkedHashMap<>();
private FunctionType functionType; private Function function;
private FunctionType functionType;
/** /**
* Create new instance. * Create new instance.
@ -83,6 +85,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
wasm.writeInt32( WASM_BINARY_VERSION ); wasm.writeInt32( WASM_BINARY_VERSION );
writeTypeSection(); writeTypeSection();
writeImportSection();
writeFunctionSection(); writeFunctionSection();
writeExportSection(); writeExportSection();
writeCodeSection(); writeCodeSection();
@ -118,6 +121,32 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
} }
} }
/**
* Write the import section to the output. This section declare all imports.
*
* @throws IOException
* if any I/O error occur
*/
private void writeImportSection() throws IOException {
int count = imports.size();
if( count > 0 ) {
WasmOutputStream stream = new WasmOutputStream();
stream.writeVaruint32( count );
for( ImportEntry entry : imports.values() ) {
byte[] bytes = entry.module.getBytes( StandardCharsets.UTF_8 );
stream.writeVaruint32( bytes.length );
stream.write( bytes );
bytes = entry.name.getBytes( StandardCharsets.UTF_8 );
stream.writeVaruint32( bytes.length );
stream.write( bytes );
stream.writeVaruint32( ExternalKind.Function.ordinal() );
int typeIdx = 0; //TODO
stream.writeVaruint32( typeIdx );
}
wasm.writeSection( SectionType.Import, stream, null );
}
}
/** /**
* Write the function section to the output. This section contains a mapping from the function index to the type signature index. * Write the function section to the output. This section contains a mapping from the function index to the type signature index.
* *
@ -180,14 +209,29 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
protected void prepareMethod( MethodInfo method ) throws WasmException { @Override
String methodName = method.getName(); protected void prepareFunction( FunctionName name, String importModule, String importName ) {
String className = method.getDeclaringClassFile().getThisClass().getName(); if( importName != null ) {
String fullName = className + '.' + methodName; imports.put( name.signatureName, new ImportEntry(importModule, importName) );
String signatureName = fullName + method.getDescription(); } else {
Function function = new Function(); functions.put( name.signatureName, new Function() );
function.id = functions.size(); }
functions.put( signatureName, function ); }
/**
* {@inheritDoc}
*/
@Override
public void prepareFinish() {
// initialize the function index IDs
// https://github.com/WebAssembly/design/blob/master/Modules.md#function-index-space
int id = 0;
for( ImportEntry entry : imports.values() ) {
entry.id = id++;
}
for( Function function : functions.values() ) {
function.id = id++;
}
} }
/** /**

View File

@ -0,0 +1,35 @@
/*
* Copyright 2018 Volker Berlin (i-net software)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.inetsoftware.jwebassembly.binary;
/**
* An entry in the import section of the WebAssembly.
*
* @author Volker Berlin
*/
class ImportEntry {
final String module;
final String name;
int id;
public ImportEntry( String module, String name ) {
this.module = module;
this.name = name;
}
}

View File

@ -26,7 +26,6 @@ import javax.annotation.Nonnegative;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import de.inetsoftware.classparser.Annotations;
import de.inetsoftware.classparser.ClassFile; 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;
@ -66,6 +65,14 @@ public abstract class ModuleWriter implements Closeable {
iterateMethods( classFile, m -> prepareMethod( m ) ); iterateMethods( classFile, m -> prepareMethod( m ) );
} }
/**
* Finish the prepare after all classes/methods are prepare. This must be call before we can start with write the
* first method.
*/
public void prepareFinish() {
}
/** /**
* Write the content of the class to the writer. * Write the content of the class to the writer.
* *
@ -107,10 +114,35 @@ public abstract class ModuleWriter implements Closeable {
* @throws WasmException * @throws WasmException
* if some Java code can't converted * if some Java code can't converted
*/ */
protected void prepareMethod( MethodInfo method ) throws WasmException { private void prepareMethod( MethodInfo method ) throws WasmException {
// Nothing try {
String module = null;
String name = null;
Map<String,Object> annotationValues = method.getAnnotation( "org.webassembly.annotation.Import" );
if( annotationValues != null ) {
module = (String)annotationValues.get( "module" );
name = (String)annotationValues.get( "name" );
}
prepareFunction( new FunctionName( method ), module, name );
} catch( IOException ioex ) {
throw WasmException.create( ioex, sourceFile, -1 );
}
} }
/**
* Prepare a single function in the prepare phase.
*
* @param name
* the function name
* @param importModule
* the import module name if it is a import function
* @param importName
* the import name if it is a import function
* @throws IOException
* if any I/O error occur
*/
protected abstract void prepareFunction( FunctionName name, String importModule, String importName ) throws IOException;
/** /**
* Write the content of a method. * Write the content of a method.
* *
@ -123,7 +155,7 @@ public abstract class ModuleWriter implements Closeable {
int lineNumber = -1; int lineNumber = -1;
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 && method.getAnnotation( "org.webassembly.annotation.Import" ) == null ) { // abstract methods and interface methods does not have code
FunctionName name = new FunctionName( method ); FunctionName name = new FunctionName( method );
writeExport( name, method ); writeExport( name, method );
writeMethodStart( name ); writeMethodStart( name );
@ -185,16 +217,13 @@ public abstract class ModuleWriter implements Closeable {
* if any IOException occur * if any IOException occur
*/ */
private void writeExport( FunctionName name, MethodInfo method ) throws IOException { private void writeExport( FunctionName name, MethodInfo method ) throws IOException {
Annotations annotations = method.getRuntimeInvisibleAnnotations(); Map<String,Object> export = method.getAnnotation( "org.webassembly.annotation.Export" );
if( annotations != null ) { if( export != null ) {
Map<String,Object> export = annotations.get( "org.webassembly.annotation.Export" ); String exportName = (String)export.get( "name" );
if( export != null ) { if( exportName == null ) {
String exportName = (String)export.get( "name" ); exportName = method.getName(); // TODO naming conversion rule if no name was set
if( exportName == null ) {
exportName = method.getName(); // TODO naming conversion rule if no name was set
}
writeExport( name, exportName );
} }
writeExport( name, exportName );
} }
} }

View File

@ -66,6 +66,17 @@ public class TextModuleWriter extends ModuleWriter {
output.append( ')' ); output.append( ')' );
} }
/**
* {@inheritDoc}
*/
@Override
protected void prepareFunction( FunctionName name, String importModule, String importName ) throws IOException {
if( importName != null ) {
newline( output );
output.append( "(import \"" ).append( importModule ).append( "\" \"" ).append( importName ).append( "\" (func $" ).append( name.fullName ).append( "))" );
}
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */