Adds fixes to make `samples' project to work properly

This commit is contained in:
konsoletyper 2013-12-19 12:13:31 +04:00
parent d560f249ba
commit 56991af700
32 changed files with 223 additions and 27 deletions

View File

@ -117,7 +117,7 @@ public class TPrintStream extends TFilterOutputStream {
private void print(char[] s, int begin, int end) { private void print(char[] s, int begin, int end) {
CharBuffer src = new CharBuffer(s, begin, end); CharBuffer src = new CharBuffer(s, begin, end);
byte[] destBytes = new byte[TMath.max(16, TMath.min(s.length, 1024))]; byte[] destBytes = new byte[TMath.max(16, TMath.min(s.length, 1024))];
ByteBuffer dest = new ByteBuffer(new byte[TMath.max(16, TMath.min(s.length, 1024))]); ByteBuffer dest = new ByteBuffer(destBytes);
while (!src.end()) { while (!src.end()) {
charset.encode(src, dest); charset.encode(src, dest);
write(destBytes, 0, dest.position()); write(destBytes, 0, dest.position());
@ -135,13 +135,28 @@ public class TPrintStream extends TFilterOutputStream {
printSB(); printSB();
} }
public void println(int i) {
sb.append(i).append('\n');
printSB();
}
public void print(long l) {
sb.append(l);
printSB();
}
public void println(long l) {
sb.append(l).append('\n');
printSB();
}
public void print(TString s) { public void print(TString s) {
sb.append(s).append('\n'); sb.append(s);
printSB(); printSB();
} }
public void println(TString s) { public void println(TString s) {
sb.append(s); sb.append(s).append('\n');
printSB(); printSB();
} }
@ -152,7 +167,7 @@ public class TPrintStream extends TFilterOutputStream {
private void printSB() { private void printSB() {
char[] buffer = sb.length() > this.buffer.length ? new char[sb.length()] : this.buffer; char[] buffer = sb.length() > this.buffer.length ? new char[sb.length()] : this.buffer;
sb.getChars(0, sb.length(), buffer, 0); sb.getChars(0, sb.length(), buffer, 0);
print(buffer); print(buffer, 0, sb.length());
sb.setLength(0); sb.setLength(0);
} }
} }

View File

@ -43,6 +43,13 @@ public class StringBuilderTest {
assertEquals("23", sb.toString()); assertEquals("23", sb.toString());
} }
@Test
public void longAppended2() {
StringBuilder sb = new StringBuilder();
sb.append(2971215073L);
assertEquals("2971215073", sb.toString());
}
@Test @Test
public void negativeLongAppended() { public void negativeLongAppended() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();

View File

@ -1,6 +1,6 @@
package org.teavm.classlib.java.lang; package org.teavm.classlib.java.lang;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
import org.junit.Test; import org.junit.Test;
/** /**
@ -36,4 +36,11 @@ public class VMTest {
assertEquals(11997458712L, a / b); assertEquals(11997458712L, a / b);
assertEquals(-11997458712L, a / -b); assertEquals(-11997458712L, a / -b);
} }
@Test
public void longAdditionWorks() {
long a = 1134903170;
long b = 1836311903;
assertEquals(2971215073L, a + b);
}
} }

View File

@ -146,7 +146,7 @@ public class DependencyChecker {
return methodCache.map(methodRef); return methodCache.map(methodRef);
} }
private void initClass(String className) { public void initClass(String className) {
MethodDescriptor clinitDesc = new MethodDescriptor("<clinit>", ValueType.VOID); MethodDescriptor clinitDesc = new MethodDescriptor("<clinit>", ValueType.VOID);
while (className != null) { while (className != null) {
if (initializedClasses.putIfAbsent(className, clinitDesc) != null) { if (initializedClasses.putIfAbsent(className, clinitDesc) != null) {
@ -184,8 +184,7 @@ public class DependencyChecker {
for (int i = 0; i < varCount; ++i) { for (int i = 0; i < varCount; ++i) {
parameterNodes[i] = new DependencyNode(this); parameterNodes[i] = new DependencyNode(this);
if (shouldLog) { if (shouldLog) {
parameterNodes[i].setTag(method.getOwner().getName() + "#" + parameterNodes[i].setTag(method.getOwner().getName() + "#" + method.getDescriptor() + ":" + i);
method.getName() + method.getDescriptor() + ":" + i);
} }
} }
DependencyNode resultNode; DependencyNode resultNode;
@ -194,8 +193,7 @@ public class DependencyChecker {
} else { } else {
resultNode = new DependencyNode(this); resultNode = new DependencyNode(this);
if (shouldLog) { if (shouldLog) {
resultNode.setTag(method.getOwner().getName() + "#" + resultNode.setTag(method.getOwner().getName() + "#" + method.getDescriptor() + ":RESULT");
method.getName() + MethodDescriptor.get(method) + ":RESULT");
} }
} }
final MethodGraph graph = new MethodGraph(parameterNodes, paramCount, resultNode, this); final MethodGraph graph = new MethodGraph(parameterNodes, paramCount, resultNode, this);
@ -236,6 +234,21 @@ public class DependencyChecker {
private DependencyNode createFieldNode(FieldReference fieldRef) { private DependencyNode createFieldNode(FieldReference fieldRef) {
initClass(fieldRef.getClassName()); initClass(fieldRef.getClassName());
ClassHolder cls = classSource.getClassHolder(fieldRef.getClassName());
if (cls == null) {
throw new RuntimeException("Class not found: " + fieldRef.getClassName());
}
FieldHolder field = cls.getField(fieldRef.getFieldName());
if (field == null) {
while (cls != null) {
field = cls.getField(fieldRef.getFieldName());
if (field != null) {
return fieldCache.map(new FieldReference(cls.getName(), fieldRef.getFieldName()));
}
cls = cls.getParent() != null ? classSource.getClassHolder(cls.getParent()) : null;
}
throw new RuntimeException("Field not found: " + fieldRef);
}
DependencyNode node = new DependencyNode(this); DependencyNode node = new DependencyNode(this);
if (shouldLog) { if (shouldLog) {
node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName()); node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName());

View File

@ -334,5 +334,10 @@ class DependencyGraphBuilder {
@Override @Override
public void visit(EmptyInstruction insn) { public void visit(EmptyInstruction insn) {
} }
@Override
public void visit(InitClassInstruction insn) {
dependencyChecker.initClass(insn.getClassName());
}
}; };
} }

View File

@ -77,7 +77,6 @@ public class JavascriptBuilder {
builder.setMinified(minifying); builder.setMinified(minifying);
SourceWriter sourceWriter = builder.build(writer); SourceWriter sourceWriter = builder.build(writer);
Renderer renderer = new Renderer(sourceWriter, classSource); Renderer renderer = new Renderer(sourceWriter, classSource);
renderer.renderRuntime();
dependencyChecker.attachMethodGraph(new MethodReference("java.lang.Class", new MethodDescriptor("createNew", dependencyChecker.attachMethodGraph(new MethodReference("java.lang.Class", new MethodDescriptor("createNew",
ValueType.object("java.lang.Class")))); ValueType.object("java.lang.Class"))));
dependencyChecker.attachMethodGraph(new MethodReference("java.lang.String", new MethodDescriptor("<init>", dependencyChecker.attachMethodGraph(new MethodReference("java.lang.String", new MethodDescriptor("<init>",

View File

@ -478,4 +478,9 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
public void visit(IncrementStatement statement) { public void visit(IncrementStatement statement) {
resultStmt = Statement.increment(statement.getVar(), statement.getAmount()); resultStmt = Statement.increment(statement.getVar(), statement.getAmount());
} }
@Override
public void visit(InitClassStatement statement) {
resultStmt = statement;
}
} }

View File

@ -191,4 +191,8 @@ class ReadWriteStatsBuilder implements StatementVisitor, ExprVisitor {
reads[statement.getVar()]++; reads[statement.getVar()]++;
writes[statement.getVar()]++; writes[statement.getVar()]++;
} }
@Override
public void visit(InitClassStatement statement) {
}
} }

View File

@ -100,4 +100,7 @@ class ReferenceCountingVisitor implements StatementVisitor {
public void visit(IncrementStatement statement) { public void visit(IncrementStatement statement) {
} }
@Override
public void visit(InitClassStatement statement) {
}
} }

View File

@ -174,7 +174,8 @@ public class Renderer implements ExprVisitor, StatementVisitor {
writer.ws().append("};").softNewLine(); writer.ws().append("};").softNewLine();
writer.appendClass(cls.getName()).append("_$clinit").ws().append("=").ws().append("function()").ws() writer.appendClass(cls.getName()).append("_$clinit").ws().append("=").ws().append("function()").ws()
.append("{").softNewLine().indent(); .append("{").softNewLine().indent();
writer.appendClass(cls.getName()).append("_$clinit").ws().append("=").ws().append("null;").newLine(); writer.appendClass(cls.getName()).append("_$clinit").ws().append("=").ws()
.append("function(){};").newLine();
List<String> stubNames = new ArrayList<>(); List<String> stubNames = new ArrayList<>();
for (MethodNode method : cls.getMethods()) { for (MethodNode method : cls.getMethods()) {
renderBody(method); renderBody(method);
@ -529,6 +530,15 @@ public class Renderer implements ExprVisitor, StatementVisitor {
} }
} }
@Override
public void visit(InitClassStatement statement) {
try {
writer.appendClass(statement.getClassName()).append("_$clinit();").softNewLine();
} catch (IOException e) {
throw new RenderingException("IO error occured", e);
}
}
public String variableName(int index) { public String variableName(int index) {
if (index == 0) { if (index == 0) {
return minifying ? "$t" : "$this"; return minifying ? "$t" : "$this";

View File

@ -628,4 +628,9 @@ class StatementGenerator implements InstructionVisitor {
private Expr compare(BinaryOperation op, Variable value) { private Expr compare(BinaryOperation op, Variable value) {
return Expr.binary(op, Expr.var(value.getIndex()), Expr.constant(0)); return Expr.binary(op, Expr.var(value.getIndex()), Expr.constant(0));
} }
@Override
public void visit(InitClassInstruction insn) {
statements.add(Statement.initClass(insn.getClassName()));
}
} }

View File

@ -196,4 +196,8 @@ class UnusedVariableEliminator implements ExprVisitor, StatementVisitor {
@Override @Override
public void visit(StaticClassExpr expr) { public void visit(StaticClassExpr expr) {
} }
@Override
public void visit(InitClassStatement statement) {
}
} }

View File

@ -0,0 +1,22 @@
package org.teavm.javascript.ast;
/**
*
* @author Alexey Andreev
*/
public class InitClassStatement extends Statement {
private String className;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
@Override
public void acceptVisitor(StatementVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -166,4 +166,8 @@ public class RenamingVisitor implements StatementVisitor, ExprVisitor {
public void visit(IncrementStatement statement) { public void visit(IncrementStatement statement) {
statement.setVar(varNames[statement.getVar()]); statement.setVar(varNames[statement.getVar()]);
} }
@Override
public void visit(InitClassStatement statement) {
}
} }

View File

@ -63,4 +63,10 @@ public abstract class Statement {
public static Statement cond(Expr predicate, Statement consequent) { public static Statement cond(Expr predicate, Statement consequent) {
return cond(predicate, consequent, null); return cond(predicate, consequent, null);
} }
public static Statement initClass(String className) {
InitClassStatement stmt = new InitClassStatement();
stmt.setClassName(className);
return stmt;
}
} }

View File

@ -43,4 +43,6 @@ public interface StatementVisitor {
void visit(ThrowStatement statement); void visit(ThrowStatement statement);
void visit(IncrementStatement statement); void visit(IncrementStatement statement);
void visit(InitClassStatement statement);
} }

View File

@ -0,0 +1,24 @@
package org.teavm.model.instructions;
import org.teavm.model.Instruction;
/**
*
* @author Alexey Andreev
*/
public class InitClassInstruction extends Instruction {
private String className;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
@Override
public void acceptVisitor(InstructionVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -68,4 +68,6 @@ public interface InstructionVisitor {
void visit(InvokeInstruction insn); void visit(InvokeInstruction insn);
void visit(IsInstanceInstruction insn); void visit(IsInstanceInstruction insn);
void visit(InitClassInstruction insn);
} }

View File

@ -249,4 +249,9 @@ class ClassRefsRenamer implements InstructionVisitor {
public void visit(IsInstanceInstruction insn) { public void visit(IsInstanceInstruction insn) {
insn.setType(rename(insn.getType())); insn.setType(rename(insn.getType()));
} }
@Override
public void visit(InitClassInstruction insn) {
insn.setClassName(classNameMapper.map(insn.getClassName()));
}
} }

View File

@ -177,4 +177,8 @@ public class DefinitionExtractor implements InstructionVisitor {
public void visit(CloneArrayInstruction insn) { public void visit(CloneArrayInstruction insn) {
definedVariables = new Variable[] { insn.getReceiver() }; definedVariables = new Variable[] { insn.getReceiver() };
} }
@Override
public void visit(InitClassInstruction insn) {
}
} }

View File

@ -331,4 +331,9 @@ public class InstructionStringifier implements InstructionVisitor {
sb.append("@").append(insn.getReceiver().getIndex()).append("@") sb.append("@").append(insn.getReceiver().getIndex()).append("@")
.append(insn.getArray().getIndex()).append(".clone()"); .append(insn.getArray().getIndex()).append(".clone()");
} }
@Override
public void visit(InitClassInstruction insn) {
sb.append("initclass ").append(insn.getClassName());
}
} }

View File

@ -179,4 +179,9 @@ public class InstructionTransitionExtractor implements InstructionVisitor {
public void visit(CloneArrayInstruction insn) { public void visit(CloneArrayInstruction insn) {
targets = null; targets = null;
} }
@Override
public void visit(InitClassInstruction insn) {
targets = null;
}
} }

View File

@ -358,5 +358,9 @@ public class CommonSubexpressionElimination implements MethodOptimization {
insn.setValue(program.variableAt(val)); insn.setValue(program.variableAt(val));
bind(insn.getReceiver().getIndex(), "@" + val + " :? " + insn.getType()); bind(insn.getReceiver().getIndex(), "@" + val + " :? " + insn.getType());
} }
@Override
public void visit(InitClassInstruction insn) {
}
}; };
} }

View File

@ -225,5 +225,9 @@ public class UnusedVariableElimination implements MethodOptimization {
public void visit(IsInstanceInstruction insn) { public void visit(IsInstanceInstruction insn) {
requestUsage(insn.getReceiver()); requestUsage(insn.getReceiver());
} }
@Override
public void visit(InitClassInstruction insn) {
}
} }
} }

View File

@ -178,5 +178,9 @@ public class VariableEscapeAnalyzer {
@Override @Override
public void visit(IsInstanceInstruction insn) { public void visit(IsInstanceInstruction insn) {
} }
@Override
public void visit(InitClassInstruction insn) {
}
} }
} }

View File

@ -183,5 +183,9 @@ public class VariableUsageGraphBuilder {
public void visit(IsInstanceInstruction insn) { public void visit(IsInstanceInstruction insn) {
use(insn.getReceiver(), insn.getValue()); use(insn.getReceiver(), insn.getValue());
} }
@Override
public void visit(InitClassInstruction insn) {
}
} }
} }

View File

@ -13,12 +13,12 @@ import org.teavm.optimization.UnreachableBasicBlockEliminator;
* @author Alexey Andreev * @author Alexey Andreev
*/ */
public class Parser { public class Parser {
public static MethodHolder parseMethod(MethodNode node) { public static MethodHolder parseMethod(MethodNode node, String className) {
ValueType[] signature = MethodDescriptor.parseSignature(node.desc); ValueType[] signature = MethodDescriptor.parseSignature(node.desc);
MethodHolder method = new MethodHolder(node.name, signature); MethodHolder method = new MethodHolder(node.name, signature);
parseModifiers(node.access, method); parseModifiers(node.access, method);
ProgramParser programParser = new ProgramParser(); ProgramParser programParser = new ProgramParser();
Program program = programParser.parse(node); Program program = programParser.parse(node, className);
new UnreachableBasicBlockEliminator().optimize(program); new UnreachableBasicBlockEliminator().optimize(program);
SSATransformer ssaProducer = new SSATransformer(); SSATransformer ssaProducer = new SSATransformer();
ssaProducer.transformToSSA(program, method.getParameterTypes()); ssaProducer.transformToSSA(program, method.getParameterTypes());
@ -44,7 +44,7 @@ public class Parser {
} }
for (Object obj : node.methods) { for (Object obj : node.methods) {
MethodNode methodNode = (MethodNode)obj; MethodNode methodNode = (MethodNode)obj;
cls.addMethod(parseMethod(methodNode)); cls.addMethod(parseMethod(methodNode, node.name));
} }
parseAnnotations(cls.getAnnotations(), node); parseAnnotations(cls.getAnnotations(), node);
return cls; return cls;

View File

@ -42,6 +42,7 @@ public class ProgramParser {
private int[] localsMap; private int[] localsMap;
private int minLocal; private int minLocal;
private Program program; private Program program;
private String currentClassName;
private static class Step { private static class Step {
public final int source; public final int source;
@ -53,8 +54,9 @@ public class ProgramParser {
} }
} }
public Program parse(MethodNode method) { public Program parse(MethodNode method, String className) {
program = new Program(); program = new Program();
this.currentClassName = className;
InsnList instructions = method.instructions; InsnList instructions = method.instructions;
if (instructions.size() == 0) { if (instructions.size() == 0) {
return program; return program;
@ -1402,6 +1404,11 @@ public class ProgramParser {
if (desc.equals("D") || desc.equals("J")) { if (desc.equals("D") || desc.equals("J")) {
currentDepth++; currentDepth++;
} }
if (!owner.equals(currentClassName)) {
InitClassInstruction initInsn = new InitClassInstruction();
initInsn.setClassName(ownerCls);
builder.add(initInsn);
}
GetFieldInstruction insn = new GetFieldInstruction(); GetFieldInstruction insn = new GetFieldInstruction();
insn.setField(new FieldReference(ownerCls, name)); insn.setField(new FieldReference(ownerCls, name));
insn.setFieldType(type); insn.setFieldType(type);
@ -1413,6 +1420,11 @@ public class ProgramParser {
if (desc.equals("D") || desc.equals("J")) { if (desc.equals("D") || desc.equals("J")) {
currentDepth--; currentDepth--;
} }
if (!owner.equals(currentClassName)) {
InitClassInstruction initInsn = new InitClassInstruction();
initInsn.setClassName(ownerCls);
builder.add(initInsn);
}
int value = --currentDepth; int value = --currentDepth;
PutFieldInstruction insn = new PutFieldInstruction(); PutFieldInstruction insn = new PutFieldInstruction();
insn.setField(new FieldReference(ownerCls, name)); insn.setField(new FieldReference(ownerCls, name));

View File

@ -374,5 +374,9 @@ public class SSATransformer {
insn.setArray(use(insn.getArray())); insn.setArray(use(insn.getArray()));
insn.setReceiver(define(insn.getReceiver())); insn.setReceiver(define(insn.getReceiver()));
} }
@Override
public void visit(InitClassInstruction insn) {
}
}; };
} }

View File

@ -250,7 +250,7 @@ $rt_methodStubs = function(clinit, names) {
} }
$rt_stdoutBuffer = ""; $rt_stdoutBuffer = "";
$rt_putStdout = function(ch) { $rt_putStdout = function(ch) {
if (ch == '\n') { if (ch === 0xA) {
if (console) { if (console) {
console.info($rt_stdoutBuffer); console.info($rt_stdoutBuffer);
} }
@ -261,7 +261,7 @@ $rt_putStdout = function(ch) {
} }
$rt_stderrBuffer = ""; $rt_stderrBuffer = "";
$rt_putStderr = function(ch) { $rt_putStderr = function(ch) {
if (ch == '\n') { if (ch === 0xA) {
if (console) { if (console) {
console.info($rt_stderrBuffer); console.info($rt_stderrBuffer);
} }

View File

@ -8,21 +8,19 @@
</parent> </parent>
<artifactId>teavm-samples</artifactId> <artifactId>teavm-samples</artifactId>
<dependencies>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-classlib</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.teavm</groupId> <groupId>org.teavm</groupId>
<artifactId>teavm-maven-plugin</artifactId> <artifactId>teavm-maven-plugin</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<dependencies>
<dependency>
<groupId>org.teavm</groupId>
<artifactId>teavm-classlib</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<executions> <executions>
<execution> <execution>
<id>generate-javascript</id> <id>generate-javascript</id>

View File

@ -7,5 +7,15 @@ package org.teavm.samples;
public class HelloWorld { public class HelloWorld {
public static void main(String[] args) { public static void main(String[] args) {
System.out.println("Hello, world!"); System.out.println("Hello, world!");
System.out.println("Here is the Fibonacci sequence:");
long a = 0;
long b = 1;
for (int i = 0; i < 70; ++i) {
System.out.println(a);
long c = a + b;
a = b;
b = c;
}
System.out.println("And so on...");
} }
} }