mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-08 07:54:11 -08:00
Recognize array initialization pattern in bytecode and translate it to array initializer in target platform
This commit is contained in:
parent
66250cb125
commit
37e6ca3e17
58
core/src/main/java/org/teavm/ast/ArrayFromDataExpr.java
Normal file
58
core/src/main/java/org/teavm/ast/ArrayFromDataExpr.java
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2016 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.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public class ArrayFromDataExpr extends Expr {
|
||||
private ValueType type;
|
||||
private final List<Expr> data = new ArrayList<>();
|
||||
|
||||
public ValueType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(ValueType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public List<Expr> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(ExprVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Expr clone(Map<Expr, Expr> cache) {
|
||||
Expr known = cache.get(this);
|
||||
if (known != null) {
|
||||
return known;
|
||||
}
|
||||
ArrayFromDataExpr copy = new ArrayFromDataExpr();
|
||||
cache.put(this, copy);
|
||||
copy.setType(type);
|
||||
for (Expr elem : data) {
|
||||
copy.data.add(elem.clone(cache));
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
}
|
|
@ -40,6 +40,8 @@ public interface ExprVisitor {
|
|||
|
||||
void visit(NewMultiArrayExpr expr);
|
||||
|
||||
void visit(ArrayFromDataExpr expr);
|
||||
|
||||
void visit(InstanceOfExpr expr);
|
||||
|
||||
void visit(CastExpr expr);
|
||||
|
|
|
@ -52,7 +52,7 @@ public class NewArrayExpr extends Expr {
|
|||
NewArrayExpr copy = new NewArrayExpr();
|
||||
cache.put(this, copy);
|
||||
copy.setType(type);
|
||||
copy.setLength(length != null ? length.clone() : null);
|
||||
copy.setLength(length != null ? length.clone(cache) : null);
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -171,6 +171,15 @@ public class RecursiveVisitor implements ExprVisitor, StatementVisitor {
|
|||
afterVisit(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ArrayFromDataExpr expr) {
|
||||
beforeVisit(expr);
|
||||
for (Expr element : expr.getData()) {
|
||||
element.acceptVisitor(this);
|
||||
}
|
||||
afterVisit(expr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ReturnStatement statement) {
|
||||
if (statement.getResult() != null) {
|
||||
|
|
|
@ -23,6 +23,8 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import org.teavm.ast.ArrayFromDataExpr;
|
||||
import org.teavm.ast.ArrayType;
|
||||
import org.teavm.ast.AssignmentStatement;
|
||||
import org.teavm.ast.BinaryExpr;
|
||||
import org.teavm.ast.BinaryOperation;
|
||||
|
@ -63,6 +65,7 @@ import org.teavm.ast.UnwrapArrayExpr;
|
|||
import org.teavm.ast.VariableExpr;
|
||||
import org.teavm.ast.WhileStatement;
|
||||
import org.teavm.model.TextLocation;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||
private static final int MAX_DEPTH = 20;
|
||||
|
@ -78,6 +81,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
private TextLocation currentLocation;
|
||||
private Deque<TextLocation> locationStack = new LinkedList<>();
|
||||
private Deque<TextLocation> notNullLocationStack = new ArrayDeque<>();
|
||||
private List<ArrayOptimization> pendingArrayOptimizations;
|
||||
|
||||
OptimizingVisitor(boolean[] preservedVars, int[] writeFrequencies, int[] readFrequencies, Object[] constants,
|
||||
boolean friendlyToDebugger) {
|
||||
|
@ -505,6 +509,21 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ArrayFromDataExpr expr) {
|
||||
pushLocation(expr.getLocation());
|
||||
try {
|
||||
for (int i = 0; i < expr.getData().size(); ++i) {
|
||||
Expr element = expr.getData().get(i);
|
||||
element.acceptVisitor(this);
|
||||
expr.getData().set(i, resultExpr);
|
||||
}
|
||||
resultExpr = expr;
|
||||
} finally {
|
||||
popLocation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(InstanceOfExpr expr) {
|
||||
pushLocation(expr.getLocation());
|
||||
|
@ -580,10 +599,13 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
private List<Statement> processSequence(List<Statement> statements) {
|
||||
List<Statement> backup = resultSequence;
|
||||
resultSequence = new ArrayList<>();
|
||||
List<ArrayOptimization> pendingArrayOptimizationsBackup = pendingArrayOptimizations;
|
||||
pendingArrayOptimizations = new ArrayList<>();
|
||||
processSequenceImpl(statements);
|
||||
wieldTryCatch(resultSequence);
|
||||
List<Statement> result = resultSequence.stream().filter(part -> part != null).collect(Collectors.toList());
|
||||
resultSequence = backup;
|
||||
pendingArrayOptimizations = pendingArrayOptimizationsBackup;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -604,6 +626,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
continue;
|
||||
}
|
||||
resultSequence.add(part);
|
||||
tryArrayOptimization();
|
||||
if (part instanceof BreakStatement) {
|
||||
return false;
|
||||
}
|
||||
|
@ -611,6 +634,153 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
return true;
|
||||
}
|
||||
|
||||
private void tryArrayOptimization() {
|
||||
Statement statement;
|
||||
while (!pendingArrayOptimizations.isEmpty()) {
|
||||
statement = resultSequence.get(resultSequence.size() - 1);
|
||||
int i = pendingArrayOptimizations.size() - 1;
|
||||
if (!tryArrayUnwrap(pendingArrayOptimizations.get(i), statement)
|
||||
|| tryArraySet(pendingArrayOptimizations.get(i), statement)) {
|
||||
pendingArrayOptimizations.remove(i);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
statement = resultSequence.get(resultSequence.size() - 1);
|
||||
tryArrayConstruction(statement);
|
||||
}
|
||||
|
||||
private void tryArrayConstruction(Statement statement) {
|
||||
if (!(statement instanceof AssignmentStatement)) {
|
||||
return;
|
||||
}
|
||||
AssignmentStatement assign = (AssignmentStatement) statement;
|
||||
|
||||
if (!(assign.getLeftValue() instanceof VariableExpr)) {
|
||||
return;
|
||||
}
|
||||
int constructedArrayVariable = ((VariableExpr) assign.getLeftValue()).getIndex();
|
||||
|
||||
if (!(assign.getRightValue() instanceof NewArrayExpr)) {
|
||||
return;
|
||||
}
|
||||
NewArrayExpr constructedArray = (NewArrayExpr) assign.getRightValue();
|
||||
if (!(constructedArray.getLength() instanceof ConstantExpr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object sizeConst = ((ConstantExpr) constructedArray.getLength()).getValue();
|
||||
if (!(sizeConst instanceof Integer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int constructedArraySize = (int) sizeConst;
|
||||
ArrayOptimization optimization = new ArrayOptimization();
|
||||
optimization.index = resultSequence.size() - 1;
|
||||
optimization.arrayVariable = constructedArrayVariable;
|
||||
optimization.arraySize = constructedArraySize;
|
||||
optimization.array = constructedArray;
|
||||
pendingArrayOptimizations.add(optimization);
|
||||
}
|
||||
|
||||
private boolean tryArrayUnwrap(ArrayOptimization optimization, Statement statement) {
|
||||
if (optimization.unwrappedArray != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(statement instanceof AssignmentStatement)) {
|
||||
return false;
|
||||
}
|
||||
AssignmentStatement assign = (AssignmentStatement) statement;
|
||||
|
||||
if (!(assign.getLeftValue() instanceof VariableExpr)) {
|
||||
return false;
|
||||
}
|
||||
optimization.unwrappedArrayVariable = ((VariableExpr) assign.getLeftValue()).getIndex();
|
||||
if (writeFrequencies[optimization.unwrappedArrayVariable] != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(assign.getRightValue() instanceof UnwrapArrayExpr)) {
|
||||
return false;
|
||||
}
|
||||
optimization.unwrappedArray = (UnwrapArrayExpr) assign.getRightValue();
|
||||
|
||||
if (!(optimization.unwrappedArray.getArray() instanceof VariableExpr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VariableExpr arrayVar = (VariableExpr) optimization.unwrappedArray.getArray();
|
||||
if (arrayVar.getIndex() != optimization.arrayVariable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!matchArrayType(optimization.array.getType(), optimization.unwrappedArray.getElementType())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (optimization.arraySize != readFrequencies[optimization.unwrappedArrayVariable]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
optimization.arrayElementIndex = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean tryArraySet(ArrayOptimization optimization, Statement statement) {
|
||||
int expectedIndex = optimization.index + 2 + optimization.arrayElementIndex;
|
||||
if (resultSequence.size() - 1 != expectedIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(statement instanceof AssignmentStatement)) {
|
||||
return false;
|
||||
}
|
||||
AssignmentStatement assign = (AssignmentStatement) statement;
|
||||
|
||||
if (!(assign.getLeftValue() instanceof SubscriptExpr)) {
|
||||
return false;
|
||||
}
|
||||
SubscriptExpr subscript = (SubscriptExpr) assign.getLeftValue();
|
||||
|
||||
if (subscript.getType() != optimization.unwrappedArray.getElementType()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(subscript.getArray() instanceof VariableExpr)) {
|
||||
return false;
|
||||
}
|
||||
if (((VariableExpr) subscript.getArray()).getIndex() != optimization.unwrappedArrayVariable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(subscript.getIndex() instanceof ConstantExpr)) {
|
||||
return false;
|
||||
}
|
||||
Object constantValue = ((ConstantExpr) subscript.getIndex()).getValue();
|
||||
if (!Integer.valueOf(optimization.arrayElementIndex).equals(constantValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
optimization.elements.add(assign.getRightValue());
|
||||
if (++optimization.arrayElementIndex == optimization.arraySize) {
|
||||
applyArrayOptimization(optimization);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void applyArrayOptimization(ArrayOptimization optimization) {
|
||||
AssignmentStatement assign = (AssignmentStatement) resultSequence.get(optimization.index);
|
||||
ArrayFromDataExpr arrayFromData = new ArrayFromDataExpr();
|
||||
arrayFromData.setLocation(optimization.array.getLocation());
|
||||
arrayFromData.setType(optimization.array.getType());
|
||||
arrayFromData.getData().addAll(optimization.elements);
|
||||
assign.setRightValue(arrayFromData);
|
||||
readFrequencies[optimization.arrayVariable]--;
|
||||
resultSequence.subList(optimization.index + 1, resultSequence.size()).clear();
|
||||
}
|
||||
|
||||
private void wieldTryCatch(List<Statement> statements) {
|
||||
for (int i = 0; i < statements.size() - 1; ++i) {
|
||||
if (statements.get(i) instanceof TryCatchStatement && statements.get(i + 1) instanceof TryCatchStatement) {
|
||||
|
@ -645,6 +815,29 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
return false;
|
||||
}
|
||||
|
||||
private static boolean matchArrayType(ValueType type, ArrayType arrayType) {
|
||||
switch (arrayType) {
|
||||
case BYTE:
|
||||
return type == ValueType.BYTE || type == ValueType.BOOLEAN;
|
||||
case SHORT:
|
||||
return type == ValueType.SHORT;
|
||||
case CHAR:
|
||||
return type == ValueType.CHARACTER;
|
||||
case INT:
|
||||
return type == ValueType.INTEGER;
|
||||
case LONG:
|
||||
return type == ValueType.LONG;
|
||||
case FLOAT:
|
||||
return type == ValueType.FLOAT;
|
||||
case DOUBLE:
|
||||
return type == ValueType.DOUBLE;
|
||||
case OBJECT:
|
||||
return type instanceof ValueType.Object || type instanceof ValueType.Array;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void eliminateRedundantBreaks(List<Statement> statements, IdentifiedStatement exit) {
|
||||
if (statements.isEmpty()) {
|
||||
return;
|
||||
|
@ -1122,4 +1315,15 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
static class ArrayOptimization {
|
||||
int index;
|
||||
NewArrayExpr array;
|
||||
int arrayVariable;
|
||||
UnwrapArrayExpr unwrappedArray;
|
||||
int unwrappedArrayVariable;
|
||||
int arrayElementIndex;
|
||||
int arraySize;
|
||||
List<Expr> elements = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.teavm.ast.ArrayFromDataExpr;
|
||||
import org.teavm.ast.ArrayType;
|
||||
import org.teavm.ast.AssignmentStatement;
|
||||
import org.teavm.ast.BinaryExpr;
|
||||
|
@ -947,6 +948,69 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
popLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ArrayFromDataExpr expr) {
|
||||
pushLocation(expr.getLocation());
|
||||
|
||||
boolean needParenthesis = false;
|
||||
if (needsCallSiteId()) {
|
||||
needParenthesis = true;
|
||||
withCallSite();
|
||||
}
|
||||
|
||||
if (expr.getType() instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) expr.getType()).getKind()) {
|
||||
case BOOLEAN:
|
||||
writer.print("teavm_fillBooleanArray");
|
||||
break;
|
||||
case BYTE:
|
||||
writer.print("teavm_fillByteArray");
|
||||
break;
|
||||
case SHORT:
|
||||
writer.print("teavm_fillShortArray");
|
||||
break;
|
||||
case CHARACTER:
|
||||
writer.print("teavm_fillCharArray");
|
||||
break;
|
||||
case INTEGER:
|
||||
writer.print("teavm_fillIntArray");
|
||||
break;
|
||||
case LONG:
|
||||
writer.print("teavm_fillLongArray");
|
||||
break;
|
||||
case FLOAT:
|
||||
writer.print("teavm_fillFloatArray");
|
||||
break;
|
||||
case DOUBLE:
|
||||
writer.print("teavm_fillDoubleArray");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
writer.print("teavm_fillArray");
|
||||
}
|
||||
writer.print("(");
|
||||
|
||||
ValueType type = ValueType.arrayOf(expr.getType());
|
||||
writer.print(names.forMethod(ALLOC_ARRAY_METHOD)).print("(&")
|
||||
.print(names.forClassInstance(type)).print(", ");
|
||||
classContext.importMethod(ALLOC_ARRAY_METHOD, true);
|
||||
includes.includeType(type);
|
||||
writer.print(expr.getData().size() + ")");
|
||||
|
||||
for (Expr element : expr.getData()) {
|
||||
writer.print(", ");
|
||||
element.acceptVisitor(this);
|
||||
}
|
||||
|
||||
writer.print(")");
|
||||
|
||||
if (needParenthesis) {
|
||||
writer.print(")");
|
||||
}
|
||||
|
||||
popLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewMultiArrayExpr expr) {
|
||||
pushLocation(expr.getLocation());
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package org.teavm.backend.javascript.rendering;
|
||||
|
||||
import java.util.Set;
|
||||
import org.teavm.ast.ArrayFromDataExpr;
|
||||
import org.teavm.ast.AssignmentStatement;
|
||||
import org.teavm.ast.AsyncMethodNode;
|
||||
import org.teavm.ast.AsyncMethodPart;
|
||||
|
@ -295,6 +296,42 @@ class NameFrequencyEstimator extends RecursiveVisitor implements MethodNodeVisit
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ArrayFromDataExpr expr) {
|
||||
super.visit(expr);
|
||||
visitType(expr.getType());
|
||||
if (expr.getType() instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) expr.getType()).getKind()) {
|
||||
case BOOLEAN:
|
||||
consumer.consumeFunction("$rt_createBooleanArrayFromData");
|
||||
break;
|
||||
case BYTE:
|
||||
consumer.consumeFunction("$rt_createByteArrayFromData");
|
||||
break;
|
||||
case SHORT:
|
||||
consumer.consumeFunction("$rt_createShortArrayFromData");
|
||||
break;
|
||||
case CHARACTER:
|
||||
consumer.consumeFunction("$rt_createCharArrayFromData");
|
||||
break;
|
||||
case INTEGER:
|
||||
consumer.consumeFunction("$rt_createIntArrayFromData");
|
||||
break;
|
||||
case LONG:
|
||||
consumer.consumeFunction("$rt_createLongArrayFromData");
|
||||
break;
|
||||
case FLOAT:
|
||||
consumer.consumeFunction("$rt_createFloatArrayFromData");
|
||||
break;
|
||||
case DOUBLE:
|
||||
consumer.consumeFunction("$rt_createDoubleArrayFromData");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
consumer.consumeFunction("$rt_createArrayFromData");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewMultiArrayExpr expr) {
|
||||
super.visit(expr);
|
||||
|
|
|
@ -255,7 +255,10 @@ public class Renderer implements RenderingManager {
|
|||
"$rt_s", "$rt_eraseClinit", "$rt_imul", "$rt_wrapException", "$rt_checkBounds",
|
||||
"$rt_checkUpperBound", "$rt_checkLowerBound", "$rt_wrapFunction0", "$rt_wrapFunction1",
|
||||
"$rt_wrapFunction2", "$rt_wrapFunction3", "$rt_wrapFunction4",
|
||||
"$rt_classWithoutFields" };
|
||||
"$rt_classWithoutFields", "$rt_createArrayFromData", "$rt_createCharArrayFromData",
|
||||
"$rt_createByteArrayFromData", "$rt_createShortArrayFromData", "$rt_createIntArrayFromData",
|
||||
"$rt_createBooleanArrayFromData", "$rt_createFloatArrayFromData", "$rt_createDoubleArrayFromData",
|
||||
"$rt_createLongArrayFromData" };
|
||||
boolean first = true;
|
||||
for (String name : names) {
|
||||
if (!first) {
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import org.teavm.ast.ArrayFromDataExpr;
|
||||
import org.teavm.ast.AssignmentStatement;
|
||||
import org.teavm.ast.BinaryExpr;
|
||||
import org.teavm.ast.BinaryOperation;
|
||||
|
@ -1326,6 +1327,71 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ArrayFromDataExpr expr) {
|
||||
try {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
ValueType type = expr.getType();
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) type).getKind()) {
|
||||
case BOOLEAN:
|
||||
writer.appendFunction("$rt_createBooleanArrayFromData");
|
||||
break;
|
||||
case BYTE:
|
||||
writer.appendFunction("$rt_createByteArrayFromData");
|
||||
break;
|
||||
case SHORT:
|
||||
writer.appendFunction("$rt_createShortArrayFromData");
|
||||
break;
|
||||
case INTEGER:
|
||||
writer.appendFunction("$rt_createIntArrayFromData");
|
||||
break;
|
||||
case LONG:
|
||||
writer.appendFunction("$rt_createLongArrayFromData");
|
||||
break;
|
||||
case FLOAT:
|
||||
writer.appendFunction("$rt_createFloatArrayFromData");
|
||||
break;
|
||||
case DOUBLE:
|
||||
writer.appendFunction("$rt_createDoubleArrayFromData");
|
||||
break;
|
||||
case CHARACTER:
|
||||
writer.appendFunction("$rt_createCharArrayFromData");
|
||||
break;
|
||||
}
|
||||
writer.append("(");
|
||||
} else {
|
||||
writer.appendFunction("$rt_createArrayFromData").append("(");
|
||||
context.typeToClsString(writer, expr.getType());
|
||||
writer.append(",").ws();
|
||||
}
|
||||
|
||||
writer.append("[");
|
||||
writeCommaSeparated(expr.getData());
|
||||
writer.append("])");
|
||||
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occurred", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeCommaSeparated(List<Expr> expressions) throws IOException {
|
||||
boolean first = true;
|
||||
for (Expr element : expressions) {
|
||||
if (!first) {
|
||||
writer.append(",").ws();
|
||||
}
|
||||
first = false;
|
||||
precedence = Precedence.min();
|
||||
element.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewMultiArrayExpr expr) {
|
||||
try {
|
||||
|
|
|
@ -25,6 +25,8 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.teavm.ast.ArrayFromDataExpr;
|
||||
import org.teavm.ast.ArrayType;
|
||||
import org.teavm.ast.AssignmentStatement;
|
||||
import org.teavm.ast.BinaryExpr;
|
||||
import org.teavm.ast.BlockStatement;
|
||||
|
@ -524,32 +526,34 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
|
||||
private void storeArrayItem(SubscriptExpr leftValue, Expr rightValue) {
|
||||
WasmExpression ptr = getArrayElementPointer(leftValue);
|
||||
accept(rightValue);
|
||||
leftValue.getArray().acceptVisitor(this);
|
||||
WasmExpression array = result;
|
||||
leftValue.getIndex().acceptVisitor(this);
|
||||
WasmExpression index = result;
|
||||
rightValue.acceptVisitor(this);
|
||||
WasmExpression value = result;
|
||||
result = storeArrayItem(getArrayElementPointer(array, index, leftValue.getType()), value, leftValue.getType());
|
||||
}
|
||||
|
||||
switch (leftValue.getType()) {
|
||||
private static WasmExpression storeArrayItem(WasmExpression array, WasmExpression value, ArrayType type) {
|
||||
switch (type) {
|
||||
case BYTE:
|
||||
result = new WasmStoreInt32(1, ptr, result, WasmInt32Subtype.INT8);
|
||||
break;
|
||||
return new WasmStoreInt32(1, array, value, WasmInt32Subtype.INT8);
|
||||
case SHORT:
|
||||
result = new WasmStoreInt32(2, ptr, result, WasmInt32Subtype.INT16);
|
||||
break;
|
||||
return new WasmStoreInt32(2, array, value, WasmInt32Subtype.INT16);
|
||||
case CHAR:
|
||||
result = new WasmStoreInt32(2, ptr, result, WasmInt32Subtype.UINT16);
|
||||
break;
|
||||
return new WasmStoreInt32(2, array, value, WasmInt32Subtype.UINT16);
|
||||
case INT:
|
||||
case OBJECT:
|
||||
result = new WasmStoreInt32(4, ptr, result, WasmInt32Subtype.INT32);
|
||||
break;
|
||||
return new WasmStoreInt32(4, array, value, WasmInt32Subtype.INT32);
|
||||
case LONG:
|
||||
result = new WasmStoreInt64(8, ptr, result, WasmInt64Subtype.INT64);
|
||||
break;
|
||||
return new WasmStoreInt64(8, array, value, WasmInt64Subtype.INT64);
|
||||
case FLOAT:
|
||||
result = new WasmStoreFloat32(4, ptr, result);
|
||||
break;
|
||||
return new WasmStoreFloat32(4, array, value);
|
||||
case DOUBLE:
|
||||
result = new WasmStoreFloat64(8, ptr, result);
|
||||
break;
|
||||
return new WasmStoreFloat64(8, array, value);
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -666,14 +670,16 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
|
||||
private WasmExpression getArrayElementPointer(SubscriptExpr expr) {
|
||||
accept(expr.getArray());
|
||||
expr.getArray().acceptVisitor(this);
|
||||
WasmExpression array = result;
|
||||
|
||||
accept(expr.getIndex());
|
||||
expr.getIndex().acceptVisitor(this);
|
||||
WasmExpression index = result;
|
||||
return getArrayElementPointer(array, index, expr.getType());
|
||||
}
|
||||
|
||||
private WasmExpression getArrayElementPointer(WasmExpression array, WasmExpression index, ArrayType type) {
|
||||
int size = -1;
|
||||
switch (expr.getType()) {
|
||||
switch (type) {
|
||||
case BYTE:
|
||||
size = 0;
|
||||
break;
|
||||
|
@ -1236,6 +1242,62 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
|||
result = call;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ArrayFromDataExpr expr) {
|
||||
ValueType type = expr.getType();
|
||||
|
||||
ArrayType arrayType = ArrayType.OBJECT;
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) type).getKind()) {
|
||||
case BOOLEAN:
|
||||
case BYTE:
|
||||
arrayType = ArrayType.BYTE;
|
||||
break;
|
||||
case SHORT:
|
||||
arrayType = ArrayType.SHORT;
|
||||
break;
|
||||
case CHARACTER:
|
||||
arrayType = ArrayType.CHAR;
|
||||
break;
|
||||
case INTEGER:
|
||||
arrayType = ArrayType.INT;
|
||||
break;
|
||||
case LONG:
|
||||
arrayType = ArrayType.LONG;
|
||||
break;
|
||||
case FLOAT:
|
||||
arrayType = ArrayType.FLOAT;
|
||||
break;
|
||||
case DOUBLE:
|
||||
arrayType = ArrayType.DOUBLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WasmBlock block = new WasmBlock(false);
|
||||
|
||||
WasmLocal array = getTemporary(WasmType.INT32);
|
||||
int classPointer = classGenerator.getClassPointer(ValueType.arrayOf(type));
|
||||
String allocName = context.names.forMethod(new MethodReference(Allocator.class, "allocateArray",
|
||||
RuntimeClass.class, int.class, Address.class));
|
||||
WasmCall call = new WasmCall(allocName);
|
||||
call.getArguments().add(new WasmInt32Constant(classPointer));
|
||||
call.getArguments().add(new WasmInt32Constant(expr.getData().size()));
|
||||
call.setLocation(expr.getLocation());
|
||||
block.getBody().add(new WasmSetLocal(array, call));
|
||||
|
||||
for (int i = 0; i < expr.getData().size(); ++i) {
|
||||
WasmExpression ptr = getArrayElementPointer(new WasmGetLocal(array), new WasmInt32Constant(i), arrayType);
|
||||
expr.getData().get(i).acceptVisitor(this);
|
||||
block.getBody().add(storeArrayItem(ptr, result, arrayType));
|
||||
}
|
||||
|
||||
block.getBody().add(new WasmGetLocal(array));
|
||||
block.setLocation(expr.getLocation());
|
||||
|
||||
result = block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewMultiArrayExpr expr) {
|
||||
ValueType type = expr.getType();
|
||||
|
|
24
core/src/main/java/org/teavm/cache/AstIO.java
vendored
24
core/src/main/java/org/teavm/cache/AstIO.java
vendored
|
@ -22,6 +22,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import org.teavm.ast.ArrayFromDataExpr;
|
||||
import org.teavm.ast.ArrayType;
|
||||
import org.teavm.ast.AssignmentStatement;
|
||||
import org.teavm.ast.AsyncMethodNode;
|
||||
|
@ -682,6 +683,20 @@ public class AstIO {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ArrayFromDataExpr expr) {
|
||||
try {
|
||||
output.writeUnsigned(28);
|
||||
output.writeUnsigned(symbolTable.lookup(expr.getType().toString()));
|
||||
output.writeUnsigned(expr.getData().size());
|
||||
for (Expr element : expr.getData()) {
|
||||
writeExpr(element);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IOExceptionWrapper(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(InstanceOfExpr expr) {
|
||||
try {
|
||||
|
@ -1117,6 +1132,15 @@ public class AstIO {
|
|||
expr.setLower(true);
|
||||
return expr;
|
||||
}
|
||||
case 28: {
|
||||
ArrayFromDataExpr expr = new ArrayFromDataExpr();
|
||||
expr.setType(ValueType.parse(symbolTable.at(input.readUnsigned())));
|
||||
int count = input.readUnsigned();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
expr.getData().add(readExpr(input));
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
default:
|
||||
throw new RuntimeException("Unknown expression type: " + type);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#if TEAVM_INCREMENTAL
|
||||
#include "virtcall.h"
|
||||
|
@ -70,4 +71,26 @@ void teavm_initClasses() {
|
|||
for (int i = 0; i < teavm_classReferencesCount; ++i) {
|
||||
teavm_classReferences[i]->parent.header = classHeader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define TEAVM_FILL_ARRAY_F(name, type, arrayType) \
|
||||
void* name(void* array, ...) { \
|
||||
type* data = TEAVM_ARRAY_DATA(array, type); \
|
||||
int32_t size = TEAVM_ARRAY_LENGTH(array); \
|
||||
va_list args; \
|
||||
va_start(args, array); \
|
||||
for (int32_t i = 0; i < size; ++i) { \
|
||||
*data++ = (type) va_arg(args, arrayType); \
|
||||
} \
|
||||
va_end(args); \
|
||||
}
|
||||
|
||||
TEAVM_FILL_ARRAY_F(teavm_fillArray, void*, void*)
|
||||
TEAVM_FILL_ARRAY_F(teavm_fillBooleanArray, int8_t, int)
|
||||
TEAVM_FILL_ARRAY_F(teavm_fillByteArray, int8_t, int)
|
||||
TEAVM_FILL_ARRAY_F(teavm_fillShortArray, int16_t, int)
|
||||
TEAVM_FILL_ARRAY_F(teavm_fillCharArray, char16_t, int)
|
||||
TEAVM_FILL_ARRAY_F(teavm_fillIntArray, int32_t, int)
|
||||
TEAVM_FILL_ARRAY_F(teavm_fillLongArray, int64_t, int64_t)
|
||||
TEAVM_FILL_ARRAY_F(teavm_fillFloatArray, float, double)
|
||||
TEAVM_FILL_ARRAY_F(teavm_fillDoubleArray, double, double)
|
||||
|
|
|
@ -185,4 +185,14 @@ extern void teavm_initClasses();
|
|||
inline static void teavm_gc_writeBarrier(void* object) {
|
||||
intptr_t offset = (intptr_t) ((char*) object - (char*) teavm_gc_heapAddress) / teavm_gc_regionSize;
|
||||
((char*) teavm_gc_cardTable)[offset] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern void* teavm_fillArray(void* array, ...);
|
||||
extern void* teavm_fillBooleanArray(void* array, ...);
|
||||
extern void* teavm_fillByteArray(void* array, ...);
|
||||
extern void* teavm_fillShortArray(void* array, ...);
|
||||
extern void* teavm_fillCharArray(void* array, ...);
|
||||
extern void* teavm_fillIntArray(void* array, ...);
|
||||
extern void* teavm_fillLongArray(void* array, ...);
|
||||
extern void* teavm_fillFloatArray(void* array, ...);
|
||||
extern void* teavm_fillDoubleArray(void* array, ...);
|
||||
|
|
|
@ -62,9 +62,11 @@ Array.prototype.fill = Array.prototype.fill || function(value,start,end) {
|
|||
};
|
||||
function $rt_createArray(cls, sz) {
|
||||
var data = new Array(sz);
|
||||
var arr = new $rt_array(cls, data);
|
||||
data.fill(null);
|
||||
return arr;
|
||||
return new $rt_array(cls, data);
|
||||
}
|
||||
function $rt_createArrayFromData(cls, init) {
|
||||
return $rt_wrapArray(cls, init);
|
||||
}
|
||||
function $rt_wrapArray(cls, data) {
|
||||
return new $rt_array(cls, data);
|
||||
|
@ -78,30 +80,68 @@ function $rt_createLongArray(sz) {
|
|||
data.fill(Long_ZERO);
|
||||
return arr;
|
||||
}
|
||||
function $rt_createLongArrayFromData(init) {
|
||||
return new $rt_array($rt_longcls(), init);
|
||||
}
|
||||
function $rt_createNumericArray(cls, nativeArray) {
|
||||
return new $rt_array(cls, nativeArray);
|
||||
}
|
||||
function $rt_createCharArray(sz) {
|
||||
return $rt_createNumericArray($rt_charcls(), new Uint16Array(sz));
|
||||
}
|
||||
function $rt_createCharArrayFromData(data) {
|
||||
var buffer = new Uint16Array(data.length);
|
||||
buffer.set(data);
|
||||
return $rt_createNumericArray($rt_charcls(), buffer);
|
||||
}
|
||||
function $rt_createByteArray(sz) {
|
||||
return $rt_createNumericArray($rt_bytecls(), new Int8Array(sz));
|
||||
}
|
||||
function $rt_createByteArrayFromData(data) {
|
||||
var buffer = new Int8Array(data.length);
|
||||
buffer.set(data);
|
||||
return $rt_createNumericArray($rt_bytecls(), buffer);
|
||||
}
|
||||
function $rt_createShortArray(sz) {
|
||||
return $rt_createNumericArray($rt_shortcls(), new Int16Array(sz));
|
||||
}
|
||||
function $rt_createShortArrayFromData(data) {
|
||||
var buffer = new Int16Array(data.length);
|
||||
buffer.set(data);
|
||||
return $rt_createNumericArray($rt_shortcls(), buffer);
|
||||
}
|
||||
function $rt_createIntArray(sz) {
|
||||
return $rt_createNumericArray($rt_intcls(), new Int32Array(sz));
|
||||
}
|
||||
function $rt_createIntArrayFromData(data) {
|
||||
var buffer = new Int32Array(data.length);
|
||||
buffer.set(data);
|
||||
return $rt_createNumericArray($rt_intcls(), buffer);
|
||||
}
|
||||
function $rt_createBooleanArray(sz) {
|
||||
return $rt_createNumericArray($rt_booleancls(), new Int8Array(sz));
|
||||
}
|
||||
function $rt_createBooleanArrayFromData(data) {
|
||||
var buffer = new Int8Array(data.length);
|
||||
buffer.set(data);
|
||||
return $rt_createNumericArray($rt_booleancls(), buffer);
|
||||
}
|
||||
function $rt_createFloatArray(sz) {
|
||||
return $rt_createNumericArray($rt_floatcls(), new Float32Array(sz));
|
||||
}
|
||||
function $rt_createFloatArrayFromData(data) {
|
||||
var buffer = new Float32Array(data.length);
|
||||
buffer.set(data);
|
||||
return $rt_createNumericArray($rt_floatcls(), buffer);
|
||||
}
|
||||
function $rt_createDoubleArray(sz) {
|
||||
return $rt_createNumericArray($rt_doublecls(), new Float64Array(sz));
|
||||
}
|
||||
function $rt_createDoubleArrayFromData(data) {
|
||||
var buffer = new Float64Array(data.length);
|
||||
buffer.set(data);
|
||||
return $rt_createNumericArray($rt_doublecls(), buffer);
|
||||
}
|
||||
|
||||
function $rt_arraycls(cls) {
|
||||
var result = cls.$array;
|
||||
|
|
Loading…
Reference in New Issue
Block a user