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");
* 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() ) );
writer.prepare( classFile );
}
writer.prepareFinish();
for( URL url : classFiles ) {
ClassFile classFile = new ClassFile( new BufferedInputStream( url.openStream() ) );
writer.write( classFile );

View File

@ -42,25 +42,27 @@ import de.inetsoftware.jwebassembly.module.ValueTypeConvertion;
*/
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.
@ -83,6 +85,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
wasm.writeInt32( WASM_BINARY_VERSION );
writeTypeSection();
writeImportSection();
writeFunctionSection();
writeExportSection();
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.
*
@ -180,14 +209,29 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
/**
* {@inheritDoc}
*/
protected void prepareMethod( MethodInfo method ) throws WasmException {
String methodName = method.getName();
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 );
@Override
protected void prepareFunction( FunctionName name, String importModule, String importName ) {
if( importName != null ) {
imports.put( name.signatureName, new ImportEntry(importModule, importName) );
} else {
functions.put( name.signatureName, new 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.Nullable;
import de.inetsoftware.classparser.Annotations;
import de.inetsoftware.classparser.ClassFile;
import de.inetsoftware.classparser.Code;
import de.inetsoftware.classparser.CodeInputStream;
@ -66,6 +65,14 @@ public abstract class ModuleWriter implements Closeable {
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.
*
@ -107,10 +114,35 @@ public abstract class ModuleWriter implements Closeable {
* @throws WasmException
* if some Java code can't converted
*/
protected void prepareMethod( MethodInfo method ) throws WasmException {
// Nothing
private void prepareMethod( MethodInfo method ) throws WasmException {
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.
*
@ -123,7 +155,7 @@ public abstract class ModuleWriter implements Closeable {
int lineNumber = -1;
try {
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 );
writeExport( name, method );
writeMethodStart( name );
@ -185,16 +217,13 @@ public abstract class ModuleWriter implements Closeable {
* if any IOException occur
*/
private void writeExport( FunctionName name, MethodInfo method ) throws IOException {
Annotations annotations = method.getRuntimeInvisibleAnnotations();
if( annotations != null ) {
Map<String,Object> export = annotations.get( "org.webassembly.annotation.Export" );
if( export != null ) {
String exportName = (String)export.get( "name" );
if( exportName == null ) {
exportName = method.getName(); // TODO naming conversion rule if no name was set
}
writeExport( name, exportName );
Map<String,Object> export = method.getAnnotation( "org.webassembly.annotation.Export" );
if( export != null ) {
String exportName = (String)export.get( "name" );
if( exportName == null ) {
exportName = method.getName(); // TODO naming conversion rule if no name was set
}
writeExport( name, exportName );
}
}

View File

@ -66,6 +66,17 @@ public class TextModuleWriter extends ModuleWriter {
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}
*/