diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmFunctionTypes.java b/core/src/main/java/org/teavm/backend/wasm/WasmFunctionTypes.java index 02a5679aa..cf6a78d87 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmFunctionTypes.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmFunctionTypes.java @@ -32,7 +32,7 @@ public class WasmFunctionTypes { public WasmFunctionType get(WasmSignature signature) { return types.computeIfAbsent(signature, k -> { - var type = new WasmFunctionType(signature.getReturnType(), signature.getParameterTypes()); + var type = new WasmFunctionType(null, signature.getReturnType(), signature.getParameterTypes()); module.types.add(type); return type; }); diff --git a/core/src/main/java/org/teavm/backend/wasm/model/WasmArray.java b/core/src/main/java/org/teavm/backend/wasm/model/WasmArray.java index ea1efa9a8..746706c51 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/WasmArray.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/WasmArray.java @@ -22,11 +22,13 @@ public class WasmArray extends WasmCompositeType { private WasmStorageType elementType; private Supplier elementTypeSupplier; - public WasmArray(WasmStorageType elementType) { + public WasmArray(String name, WasmStorageType elementType) { + super(name); this.elementType = Objects.requireNonNull(elementType); } - public WasmArray(Supplier elementTypeSupplier) { + public WasmArray(String name, Supplier elementTypeSupplier) { + super(name); this.elementTypeSupplier = elementTypeSupplier; } diff --git a/core/src/main/java/org/teavm/backend/wasm/model/WasmCompositeType.java b/core/src/main/java/org/teavm/backend/wasm/model/WasmCompositeType.java index eb89b878f..e0da99d22 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/WasmCompositeType.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/WasmCompositeType.java @@ -16,9 +16,15 @@ package org.teavm.backend.wasm.model; public abstract class WasmCompositeType extends WasmEntity { + private String name; private WasmType.Reference reference; - WasmCompositeType() { + WasmCompositeType(String name) { + this.name = name; + } + + public String getName() { + return name; } public WasmType.Reference getReference() { diff --git a/core/src/main/java/org/teavm/backend/wasm/model/WasmFunctionType.java b/core/src/main/java/org/teavm/backend/wasm/model/WasmFunctionType.java index 901d210a0..3e4dcd437 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/WasmFunctionType.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/WasmFunctionType.java @@ -24,13 +24,15 @@ public class WasmFunctionType extends WasmCompositeType { private Supplier> parameterTypesSupplier; private Supplier returnTypeSupplier; - public WasmFunctionType(WasmType returnType, List parameterTypes) { + public WasmFunctionType(String name, WasmType returnType, List parameterTypes) { + super(name); this.returnType = returnType; this.parameterTypes = parameterTypes; } - public WasmFunctionType(Supplier returnTypeSupplier, + public WasmFunctionType(String name, Supplier returnTypeSupplier, Supplier> parameterTypesSupplier) { + super(name); this.returnTypeSupplier = returnTypeSupplier; this.parameterTypesSupplier = parameterTypesSupplier; } diff --git a/core/src/main/java/org/teavm/backend/wasm/model/WasmStorageType.java b/core/src/main/java/org/teavm/backend/wasm/model/WasmStorageType.java index 00ad7d9ee..523b6de65 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/WasmStorageType.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/WasmStorageType.java @@ -22,6 +22,8 @@ public abstract class WasmStorageType { private WasmStorageType() { } + public abstract WasmType asUnpackedType(); + public static WasmStorageType.Packed packed(WasmPackedType type) { switch (type) { case INT8: @@ -39,6 +41,11 @@ public abstract class WasmStorageType { Regular(WasmType type) { this.type = type; } + + @Override + public WasmType asUnpackedType() { + return type; + } } public static final class Packed extends WasmStorageType { @@ -47,5 +54,10 @@ public abstract class WasmStorageType { private Packed(WasmPackedType type) { this.type = type; } + + @Override + public WasmType asUnpackedType() { + return WasmType.INT32; + } } } diff --git a/core/src/main/java/org/teavm/backend/wasm/model/WasmStructure.java b/core/src/main/java/org/teavm/backend/wasm/model/WasmStructure.java index 645bba70a..282c0ad8e 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/WasmStructure.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/WasmStructure.java @@ -22,11 +22,13 @@ public class WasmStructure extends WasmCompositeType { private List fields; private Supplier> fieldsSupplier; - public WasmStructure(List fields) { + public WasmStructure(String name, List fields) { + super(name); this.fields = List.copyOf(fields); } - public WasmStructure(Supplier> fieldsSupplier) { + public WasmStructure(String name, Supplier> fieldsSupplier) { + super(name); this.fieldsSupplier = fieldsSupplier; } diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmArrayGet.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmArrayGet.java new file mode 100644 index 000000000..b1d7bd348 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmArrayGet.java @@ -0,0 +1,69 @@ +/* + * 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.WasmArray; + +public class WasmArrayGet extends WasmExpression { + private WasmArray type; + private WasmExpression instance; + private WasmSignedType signedType; + private WasmExpression index; + + public WasmArrayGet(WasmArray type, WasmExpression instance, WasmExpression index) { + this.type = Objects.requireNonNull(type); + this.instance = Objects.requireNonNull(instance); + this.index = Objects.requireNonNull(index); + } + + public WasmArray getType() { + return type; + } + + public void setType(WasmArray type) { + this.type = Objects.requireNonNull(type); + } + + public WasmExpression getInstance() { + return instance; + } + + public void setInstance(WasmExpression instance) { + this.instance = instance; + } + + public WasmSignedType getSignedType() { + return signedType; + } + + public void setSignedType(WasmSignedType signedType) { + this.signedType = signedType; + } + + public WasmExpression getIndex() { + return index; + } + + public void setIndex(WasmExpression index) { + this.index = Objects.requireNonNull(index); + } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmArrayLength.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmArrayLength.java new file mode 100644 index 000000000..db25b1456 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmArrayLength.java @@ -0,0 +1,39 @@ +/* + * 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; + +public class WasmArrayLength extends WasmExpression { + private WasmExpression instance; + + public WasmArrayLength(WasmExpression instance) { + this.instance = Objects.requireNonNull(instance); + } + + public WasmExpression getInstance() { + return instance; + } + + public void setInstance(WasmExpression instance) { + this.instance = Objects.requireNonNull(instance); + } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmArrayNewDefault.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmArrayNewDefault.java new file mode 100644 index 000000000..149884997 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmArrayNewDefault.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.WasmArray; + +public class WasmArrayNewDefault extends WasmExpression { + private WasmArray type; + private WasmExpression length; + + public WasmArrayNewDefault(WasmArray type, WasmExpression length) { + this.type = Objects.requireNonNull(type); + this.length = Objects.requireNonNull(length); + } + + public WasmArray getType() { + return type; + } + + public void setType(WasmArray type) { + this.type = Objects.requireNonNull(type); + } + + public WasmExpression getLength() { + return length; + } + + public void setLength(WasmExpression length) { + this.length = Objects.requireNonNull(length); + } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmArraySet.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmArraySet.java new file mode 100644 index 000000000..8e8d994ea --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmArraySet.java @@ -0,0 +1,70 @@ +/* + * 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.WasmArray; + +public class WasmArraySet extends WasmExpression { + private WasmArray type; + private WasmExpression instance; + private WasmExpression index; + private WasmExpression value; + + public WasmArraySet(WasmArray type, WasmExpression instance, WasmExpression index, WasmExpression value) { + this.type = Objects.requireNonNull(type); + this.instance = Objects.requireNonNull(instance); + this.index = Objects.requireNonNull(index); + this.value = Objects.requireNonNull(value); + } + + public WasmArray getType() { + return type; + } + + public void setType(WasmArray type) { + this.type = type; + } + + public WasmExpression getInstance() { + return instance; + } + + public void setInstance(WasmExpression instance) { + this.instance = instance; + } + + public WasmExpression getIndex() { + return index; + } + + public void setIndex(WasmExpression index) { + this.index = index; + } + + public WasmExpression getValue() { + return value; + } + + public void setValue(WasmExpression value) { + this.value = value; + } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmCast.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmCast.java new file mode 100644 index 000000000..cdc8cc684 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmCast.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.WasmType; + +public class WasmCast extends WasmExpression { + private WasmExpression value; + private WasmType.Reference targetType; + + public WasmCast(WasmExpression value, WasmType.Reference targetType) { + this.value = Objects.requireNonNull(value); + this.targetType = Objects.requireNonNull(targetType); + } + + public WasmExpression getValue() { + return value; + } + + public void setValue(WasmExpression value) { + this.value = Objects.requireNonNull(value); + } + + public WasmType.Reference getTargetType() { + return targetType; + } + + public void setTargetType(WasmType.Reference targetType) { + this.targetType = Objects.requireNonNull(targetType); + } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } +} 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 1ac0c0933..2a94f9ef2 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 @@ -222,4 +222,56 @@ public class WasmDefaultExpressionVisitor implements WasmExpressionVisitor { arg.acceptVisitor(this); } } + + @Override + public void visit(WasmReferencesEqual expression) { + expression.getFirst().acceptVisitor(this); + expression.getSecond().acceptVisitor(this); + } + + @Override + public void visit(WasmCast expression) { + expression.getValue().acceptVisitor(this); + } + + @Override + public void visit(WasmStructNew expression) { + for (var initializer : expression.getInitializers()) { + initializer.acceptVisitor(this); + } + } + + @Override + public void visit(WasmStructGet expression) { + expression.getInstance().acceptVisitor(this); + } + + @Override + public void visit(WasmStructSet expression) { + expression.getInstance().acceptVisitor(this); + expression.getValue().acceptVisitor(this); + } + + @Override + public void visit(WasmArrayNewDefault expression) { + expression.getLength().acceptVisitor(this); + } + + @Override + public void visit(WasmArrayGet expression) { + expression.getInstance().acceptVisitor(this); + expression.getIndex().acceptVisitor(this); + } + + @Override + public void visit(WasmArraySet expression) { + expression.getInstance().acceptVisitor(this); + expression.getIndex().acceptVisitor(this); + expression.getValue().acceptVisitor(this); + } + + @Override + public void visit(WasmArrayLength expression) { + expression.getInstance().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 0fbc0fc7c..918f790c5 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 @@ -85,4 +85,22 @@ public interface WasmExpressionVisitor { void visit(WasmTry expression); void visit(WasmThrow expression); + + void visit(WasmReferencesEqual expression); + + void visit(WasmCast expression); + + void visit(WasmStructNew expression); + + void visit(WasmStructGet expression); + + void visit(WasmStructSet expression); + + void visit(WasmArrayNewDefault expression); + + void visit(WasmArrayGet expression); + + void visit(WasmArraySet expression); + + void visit(WasmArrayLength expression); } diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmReferencesEqual.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmReferencesEqual.java new file mode 100644 index 000000000..94535572e --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmReferencesEqual.java @@ -0,0 +1,49 @@ +/* + * 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; + +public class WasmReferencesEqual extends WasmExpression { + private WasmExpression first; + private WasmExpression second; + + public WasmReferencesEqual(WasmExpression first, WasmExpression second) { + this.first = Objects.requireNonNull(first); + this.second = Objects.requireNonNull(second); + } + + public WasmExpression getFirst() { + return first; + } + + public void setFirst(WasmExpression first) { + this.first = Objects.requireNonNull(first); + } + + public WasmExpression getSecond() { + return second; + } + + public void setSecond(WasmExpression second) { + this.second = Objects.requireNonNull(second); + } + + @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 60b4e4b0a..a502888ed 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 @@ -268,4 +268,71 @@ public class WasmReplacingExpressionVisitor implements WasmExpressionVisitor { public void visit(WasmThrow expression) { replaceExpressions(expression.getArguments()); } + + @Override + public void visit(WasmReferencesEqual expression) { + expression.getFirst().acceptVisitor(this); + expression.setFirst(mapper.apply(expression.getFirst())); + + expression.getSecond().acceptVisitor(this); + expression.setSecond(mapper.apply(expression.getSecond())); + } + + @Override + public void visit(WasmCast expression) { + expression.getValue().acceptVisitor(this); + expression.setValue(mapper.apply(expression.getValue())); + } + + @Override + public void visit(WasmStructNew expression) { + } + + @Override + public void visit(WasmStructGet expression) { + expression.getInstance().acceptVisitor(this); + expression.setInstance(mapper.apply(expression.getInstance())); + } + + @Override + public void visit(WasmStructSet expression) { + expression.getInstance().acceptVisitor(this); + expression.setInstance(mapper.apply(expression.getInstance())); + + expression.getValue().acceptVisitor(this); + expression.setValue(mapper.apply(expression.getValue())); + } + + @Override + public void visit(WasmArrayNewDefault expression) { + expression.getLength().acceptVisitor(this); + expression.setLength(mapper.apply(expression.getLength())); + } + + @Override + public void visit(WasmArrayGet expression) { + expression.getInstance().acceptVisitor(this); + expression.setInstance(mapper.apply(expression.getInstance())); + + expression.getIndex().acceptVisitor(this); + expression.setIndex(mapper.apply(expression.getIndex())); + } + + @Override + public void visit(WasmArraySet expression) { + expression.getInstance().acceptVisitor(this); + expression.setInstance(mapper.apply(expression.getInstance())); + + expression.getIndex().acceptVisitor(this); + expression.setIndex(mapper.apply(expression.getIndex())); + + expression.getValue().acceptVisitor(this); + expression.setValue(mapper.apply(expression.getIndex())); + } + + @Override + public void visit(WasmArrayLength expression) { + expression.getInstance().acceptVisitor(this); + expression.setInstance(mapper.apply(expression.getInstance())); + } } diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmSignedType.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmSignedType.java new file mode 100644 index 000000000..f40d64843 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmSignedType.java @@ -0,0 +1,21 @@ +/* + * 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; + +public enum WasmSignedType { + SIGNED, + UNSIGNED +} diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmStructGet.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmStructGet.java new file mode 100644 index 000000000..4440ca7d6 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmStructGet.java @@ -0,0 +1,69 @@ +/* + * 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.WasmStructure; + +public class WasmStructGet extends WasmExpression { + private WasmStructure type; + private WasmExpression instance; + private int fieldIndex; + private WasmSignedType signedType; + + public WasmStructGet(WasmStructure type, WasmExpression instance, int fieldIndex) { + this.type = Objects.requireNonNull(type); + this.instance = Objects.requireNonNull(instance); + this.fieldIndex = fieldIndex; + } + + public WasmStructure getType() { + return type; + } + + public void setType(WasmStructure type) { + this.type = Objects.requireNonNull(type); + } + + public WasmExpression getInstance() { + return instance; + } + + public void setInstance(WasmExpression instance) { + this.instance = Objects.requireNonNull(instance); + } + + public int getFieldIndex() { + return fieldIndex; + } + + public void setFieldIndex(int fieldIndex) { + this.fieldIndex = fieldIndex; + } + + public WasmSignedType getSignedType() { + return signedType; + } + + public void setSignedType(WasmSignedType signedType) { + this.signedType = signedType; + } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmStructNew.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmStructNew.java new file mode 100644 index 000000000..1ea922401 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmStructNew.java @@ -0,0 +1,47 @@ +/* + * 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.ArrayList; +import java.util.List; +import java.util.Objects; +import org.teavm.backend.wasm.model.WasmStructure; + +public class WasmStructNew extends WasmExpression { + private WasmStructure type; + private List initializers = new ArrayList<>(); + + public WasmStructNew(WasmStructure type) { + this.type = Objects.requireNonNull(type); + } + + public WasmStructure getType() { + return type; + } + + public void setType(WasmStructure type) { + this.type = Objects.requireNonNull(type); + } + + public List getInitializers() { + return initializers; + } + + @Override + public void acceptVisitor(WasmExpressionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmStructSet.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmStructSet.java new file mode 100644 index 000000000..c3ad5b180 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmStructSet.java @@ -0,0 +1,70 @@ +/* + * 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.WasmStructure; + +public class WasmStructSet extends WasmExpression { + private WasmStructure type; + private WasmExpression instance; + private int fieldIndex; + private WasmExpression value; + + public WasmStructSet(WasmStructure type, WasmExpression instance, int fieldIndex, WasmExpression value) { + this.type = Objects.requireNonNull(type); + this.instance = Objects.requireNonNull(instance); + this.fieldIndex = fieldIndex; + this.value = Objects.requireNonNull(value); + } + + public WasmStructure getType() { + return type; + } + + public void setType(WasmStructure type) { + this.type = Objects.requireNonNull(type); + } + + public WasmExpression getInstance() { + return instance; + } + + public void setInstance(WasmExpression instance) { + this.instance = Objects.requireNonNull(instance); + } + + public int getFieldIndex() { + return fieldIndex; + } + + public void setFieldIndex(int fieldIndex) { + this.fieldIndex = fieldIndex; + } + + 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 14165a652..a0fc77901 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 @@ -25,10 +25,15 @@ import org.teavm.backend.wasm.debug.DebugLines; import org.teavm.backend.wasm.generate.DwarfGenerator; import org.teavm.backend.wasm.model.WasmModule; import org.teavm.backend.wasm.model.WasmType; +import org.teavm.backend.wasm.model.expression.WasmArrayGet; +import org.teavm.backend.wasm.model.expression.WasmArrayLength; +import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault; +import org.teavm.backend.wasm.model.expression.WasmArraySet; import org.teavm.backend.wasm.model.expression.WasmBlock; import org.teavm.backend.wasm.model.expression.WasmBranch; import org.teavm.backend.wasm.model.expression.WasmBreak; import org.teavm.backend.wasm.model.expression.WasmCall; +import org.teavm.backend.wasm.model.expression.WasmCast; import org.teavm.backend.wasm.model.expression.WasmConditional; import org.teavm.backend.wasm.model.expression.WasmConversion; import org.teavm.backend.wasm.model.expression.WasmCopy; @@ -52,12 +57,16 @@ import org.teavm.backend.wasm.model.expression.WasmLoadInt32; import org.teavm.backend.wasm.model.expression.WasmLoadInt64; 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.WasmSetLocal; import org.teavm.backend.wasm.model.expression.WasmStoreFloat32; import org.teavm.backend.wasm.model.expression.WasmStoreFloat64; import org.teavm.backend.wasm.model.expression.WasmStoreInt32; import org.teavm.backend.wasm.model.expression.WasmStoreInt64; +import org.teavm.backend.wasm.model.expression.WasmStructGet; +import org.teavm.backend.wasm.model.expression.WasmStructNew; +import org.teavm.backend.wasm.model.expression.WasmStructSet; import org.teavm.backend.wasm.model.expression.WasmSwitch; import org.teavm.backend.wasm.model.expression.WasmThrow; import org.teavm.backend.wasm.model.expression.WasmTry; @@ -969,6 +978,125 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor { pushLocation(expression); writer.writeByte(0x8); writer.writeLEB(expression.getTag().getIndex()); + popLocation(); + } + + @Override + public void visit(WasmReferencesEqual expression) { + pushLocation(expression); + expression.getFirst().acceptVisitor(this); + expression.getSecond().acceptVisitor(this); + writer.writeByte(0xd3); + popLocation(); + } + + @Override + public void visit(WasmCast expression) { + pushLocation(expression); + expression.getValue().acceptVisitor(this); + writer.writeByte(0xfb); + writer.writeByte(23); + writer.writeType(expression.getTargetType(), module); + popLocation(); + } + + @Override + public void visit(WasmStructNew expression) { + pushLocation(expression); + for (var initializer : expression.getInitializers()) { + initializer.acceptVisitor(this); + } + writer.writeByte(0xfb); + writer.writeByte(0); + writer.writeInt32(module.types.indexOf(expression.getType())); + popLocation(); + } + + @Override + public void visit(WasmStructGet expression) { + pushLocation(expression); + expression.getInstance().acceptVisitor(this); + writer.writeByte(0xfb); + if (expression.getSignedType() == null) { + writer.writeByte(2); + } else { + switch (expression.getSignedType()) { + case SIGNED: + writer.writeByte(3); + break; + case UNSIGNED: + writer.writeByte(4); + break; + } + } + writer.writeInt32(module.types.indexOf(expression.getType())); + writer.writeInt32(expression.getFieldIndex()); + popLocation(); + } + + @Override + public void visit(WasmStructSet expression) { + pushLocation(expression); + expression.getInstance().acceptVisitor(this); + expression.getValue().acceptVisitor(this); + writer.writeByte(0xfb); + writer.writeByte(5); + writer.writeInt32(module.types.indexOf(expression.getType())); + writer.writeInt32(expression.getFieldIndex()); + popLocation(); + } + + @Override + public void visit(WasmArrayNewDefault expression) { + pushLocation(expression); + expression.getLength().acceptVisitor(this); + writer.writeByte(0xfb); + writer.writeByte(7); + writer.writeInt32(module.types.indexOf(expression.getType())); + popLocation(); + } + + @Override + public void visit(WasmArrayGet expression) { + pushLocation(expression); + expression.getInstance().acceptVisitor(this); + expression.getIndex().acceptVisitor(this); + writer.writeByte(0xfb); + if (expression.getSignedType() == null) { + writer.writeByte(11); + } else { + switch (expression.getSignedType()) { + case SIGNED: + writer.writeByte(12); + break; + case UNSIGNED: + writer.writeByte(13); + break; + } + } + writer.writeInt32(module.types.indexOf(expression.getType())); + popLocation(); + } + + @Override + public void visit(WasmArraySet expression) { + pushLocation(expression); + expression.getInstance().acceptVisitor(this); + expression.getIndex().acceptVisitor(this); + expression.getValue().acceptVisitor(this); + writer.writeByte(0xfb); + writer.writeByte(14); + writer.writeInt32(module.types.indexOf(expression.getType())); + popLocation(); + } + + @Override + public void visit(WasmArrayLength expression) { + pushLocation(expression); + expression.getInstance().acceptVisitor(this); + writer.writeByte(0xfb); + writer.writeByte(15); + popLocation(); } private int alignment(int value) { 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 943520d7d..93232c5f1 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 @@ -26,10 +26,15 @@ import org.teavm.backend.wasm.model.WasmLocal; import org.teavm.backend.wasm.model.WasmModule; import org.teavm.backend.wasm.model.WasmNumType; import org.teavm.backend.wasm.model.WasmType; +import org.teavm.backend.wasm.model.expression.WasmArrayGet; +import org.teavm.backend.wasm.model.expression.WasmArrayLength; +import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault; +import org.teavm.backend.wasm.model.expression.WasmArraySet; import org.teavm.backend.wasm.model.expression.WasmBlock; import org.teavm.backend.wasm.model.expression.WasmBranch; import org.teavm.backend.wasm.model.expression.WasmBreak; import org.teavm.backend.wasm.model.expression.WasmCall; +import org.teavm.backend.wasm.model.expression.WasmCast; import org.teavm.backend.wasm.model.expression.WasmConditional; import org.teavm.backend.wasm.model.expression.WasmConversion; import org.teavm.backend.wasm.model.expression.WasmCopy; @@ -55,12 +60,16 @@ import org.teavm.backend.wasm.model.expression.WasmLoadInt32; import org.teavm.backend.wasm.model.expression.WasmLoadInt64; 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.WasmSetLocal; import org.teavm.backend.wasm.model.expression.WasmStoreFloat32; import org.teavm.backend.wasm.model.expression.WasmStoreFloat64; import org.teavm.backend.wasm.model.expression.WasmStoreInt32; import org.teavm.backend.wasm.model.expression.WasmStoreInt64; +import org.teavm.backend.wasm.model.expression.WasmStructGet; +import org.teavm.backend.wasm.model.expression.WasmStructNew; +import org.teavm.backend.wasm.model.expression.WasmStructSet; import org.teavm.backend.wasm.model.expression.WasmSwitch; import org.teavm.backend.wasm.model.expression.WasmThrow; import org.teavm.backend.wasm.model.expression.WasmTry; @@ -1121,6 +1130,55 @@ class WasmCRenderingVisitor implements WasmExpressionVisitor { value = new CExpression("/* THROW */"); } + @Override + public void visit(WasmReferencesEqual expression) { + unsupported(); + } + + @Override + public void visit(WasmCast expression) { + unsupported(); + } + + @Override + public void visit(WasmStructNew expression) { + unsupported(); + } + + @Override + public void visit(WasmStructGet expression) { + unsupported(); + } + + @Override + public void visit(WasmStructSet expression) { + unsupported(); + } + + @Override + public void visit(WasmArrayNewDefault expression) { + unsupported(); + } + + @Override + public void visit(WasmArrayGet expression) { + unsupported(); + } + + @Override + public void visit(WasmArraySet expression) { + unsupported(); + } + + @Override + public void visit(WasmArrayLength expression) { + unsupported(); + } + + private void unsupported() { + value = new CExpression("/* unsupported */"); + } + private CExpression checkAddress(CExpression index) { if (!memoryAccessChecked) { return index; 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 ecf7a8138..9a0879fa4 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 @@ -17,14 +17,20 @@ 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.WasmLocal; import org.teavm.backend.wasm.model.WasmModule; import org.teavm.backend.wasm.model.WasmNumType; import org.teavm.backend.wasm.model.WasmType; +import org.teavm.backend.wasm.model.expression.WasmArrayGet; +import org.teavm.backend.wasm.model.expression.WasmArrayLength; +import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault; +import org.teavm.backend.wasm.model.expression.WasmArraySet; import org.teavm.backend.wasm.model.expression.WasmBlock; import org.teavm.backend.wasm.model.expression.WasmBranch; import org.teavm.backend.wasm.model.expression.WasmBreak; import org.teavm.backend.wasm.model.expression.WasmCall; +import org.teavm.backend.wasm.model.expression.WasmCast; import org.teavm.backend.wasm.model.expression.WasmConditional; import org.teavm.backend.wasm.model.expression.WasmConversion; import org.teavm.backend.wasm.model.expression.WasmCopy; @@ -55,12 +61,16 @@ import org.teavm.backend.wasm.model.expression.WasmLoadInt32; import org.teavm.backend.wasm.model.expression.WasmLoadInt64; 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.WasmSetLocal; import org.teavm.backend.wasm.model.expression.WasmStoreFloat32; import org.teavm.backend.wasm.model.expression.WasmStoreFloat64; import org.teavm.backend.wasm.model.expression.WasmStoreInt32; import org.teavm.backend.wasm.model.expression.WasmStoreInt64; +import org.teavm.backend.wasm.model.expression.WasmStructGet; +import org.teavm.backend.wasm.model.expression.WasmStructNew; +import org.teavm.backend.wasm.model.expression.WasmStructSet; import org.teavm.backend.wasm.model.expression.WasmSwitch; import org.teavm.backend.wasm.model.expression.WasmThrow; import org.teavm.backend.wasm.model.expression.WasmTry; @@ -644,16 +654,122 @@ class WasmRenderingVisitor implements WasmExpressionVisitor { close(); } + @Override + public void visit(WasmReferencesEqual expression) { + open().append("ref.eq "); + line(expression.getFirst()); + line(expression.getSecond()); + close(); + } + + @Override + public void visit(WasmCast expression) { + open().append("ref.cast ").append(type(expression.getTargetType())); + line(expression.getValue()); + close(); + } + + @Override + public void visit(WasmStructNew expression) { + open().append("struct.new "); + append(expression.getType().getReference()); + for (var initializer : expression.getInitializers()) { + line(initializer); + } + close(); + } + + @Override + public void visit(WasmStructGet expression) { + open(); + if (expression.getSignedType() == null) { + append("struct.get"); + } else { + switch (expression.getSignedType()) { + case SIGNED: + append("struct.get_s"); + break; + case UNSIGNED: + append("struct.get_u"); + break; + } + } + append(" ").append(typeName(expression.getType())); + append(" ").append(String.valueOf(expression.getFieldIndex())); + line(expression.getInstance()); + close(); + } + + @Override + public void visit(WasmStructSet expression) { + open().append("struct.set"); + append(" ").append(typeName(expression.getType())); + append(" ").append(String.valueOf(expression.getFieldIndex())); + line(expression.getInstance()); + line(expression.getValue()); + close(); + } + + @Override + public void visit(WasmArrayNewDefault expression) { + open().append("array.new_default"); + append(" ").append(typeName(expression.getType())); + line(expression.getLength()); + close(); + } + + @Override + public void visit(WasmArrayGet expression) { + open(); + if (expression.getSignedType() == null) { + append("array.get"); + } else { + switch (expression.getSignedType()) { + case SIGNED: + append("array.get_s"); + break; + case UNSIGNED: + append("array.get_u"); + break; + } + } + append(" ").append(typeName(expression.getType())); + line(expression.getInstance()); + line(expression.getIndex()); + close(); + } + + @Override + public void visit(WasmArraySet expression) { + open().append("array.set"); + append(" ").append(typeName(expression.getType())); + line(expression.getInstance()); + line(expression.getIndex()); + line(expression.getValue()); + close(); + } + + @Override + public void visit(WasmArrayLength expression) { + open().append("array.length"); + line(expression.getInstance()); + close(); + } + private String type(WasmType type) { if (type instanceof WasmType.Number) { return type(((WasmType.Number) type).number); } else if (type instanceof WasmType.Reference) { - return "(ref " + module.types.indexOf(((WasmType.Reference) type).composite) + ")"; + return "(ref " + typeName(((WasmType.Reference) type).composite) + ")"; } else { throw new IllegalArgumentException(); } } + private String typeName(WasmCompositeType type) { + return type.getName() != null ? "$" + type.getName() : String.valueOf(module.types.indexOf(type)); + } + private String type(WasmNumType type) { switch (type) { case INT32: 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 d4e04b6e5..908fae512 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 @@ -16,10 +16,15 @@ package org.teavm.backend.wasm.render; import org.teavm.backend.wasm.model.WasmType; +import org.teavm.backend.wasm.model.expression.WasmArrayGet; +import org.teavm.backend.wasm.model.expression.WasmArrayLength; +import org.teavm.backend.wasm.model.expression.WasmArrayNewDefault; +import org.teavm.backend.wasm.model.expression.WasmArraySet; import org.teavm.backend.wasm.model.expression.WasmBlock; import org.teavm.backend.wasm.model.expression.WasmBranch; import org.teavm.backend.wasm.model.expression.WasmBreak; import org.teavm.backend.wasm.model.expression.WasmCall; +import org.teavm.backend.wasm.model.expression.WasmCast; import org.teavm.backend.wasm.model.expression.WasmConditional; import org.teavm.backend.wasm.model.expression.WasmConversion; import org.teavm.backend.wasm.model.expression.WasmCopy; @@ -44,12 +49,16 @@ import org.teavm.backend.wasm.model.expression.WasmLoadInt32; import org.teavm.backend.wasm.model.expression.WasmLoadInt64; 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.WasmSetLocal; import org.teavm.backend.wasm.model.expression.WasmStoreFloat32; import org.teavm.backend.wasm.model.expression.WasmStoreFloat64; import org.teavm.backend.wasm.model.expression.WasmStoreInt32; import org.teavm.backend.wasm.model.expression.WasmStoreInt64; +import org.teavm.backend.wasm.model.expression.WasmStructGet; +import org.teavm.backend.wasm.model.expression.WasmStructNew; +import org.teavm.backend.wasm.model.expression.WasmStructSet; import org.teavm.backend.wasm.model.expression.WasmSwitch; import org.teavm.backend.wasm.model.expression.WasmThrow; import org.teavm.backend.wasm.model.expression.WasmTry; @@ -238,6 +247,51 @@ public class WasmTypeInference implements WasmExpressionVisitor { result = null; } + @Override + public void visit(WasmReferencesEqual expression) { + result = WasmType.INT32; + } + + @Override + public void visit(WasmCast expression) { + result = expression.getTargetType(); + } + + @Override + public void visit(WasmStructNew expression) { + result = expression.getType().getReference(); + } + + @Override + public void visit(WasmStructGet expression) { + result = expression.getType().getFields().get(expression.getFieldIndex()).asUnpackedType(); + } + + @Override + public void visit(WasmStructSet expression) { + result = null; + } + + @Override + public void visit(WasmArrayNewDefault expression) { + result = expression.getType().getReference(); + } + + @Override + public void visit(WasmArrayGet expression) { + result = expression.getType().getElementType().asUnpackedType(); + } + + @Override + public void visit(WasmArraySet expression) { + result = null; + } + + @Override + public void visit(WasmArrayLength expression) { + result = WasmType.INT32; + } + private static WasmType map(WasmIntType type) { switch (type) { case INT32: