mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-10 08:54:11 -08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
3564230cf3
|
@ -32,7 +32,7 @@ class JCLComparisonVisitor extends ClassVisitor {
|
||||||
private JCLClass jclClass;
|
private JCLClass jclClass;
|
||||||
|
|
||||||
public JCLComparisonVisitor(ClassReaderSource classSource, Map<String, JCLPackage> packageMap) {
|
public JCLComparisonVisitor(ClassReaderSource classSource, Map<String, JCLPackage> packageMap) {
|
||||||
super(Opcodes.ASM4);
|
super(Opcodes.ASM5);
|
||||||
this.classSource = classSource;
|
this.classSource = classSource;
|
||||||
this.packageMap = packageMap;
|
this.packageMap = packageMap;
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ public final class TMath extends TObject {
|
||||||
public static native double atan2(double y, double x);
|
public static native double atan2(double y, double x);
|
||||||
|
|
||||||
public static int round(float a) {
|
public static int round(float a) {
|
||||||
return (int)(a + 1.5f);
|
return (int)(a + 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long round(double a) {
|
public static long round(double a) {
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2015 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.classlib.java.lang;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import org.teavm.classlib.java.io.TSerializable;
|
||||||
|
import org.teavm.classlib.java.util.TObjects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public final class TStackTraceElement extends TObject implements TSerializable {
|
||||||
|
private TString declaringClass;
|
||||||
|
private TString methodName;
|
||||||
|
private TString fileName;
|
||||||
|
private int lineNumber;
|
||||||
|
|
||||||
|
public TStackTraceElement(TString declaringClass, TString methodName, TString fileName, int lineNumber) {
|
||||||
|
if (declaringClass == null || methodName == null) {
|
||||||
|
throw new TNullPointerException();
|
||||||
|
}
|
||||||
|
this.declaringClass = declaringClass;
|
||||||
|
this.methodName = methodName;
|
||||||
|
this.fileName = fileName;
|
||||||
|
this.lineNumber = lineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TString getClassName() {
|
||||||
|
return declaringClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TString getMethodName() {
|
||||||
|
return methodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TString getFileName() {
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLineNumber() {
|
||||||
|
return lineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNativeMethod() {
|
||||||
|
return fileName == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(declaringClass, methodName, fileName, lineNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof TStackTraceElement)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TStackTraceElement other = (TStackTraceElement)obj;
|
||||||
|
return TObjects.equals(declaringClass, other.declaringClass) &&
|
||||||
|
TObjects.equals(methodName, other.methodName) &&
|
||||||
|
TObjects.equals(fileName, other.fileName) &&
|
||||||
|
lineNumber == other.lineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
TStringBuilder sb = new TStringBuilder();
|
||||||
|
int index = declaringClass.lastIndexOf('.');
|
||||||
|
sb.append(declaringClass.substring(index + 1)).append('.').append(methodName).append('(');
|
||||||
|
if (fileName != null) {
|
||||||
|
sb.append(fileName).append(':').append(lineNumber);
|
||||||
|
} else {
|
||||||
|
sb.append(TString.wrap("Unknown Source"));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -167,4 +167,8 @@ public class TThread extends TObject implements TRunnable {
|
||||||
public final int getPriority(){
|
public final int getPriority(){
|
||||||
return this.priority;
|
return this.priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TStackTraceElement[] getStackTrace() {
|
||||||
|
return new TStackTraceElement[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,6 +146,15 @@ public class TThrowable extends RuntimeException {
|
||||||
stream.println(TString.wrap(getClass().getName() + ": " + getMessage()));
|
stream.println(TString.wrap(getClass().getName() + ": " + getMessage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Rename("getStackTrace")
|
||||||
|
public TStackTraceElement[] getStackTrace0() {
|
||||||
|
return new TStackTraceElement[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStackTrace(@SuppressWarnings("unused") TStackTraceElement[] stackTrace) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
@Rename("getSuppressed")
|
@Rename("getSuppressed")
|
||||||
public final TThrowable[] getSuppressed0() {
|
public final TThrowable[] getSuppressed0() {
|
||||||
return TArrays.copyOf(suppressed, suppressed.length);
|
return TArrays.copyOf(suppressed, suppressed.length);
|
||||||
|
|
|
@ -37,11 +37,14 @@ public class GraphIndexer {
|
||||||
private DominatorTree domTree;
|
private DominatorTree domTree;
|
||||||
private int lastIndex;
|
private int lastIndex;
|
||||||
private int[] weights;
|
private int[] weights;
|
||||||
|
private int[] priorities;
|
||||||
|
|
||||||
public GraphIndexer(Graph graph, int[] weights) {
|
public GraphIndexer(Graph graph, int[] weights, int[] priorities) {
|
||||||
int sz = graph.size();
|
int sz = graph.size();
|
||||||
this.weights = weights;
|
this.weights = weights.clone();
|
||||||
propagateWeights(graph, weights);
|
propagateWeights(graph, this.weights);
|
||||||
|
this.priorities = priorities.clone();
|
||||||
|
propagatePriorities(graph, this.priorities);
|
||||||
indexToNode = new int[sz + 1];
|
indexToNode = new int[sz + 1];
|
||||||
nodeToIndex = new int[sz + 1];
|
nodeToIndex = new int[sz + 1];
|
||||||
Arrays.fill(nodeToIndex, -1);
|
Arrays.fill(nodeToIndex, -1);
|
||||||
|
@ -99,6 +102,39 @@ public class GraphIndexer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void propagatePriorities(Graph graph, int[] priorities) {
|
||||||
|
boolean allZero = true;
|
||||||
|
for (int i = 0; i < priorities.length; ++i) {
|
||||||
|
if (priorities[i] != 0) {
|
||||||
|
allZero = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allZero) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DominatorTree domTree = GraphUtils.buildDominatorTree(graph);
|
||||||
|
Graph domGraph = GraphUtils.buildDominatorGraph(domTree, graph.size());
|
||||||
|
IntegerStack stack = new IntegerStack(graph.size() * 2);
|
||||||
|
for (int i = 0; i < domGraph.size(); ++i) {
|
||||||
|
if (domGraph.outgoingEdgesCount(i) == 0) {
|
||||||
|
stack.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!stack.isEmpty()) {
|
||||||
|
int node = stack.pop();
|
||||||
|
int parent = domTree.immediateDominatorOf(node);
|
||||||
|
if (parent < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (priorities[parent] < priorities[node]) {
|
||||||
|
priorities[parent] = priorities[node];
|
||||||
|
stack.push(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void sort(Graph graph) {
|
private void sort(Graph graph) {
|
||||||
int sz = graph.size();
|
int sz = graph.size();
|
||||||
byte[] state = new byte[sz];
|
byte[] state = new byte[sz];
|
||||||
|
@ -128,7 +164,7 @@ public class GraphIndexer {
|
||||||
IntSet loopNodes = IntOpenHashSet.from(findNaturalLoop(node, terminalNodes.getAll()));
|
IntSet loopNodes = IntOpenHashSet.from(findNaturalLoop(node, terminalNodes.getAll()));
|
||||||
for (int succ : successors) {
|
for (int succ : successors) {
|
||||||
if (loopNodes.contains(succ)) {
|
if (loopNodes.contains(succ)) {
|
||||||
succList.add(new WeightedNode(succ, weights[succ]));
|
succList.add(new WeightedNode(succ, priorities[succ], weights[succ]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Collections.sort(succList);
|
Collections.sort(succList);
|
||||||
|
@ -142,7 +178,7 @@ public class GraphIndexer {
|
||||||
for (int succ : graph.outgoingEdges(loopNode.value)) {
|
for (int succ : graph.outgoingEdges(loopNode.value)) {
|
||||||
if (!loopNodes.contains(succ)) {
|
if (!loopNodes.contains(succ)) {
|
||||||
if (outerSuccessors.add(succ)) {
|
if (outerSuccessors.add(succ)) {
|
||||||
succList.add(new WeightedNode(succ, weights[succ]));
|
succList.add(new WeightedNode(succ, priorities[succ], weights[succ]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,7 +189,7 @@ public class GraphIndexer {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int succ : successors) {
|
for (int succ : successors) {
|
||||||
succList.add(new WeightedNode(succ, weights[succ]));
|
succList.add(new WeightedNode(succ, priorities[succ], weights[succ]));
|
||||||
}
|
}
|
||||||
Collections.sort(succList);
|
Collections.sort(succList);
|
||||||
for (WeightedNode wnode : succList) {
|
for (WeightedNode wnode : succList) {
|
||||||
|
@ -209,15 +245,21 @@ public class GraphIndexer {
|
||||||
|
|
||||||
static class WeightedNode implements Comparable<WeightedNode> {
|
static class WeightedNode implements Comparable<WeightedNode> {
|
||||||
int index;
|
int index;
|
||||||
|
int priority;
|
||||||
int weight;
|
int weight;
|
||||||
|
|
||||||
public WeightedNode(int index, int weight) {
|
public WeightedNode(int index, int priority, int weight) {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
|
this.priority = priority;
|
||||||
this.weight = weight;
|
this.weight = weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(WeightedNode o) {
|
public int compareTo(WeightedNode o) {
|
||||||
|
int r = Integer.compare(priority, o.priority);
|
||||||
|
if (r != 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
return Integer.compare(weight, o.weight);
|
return Integer.compare(weight, o.weight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,6 +156,6 @@ class BreakEliminator implements StatementVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean escapes(List<Statement> statements) {
|
private boolean escapes(List<Statement> statements) {
|
||||||
return new EscapingStatementFinder().check(statements);
|
return new EscapingStatementFinder(usageCounter).check(statements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -338,7 +338,13 @@ public class Decompiler {
|
||||||
for (int i = 0; i < weights.length; ++i) {
|
for (int i = 0; i < weights.length; ++i) {
|
||||||
weights[i] = program.basicBlockAt(i).getInstructions().size();
|
weights[i] = program.basicBlockAt(i).getInstructions().size();
|
||||||
}
|
}
|
||||||
indexer = new GraphIndexer(graph, weights);
|
int[] priorities = new int[graph.size()];
|
||||||
|
for (int i = 0; i < targetBlocks.length; ++i) {
|
||||||
|
if (targetBlocks[i] >= 0) {
|
||||||
|
priorities[i] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
indexer = new GraphIndexer(graph, weights, priorities);
|
||||||
graph = indexer.getGraph();
|
graph = indexer.getGraph();
|
||||||
loopGraph = new LoopGraph(this.graph);
|
loopGraph = new LoopGraph(this.graph);
|
||||||
unflatCode();
|
unflatCode();
|
||||||
|
|
|
@ -15,9 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.javascript;
|
package org.teavm.javascript;
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
import org.teavm.javascript.ast.*;
|
import org.teavm.javascript.ast.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,39 +23,48 @@ import org.teavm.javascript.ast.*;
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
*/
|
*/
|
||||||
class EscapingStatementFinder implements StatementVisitor {
|
class EscapingStatementFinder implements StatementVisitor {
|
||||||
|
AllBlocksCountVisitor blockCountVisitor;
|
||||||
public boolean escaping;
|
public boolean escaping;
|
||||||
private boolean last = true;
|
|
||||||
private Set<IdentifiedStatement> outerStatements = new HashSet<>();
|
public EscapingStatementFinder(AllBlocksCountVisitor blockCountVisitor) {
|
||||||
private Set<IdentifiedStatement> breakTargets = new HashSet<>();
|
this.blockCountVisitor = blockCountVisitor;
|
||||||
private IdentifiedStatement currentBlock;
|
}
|
||||||
|
|
||||||
|
private boolean isEmpty(Statement statement) {
|
||||||
|
if (!(statement instanceof SequentialStatement)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SequentialStatement seq = (SequentialStatement)statement;
|
||||||
|
for (int i = seq.getSequence().size() - 1; i >= 0; --i) {
|
||||||
|
if (!isEmpty(seq.getSequence().get(i))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean check(List<Statement> statements) {
|
public boolean check(List<Statement> statements) {
|
||||||
if (escaping) {
|
if (escaping) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (statements.isEmpty()) {
|
if (statements.isEmpty()) {
|
||||||
escaping = last;
|
escaping = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
boolean oldLast = last;
|
for (int i = statements.size() - 1; i >= 0; --i) {
|
||||||
for (int i = 0; i < statements.size(); ++i) {
|
Statement stmt = statements.get(i);
|
||||||
last = false;
|
if (!isEmpty(stmt)) {
|
||||||
statements.get(i).acceptVisitor(this);
|
stmt.acceptVisitor(this);
|
||||||
if (escaping) {
|
return escaping;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
last = oldLast;
|
escaping = true;
|
||||||
if (!escaping) {
|
return true;
|
||||||
statements.get(statements.size() - 1).acceptVisitor(this);
|
|
||||||
}
|
|
||||||
last = oldLast;
|
|
||||||
return escaping;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(AssignmentStatement statement) {
|
public void visit(AssignmentStatement statement) {
|
||||||
escaping |= last;
|
escaping |= true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -74,56 +81,42 @@ class EscapingStatementFinder implements StatementVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(SwitchStatement statement) {
|
public void visit(SwitchStatement statement) {
|
||||||
IdentifiedStatement oldCurrentBlock = currentBlock;
|
if (blockCountVisitor.getCount(statement) > 0) {
|
||||||
currentBlock = statement;
|
escaping = true;
|
||||||
outerStatements.add(statement);
|
return;
|
||||||
|
}
|
||||||
for (SwitchClause clause : statement.getClauses()) {
|
for (SwitchClause clause : statement.getClauses()) {
|
||||||
if (check(clause.getBody())) {
|
if (check(clause.getBody())) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
check(statement.getDefaultClause());
|
if (!escaping) {
|
||||||
outerStatements.remove(statement);
|
check(statement.getDefaultClause());
|
||||||
currentBlock = oldCurrentBlock;
|
|
||||||
if (breakTargets.contains(statement)) {
|
|
||||||
escaping |= last;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(WhileStatement statement) {
|
public void visit(WhileStatement statement) {
|
||||||
IdentifiedStatement oldCurrentBlock = currentBlock;
|
if (blockCountVisitor.getCount(statement) > 0) {
|
||||||
currentBlock = statement;
|
escaping = true;
|
||||||
outerStatements.add(statement);
|
return;
|
||||||
if (!check(statement.getBody()) && statement.getCondition() != null) {
|
|
||||||
escaping |= last;
|
|
||||||
}
|
}
|
||||||
outerStatements.remove(statement);
|
if (statement.getCondition() != null && check(statement.getBody())) {
|
||||||
currentBlock = oldCurrentBlock;
|
escaping = true;
|
||||||
if (breakTargets.contains(statement)) {
|
|
||||||
escaping |= last;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(BlockStatement statement) {
|
public void visit(BlockStatement statement) {
|
||||||
IdentifiedStatement oldCurrentBlock = currentBlock;
|
if (blockCountVisitor.getCount(statement) > 0) {
|
||||||
currentBlock = statement;
|
escaping = true;
|
||||||
outerStatements.add(statement);
|
return;
|
||||||
check(statement.getBody());
|
|
||||||
outerStatements.remove(statement);
|
|
||||||
currentBlock = oldCurrentBlock;
|
|
||||||
if (breakTargets.contains(statement)) {
|
|
||||||
escaping |= last;
|
|
||||||
}
|
}
|
||||||
|
check(statement.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(BreakStatement statement) {
|
public void visit(BreakStatement statement) {
|
||||||
IdentifiedStatement target = statement.getTarget() != null ? statement.getTarget() : currentBlock;
|
|
||||||
if (target != null) {
|
|
||||||
breakTargets.add(target);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -140,13 +133,14 @@ class EscapingStatementFinder implements StatementVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(InitClassStatement statement) {
|
public void visit(InitClassStatement statement) {
|
||||||
escaping |= last;
|
escaping = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(TryCatchStatement statement) {
|
public void visit(TryCatchStatement statement) {
|
||||||
check(statement.getProtectedBody());
|
if (!check(statement.getProtectedBody())) {
|
||||||
check(statement.getHandler());
|
check(statement.getHandler());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -155,11 +149,11 @@ class EscapingStatementFinder implements StatementVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MonitorEnterStatement statement) {
|
public void visit(MonitorEnterStatement statement) {
|
||||||
escaping |= last;
|
escaping = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MonitorExitStatement statement) {
|
public void visit(MonitorExitStatement statement) {
|
||||||
escaping |= last;
|
escaping = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
private Map<String, String> blockIdMap = new HashMap<>();
|
private Map<String, String> blockIdMap = new HashMap<>();
|
||||||
private List<Set<String>> debugNames = new ArrayList<>();
|
private List<Set<String>> debugNames = new ArrayList<>();
|
||||||
private List<String> cachedVariableNames = new ArrayList<>();
|
private List<String> cachedVariableNames = new ArrayList<>();
|
||||||
|
private boolean end;
|
||||||
|
private int currentPart;
|
||||||
|
|
||||||
private static class OperatorPrecedence {
|
private static class OperatorPrecedence {
|
||||||
Priority priority;
|
Priority priority;
|
||||||
|
@ -657,6 +659,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
}
|
}
|
||||||
writer.append(";").softNewLine();
|
writer.append(";").softNewLine();
|
||||||
}
|
}
|
||||||
|
end = true;
|
||||||
|
currentPart = 0;
|
||||||
method.getBody().acceptVisitor(Renderer.this);
|
method.getBody().acceptVisitor(Renderer.this);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RenderingException("IO error occured", e);
|
throw new RenderingException("IO error occured", e);
|
||||||
|
@ -743,6 +747,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
emitSuspendChecker();
|
emitSuspendChecker();
|
||||||
}
|
}
|
||||||
AsyncMethodPart part = methodNode.getBody().get(i);
|
AsyncMethodPart part = methodNode.getBody().get(i);
|
||||||
|
end = true;
|
||||||
|
currentPart = i;
|
||||||
part.getStatement().acceptVisitor(Renderer.this);
|
part.getStatement().acceptVisitor(Renderer.this);
|
||||||
writer.outdent();
|
writer.outdent();
|
||||||
}
|
}
|
||||||
|
@ -901,9 +907,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(SequentialStatement statement) {
|
public void visit(SequentialStatement statement) {
|
||||||
for (Statement part : statement.getSequence()) {
|
visitStatements(statement.getSequence());
|
||||||
part.acceptVisitor(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -924,9 +928,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
}
|
}
|
||||||
debugEmitter.emitCallSite();
|
debugEmitter.emitCallSite();
|
||||||
writer.append(")").ws().append("{").softNewLine().indent();
|
writer.append(")").ws().append("{").softNewLine().indent();
|
||||||
for (Statement part : statement.getConsequent()) {
|
visitStatements(statement.getConsequent());
|
||||||
part.acceptVisitor(this);
|
|
||||||
}
|
|
||||||
if (!statement.getAlternative().isEmpty()) {
|
if (!statement.getAlternative().isEmpty()) {
|
||||||
writer.outdent().append("}").ws();
|
writer.outdent().append("}").ws();
|
||||||
if (statement.getAlternative().size() == 1 &&
|
if (statement.getAlternative().size() == 1 &&
|
||||||
|
@ -936,9 +938,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
writer.append("else").ws().append("{").indent().softNewLine();
|
writer.append("else").ws().append("{").indent().softNewLine();
|
||||||
for (Statement part : statement.getAlternative()) {
|
visitStatements(statement.getAlternative());
|
||||||
part.acceptVisitor(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -973,16 +973,22 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
writer.append("case ").append(condition).append(":").softNewLine();
|
writer.append("case ").append(condition).append(":").softNewLine();
|
||||||
}
|
}
|
||||||
writer.indent();
|
writer.indent();
|
||||||
|
boolean oldEnd = end;
|
||||||
for (Statement part : clause.getBody()) {
|
for (Statement part : clause.getBody()) {
|
||||||
|
end = false;
|
||||||
part.acceptVisitor(this);
|
part.acceptVisitor(this);
|
||||||
}
|
}
|
||||||
|
end = oldEnd;
|
||||||
writer.outdent();
|
writer.outdent();
|
||||||
}
|
}
|
||||||
if (statement.getDefaultClause() != null) {
|
if (statement.getDefaultClause() != null) {
|
||||||
writer.append("default:").softNewLine().indent();
|
writer.append("default:").softNewLine().indent();
|
||||||
|
boolean oldEnd = end;
|
||||||
for (Statement part : statement.getDefaultClause()) {
|
for (Statement part : statement.getDefaultClause()) {
|
||||||
|
end = false;
|
||||||
part.acceptVisitor(this);
|
part.acceptVisitor(this);
|
||||||
}
|
}
|
||||||
|
end = oldEnd;
|
||||||
writer.outdent();
|
writer.outdent();
|
||||||
}
|
}
|
||||||
writer.outdent().append("}").softNewLine();
|
writer.outdent().append("}").softNewLine();
|
||||||
|
@ -1015,9 +1021,12 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
writer.append("true");
|
writer.append("true");
|
||||||
}
|
}
|
||||||
writer.append(")").ws().append("{").softNewLine().indent();
|
writer.append(")").ws().append("{").softNewLine().indent();
|
||||||
|
boolean oldEnd = end;
|
||||||
for (Statement part : statement.getBody()) {
|
for (Statement part : statement.getBody()) {
|
||||||
|
end = false;
|
||||||
part.acceptVisitor(this);
|
part.acceptVisitor(this);
|
||||||
}
|
}
|
||||||
|
end = oldEnd;
|
||||||
writer.outdent().append("}").softNewLine();
|
writer.outdent().append("}").softNewLine();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RenderingException("IO error occured", e);
|
throw new RenderingException("IO error occured", e);
|
||||||
|
@ -1047,9 +1056,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
public void visit(BlockStatement statement) {
|
public void visit(BlockStatement statement) {
|
||||||
try {
|
try {
|
||||||
writer.append(mapBlockId(statement.getId())).append(":").ws().append("{").softNewLine().indent();
|
writer.append(mapBlockId(statement.getId())).append(":").ws().append("{").softNewLine().indent();
|
||||||
for (Statement part : statement.getBody()) {
|
visitStatements(statement.getBody());
|
||||||
part.acceptVisitor(this);
|
|
||||||
}
|
|
||||||
writer.outdent().append("}").softNewLine();
|
writer.outdent().append("}").softNewLine();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RenderingException("IO error occured", e);
|
throw new RenderingException("IO error occured", e);
|
||||||
|
@ -2019,6 +2026,17 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void visitStatements(List<Statement> statements) {
|
||||||
|
boolean oldEnd = end;
|
||||||
|
for (int i = 0; i < statements.size() - 1; ++i) {
|
||||||
|
end = false;
|
||||||
|
statements.get(i).acceptVisitor(this);
|
||||||
|
}
|
||||||
|
end = oldEnd;
|
||||||
|
statements.get(statements.size() - 1).acceptVisitor(this);
|
||||||
|
end = oldEnd;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(TryCatchStatement statement) {
|
public void visit(TryCatchStatement statement) {
|
||||||
try {
|
try {
|
||||||
|
@ -2031,9 +2049,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
sequence.add(nextStatement);
|
sequence.add(nextStatement);
|
||||||
protectedBody = nextStatement.getProtectedBody();
|
protectedBody = nextStatement.getProtectedBody();
|
||||||
}
|
}
|
||||||
for (Statement part : protectedBody) {
|
visitStatements(protectedBody);
|
||||||
part.acceptVisitor(this);
|
|
||||||
}
|
|
||||||
writer.outdent().append("}").ws().append("catch").ws().append("($e)")
|
writer.outdent().append("}").ws().append("catch").ws().append("($e)")
|
||||||
.ws().append("{").indent().softNewLine();
|
.ws().append("{").indent().softNewLine();
|
||||||
writer.append("$je").ws().append("=").ws().append("$e.$javaException;").softNewLine();
|
writer.append("$je").ws().append("=").ws().append("$e.$javaException;").softNewLine();
|
||||||
|
@ -2048,9 +2064,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
writer.append(variableName(catchClause.getExceptionVariable())).ws().append("=").ws()
|
writer.append(variableName(catchClause.getExceptionVariable())).ws().append("=").ws()
|
||||||
.append("$je;").softNewLine();
|
.append("$je;").softNewLine();
|
||||||
}
|
}
|
||||||
for (Statement part : catchClause.getHandler()) {
|
visitStatements(catchClause.getHandler());
|
||||||
part.acceptVisitor(this);
|
|
||||||
}
|
|
||||||
writer.outdent().append("}").ws().append("else ");
|
writer.outdent().append("}").ws().append("else ");
|
||||||
}
|
}
|
||||||
writer.append("{").indent().softNewLine();
|
writer.append("{").indent().softNewLine();
|
||||||
|
@ -2065,9 +2079,13 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
@Override
|
@Override
|
||||||
public void visit(GotoPartStatement statement) {
|
public void visit(GotoPartStatement statement) {
|
||||||
try {
|
try {
|
||||||
writer.append(pointerName()).ws().append("=").ws().append(statement.getPart()).append(";")
|
if (statement.getPart() != currentPart) {
|
||||||
.softNewLine();
|
writer.append(pointerName()).ws().append("=").ws().append(statement.getPart()).append(";")
|
||||||
writer.append("continue ").append(mainLoopName()).append(";").softNewLine();
|
.softNewLine();
|
||||||
|
}
|
||||||
|
if (!end || statement.getPart() != currentPart + 1) {
|
||||||
|
writer.append("continue ").append(mainLoopName()).append(";").softNewLine();
|
||||||
|
}
|
||||||
} catch (IOException ex){
|
} catch (IOException ex){
|
||||||
throw new RenderingException("IO error occured", ex);
|
throw new RenderingException("IO error occured", ex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -367,7 +367,7 @@ public class ProgramParser implements VariableDebugInformation {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: invokedynamic support (a great task, involving not only parser, but every layer of TeaVM)
|
// TODO: invokedynamic support (a great task, involving not only parser, but every layer of TeaVM)
|
||||||
private MethodVisitor methodVisitor = new MethodVisitor(Opcodes.ASM4) {
|
private MethodVisitor methodVisitor = new MethodVisitor(Opcodes.ASM5) {
|
||||||
@Override
|
@Override
|
||||||
public void visitVarInsn(int opcode, int local) {
|
public void visitVarInsn(int opcode, int local) {
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
|
@ -485,7 +485,12 @@ public class ProgramParser implements VariableDebugInformation {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
|
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
|
||||||
|
throw new IllegalStateException("InvokeDynamic is not supported in TeaVM");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case Opcodes.INVOKEINTERFACE:
|
case Opcodes.INVOKEINTERFACE:
|
||||||
case Opcodes.INVOKEVIRTUAL:
|
case Opcodes.INVOKEVIRTUAL:
|
||||||
|
|
|
@ -250,6 +250,14 @@ function $rt_createByteMultiArray(dimensions) {
|
||||||
}
|
}
|
||||||
return $rt_createMultiArrayImpl($rt_bytecls(), arrays, dimensions);
|
return $rt_createMultiArrayImpl($rt_bytecls(), arrays, dimensions);
|
||||||
}
|
}
|
||||||
|
function $rt_createCharMultiArray(dimensions) {
|
||||||
|
var arrays = new Array($rt_primitiveArrayCount(dimensions));
|
||||||
|
var firstDim = dimensions[0] | 0;
|
||||||
|
for (var i = 0 | 0; i < arrays.length; i = (i + 1) | 0) {
|
||||||
|
arrays[i] = $rt_createCharArray(firstDim);
|
||||||
|
}
|
||||||
|
return $rt_createMultiArrayImpl($rt_charcls(), arrays, dimensions);
|
||||||
|
}
|
||||||
function $rt_createBooleanMultiArray(dimensions) {
|
function $rt_createBooleanMultiArray(dimensions) {
|
||||||
var arrays = new Array($rt_primitiveArrayCount(dimensions));
|
var arrays = new Array($rt_primitiveArrayCount(dimensions));
|
||||||
var firstDim = dimensions[0] | 0;
|
var firstDim = dimensions[0] | 0;
|
||||||
|
|
|
@ -35,5 +35,6 @@
|
||||||
<module>teavm-samples-storage</module>
|
<module>teavm-samples-storage</module>
|
||||||
<module>teavm-samples-video</module>
|
<module>teavm-samples-video</module>
|
||||||
<module>teavm-samples-async</module>
|
<module>teavm-samples-async</module>
|
||||||
|
<module>teavm-samples-kotlin</module>
|
||||||
</modules>
|
</modules>
|
||||||
</project>
|
</project>
|
4
teavm-samples/teavm-samples-kotlin/.gitignore
vendored
Normal file
4
teavm-samples/teavm-samples-kotlin/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/target/
|
||||||
|
/.settings/
|
||||||
|
/.classpath
|
||||||
|
/.project
|
131
teavm-samples/teavm-samples-kotlin/pom.xml
Normal file
131
teavm-samples/teavm-samples-kotlin/pom.xml
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
<!--
|
||||||
|
Copyright 2015 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.
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.teavm</groupId>
|
||||||
|
<artifactId>teavm-samples</artifactId>
|
||||||
|
<version>0.3.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>teavm-samples-kotlin</artifactId>
|
||||||
|
|
||||||
|
<packaging>war</packaging>
|
||||||
|
|
||||||
|
<name>TeaVM Kotlin web application</name>
|
||||||
|
<description>A sample application written in Kotlin and compiled by TeaVM</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<kotlin.version>0.11.91.1</kotlin.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-stdlib</artifactId>
|
||||||
|
<version>${kotlin.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.teavm</groupId>
|
||||||
|
<artifactId>teavm-classlib</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.teavm</groupId>
|
||||||
|
<artifactId>teavm-dom</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
|
||||||
|
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
|
||||||
|
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>kotlin-maven-plugin</artifactId>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<version>${kotlin.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>compile</id>
|
||||||
|
<phase>compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>compile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>test-compile</id>
|
||||||
|
<phase>test-compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>test-compile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.teavm</groupId>
|
||||||
|
<artifactId>teavm-maven-plugin</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>web-client</id>
|
||||||
|
<phase>prepare-package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>build-javascript</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>
|
||||||
|
<mainClass>org.teavm.samples.kotlin.KotlinPackage</mainClass>
|
||||||
|
<runtime>SEPARATE</runtime>
|
||||||
|
<minifying>false</minifying>
|
||||||
|
<debugInformationGenerated>true</debugInformationGenerated>
|
||||||
|
<sourceMapsGenerated>true</sourceMapsGenerated>
|
||||||
|
<sourceFilesCopied>true</sourceFilesCopied>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-war-plugin</artifactId>
|
||||||
|
<version>2.4</version>
|
||||||
|
<configuration>
|
||||||
|
<webResources>
|
||||||
|
<resource>
|
||||||
|
<directory>${project.build.directory}/generated/js</directory>
|
||||||
|
</resource>
|
||||||
|
</webResources>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
15
teavm-samples/teavm-samples-kotlin/src/main/kotlin/Hello.kt
Normal file
15
teavm-samples/teavm-samples-kotlin/src/main/kotlin/Hello.kt
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package org.teavm.samples.kotlin
|
||||||
|
|
||||||
|
import org.teavm.jso.*
|
||||||
|
import org.teavm.dom.browser.*
|
||||||
|
import org.teavm.dom.html.*
|
||||||
|
import org.teavm.dom.events.*
|
||||||
|
|
||||||
|
fun main(args : Array<String>) {
|
||||||
|
var window = JS.getGlobal() as Window;
|
||||||
|
var document = window.getDocument();
|
||||||
|
|
||||||
|
document.getElementById("hello-kotlin").addEventListener("click", EventListener<MouseEvent>() {
|
||||||
|
window.alert("Hello, developer!");
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright 2014 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.
|
||||||
|
-->
|
||||||
|
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||||
|
version="3.0">
|
||||||
|
</web-app>
|
|
@ -0,0 +1,31 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Hello kotlin</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||||
|
<script type="text/javascript" charset="utf-8" src="teavm/runtime.js"></script>
|
||||||
|
<script type="text/javascript" charset="utf-8" src="teavm/classes.js"></script>
|
||||||
|
</head>
|
||||||
|
<body onload="main()">
|
||||||
|
<p><button id="hello-kotlin">Hello, Kotlin!</button></p>
|
||||||
|
|
||||||
|
<p>This application was compiled by TeaVM from the following Kotlin source:</p>
|
||||||
|
<pre>
|
||||||
|
package org.teavm.samples.kotlin
|
||||||
|
|
||||||
|
import org.teavm.jso.*
|
||||||
|
import org.teavm.dom.browser.*
|
||||||
|
import org.teavm.dom.html.*
|
||||||
|
import org.teavm.dom.events.*
|
||||||
|
|
||||||
|
fun main(args : Array<String>) {
|
||||||
|
var window = JS.getGlobal() as Window;
|
||||||
|
var document = window.getDocument();
|
||||||
|
|
||||||
|
document.getElementById("hello-kotlin").addEventListener("click", EventListener<MouseEvent>() {
|
||||||
|
window.alert("Hello, developer!");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user