From 947f66502b26dccdb6f92ad38a955c132e3a976d Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Mon, 18 Nov 2019 21:32:35 +0100 Subject: [PATCH] Add support for i32.load to the wat parser and some small bug fixes --- .../jwebassembly/module/WasmCodeBuilder.java | 36 ++++++++++++- .../module/WasmMemoryInstruction.java | 10 ++-- .../jwebassembly/text/TextModuleWriter.java | 4 +- .../jwebassembly/watparser/WatParser.java | 54 +++++++++++++++++++ .../jwebassembly/module/WatParserTest.java | 10 ++++ 5 files changed, 107 insertions(+), 7 deletions(-) diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index 80bce5e..143c51a 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -33,6 +33,7 @@ import de.inetsoftware.jwebassembly.javascript.NonGC; import de.inetsoftware.jwebassembly.module.WasmInstruction.Type; import de.inetsoftware.jwebassembly.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.ArrayOperator; +import de.inetsoftware.jwebassembly.wasm.MemoryOperator; import de.inetsoftware.jwebassembly.wasm.NamedStorageType; import de.inetsoftware.jwebassembly.wasm.NumericOperator; import de.inetsoftware.jwebassembly.wasm.StructOperator; @@ -356,7 +357,20 @@ public abstract class WasmCodeBuilder { if( id == null ) { strings.put( (String)value, id = strings.size() ); } - FunctionName name = getNonGC( "stringConstant", lineNumber ); + String wat = "local.get 0 " + // + "table.get 1 " + // strings table + "local.tee 1 " + // + "ref.is_null " + // + "if " + // + "local.get 0 " + // + "i32.const 4 " + // + "i32.mul " + // + "i32.load offset=0 " + // + "drop " + // + "end " + // + "local.get 1 " + // + "return"; + FunctionName name = new WatCodeSyntheticFunctionName( "stringConstant", wat, ValueType.i32, null, ValueType.anyref ); instructions.add( new WasmConstInstruction( id, ValueType.i32, javaCodePos, lineNumber ) ); addCallInstruction( name, javaCodePos, lineNumber ); } else { @@ -586,4 +600,24 @@ public abstract class WasmCodeBuilder { } } } + + /** + * Create an instance of a load/store to the linear memory instruction + * + * @param op + * the operation + * @param type + * the type of the static field + * @param offset + * the base offset which will be added to the offset value on the stack + * @param alignment + * the alignment of the value on the linear memory (0: 8 Bit; 1: 16 Bit; 2: 32 Bit) + * @param javaCodePos + * the code position/offset in the Java method + * @param lineNumber + * the line number in the Java source code + */ + protected void addMemoryInstruction( MemoryOperator op, ValueType type, int offset, int alignment, int javaCodePos, int lineNumber ) { + instructions.add( new WasmMemoryInstruction( op, type, offset, alignment, javaCodePos, lineNumber ) ); + } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmMemoryInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmMemoryInstruction.java index 82a9026..6bbd640 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmMemoryInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmMemoryInstruction.java @@ -38,10 +38,10 @@ class WasmMemoryInstruction extends WasmInstruction { private int offset; - private int aligment; + private int alignment; /** - * Create an instance of a load/store instruction + * Create an instance of a load/store to the linear memory instruction * * @param op * the operation @@ -56,12 +56,12 @@ class WasmMemoryInstruction extends WasmInstruction { * @param lineNumber * the line number in the Java source code */ - WasmMemoryInstruction( MemoryOperator op, ValueType type, int offset, int aligment, int javaCodePos, int lineNumber ) { + WasmMemoryInstruction( MemoryOperator op, ValueType type, int offset, int alignment, int javaCodePos, int lineNumber ) { super( javaCodePos, lineNumber ); this.op = op; this.type = type; this.offset = offset; - this.aligment = aligment; + this.alignment = alignment; } /** @@ -77,7 +77,7 @@ class WasmMemoryInstruction extends WasmInstruction { */ @Override public void writeTo( @Nonnull ModuleWriter writer ) throws IOException { - writer.writeMemoryOperator( op, type, offset, aligment ); + writer.writeMemoryOperator( op, type, offset, alignment ); } /** diff --git a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java index 5eb4ad0..089e351 100644 --- a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java @@ -149,8 +149,10 @@ public class TextModuleWriter extends ModuleWriter { if( stringCount > 0 ) { if( !callIndirect ) { // we need to create a placeholder table with index 0 if not exists + newline( output ); output.append( "(table 0 funcref)" ); } + newline( output ); output.append( "(table " ).append( Integer.toString( stringCount ) ).append( " anyref)" ); } @@ -843,6 +845,6 @@ public class TextModuleWriter extends ModuleWriter { newline( methodOutput ); methodOutput.append( valueType ).append( '.' ).append( memOp ) .append( " offset=" ).append( offset ) - .append( " align=" ).append( alignment ); + .append( " align=" ).append( 1 << alignment ); } } diff --git a/src/de/inetsoftware/jwebassembly/watparser/WatParser.java b/src/de/inetsoftware/jwebassembly/watparser/WatParser.java index 5beabd5..09b493e 100644 --- a/src/de/inetsoftware/jwebassembly/watparser/WatParser.java +++ b/src/de/inetsoftware/jwebassembly/watparser/WatParser.java @@ -27,6 +27,7 @@ import de.inetsoftware.classparser.MethodInfo; import de.inetsoftware.jwebassembly.WasmException; import de.inetsoftware.jwebassembly.module.ValueTypeConvertion; import de.inetsoftware.jwebassembly.module.WasmCodeBuilder; +import de.inetsoftware.jwebassembly.wasm.MemoryOperator; import de.inetsoftware.jwebassembly.wasm.NumericOperator; import de.inetsoftware.jwebassembly.wasm.ValueType; import de.inetsoftware.jwebassembly.wasm.VariableOperator; @@ -220,6 +221,12 @@ public class WatParser extends WasmCodeBuilder { case "end": addBlockInstruction( WasmBlockOperator.END, null, javaCodePos, lineNumber ); break; + case "drop": + addBlockInstruction( WasmBlockOperator.DROP, null, javaCodePos, lineNumber ); + break; + case "i32.load": + i = addMemoryInstruction( MemoryOperator.load, ValueType.i32, tokens, i, lineNumber ); + break; default: throw new WasmException( "Unknown WASM token: " + tok, lineNumber ); } @@ -301,4 +308,51 @@ public class WatParser extends WasmCodeBuilder { } return tokens; } + + /** + * Parse the optional tokens of a load memory instruction and add it. + * + * @param op + * the operation + * @param type + * the type of the static field + * @param tokens + * the token list + * @param i + * the position in the tokens + * @param lineNumber + * the line number in the Java source code + * @return the current index to the tokens + */ + private int addMemoryInstruction( MemoryOperator op, ValueType type, List tokens, int i, int lineNumber ) { + int offset = 0; + int alignment = 0; + if( i < tokens.size() ) { + String str = tokens.get( i + 1 ); + if( str.startsWith( "offset=" ) ) { + offset = Integer.parseInt( str.substring( 7 ) ); + i++; + } + str = tokens.get( i + 1 ); + if( str.startsWith( "align=" ) ) { + int align = Integer.parseInt( str.substring( 6 ) ); + switch( align ) { + case 1: + alignment = 0; + break; + case 2: + alignment = 1; + break; + case 4: + alignment = 2; + break; + default: + throw new WasmException( "alignment must be power-of-two", lineNumber ); + } + i++; + } + } + addMemoryInstruction( op, type, offset, alignment, i, lineNumber ); + return i; + } } diff --git a/test/de/inetsoftware/jwebassembly/module/WatParserTest.java b/test/de/inetsoftware/jwebassembly/module/WatParserTest.java index 0892710..c00f322 100644 --- a/test/de/inetsoftware/jwebassembly/module/WatParserTest.java +++ b/test/de/inetsoftware/jwebassembly/module/WatParserTest.java @@ -315,6 +315,11 @@ public class WatParserTest { test( "if (result i32) else end" ); } + @Test + public void drop() throws IOException { + test( "drop" ); + } + @Test public void table_get() throws IOException { test( "table.get 1" ); @@ -326,6 +331,11 @@ public class WatParserTest { } @Test + public void i32_load() throws IOException { + test( "i32.load offset=2 align=1" ); + } + + @Test public void errorMissingToken() throws IOException { testError( "i32.const", "Missing Token in wasm text format after token: i32.const" ); }