prepare the using of call_indirect

This commit is contained in:
Volker Berlin 2019-05-05 17:25:43 +02:00
parent 8e439eb83e
commit 4e98efeb5d
5 changed files with 224 additions and 1 deletions

View File

@ -87,6 +87,8 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
private String javaSourceFile;
private boolean callIndirect;
/**
* Create new instance.
*
@ -123,10 +125,12 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
writeSection( SectionType.Type, functionTypes );
writeSection( SectionType.Import, imports.values() );
writeSection( SectionType.Function, functions.values() );
writeTableSection();
writeMemorySection();
writeSection( SectionType.Global, globals.values() );
writeEventSection();
writeExportSection();
writeElementSection();
writeCodeSection();
writeDataSection();
writeDebugNames();
@ -158,6 +162,31 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
}
}
/**
* Write the table section. It declare the space for the element section.
*
* @throws IOException
* if any I/O error occur
*/
private void writeTableSection() throws IOException {
if( !callIndirect ) {
return;
}
int elemCount = imports.size() + functions.size();
WasmOutputStream stream = new WasmOutputStream();
int count = 1;
stream.writeVaruint32( count ); // count of tables
for( int i = 0; i < count; i++ ) {
stream.writeValueType( ValueType.anyfunc ); // the type of elements
stream.writeVaruint32( 1 ); // flags; 1-maximum is available, 0-no maximum value available
stream.writeVaruint32( elemCount ); // initial length
stream.writeVaruint32( elemCount ); // maximum length
}
wasm.writeSection( SectionType.Table, stream );
}
/**
* Write the memory section.
*
@ -220,6 +249,33 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
}
}
/**
* Write element section. This section create a matching between direct and indirect function call IDs.
*
* @throws IOException
* if any I/O error occur
*/
private void writeElementSection() throws IOException {
if( !callIndirect ) {
return;
}
int elemCount = imports.size() + functions.size();
WasmOutputStream stream = new WasmOutputStream();
stream.writeVaruint32( 1 ); // count of element segments to follow
// element_segment
stream.writeVaruint32( 0 ); // the table index (0 in the MVP)
stream.writeConst( 0, ValueType.i32 ); // the offset on which the elements start
stream.writeOpCode( END ); // end of offset instruction
stream.writeVaruint32( elemCount );
for( int i = 0; i < elemCount; i++ ) {
stream.writeVaruint32( i ); // we use a 1:1 matching between direct function call numbers and indrect function numbers because the most functions will be indirect
}
wasm.writeSection( SectionType.Element, stream );
}
/**
* Write the code section to the output. This section contains the byte code.
*
@ -941,6 +997,18 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
codeStream.writeVaruint32( func.id );
}
/**
* {@inheritDoc}
*/
@Override
protected void writeFunctionCallIndirect( FunctionName name ) throws IOException {
callIndirect = true;
Function func = getFunction( name );
codeStream.writeOpCode( CALL_INDIRECT );
codeStream.writeVaruint32( func.typeId );
codeStream.writeVaruint32( 0 ); // table 0
}
/**
* Get the function object for the name. If not exists then it will be created.
*

View File

@ -224,6 +224,16 @@ public abstract class ModuleWriter implements Closeable {
*/
protected abstract void writeFunctionCall( FunctionName name ) throws IOException;
/**
* Write a call indirect to a function.
*
* @param name
* the function name
* @throws IOException
* if any I/O error occur
*/
protected abstract void writeFunctionCallIndirect( FunctionName name ) throws IOException;
/**
* Write a block/branch code
*

View File

@ -0,0 +1,115 @@
/*
Copyright 2019 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.module;
import java.io.IOException;
import java.util.Iterator;
import javax.annotation.Nonnull;
import de.inetsoftware.jwebassembly.wasm.AnyType;
/**
* WasmInstruction for a function call.
*
* @author Volker Berlin
*
*/
class WasmCallIndirectInstruction extends WasmInstruction {
private AnyType valueType;
private final FunctionName name;
private int paramCount = -1;
/**
* Create an instance of a function call instruction
*
* @param name
* the function name that should be called
* @param javaCodePos
* the code position/offset in the Java method
* @param lineNumber
* the line number in the Java source code
*/
WasmCallIndirectInstruction( FunctionName name, int javaCodePos, int lineNumber ) {
super( javaCodePos, lineNumber );
this.name = name;
}
/**
* {@inheritDoc}
*/
@Override
Type getType() {
return Type.CallIndirect;
}
/**
* Get the function name that should be called
*
* @return the name
*/
@Nonnull
FunctionName getFunctionName() {
return name;
}
/**
* {@inheritDoc}
*/
public void writeTo( @Nonnull ModuleWriter writer ) throws IOException {
writer.writeFunctionCallIndirect( name );
}
/**
* {@inheritDoc}
*/
AnyType getPushValueType() {
countParams();
return valueType;
}
/**
* {@inheritDoc}
*/
@Override
int getPopCount() {
countParams();
return paramCount;
}
/**
* Count the parameters in the signature
*/
private void countParams() {
if( paramCount >= 0 ) {
return;
}
Iterator<AnyType> parser = name.getSignature();
paramCount = 1;
while( parser.next() != null ) {
paramCount++;
}
valueType = parser.next();
while( parser.hasNext() ) {
valueType = parser.next();
paramCount--;
}
}
}

View File

@ -35,7 +35,7 @@ abstract class WasmInstruction {
* Type of instruction to faster differ as with instanceof.
*/
static enum Type {
Const, Convert, Local, Global, Block, Numeric, Nop, Call, Array, Struct;
Const, Convert, Local, Global, Block, Numeric, Nop, Call, CallIndirect, Array, Struct;
}
private int javaCodePos;

View File

@ -67,6 +67,12 @@ public class TextModuleWriter extends ModuleWriter {
private boolean useExceptions;
private int importCount;
private int functionCount;
private boolean callIndirect;
/**
* Create a new instance.
*
@ -94,6 +100,18 @@ public class TextModuleWriter extends ModuleWriter {
public void close() throws IOException {
output.append( methodOutput );
if( callIndirect ) {
int count = importCount + functionCount;
String countStr = Integer.toString( count );
output.append( "(table " ).append( countStr ).append( ' ' ).append( countStr ).append( " anyfunc)" );
newline( output );
output.append( "(elem (i32.const 0) " );
for( int i = 0; i < count; i++ ) {
output.append( Integer.toString( i ) ).append( ' ' );
}
output.append( ')' );
}
int dataSize = dataStream.size();
if( dataSize > 0 ) {
int pages = (dataSize + 0xFFFF) / 0x10000;
@ -166,6 +184,7 @@ public class TextModuleWriter extends ModuleWriter {
newline( methodOutput );
methodOutput.append( "(import \"" ).append( importModule ).append( "\" \"" ).append( importName ).append( "\" (func $" ).append( normalizeName( name ) );
isImport = true;
importCount++;
}
}
@ -215,6 +234,7 @@ public class TextModuleWriter extends ModuleWriter {
methodOutput.append( normalizeName( name ) );
inset++;
methodParamNames.clear();
functionCount++;
}
/**
@ -504,6 +524,16 @@ public class TextModuleWriter extends ModuleWriter {
methodOutput.append( "call $" ).append( normalizeName( name ) );
}
/**
* {@inheritDoc}
*/
@Override
protected void writeFunctionCallIndirect( FunctionName name ) throws IOException {
callIndirect = true;
newline( methodOutput );
methodOutput.append( "call_indirect $" ).append( normalizeName( name ) );
}
/**
* {@inheritDoc}
*/