mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
wasm gc: use non-null array storage type
This commit is contained in:
parent
1d81b7004f
commit
33f4537f43
|
@ -937,38 +937,34 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
module.functions.add(function);
|
module.functions.add(function);
|
||||||
var instanceLocal = new WasmLocal(standardClasses.objectClass().getType(), "instance");
|
var instanceLocal = new WasmLocal(standardClasses.objectClass().getType(), "instance");
|
||||||
var originalLocal = new WasmLocal(objectStructure.getReference(), "original");
|
var originalLocal = new WasmLocal(objectStructure.getReference(), "original");
|
||||||
var resultLocal = new WasmLocal(objectStructure.getReference(), "result");
|
var originalDataLocal = new WasmLocal(arrayType.getNonNullReference(), "originalData");
|
||||||
var originalDataLocal = new WasmLocal(arrayType.getReference(), "originalData");
|
var dataCopyLocal = new WasmLocal(arrayType.getNonNullReference(), "resultData");
|
||||||
var dataCopyLocal = new WasmLocal(arrayType.getReference(), "resultData");
|
|
||||||
function.add(instanceLocal);
|
function.add(instanceLocal);
|
||||||
function.add(originalLocal);
|
function.add(originalLocal);
|
||||||
function.add(resultLocal);
|
|
||||||
function.add(originalDataLocal);
|
function.add(originalDataLocal);
|
||||||
function.add(dataCopyLocal);
|
function.add(dataCopyLocal);
|
||||||
|
|
||||||
|
var newExpr = new WasmStructNew(objectStructure);
|
||||||
function.getBody().add(new WasmSetLocal(originalLocal,
|
function.getBody().add(new WasmSetLocal(originalLocal,
|
||||||
new WasmCast(new WasmGetLocal(instanceLocal), objectStructure.getNonNullReference())));
|
new WasmCast(new WasmGetLocal(instanceLocal), objectStructure.getNonNullReference())));
|
||||||
function.getBody().add(new WasmSetLocal(resultLocal, new WasmStructNewDefault(objectStructure)));
|
|
||||||
|
|
||||||
var classValue = new WasmStructGet(objectStructure, new WasmGetLocal(originalLocal),
|
var classValue = new WasmStructGet(objectStructure, new WasmGetLocal(originalLocal),
|
||||||
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET);
|
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET);
|
||||||
function.getBody().add(new WasmStructSet(objectStructure, new WasmGetLocal(resultLocal),
|
newExpr.getInitializers().add(classValue);
|
||||||
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET, classValue));
|
newExpr.getInitializers().add(new WasmNullConstant(WasmType.Reference.EQ));
|
||||||
|
|
||||||
var originalDataValue = new WasmStructGet(objectStructure, new WasmGetLocal(originalLocal),
|
var originalDataValue = new WasmStructGet(objectStructure, new WasmGetLocal(originalLocal),
|
||||||
WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET);
|
WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET);
|
||||||
function.getBody().add(new WasmSetLocal(originalDataLocal, originalDataValue));
|
function.getBody().add(new WasmSetLocal(originalDataLocal, originalDataValue));
|
||||||
var originalLength = new WasmArrayLength(new WasmGetLocal(originalDataLocal));
|
var originalLength = new WasmArrayLength(new WasmGetLocal(originalDataLocal));
|
||||||
function.getBody().add(new WasmSetLocal(dataCopyLocal, new WasmArrayNewDefault(arrayType, originalLength)));
|
function.getBody().add(new WasmSetLocal(dataCopyLocal, new WasmArrayNewDefault(arrayType, originalLength)));
|
||||||
function.getBody().add(new WasmStructSet(objectStructure, new WasmGetLocal(resultLocal),
|
newExpr.getInitializers().add(new WasmGetLocal(dataCopyLocal));
|
||||||
WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET, new WasmGetLocal(dataCopyLocal)));
|
|
||||||
|
|
||||||
function.getBody().add(new WasmArrayCopy(arrayType, new WasmGetLocal(dataCopyLocal),
|
function.getBody().add(new WasmArrayCopy(arrayType, new WasmGetLocal(dataCopyLocal),
|
||||||
new WasmInt32Constant(0), arrayType, new WasmGetLocal(originalDataLocal),
|
new WasmInt32Constant(0), arrayType, new WasmGetLocal(originalDataLocal),
|
||||||
new WasmInt32Constant(0), new WasmArrayLength(new WasmGetLocal(originalDataLocal))));
|
new WasmInt32Constant(0), new WasmArrayLength(new WasmGetLocal(originalDataLocal))));
|
||||||
|
|
||||||
function.getBody().add(new WasmGetLocal(resultLocal));
|
function.getBody().add(newExpr);
|
||||||
|
|
||||||
return function;
|
return function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1327,7 +1323,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
classInfo.structure.getFields().add(new WasmField(wasmArray.getReference().asStorage(),
|
classInfo.structure.getFields().add(new WasmField(wasmArray.getNonNullReference().asStorage(),
|
||||||
arrayDataFieldName()));
|
arrayDataFieldName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 konsoletyper.
|
||||||
|
*
|
||||||
|
* 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.generate.gc.methods;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import org.teavm.ast.AssignmentStatement;
|
||||||
|
import org.teavm.ast.BinaryExpr;
|
||||||
|
import org.teavm.ast.BlockStatement;
|
||||||
|
import org.teavm.ast.ConditionalExpr;
|
||||||
|
import org.teavm.ast.ConditionalStatement;
|
||||||
|
import org.teavm.ast.RecursiveVisitor;
|
||||||
|
import org.teavm.ast.SwitchStatement;
|
||||||
|
import org.teavm.ast.TryCatchStatement;
|
||||||
|
import org.teavm.ast.VariableExpr;
|
||||||
|
import org.teavm.ast.WhileStatement;
|
||||||
|
|
||||||
|
class NonNullVarsCalculator extends RecursiveVisitor {
|
||||||
|
private boolean[] nonNullVars;
|
||||||
|
private boolean[] definedVars;
|
||||||
|
|
||||||
|
public NonNullVarsCalculator(boolean[] nonNullVars) {
|
||||||
|
this.nonNullVars = nonNullVars;
|
||||||
|
definedVars = new boolean[nonNullVars.length];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(VariableExpr expr) {
|
||||||
|
use(expr.getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(AssignmentStatement statement) {
|
||||||
|
statement.getRightValue().acceptVisitor(this);
|
||||||
|
if (statement.getLeftValue() instanceof VariableExpr) {
|
||||||
|
var index = ((VariableExpr) statement.getLeftValue()).getIndex();
|
||||||
|
define(index);
|
||||||
|
} else if (statement.getLeftValue() != null) {
|
||||||
|
statement.getLeftValue().acceptVisitor(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(BlockStatement statement) {
|
||||||
|
runInBlock(() -> super.visit(statement));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(WhileStatement statement) {
|
||||||
|
runInBlock(() -> super.visit(statement));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(SwitchStatement statement) {
|
||||||
|
statement.getValue().acceptVisitor(this);
|
||||||
|
for (var clause : statement.getClauses()) {
|
||||||
|
runInBlock(() -> visit(clause.getBody()));
|
||||||
|
}
|
||||||
|
runInBlock(() -> visit(statement.getDefaultClause()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(TryCatchStatement statement) {
|
||||||
|
runInBlock(() -> visit(statement.getProtectedBody()));
|
||||||
|
runInBlock(() -> visit(statement.getHandler()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ConditionalStatement statement) {
|
||||||
|
statement.getCondition().acceptVisitor(this);
|
||||||
|
runInBlock(() -> visit(statement.getConsequent()));
|
||||||
|
runInBlock(() -> visit(statement.getAlternative()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ConditionalExpr expr) {
|
||||||
|
expr.getCondition().acceptVisitor(this);
|
||||||
|
runInBlock(() -> expr.getConsequent().acceptVisitor(this));
|
||||||
|
runInBlock(() -> expr.getAlternative().acceptVisitor(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(BinaryExpr expr) {
|
||||||
|
switch (expr.getOperation()) {
|
||||||
|
case AND:
|
||||||
|
case OR:
|
||||||
|
expr.getFirstOperand().acceptVisitor(this);
|
||||||
|
runInBlock(() -> expr.getSecondOperand().acceptVisitor(this));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
super.visit(expr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runInBlock(Runnable action) {
|
||||||
|
var oldDefinedVars = definedVars;
|
||||||
|
definedVars = Arrays.copyOf(definedVars, definedVars.length);
|
||||||
|
action.run();
|
||||||
|
definedVars = oldDefinedVars;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void use(int index) {
|
||||||
|
if (!definedVars[index]) {
|
||||||
|
nonNullVars[index] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void define(int index) {
|
||||||
|
definedVars[index] = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import org.teavm.ast.RegularMethodNode;
|
||||||
import org.teavm.ast.decompilation.Decompiler;
|
import org.teavm.ast.decompilation.Decompiler;
|
||||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||||
|
@ -269,16 +270,29 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var nonNullableVars = new boolean[ast.getVariables().size()];
|
||||||
|
var preciseTypes = new PreciseValueType[ast.getVariables().size()];
|
||||||
for (var i = firstVar; i < ast.getVariables().size(); ++i) {
|
for (var i = firstVar; i < ast.getVariables().size(); ++i) {
|
||||||
var localVar = ast.getVariables().get(i);
|
|
||||||
var representative = method.getProgram().variableAt(variableRepresentatives[i]);
|
var representative = method.getProgram().variableAt(variableRepresentatives[i]);
|
||||||
var inferredType = typeInference.typeOf(representative);
|
var inferredType = typeInference.typeOf(representative);
|
||||||
if (inferredType == null) {
|
if (inferredType == null) {
|
||||||
inferredType = new PreciseValueType(ValueType.object("java.lang.Object"), false);
|
inferredType = new PreciseValueType(ValueType.object("java.lang.Object"), false);
|
||||||
}
|
}
|
||||||
var type = !inferredType.isArrayUnwrap
|
preciseTypes[i] = inferredType;
|
||||||
? typeMapper.mapType(inferredType.valueType)
|
nonNullableVars[i] = inferredType.isArrayUnwrap;
|
||||||
: classInfoProvider.getClassInfo(inferredType.valueType).getArray().getReference();
|
}
|
||||||
|
calculateNonNullableVars(nonNullableVars, ast);
|
||||||
|
|
||||||
|
for (var i = firstVar; i < ast.getVariables().size(); ++i) {
|
||||||
|
var localVar = ast.getVariables().get(i);
|
||||||
|
var inferredType = preciseTypes[i];
|
||||||
|
WasmType type;
|
||||||
|
if (!inferredType.isArrayUnwrap) {
|
||||||
|
type = typeMapper.mapType(inferredType.valueType);
|
||||||
|
} else {
|
||||||
|
var arrayType = classInfoProvider.getClassInfo(inferredType.valueType).getArray();
|
||||||
|
type = nonNullableVars[i] ? arrayType.getNonNullReference() : arrayType.getReference();
|
||||||
|
}
|
||||||
var wasmLocal = new WasmLocal(type, localVar.getName());
|
var wasmLocal = new WasmLocal(type, localVar.getName());
|
||||||
function.add(wasmLocal);
|
function.add(wasmLocal);
|
||||||
}
|
}
|
||||||
|
@ -289,6 +303,11 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
||||||
visitor.generate(ast.getBody(), function.getBody());
|
visitor.generate(ast.getBody(), function.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void calculateNonNullableVars(boolean[] nonNullVars, RegularMethodNode ast) {
|
||||||
|
var calculator = new NonNullVarsCalculator(nonNullVars);
|
||||||
|
ast.getBody().acceptVisitor(calculator);
|
||||||
|
}
|
||||||
|
|
||||||
private void generateNativeMethodBody(MethodHolder method, WasmFunction function) {
|
private void generateNativeMethodBody(MethodHolder method, WasmFunction function) {
|
||||||
var importAnnot = method.getAnnotations().get(Import.class.getName());
|
var importAnnot = method.getAnnotations().get(Import.class.getName());
|
||||||
if (importAnnot == null) {
|
if (importAnnot == null) {
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 konsoletyper.
|
||||||
|
*
|
||||||
|
* 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.model.optimization;
|
||||||
|
|
||||||
|
import org.teavm.model.Program;
|
||||||
|
import org.teavm.model.Variable;
|
||||||
|
import org.teavm.model.util.InstructionVariableMapper;
|
||||||
|
|
||||||
|
public class RedundantPhiElimination implements MethodOptimization {
|
||||||
|
@Override
|
||||||
|
public boolean optimize(MethodOptimizationContext context, Program program) {
|
||||||
|
var changed = false;
|
||||||
|
var map = new int[program.variableCount()];
|
||||||
|
for (var i = 0; i < map.length; ++i) {
|
||||||
|
map[i] = i;
|
||||||
|
}
|
||||||
|
for (var block : program.getBasicBlocks()) {
|
||||||
|
changed |= block.getPhis().removeIf(phi -> {
|
||||||
|
if (phi.getIncomings().isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Variable singleInput = null;
|
||||||
|
for (var incoming : phi.getIncomings()) {
|
||||||
|
if (incoming.getValue() != phi.getReceiver()) {
|
||||||
|
if (singleInput == null) {
|
||||||
|
singleInput = incoming.getValue();
|
||||||
|
} else if (singleInput != incoming.getValue()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (singleInput != null) {
|
||||||
|
map[phi.getReceiver().getIndex()] = map[singleInput.getIndex()];
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
var mapper = new InstructionVariableMapper(v -> program.variableAt(map(map, v.getIndex())));
|
||||||
|
for (var block : program.getBasicBlocks()) {
|
||||||
|
mapper.apply(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int map(int[] array, int index) {
|
||||||
|
var result = array[index];
|
||||||
|
if (result != index) {
|
||||||
|
var newResult = map(array, result);
|
||||||
|
if (newResult != result) {
|
||||||
|
array[index] = newResult;
|
||||||
|
}
|
||||||
|
result = newResult;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -88,6 +88,7 @@ import org.teavm.model.optimization.MethodOptimization;
|
||||||
import org.teavm.model.optimization.MethodOptimizationContext;
|
import org.teavm.model.optimization.MethodOptimizationContext;
|
||||||
import org.teavm.model.optimization.RedundantJumpElimination;
|
import org.teavm.model.optimization.RedundantJumpElimination;
|
||||||
import org.teavm.model.optimization.RedundantNullCheckElimination;
|
import org.teavm.model.optimization.RedundantNullCheckElimination;
|
||||||
|
import org.teavm.model.optimization.RedundantPhiElimination;
|
||||||
import org.teavm.model.optimization.RepeatedFieldReadElimination;
|
import org.teavm.model.optimization.RepeatedFieldReadElimination;
|
||||||
import org.teavm.model.optimization.ScalarReplacement;
|
import org.teavm.model.optimization.ScalarReplacement;
|
||||||
import org.teavm.model.optimization.SystemArrayCopyOptimization;
|
import org.teavm.model.optimization.SystemArrayCopyOptimization;
|
||||||
|
@ -830,6 +831,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
if (target.needsSystemArrayCopyOptimization()) {
|
if (target.needsSystemArrayCopyOptimization()) {
|
||||||
optimizations.add(new SystemArrayCopyOptimization());
|
optimizations.add(new SystemArrayCopyOptimization());
|
||||||
}
|
}
|
||||||
|
optimizations.add(new RedundantPhiElimination());
|
||||||
return optimizations;
|
return optimizations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user