Refactoring of array generation

This commit is contained in:
konsoletyper 2013-12-01 21:57:41 +04:00
parent ce56214ed5
commit ac0df0ca6b
26 changed files with 290 additions and 38 deletions

View File

@ -39,7 +39,7 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin {
String destPos = context.getParameterName(4);
String length = context.getParameterName(5);
writer.append("for (var i = 0; i < " + length + "; i = (i + 1) | 0) {").indent().newLine();
writer.append(dest + "[" + srcPos + "++] = " + src + "[" + destPos + "++];").newLine();
writer.append(dest + ".data[" + srcPos + "++] = " + src + ".data[" + destPos + "++];").newLine();
writer.outdent().append("}").newLine();
}

View File

@ -0,0 +1,17 @@
package org.teavm.classlib.java.lang;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class TArrayStoreException extends TRuntimeException {
private static final long serialVersionUID = 3911921304974631232L;
public TArrayStoreException() {
super();
}
public TArrayStoreException(TString message) {
super(message);
}
}

View File

@ -15,12 +15,12 @@ public final class TSystem extends TObject {
if (src == null || dest == null) {
throw new TNullPointerException(TString.wrap("Either src or dest is null"));
}
if (src.getClass0() != dest.getClass0()) {
throw new ArrayStoreException();
if (src.getClass() != dest.getClass()) {
throw new TArrayStoreException();
}
if (srcPos < 0 || destPos < 0 || length < 0 || srcPos + length > TArray.getLength(src) ||
destPos + length > TArray.getLength(dest)) {
throw new IndexOutOfBoundsException();
throw new TIndexOutOfBoundsException();
}
doArrayCopy(src, srcPos, dest, destPos, length);
}

View File

@ -14,22 +14,45 @@ public class TThrowable extends RuntimeException {
private TString message;
private TThrowable cause;
@Rename("fakeInit")
public TThrowable() {
}
@Rename("<init>")
private void init() {
fillInStackTrace();
}
public TThrowable(TString message) {
@Rename("fakeInit")
public TThrowable(@SuppressWarnings("unused") TString message) {
}
@Rename("<init>")
private void init(TString message) {
fillInStackTrace();
this.message = message;
}
@SuppressWarnings("unused")
@Rename("fakeInit")
public TThrowable(TString message, TThrowable cause) {
}
@Rename("<init>")
private void init(TString message, TThrowable cause) {
fillInStackTrace();
this.message = message;
this.cause = cause;
}
@SuppressWarnings("unused")
@Rename("fakeInit")
public TThrowable(TThrowable cause) {
}
@Rename("<init>")
private void init(TThrowable cause) {
fillInStackTrace();
this.cause = cause;
}

View File

@ -40,7 +40,7 @@ public class TArrayNativeGenerator implements Generator, DependencyPlugin {
MethodReference cons = new MethodReference(clsName, new MethodDescriptor("<init>", ValueType.VOID));
writer.append("$rt_throw(").appendClass(clsName).append(".").appendMethod(cons).append("());").newLine();
writer.outdent().append("}").newLine();
writer.append("return array.length");
writer.append("return " + array + ".data.length;").newLine();
}
private void achieveGetLength(final DependencyChecker checker, MethodReference methodRef) {

View File

@ -121,7 +121,7 @@ public class DependencyChecker {
exceptionOccured.set(null);
while (true) {
try {
if (executor.getActiveCount() == 0 || executor.awaitTermination(1, TimeUnit.SECONDS)) {
if (executor.getActiveCount() == 0 || executor.awaitTermination(10, TimeUnit.MILLISECONDS)) {
break;
}
} catch (InterruptedException e) {
@ -197,7 +197,7 @@ public class DependencyChecker {
}
final MethodGraph graph = new MethodGraph(parameterNodes, paramCount, resultNode, this);
final MethodHolder currentMethod = method;
executor.submit(new Runnable() {
schedule(new Runnable() {
@Override public void run() {
DependencyGraphBuilder graphBuilder = new DependencyGraphBuilder(DependencyChecker.this);
graphBuilder.buildGraph(currentMethod, graph);

View File

@ -174,6 +174,13 @@ class DependencyGraphBuilder {
arrayNode.getArrayItemNode().connect(receiverNode);
}
@Override
public void visit(UnwrapArrayInstruction insn) {
DependencyNode arrayNode = nodes[insn.getArray().getIndex()];
DependencyNode receiverNode = nodes[insn.getReceiver().getIndex()];
arrayNode.connect(receiverNode);
}
@Override
public void visit(CloneArrayInstruction insn) {
DependencyNode arrayNode = nodes[insn.getArray().getIndex()];

View File

@ -147,6 +147,15 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
resultExpr = Expr.subscript(array, index);
}
@Override
public void visit(UnwrapArrayExpr expr) {
expr.getArray().acceptVisitor(this);
Expr arrayExpr = resultExpr;
UnwrapArrayExpr result = new UnwrapArrayExpr(expr.getElementType());
result.setArray(arrayExpr);
resultExpr = result;
}
@Override
public void visit(InvocationExpr expr) {
Expr[] args = new Expr[expr.getArguments().size()];

View File

@ -63,6 +63,11 @@ class ReadWriteStatsBuilder implements StatementVisitor, ExprVisitor {
expr.getIndex().acceptVisitor(this);
}
@Override
public void visit(UnwrapArrayExpr expr) {
expr.getArray().acceptVisitor(this);
}
@Override
public void visit(InvocationExpr expr) {
for (Expr arg : expr.getArguments()) {

View File

@ -48,6 +48,7 @@ public class Renderer implements ExprVisitor, StatementVisitor {
public void renderRuntime() {
renderRuntimeCls();
renderRuntimeString();
renderRuntimeObjcls();
}
private void renderRuntimeCls() {
@ -72,14 +73,19 @@ public class Renderer implements ExprVisitor, StatementVisitor {
ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID));
writer.append("$rt_str = function(str) {").indent().newLine();
writer.append("var characters = $rt_createNumericArray($rt_charcls(), str.length);").newLine();
writer.append("var charsBuffer = characters.data;").newLine();
writer.append("for (var i = 0; i < str.length; i = (i + 1) | 0) {").indent().newLine();
writer.append("characters[i] = str.charCodeAt(i);").newLine();
writer.append("charsBuffer[i] = str.charCodeAt(i);").newLine();
writer.outdent().append("}").newLine();
writer.append("return ").appendClass("java.lang.String").append(".")
.appendMethod(stringCons).append("(characters);").newLine();
writer.outdent().append("}").newLine();
}
private void renderRuntimeObjcls() {
writer.append("$rt_objcls = function() { return ").appendClass("java.lang.Object").append("; }").newLine();
}
public void render(ClassNode cls) {
writer.appendClass(cls.getName()).append(" = function() {").indent().newLine();
for (FieldNode field : cls.getFields()) {
@ -375,9 +381,9 @@ public class Renderer implements ExprVisitor, StatementVisitor {
@Override
public void visit(ThrowStatement statement) {
writer.append("throw ");
writer.append("$rt_throw(");
statement.getException().acceptVisitor(this);
writer.append(";").newLine();
writer.append(");").newLine();
}
@Override
@ -722,6 +728,12 @@ public class Renderer implements ExprVisitor, StatementVisitor {
writer.append(']');
}
@Override
public void visit(UnwrapArrayExpr expr) {
expr.getArray().acceptVisitor(this);
writer.append(".data");
}
@Override
public void visit(InvocationExpr expr) {
String className = naming.getNameFor(expr.getMethod().getClassName());

View File

@ -437,6 +437,13 @@ public class StatementGenerator implements InstructionVisitor {
assign(Expr.unary(UnaryOperation.LENGTH, Expr.var(insn.getArray().getIndex())), insn.getReceiver().getIndex());
}
@Override
public void visit(UnwrapArrayInstruction insn) {
UnwrapArrayExpr unwrapExpr = new UnwrapArrayExpr(insn.getElementType());
unwrapExpr.setArray(Expr.var(insn.getArray().getIndex()));
assign(unwrapExpr, insn.getReceiver().getIndex());
}
@Override
public void visit(CloneArrayInstruction insn) {
MethodDescriptor cloneMethodDesc = new MethodDescriptor("clone", ValueType.object("java.lang.Object"));

View File

@ -155,6 +155,11 @@ class UnusedVariableEliminator implements ExprVisitor, StatementVisitor {
expr.getIndex().acceptVisitor(this);
}
@Override
public void visit(UnwrapArrayExpr expr) {
expr.getArray().acceptVisitor(this);
}
@Override
public void visit(InvocationExpr expr) {
for (Expr arg : expr.getArguments()) {

View File

@ -32,6 +32,8 @@ public interface ExprVisitor {
void visit(SubscriptExpr expr);
void visit(UnwrapArrayExpr expr);
void visit(InvocationExpr expr);
void visit(QualificationExpr expr);

View File

@ -44,6 +44,11 @@ public class RenamingVisitor implements StatementVisitor, ExprVisitor {
expr.getIndex().acceptVisitor(this);
}
@Override
public void visit(UnwrapArrayExpr expr) {
expr.getArray().acceptVisitor(this);
}
@Override
public void visit(InvocationExpr expr) {
for (Expr arg : expr.getArguments()) {

View File

@ -0,0 +1,45 @@
package org.teavm.javascript.ast;
import java.util.Map;
import org.teavm.model.instructions.ArrayElementType;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class UnwrapArrayExpr extends Expr {
private ArrayElementType elementType;
private Expr array;
public UnwrapArrayExpr(ArrayElementType elementType) {
this.elementType = elementType;
}
public ArrayElementType getElementType() {
return elementType;
}
public Expr getArray() {
return array;
}
public void setArray(Expr array) {
this.array = array;
}
@Override
public void acceptVisitor(ExprVisitor visitor) {
visitor.visit(this);
}
@Override
protected UnwrapArrayExpr clone(Map<Expr, Expr> cache) {
UnwrapArrayExpr copy = (UnwrapArrayExpr)cache.get(this);
if (copy == null) {
copy = new UnwrapArrayExpr(elementType);
copy.array = array != null ? array.clone(cache) : null;
cache.put(copy, copy);
}
return copy;
}
}

View File

@ -0,0 +1,16 @@
package org.teavm.model.instructions;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public enum ArrayElementType {
CHAR,
BYTE,
SHORT,
INT,
LONG,
FLOAT,
DOUBLE,
OBJECT
}

View File

@ -57,6 +57,8 @@ public interface InstructionVisitor {
void visit(CloneArrayInstruction insn);
void visit(UnwrapArrayInstruction insn);
void visit(GetElementInstruction insn);
void visit(PutElementInstruction insn);

View File

@ -1,9 +0,0 @@
package org.teavm.model.instructions;
/**
*
* @author Alexey Andreev
*/
public enum UnaryInstructionType {
NEGATE
}

View File

@ -0,0 +1,43 @@
package org.teavm.model.instructions;
import org.teavm.model.Instruction;
import org.teavm.model.Variable;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class UnwrapArrayInstruction extends Instruction {
private Variable array;
private Variable receiver;
private ArrayElementType elementType;
public UnwrapArrayInstruction(ArrayElementType elementType) {
this.elementType = elementType;
}
public Variable getArray() {
return array;
}
public void setArray(Variable array) {
this.array = array;
}
public Variable getReceiver() {
return receiver;
}
public void setReceiver(Variable receiver) {
this.receiver = receiver;
}
public ArrayElementType getElementType() {
return elementType;
}
@Override
public void acceptVisitor(InstructionVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -223,6 +223,10 @@ class ClassRefsRenamer implements InstructionVisitor {
public void visit(PutElementInstruction insn) {
}
@Override
public void visit(UnwrapArrayInstruction insn) {
}
@Override
public void visit(InvokeInstruction insn) {
String className = classNameMapper.map(insn.getMethod().getClassName());

View File

@ -124,6 +124,11 @@ public class DefinitionExtractor implements InstructionVisitor {
definedVariables = new Variable[0];
}
@Override
public void visit(UnwrapArrayInstruction insn) {
definedVariables = new Variable[] { insn.getReceiver() };
}
@Override
public void visit(GetElementInstruction insn) {
definedVariables = new Variable[] { insn.getReceiver() };

View File

@ -307,9 +307,15 @@ public class InstructionStringifier implements InstructionVisitor {
.append(" to ").append(insn.getTargetType());
}
@Override
public void visit(UnwrapArrayInstruction insn) {
sb.append("@").append(insn.getReceiver().getIndex()).append("@").append(" := @")
.append(insn.getArray()).append(".data");
}
@Override
public void visit(ArrayLengthInstruction insn) {
sb.append("@").append(insn.getReceiver().getIndex()).append("@")
sb.append("@").append(insn.getReceiver().getIndex()).append(" := @")
.append(insn.getArray().getIndex()).append(".length");
}

View File

@ -165,6 +165,11 @@ public class InstructionTransitionExtractor implements InstructionVisitor {
targets = null;
}
@Override
public void visit(UnwrapArrayInstruction insn) {
targets = null;
}
@Override
public void visit(CloneArrayInstruction insn) {
targets = null;

View File

@ -698,11 +698,15 @@ public class ProgramParser {
builder.add(insn);
}
private void loadArrayElement(int sz) {
private void loadArrayElement(int sz, ArrayElementType type) {
int arrIndex = --currentDepth;
int array = --currentDepth;
int var = currentDepth;
currentDepth += sz;
UnwrapArrayInstruction unwrapInsn = new UnwrapArrayInstruction(type);
unwrapInsn.setArray(getVariable(array));
unwrapInsn.setReceiver(unwrapInsn.getArray());
builder.add(unwrapInsn);
GetElementInstruction insn = new GetElementInstruction();
insn.setArray(getVariable(array));
insn.setIndex(getVariable(arrIndex));
@ -710,11 +714,15 @@ public class ProgramParser {
builder.add(insn);
}
private void storeArrayElement(int sz) {
private void storeArrayElement(int sz, ArrayElementType type) {
currentDepth -= sz;
int value = currentDepth;
int arrIndex = --currentDepth;
int array = --currentDepth;
UnwrapArrayInstruction unwrapInsn = new UnwrapArrayInstruction(type);
unwrapInsn.setArray(getVariable(array));
unwrapInsn.setReceiver(unwrapInsn.getArray());
builder.add(unwrapInsn);
PutElementInstruction insn = new PutElementInstruction();
insn.setArray(getVariable(array));
insn.setIndex(getVariable(arrIndex));
@ -775,28 +783,52 @@ public class ProgramParser {
pushConstant(2F);
break;
case Opcodes.BALOAD:
loadArrayElement(1, ArrayElementType.BYTE);
break;
case Opcodes.IALOAD:
loadArrayElement(1, ArrayElementType.INT);
break;
case Opcodes.FALOAD:
loadArrayElement(1, ArrayElementType.FLOAT);
break;
case Opcodes.SALOAD:
loadArrayElement(1, ArrayElementType.SHORT);
break;
case Opcodes.CALOAD:
loadArrayElement(1, ArrayElementType.CHAR);
break;
case Opcodes.AALOAD:
loadArrayElement(1);
loadArrayElement(1, ArrayElementType.OBJECT);
break;
case Opcodes.DALOAD:
loadArrayElement(2, ArrayElementType.DOUBLE);
break;
case Opcodes.LALOAD:
loadArrayElement(2);
loadArrayElement(2, ArrayElementType.LONG);
break;
case Opcodes.BASTORE:
storeArrayElement(1, ArrayElementType.BYTE);
break;
case Opcodes.IASTORE:
storeArrayElement(1, ArrayElementType.INT);
break;
case Opcodes.FASTORE:
storeArrayElement(1, ArrayElementType.FLOAT);
break;
case Opcodes.SASTORE:
storeArrayElement(1, ArrayElementType.SHORT);
break;
case Opcodes.CASTORE:
storeArrayElement(1, ArrayElementType.CHAR);
break;
case Opcodes.AASTORE:
storeArrayElement(1);
storeArrayElement(1, ArrayElementType.OBJECT);
break;
case Opcodes.DASTORE:
storeArrayElement(2, ArrayElementType.DOUBLE);
break;
case Opcodes.LASTORE:
storeArrayElement(2);
storeArrayElement(2, ArrayElementType.LONG);
break;
case Opcodes.POP:
--currentDepth;
@ -1243,6 +1275,10 @@ public class ProgramParser {
}
case Opcodes.ARRAYLENGTH: {
int a = currentDepth - 1;
UnwrapArrayInstruction unwrapInsn = new UnwrapArrayInstruction(ArrayElementType.OBJECT);
unwrapInsn.setArray(getVariable(a));
unwrapInsn.setReceiver(getVariable(a));
builder.add(unwrapInsn);
ArrayLengthInstruction insn = new ArrayLengthInstruction();
insn.setArray(getVariable(a));
insn.setReceiver(getVariable(a));

View File

@ -357,6 +357,12 @@ public class SSATransformer {
insn.setReceiver(define(insn.getReceiver()));
}
@Override
public void visit(UnwrapArrayInstruction insn) {
insn.setArray(use(insn.getArray()));
insn.setReceiver(define(insn.getReceiver()));
}
@Override
public void visit(CloneArrayInstruction insn) {
insn.setArray(use(insn.getArray()));

View File

@ -21,36 +21,37 @@ $rt_isAssignable = function(from, to) {
return false;
}
$rt_createArray = function(cls, sz) {
var arr = new Array(sz);
arr.$class = $rt_arraycls(cls);
arr.$id = $rt_lastObjectId++;
var data = new Array(sz);
var arr = new ($rt_arraycls(cls))(data);
arr.$id = $rt_nextId();
for (var i = 0; i < sz; i = (i + 1) | 0) {
arr[i] = null;
arr.data[i] = null;
}
return arr;
}
$rt_createNumericArray = function(cls, sz) {
var arr = $rt_createArray(cls, sz);
for (var i = 0; i < sz; i = (i + 1) | 0) {
arr[i] = 0;
arr.data[i] = 0;
}
return arr;
}
$rt_createLongArray = function(sz) {
var arr = $rt.createArray($rt_longcls(), sz);
for (var i = 0; i < sz; i = (i + 1) | 0) {
arr[i] = Long.ZERO;
arr.data[i] = Long.ZERO;
}
return arr;
},
$rt_arraycls = function(cls) {
if (cls.$array == undefined) {
cls.$array = {
$meta : { item : cls },
var arraycls = function(data) {
this.data = data;
this.$cls = arraycls;
};
if ($rt.objcls) {
cls.$array.$meta.supertypes = [$rt.objcls()];
}
arraycls.prototype = new ($rt_objcls())();
arraycls.$meta = { item : cls, supertypes : [$rt_objcls()] };
cls.$array = arraycls;
}
return cls.$array;
}