mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04: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);
|
||||
var instanceLocal = new WasmLocal(standardClasses.objectClass().getType(), "instance");
|
||||
var originalLocal = new WasmLocal(objectStructure.getReference(), "original");
|
||||
var resultLocal = new WasmLocal(objectStructure.getReference(), "result");
|
||||
var originalDataLocal = new WasmLocal(arrayType.getReference(), "originalData");
|
||||
var dataCopyLocal = new WasmLocal(arrayType.getReference(), "resultData");
|
||||
var originalDataLocal = new WasmLocal(arrayType.getNonNullReference(), "originalData");
|
||||
var dataCopyLocal = new WasmLocal(arrayType.getNonNullReference(), "resultData");
|
||||
function.add(instanceLocal);
|
||||
function.add(originalLocal);
|
||||
function.add(resultLocal);
|
||||
function.add(originalDataLocal);
|
||||
function.add(dataCopyLocal);
|
||||
|
||||
var newExpr = new WasmStructNew(objectStructure);
|
||||
function.getBody().add(new WasmSetLocal(originalLocal,
|
||||
new WasmCast(new WasmGetLocal(instanceLocal), objectStructure.getNonNullReference())));
|
||||
function.getBody().add(new WasmSetLocal(resultLocal, new WasmStructNewDefault(objectStructure)));
|
||||
|
||||
var classValue = new WasmStructGet(objectStructure, new WasmGetLocal(originalLocal),
|
||||
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET);
|
||||
function.getBody().add(new WasmStructSet(objectStructure, new WasmGetLocal(resultLocal),
|
||||
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET, classValue));
|
||||
newExpr.getInitializers().add(classValue);
|
||||
newExpr.getInitializers().add(new WasmNullConstant(WasmType.Reference.EQ));
|
||||
|
||||
var originalDataValue = new WasmStructGet(objectStructure, new WasmGetLocal(originalLocal),
|
||||
WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET);
|
||||
function.getBody().add(new WasmSetLocal(originalDataLocal, originalDataValue));
|
||||
var originalLength = new WasmArrayLength(new WasmGetLocal(originalDataLocal));
|
||||
function.getBody().add(new WasmSetLocal(dataCopyLocal, new WasmArrayNewDefault(arrayType, originalLength)));
|
||||
function.getBody().add(new WasmStructSet(objectStructure, new WasmGetLocal(resultLocal),
|
||||
WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET, new WasmGetLocal(dataCopyLocal)));
|
||||
newExpr.getInitializers().add(new WasmGetLocal(dataCopyLocal));
|
||||
|
||||
function.getBody().add(new WasmArrayCopy(arrayType, new WasmGetLocal(dataCopyLocal),
|
||||
new WasmInt32Constant(0), arrayType, new WasmGetLocal(originalDataLocal),
|
||||
new WasmInt32Constant(0), new WasmArrayLength(new WasmGetLocal(originalDataLocal))));
|
||||
|
||||
function.getBody().add(new WasmGetLocal(resultLocal));
|
||||
|
||||
function.getBody().add(newExpr);
|
||||
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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -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.Queue;
|
||||
import java.util.Set;
|
||||
import org.teavm.ast.RegularMethodNode;
|
||||
import org.teavm.ast.decompilation.Decompiler;
|
||||
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
|
||||
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) {
|
||||
var localVar = ast.getVariables().get(i);
|
||||
var representative = method.getProgram().variableAt(variableRepresentatives[i]);
|
||||
var inferredType = typeInference.typeOf(representative);
|
||||
if (inferredType == null) {
|
||||
inferredType = new PreciseValueType(ValueType.object("java.lang.Object"), false);
|
||||
}
|
||||
var type = !inferredType.isArrayUnwrap
|
||||
? typeMapper.mapType(inferredType.valueType)
|
||||
: classInfoProvider.getClassInfo(inferredType.valueType).getArray().getReference();
|
||||
preciseTypes[i] = inferredType;
|
||||
nonNullableVars[i] = inferredType.isArrayUnwrap;
|
||||
}
|
||||
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());
|
||||
function.add(wasmLocal);
|
||||
}
|
||||
|
@ -289,6 +303,11 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
|||
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) {
|
||||
var importAnnot = method.getAnnotations().get(Import.class.getName());
|
||||
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.RedundantJumpElimination;
|
||||
import org.teavm.model.optimization.RedundantNullCheckElimination;
|
||||
import org.teavm.model.optimization.RedundantPhiElimination;
|
||||
import org.teavm.model.optimization.RepeatedFieldReadElimination;
|
||||
import org.teavm.model.optimization.ScalarReplacement;
|
||||
import org.teavm.model.optimization.SystemArrayCopyOptimization;
|
||||
|
@ -830,6 +831,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
if (target.needsSystemArrayCopyOptimization()) {
|
||||
optimizations.add(new SystemArrayCopyOptimization());
|
||||
}
|
||||
optimizations.add(new RedundantPhiElimination());
|
||||
return optimizations;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user