Recognize array initialization pattern in bytecode and translate it to array initializer in target platform

This commit is contained in:
Alexey Andreev 2020-03-03 18:34:48 +03:00
parent 66250cb125
commit 37e6ca3e17
14 changed files with 629 additions and 27 deletions

View 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;
}
}

View File

@ -40,6 +40,8 @@ public interface ExprVisitor {
void visit(NewMultiArrayExpr expr);
void visit(ArrayFromDataExpr expr);
void visit(InstanceOfExpr expr);
void visit(CastExpr expr);

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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<>();
}
}

View File

@ -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());

View File

@ -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);

View File

@ -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) {

View File

@ -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 {

View File

@ -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();

View File

@ -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);
}

View File

@ -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)

View File

@ -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, ...);

View File

@ -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;