From efcb22b639448fe558d271aa80417d3317c88a50 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Mon, 1 Jul 2024 19:37:04 +0200 Subject: [PATCH] wasm: implement global variables They aren't used by current Wasm BE yet, but will be used by future Wasm GC BE --- .../teavm/backend/wasm/model/WasmGlobal.java | 51 +++++++++++++++++++ .../teavm/backend/wasm/model/WasmModule.java | 1 + .../WasmDefaultExpressionVisitor.java | 9 ++++ .../expression/WasmExpressionVisitor.java | 4 ++ .../wasm/model/expression/WasmGetGlobal.java | 40 +++++++++++++++ .../WasmReplacingExpressionVisitor.java | 9 ++++ .../wasm/model/expression/WasmSetGlobal.java | 50 ++++++++++++++++++ .../render/WasmBinaryRenderingVisitor.java | 19 +++++++ .../wasm/render/WasmCRenderingVisitor.java | 25 +++++++++ .../wasm/render/WasmRenderingVisitor.java | 21 +++++++- .../wasm/render/WasmTypeInference.java | 12 +++++ 11 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/org/teavm/backend/wasm/model/WasmGlobal.java create mode 100644 core/src/main/java/org/teavm/backend/wasm/model/expression/WasmGetGlobal.java create mode 100644 core/src/main/java/org/teavm/backend/wasm/model/expression/WasmSetGlobal.java diff --git a/core/src/main/java/org/teavm/backend/wasm/model/WasmGlobal.java b/core/src/main/java/org/teavm/backend/wasm/model/WasmGlobal.java new file mode 100644 index 000000000..5b89d0983 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/model/WasmGlobal.java @@ -0,0 +1,51 @@ +/* + * Copyright 2024 Alexey Andreev. + * + * 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 org.teavm.backend.wasm.model; + +import java.util.Objects; +import org.teavm.backend.wasm.model.expression.WasmExpression; + +public class WasmGlobal extends WasmEntity { + private String name; + private WasmType type; + private WasmExpression initialValue; + + public WasmGlobal(String name, WasmType type, WasmExpression initialValue) { + this.name = name; + this.type = Objects.requireNonNull(type); + this.initialValue = Objects.requireNonNull(initialValue); + } + + public String getName() { + return name; + } + + public WasmType getType() { + return type; + } + + public void setType(WasmType type) { + this.type = Objects.requireNonNull(type); + } + + public WasmExpression getInitialValue() { + return initialValue; + } + + public void setInitialValue(WasmExpression initialValue) { + this.initialValue = Objects.requireNonNull(initialValue); + } +} diff --git a/core/src/main/java/org/teavm/backend/wasm/model/WasmModule.java b/core/src/main/java/org/teavm/backend/wasm/model/WasmModule.java index 799ffdff2..199b13add 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/WasmModule.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/WasmModule.java @@ -31,6 +31,7 @@ public class WasmModule { private Map readonlyCustomSections = Collections.unmodifiableMap(customSections); public final WasmCollection functions = new WasmCollection<>(); + public final WasmCollection globals = new WasmCollection<>(); public final WasmCollection types = new WasmCollection<>(); public final WasmCollection tags = new WasmCollection<>(); diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmDefaultExpressionVisitor.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmDefaultExpressionVisitor.java index 2a94f9ef2..02cd7bf2c 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmDefaultExpressionVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmDefaultExpressionVisitor.java @@ -94,6 +94,15 @@ public class WasmDefaultExpressionVisitor implements WasmExpressionVisitor { expression.getValue().acceptVisitor(this); } + @Override + public void visit(WasmGetGlobal expression) { + } + + @Override + public void visit(WasmSetGlobal expression) { + expression.getValue().acceptVisitor(this); + } + @Override public void visit(WasmIntBinary expression) { expression.getFirst().acceptVisitor(this); diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmExpressionVisitor.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmExpressionVisitor.java index 918f790c5..0c65c0bc0 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmExpressionVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmExpressionVisitor.java @@ -44,6 +44,10 @@ public interface WasmExpressionVisitor { void visit(WasmSetLocal expression); + void visit(WasmGetGlobal expression); + + void visit(WasmSetGlobal expression); + void visit(WasmIntBinary expression); void visit(WasmFloatBinary expression); diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmGetGlobal.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmGetGlobal.java new file mode 100644 index 000000000..dce41db65 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmGetGlobal.java @@ -0,0 +1,40 @@ +/* + * Copyright 2024 Alexey Andreev. + * + * 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 org.teavm.backend.wasm.model.expression; + +import java.util.Objects; +import org.teavm.backend.wasm.model.WasmGlobal; + +public class WasmGetGlobal extends WasmExpression { + private WasmGlobal global; + + public WasmGetGlobal(WasmGlobal global) { + this.global = Objects.requireNonNull(global); + } + + public WasmGlobal getGlobal() { + return global; + } + + public void setGlobal(WasmGlobal global) { + this.global = Objects.requireNonNull(global); + } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmReplacingExpressionVisitor.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmReplacingExpressionVisitor.java index a502888ed..3ea740dbd 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmReplacingExpressionVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmReplacingExpressionVisitor.java @@ -118,6 +118,15 @@ public class WasmReplacingExpressionVisitor implements WasmExpressionVisitor { expression.getValue().acceptVisitor(this); } + @Override + public void visit(WasmGetGlobal expression) { + } + + @Override + public void visit(WasmSetGlobal expression) { + expression.getValue().acceptVisitor(this); + } + @Override public void visit(WasmIntBinary expression) { expression.getFirst().acceptVisitor(this); diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmSetGlobal.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmSetGlobal.java new file mode 100644 index 000000000..d9ca9700c --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmSetGlobal.java @@ -0,0 +1,50 @@ +/* + * Copyright 2024 Alexey Andreev. + * + * 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 org.teavm.backend.wasm.model.expression; + +import java.util.Objects; +import org.teavm.backend.wasm.model.WasmGlobal; + +public class WasmSetGlobal extends WasmExpression { + private WasmGlobal global; + private WasmExpression value; + + public WasmSetGlobal(WasmGlobal global, WasmExpression value) { + this.global = Objects.requireNonNull(global); + this.value = Objects.requireNonNull(value); + } + + public WasmGlobal getGlobal() { + return global; + } + + public void setGlobal(WasmGlobal global) { + this.global = Objects.requireNonNull(global); + } + + public WasmExpression getValue() { + return value; + } + + public void setValue(WasmExpression value) { + this.value = Objects.requireNonNull(value); + } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderingVisitor.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderingVisitor.java index a0fc77901..f6fa39d8c 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderingVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderingVisitor.java @@ -45,6 +45,7 @@ import org.teavm.backend.wasm.model.expression.WasmFloat32Constant; import org.teavm.backend.wasm.model.expression.WasmFloat64Constant; import org.teavm.backend.wasm.model.expression.WasmFloatBinary; import org.teavm.backend.wasm.model.expression.WasmFloatUnary; +import org.teavm.backend.wasm.model.expression.WasmGetGlobal; import org.teavm.backend.wasm.model.expression.WasmGetLocal; import org.teavm.backend.wasm.model.expression.WasmIndirectCall; import org.teavm.backend.wasm.model.expression.WasmInt32Constant; @@ -59,6 +60,7 @@ import org.teavm.backend.wasm.model.expression.WasmMemoryGrow; import org.teavm.backend.wasm.model.expression.WasmNullConstant; import org.teavm.backend.wasm.model.expression.WasmReferencesEqual; import org.teavm.backend.wasm.model.expression.WasmReturn; +import org.teavm.backend.wasm.model.expression.WasmSetGlobal; import org.teavm.backend.wasm.model.expression.WasmSetLocal; import org.teavm.backend.wasm.model.expression.WasmStoreFloat32; import org.teavm.backend.wasm.model.expression.WasmStoreFloat64; @@ -269,6 +271,23 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor { popLocation(); } + @Override + public void visit(WasmGetGlobal expression) { + pushLocation(expression); + writer.writeByte(0x23); + writer.writeLEB(module.globals.indexOf(expression.getGlobal())); + popLocation(); + } + + @Override + public void visit(WasmSetGlobal expression) { + pushLocation(expression); + expression.getValue().acceptVisitor(this); + writer.writeByte(0x24); + writer.writeLEB(module.globals.indexOf(expression.getGlobal())); + popLocation(); + } + @Override public void visit(WasmIntBinary expression) { pushLocation(expression); diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderingVisitor.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderingVisitor.java index 93232c5f1..b1920bd08 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderingVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmCRenderingVisitor.java @@ -22,6 +22,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import org.teavm.backend.wasm.model.WasmGlobal; import org.teavm.backend.wasm.model.WasmLocal; import org.teavm.backend.wasm.model.WasmModule; import org.teavm.backend.wasm.model.WasmNumType; @@ -47,6 +48,7 @@ import org.teavm.backend.wasm.model.expression.WasmFloat64Constant; import org.teavm.backend.wasm.model.expression.WasmFloatBinary; import org.teavm.backend.wasm.model.expression.WasmFloatType; import org.teavm.backend.wasm.model.expression.WasmFloatUnary; +import org.teavm.backend.wasm.model.expression.WasmGetGlobal; import org.teavm.backend.wasm.model.expression.WasmGetLocal; import org.teavm.backend.wasm.model.expression.WasmIndirectCall; import org.teavm.backend.wasm.model.expression.WasmInt32Constant; @@ -62,6 +64,7 @@ import org.teavm.backend.wasm.model.expression.WasmMemoryGrow; import org.teavm.backend.wasm.model.expression.WasmNullConstant; import org.teavm.backend.wasm.model.expression.WasmReferencesEqual; import org.teavm.backend.wasm.model.expression.WasmReturn; +import org.teavm.backend.wasm.model.expression.WasmSetGlobal; import org.teavm.backend.wasm.model.expression.WasmSetLocal; import org.teavm.backend.wasm.model.expression.WasmStoreFloat32; import org.teavm.backend.wasm.model.expression.WasmStoreFloat64; @@ -366,6 +369,24 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { value = result; } + @Override + public void visit(WasmGetGlobal expression) { + value = new CExpression(getVariableName(expression.getGlobal())); + } + + @Override + public void visit(WasmSetGlobal expression) { + CExpression result = new CExpression(); + requiredType = expression.getGlobal().getType(); + expression.getValue().acceptVisitor(this); + result.getLines().addAll(value.getLines()); + + result.addLine(getVariableName(expression.getGlobal()) + " = " + value.getText() + ";", + expression.getLocation()); + + value = result; + } + @Override public void visit(WasmIntBinary expression) { WasmType type = requiredType; @@ -1277,4 +1298,8 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { } return result; } + + String getVariableName(WasmGlobal global) { + return "wasm_global_" + module.globals.indexOf(global); + } } diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmRenderingVisitor.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmRenderingVisitor.java index 9a0879fa4..58030ff61 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmRenderingVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmRenderingVisitor.java @@ -18,6 +18,7 @@ package org.teavm.backend.wasm.render; import java.util.HashMap; import java.util.Map; import org.teavm.backend.wasm.model.WasmCompositeType; +import org.teavm.backend.wasm.model.WasmGlobal; import org.teavm.backend.wasm.model.WasmLocal; import org.teavm.backend.wasm.model.WasmModule; import org.teavm.backend.wasm.model.WasmNumType; @@ -46,6 +47,7 @@ import org.teavm.backend.wasm.model.expression.WasmFloatBinaryOperation; import org.teavm.backend.wasm.model.expression.WasmFloatType; import org.teavm.backend.wasm.model.expression.WasmFloatUnary; import org.teavm.backend.wasm.model.expression.WasmFloatUnaryOperation; +import org.teavm.backend.wasm.model.expression.WasmGetGlobal; import org.teavm.backend.wasm.model.expression.WasmGetLocal; import org.teavm.backend.wasm.model.expression.WasmIndirectCall; import org.teavm.backend.wasm.model.expression.WasmInt32Constant; @@ -63,6 +65,7 @@ import org.teavm.backend.wasm.model.expression.WasmMemoryGrow; import org.teavm.backend.wasm.model.expression.WasmNullConstant; import org.teavm.backend.wasm.model.expression.WasmReferencesEqual; import org.teavm.backend.wasm.model.expression.WasmReturn; +import org.teavm.backend.wasm.model.expression.WasmSetGlobal; import org.teavm.backend.wasm.model.expression.WasmSetLocal; import org.teavm.backend.wasm.model.expression.WasmStoreFloat32; import org.teavm.backend.wasm.model.expression.WasmStoreFloat64; @@ -290,18 +293,32 @@ class WasmRenderingVisitor implements WasmExpressionVisitor { @Override public void visit(WasmGetLocal expression) { - open().append("get_local " + asString(expression.getLocal())).close(); + open().append("local.get " + asString(expression.getLocal())).close(); } @Override public void visit(WasmSetLocal expression) { - open().append("set_local " + asString(expression.getLocal())).line(expression.getValue()).close(); + open().append("local.set " + asString(expression.getLocal())).line(expression.getValue()).close(); + } + + @Override + public void visit(WasmGetGlobal expression) { + open().append("global.get " + asString(expression.getGlobal())).close(); + } + + @Override + public void visit(WasmSetGlobal expression) { + open().append("global.set " + asString(expression.getGlobal())).line(expression.getValue()).close(); } private String asString(WasmLocal local) { return String.valueOf(local.getIndex()); } + private String asString(WasmGlobal global) { + return global.getName() != null ? "$" + global.getName() : String.valueOf(module.globals.indexOf(global)); + } + @Override public void visit(WasmIntBinary expression) { open().append(type(expression.getType()) + "." + operation(expression.getOperation())); diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmTypeInference.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmTypeInference.java index 908fae512..4d3ce139a 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmTypeInference.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmTypeInference.java @@ -36,6 +36,7 @@ import org.teavm.backend.wasm.model.expression.WasmFloat64Constant; import org.teavm.backend.wasm.model.expression.WasmFloatBinary; import org.teavm.backend.wasm.model.expression.WasmFloatType; import org.teavm.backend.wasm.model.expression.WasmFloatUnary; +import org.teavm.backend.wasm.model.expression.WasmGetGlobal; import org.teavm.backend.wasm.model.expression.WasmGetLocal; import org.teavm.backend.wasm.model.expression.WasmIndirectCall; import org.teavm.backend.wasm.model.expression.WasmInt32Constant; @@ -51,6 +52,7 @@ import org.teavm.backend.wasm.model.expression.WasmMemoryGrow; import org.teavm.backend.wasm.model.expression.WasmNullConstant; import org.teavm.backend.wasm.model.expression.WasmReferencesEqual; import org.teavm.backend.wasm.model.expression.WasmReturn; +import org.teavm.backend.wasm.model.expression.WasmSetGlobal; import org.teavm.backend.wasm.model.expression.WasmSetLocal; import org.teavm.backend.wasm.model.expression.WasmStoreFloat32; import org.teavm.backend.wasm.model.expression.WasmStoreFloat64; @@ -136,6 +138,16 @@ public class WasmTypeInference implements WasmExpressionVisitor { result = null; } + @Override + public void visit(WasmGetGlobal expression) { + result = expression.getGlobal().getType(); + } + + @Override + public void visit(WasmSetGlobal expression) { + result = null; + } + @Override public void visit(WasmIntBinary expression) { result = map(expression.getType());