From dd29280641ab0394aaefa4dc2cb99d97ee350693 Mon Sep 17 00:00:00 2001 From: Volker Date: Tue, 14 Aug 2018 15:11:21 +0200 Subject: [PATCH] Add support for global (static) variables --- .../binary/BinaryModuleWriter.java | 19 +++++ .../jwebassembly/binary/Global.java | 2 + .../jwebassembly/module/ModuleGenerator.java | 10 ++- .../jwebassembly/module/ModuleWriter.java | 17 +++++ .../module/WasmGlobalInstruction.java | 75 +++++++++++++++++++ .../jwebassembly/text/TextModuleWriter.java | 26 ++++++- 6 files changed, 144 insertions(+), 5 deletions(-) create mode 100644 src/de/inetsoftware/jwebassembly/module/WasmGlobalInstruction.java diff --git a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java index 4c4cc7a..169387e 100644 --- a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java @@ -26,6 +26,7 @@ import java.util.Map; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import de.inetsoftware.classparser.ConstantRef; import de.inetsoftware.jwebassembly.WasmException; import de.inetsoftware.jwebassembly.module.FunctionName; import de.inetsoftware.jwebassembly.module.ModuleWriter; @@ -387,6 +388,24 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod codeStream.writeVaruint32( idx ); } + /** + * {@inheritDoc} + */ + @Override + protected void writeGlobalAccess( boolean load, FunctionName name, ConstantRef ref ) throws IOException { + Global var = globals.get( name.fullName ); + if( var == null ) { // if not declared then create a definition in the global section + var = new Global(); + var.id = globals.size(); + var.type = ValueType.getValueType( ref.getType(), 0 ); + var.mutability = true; + globals.put( name.fullName, var ); + } + int op = load ? GET_GLOBAL : SET_GLOBAL; + codeStream.writeOpCode( op ); + codeStream.writeVaruint32( var.id ); + } + /** * {@inheritDoc} */ diff --git a/src/de/inetsoftware/jwebassembly/binary/Global.java b/src/de/inetsoftware/jwebassembly/binary/Global.java index 4835bd2..acd42da 100644 --- a/src/de/inetsoftware/jwebassembly/binary/Global.java +++ b/src/de/inetsoftware/jwebassembly/binary/Global.java @@ -24,6 +24,8 @@ import de.inetsoftware.jwebassembly.module.ValueType; */ class Global { + int id; + ValueType type; boolean mutability; diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java index 6d72e8d..375ceda 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java @@ -648,8 +648,14 @@ public class ModuleGenerator { instr = new WasmBlockInstruction( WasmBlockOperator.RETURN, type, codePos ); endWithReturn = true; break; - //TODO case 178: // getstatic - //TODO case 179: // putstatic + case 178: // getstatic + ConstantRef ref = (ConstantRef)constantPool.get( byteCode.readUnsignedShort() ); + instr = new WasmGlobalInstruction( true, ref, codePos ); + break; + case 179: // putstatic + ref = (ConstantRef)constantPool.get( byteCode.readUnsignedShort() ); + instr = new WasmGlobalInstruction( false, ref, codePos ); + break; //TODO case 180: // getfield //TODO case 181: // putfield //TODO case 182: // invokevirtual diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java index 386ed95..34ee9bb 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java @@ -22,6 +22,8 @@ import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import de.inetsoftware.classparser.ConstantRef; + /** * Module Writer base class. * @@ -144,6 +146,21 @@ public abstract class ModuleWriter implements Closeable { */ protected abstract void writeStore( int idx ) throws IOException; + /** + * Write a set_global variable + * @param load + * true: if load or GET + * @param name + * the variable name + * @param ref + * the definition of the variable + * + * @throws IOException + * if any I/O error occur + */ + protected abstract void writeGlobalAccess( boolean load, FunctionName name, ConstantRef ref ) throws IOException; + + /** * Write a add operator * diff --git a/src/de/inetsoftware/jwebassembly/module/WasmGlobalInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmGlobalInstruction.java new file mode 100644 index 0000000..35b03fc --- /dev/null +++ b/src/de/inetsoftware/jwebassembly/module/WasmGlobalInstruction.java @@ -0,0 +1,75 @@ +/* + 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.module; + +import java.io.IOException; + +import javax.annotation.Nonnull; + +import de.inetsoftware.classparser.ConstantRef; + +/** + * WasmInstruction for set and get global variables. + * + * @author Volker Berlin + * + */ +class WasmGlobalInstruction extends WasmInstruction { + + private boolean load; + + private ConstantRef ref; + + /** + * Create an instance of a load/store instruction + * + * @param load + * true: if load or GET + * @param ref + * reference to a static field + * @param javaCodePos + * the code position/offset in the Java method + */ + WasmGlobalInstruction( boolean load, ConstantRef ref, int javaCodePos ) { + super( javaCodePos ); + this.load = load; + this.ref = ref; + } + + /** + * {@inheritDoc} + */ + public void writeTo( @Nonnull ModuleWriter writer ) throws IOException { + FunctionName name = new FunctionName( ref ); + writer.writeGlobalAccess( load, name, ref ); + } + + /** + * {@inheritDoc} + */ + ValueType getPushValueType() { + return load ? ValueType.getValueType( ref.getType(), 0 ) : null; + } + + /** + * {@inheritDoc} + */ + @Override + int getPopCount() { + return load ? 0 : 1; + } +} diff --git a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java index ae07b75..5c142c4 100644 --- a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java @@ -16,11 +16,13 @@ package de.inetsoftware.jwebassembly.text; import java.io.IOException; +import java.util.HashSet; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import de.inetsoftware.classparser.ConstantRef; import de.inetsoftware.jwebassembly.module.FunctionName; import de.inetsoftware.jwebassembly.module.ModuleWriter; import de.inetsoftware.jwebassembly.module.NumericOperator; @@ -36,11 +38,13 @@ import de.inetsoftware.jwebassembly.module.WasmBlockOperator; */ public class TextModuleWriter extends ModuleWriter { - private Appendable output; + private Appendable output; - private StringBuilder methodOutput = new StringBuilder(); + private StringBuilder methodOutput = new StringBuilder(); - private int inset; + private int inset; + + private HashSet globals = new HashSet<>(); /** * Create a new instance. @@ -153,6 +157,22 @@ public class TextModuleWriter extends ModuleWriter { methodOutput.append( "set_local " ).append( Integer.toString( idx ) ); } + /** + * {@inheritDoc} + */ + @Override + protected void writeGlobalAccess( boolean load, FunctionName name, ConstantRef ref ) throws IOException { + if( !globals.contains( name.fullName ) ) { + // declare global variable if not already declared. + output.append( "\n " ); + String type = ValueType.getValueType( ref.getType(), 0 ).toString(); + output.append( "(global $" ).append( name.fullName ).append( type ).append( ' ' ).append( type ).append( ".const 0)" ); + globals.add( name.fullName ); + } + newline( methodOutput ); + methodOutput.append( load ? "get_local " : "set_local " ).append( name.fullName ); + } + /** * {@inheritDoc} */