mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-09 08:24:10 -08:00
Merge branch 'master' into add_timezone
This commit is contained in:
commit
cc8a5a6514
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,13 +240,14 @@ public class TDataInputStream extends TFilterInputStream implements TDataInput {
|
||||||
int a;
|
int a;
|
||||||
while (count < utfSize) {
|
while (count < utfSize) {
|
||||||
char ch = (char)buf[offset + count++];
|
char ch = (char)buf[offset + count++];
|
||||||
|
out[s] = ch;
|
||||||
if (ch < '\u0080') {
|
if (ch < '\u0080') {
|
||||||
out[s++] = ch;
|
s++;
|
||||||
} else if (((a = out[s]) & 0xe0) == 0xc0) {
|
} else if (((a = out[s]) & 0xe0) == 0xc0) {
|
||||||
if (count >= utfSize) {
|
if (count >= utfSize) {
|
||||||
throw new TUTFDataFormatException(TString.wrap("End of stream reached"));
|
throw new TUTFDataFormatException(TString.wrap("End of stream reached"));
|
||||||
}
|
}
|
||||||
int b = buf[count++];
|
int b = buf[offset + count++];
|
||||||
if ((b & 0xC0) != 0x80) {
|
if ((b & 0xC0) != 0x80) {
|
||||||
throw new TUTFDataFormatException(TString.wrap("Malformed UTF-8 sequence"));
|
throw new TUTFDataFormatException(TString.wrap("Malformed UTF-8 sequence"));
|
||||||
}
|
}
|
||||||
|
@ -255,8 +256,8 @@ public class TDataInputStream extends TFilterInputStream implements TDataInput {
|
||||||
if (count + 1 >= utfSize) {
|
if (count + 1 >= utfSize) {
|
||||||
throw new TUTFDataFormatException(TString.wrap("Malformed UTF-8 sequence"));
|
throw new TUTFDataFormatException(TString.wrap("Malformed UTF-8 sequence"));
|
||||||
}
|
}
|
||||||
int b = buf[count++];
|
int b = buf[offset + count++];
|
||||||
int c = buf[count++];
|
int c = buf[offset + count++];
|
||||||
if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) {
|
if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) {
|
||||||
throw new TUTFDataFormatException(TString.wrap("Malformed UTF-8 sequence"));
|
throw new TUTFDataFormatException(TString.wrap("Malformed UTF-8 sequence"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -93,13 +93,13 @@ public final class TeaVMRunner {
|
||||||
.create('c'));
|
.create('c'));
|
||||||
options.addOption(OptionBuilder
|
options.addOption(OptionBuilder
|
||||||
.withDescription("Wait for command after compilation, in order to enable hot recompilation")
|
.withDescription("Wait for command after compilation, in order to enable hot recompilation")
|
||||||
.withLongOpt("--wait")
|
.withLongOpt("wait")
|
||||||
.create('w'));
|
.create('w'));
|
||||||
options.addOption(OptionBuilder
|
options.addOption(OptionBuilder
|
||||||
.withArgName("classpath")
|
.withArgName("classpath")
|
||||||
.hasArgs()
|
.hasArgs()
|
||||||
.withDescription("Additional classpath that will be reloaded by TeaVM each time in wait mode")
|
.withDescription("Additional classpath that will be reloaded by TeaVM each time in wait mode")
|
||||||
.withLongOpt("--classpath")
|
.withLongOpt("classpath")
|
||||||
.create('p'));
|
.create('p'));
|
||||||
|
|
||||||
if (args.length == 0) {
|
if (args.length == 0) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,14 +27,24 @@ import org.teavm.javascript.ast.*;
|
||||||
class AllBlocksCountVisitor implements StatementVisitor {
|
class AllBlocksCountVisitor implements StatementVisitor {
|
||||||
private Map<IdentifiedStatement, Integer> blocksCount = new HashMap<>();
|
private Map<IdentifiedStatement, Integer> blocksCount = new HashMap<>();
|
||||||
private IdentifiedStatement currentBlock;
|
private IdentifiedStatement currentBlock;
|
||||||
|
private boolean last = true;
|
||||||
|
|
||||||
public void visit(List<Statement> statements) {
|
public void visit(List<Statement> statements) {
|
||||||
if (statements == null) {
|
if (statements == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (Statement part : statements) {
|
if (statements.isEmpty()) {
|
||||||
part.acceptVisitor(this);
|
incrementCurrentBlock();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
boolean oldLast = last;
|
||||||
|
for (int i = 0; i < statements.size() - 1; ++i) {
|
||||||
|
last = false;
|
||||||
|
statements.get(i).acceptVisitor(this);
|
||||||
|
}
|
||||||
|
last = true;
|
||||||
|
statements.get(statements.size() - 1).acceptVisitor(this);
|
||||||
|
last = oldLast;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCount(IdentifiedStatement statement) {
|
public int getCount(IdentifiedStatement statement) {
|
||||||
|
@ -44,6 +54,9 @@ class AllBlocksCountVisitor implements StatementVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(AssignmentStatement statement) {
|
public void visit(AssignmentStatement statement) {
|
||||||
|
if (last) {
|
||||||
|
incrementCurrentBlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -66,6 +79,9 @@ class AllBlocksCountVisitor implements StatementVisitor {
|
||||||
}
|
}
|
||||||
visit(statement.getDefaultClause());
|
visit(statement.getDefaultClause());
|
||||||
currentBlock = oldCurrentBlock;
|
currentBlock = oldCurrentBlock;
|
||||||
|
if (last && blocksCount.containsKey(statement)) {
|
||||||
|
incrementCurrentBlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -74,6 +90,9 @@ class AllBlocksCountVisitor implements StatementVisitor {
|
||||||
currentBlock = statement;
|
currentBlock = statement;
|
||||||
visit(statement.getBody());
|
visit(statement.getBody());
|
||||||
currentBlock = oldCurrentBlock;
|
currentBlock = oldCurrentBlock;
|
||||||
|
if (last && (statement.getCondition() != null || blocksCount.containsKey(statement))) {
|
||||||
|
incrementCurrentBlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -82,6 +101,9 @@ class AllBlocksCountVisitor implements StatementVisitor {
|
||||||
currentBlock = statement;
|
currentBlock = statement;
|
||||||
visit(statement.getBody());
|
visit(statement.getBody());
|
||||||
currentBlock = oldCurrentBlock;
|
currentBlock = oldCurrentBlock;
|
||||||
|
if (last && blocksCount.containsKey(statement)) {
|
||||||
|
incrementCurrentBlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -90,7 +112,7 @@ class AllBlocksCountVisitor implements StatementVisitor {
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
target = currentBlock;
|
target = currentBlock;
|
||||||
}
|
}
|
||||||
blocksCount.put(target, getCount(target) + 1);
|
incrementBlock(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -99,7 +121,17 @@ class AllBlocksCountVisitor implements StatementVisitor {
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
target = currentBlock;
|
target = currentBlock;
|
||||||
}
|
}
|
||||||
blocksCount.put(target, getCount(target) + 1);
|
incrementBlock(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void incrementBlock(IdentifiedStatement statement) {
|
||||||
|
blocksCount.put(statement, getCount(statement) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void incrementCurrentBlock() {
|
||||||
|
if (currentBlock != null) {
|
||||||
|
incrementBlock(currentBlock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -126,9 +158,15 @@ class AllBlocksCountVisitor implements StatementVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MonitorEnterStatement statement) {
|
public void visit(MonitorEnterStatement statement) {
|
||||||
|
if (last) {
|
||||||
|
incrementCurrentBlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(MonitorExitStatement statement) {
|
public void visit(MonitorExitStatement statement) {
|
||||||
|
if (last) {
|
||||||
|
incrementCurrentBlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ class BreakEliminator implements StatementVisitor {
|
||||||
private Map<BlockStatement, List<Statement>> blockSuccessors = new HashMap<>();
|
private Map<BlockStatement, List<Statement>> blockSuccessors = new HashMap<>();
|
||||||
private Set<IdentifiedStatement> outerStatements = new HashSet<>();
|
private Set<IdentifiedStatement> outerStatements = new HashSet<>();
|
||||||
private List<Statement> currentSequence;
|
private List<Statement> currentSequence;
|
||||||
private boolean sequenceEscapes;
|
|
||||||
private int currentIndex;
|
private int currentIndex;
|
||||||
private AllBlocksCountVisitor usageCounter;
|
private AllBlocksCountVisitor usageCounter;
|
||||||
|
|
||||||
|
@ -39,15 +38,12 @@ class BreakEliminator implements StatementVisitor {
|
||||||
private void processSequence(List<Statement> statements) {
|
private void processSequence(List<Statement> statements) {
|
||||||
List<Statement> oldSequence = currentSequence;
|
List<Statement> oldSequence = currentSequence;
|
||||||
int oldIndex = currentIndex;
|
int oldIndex = currentIndex;
|
||||||
boolean oldEscapes = sequenceEscapes;
|
|
||||||
|
|
||||||
sequenceEscapes = escapes(statements);
|
|
||||||
currentSequence = statements;
|
currentSequence = statements;
|
||||||
for (currentIndex = 0; currentIndex < currentSequence.size(); ++currentIndex) {
|
for (currentIndex = 0; currentIndex < currentSequence.size(); ++currentIndex) {
|
||||||
statements.get(currentIndex).acceptVisitor(this);
|
statements.get(currentIndex).acceptVisitor(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
sequenceEscapes = oldEscapes;
|
|
||||||
currentIndex = oldIndex;
|
currentIndex = oldIndex;
|
||||||
currentSequence = oldSequence;
|
currentSequence = oldSequence;
|
||||||
}
|
}
|
||||||
|
@ -93,7 +89,7 @@ class BreakEliminator implements StatementVisitor {
|
||||||
@Override
|
@Override
|
||||||
public void visit(BlockStatement statement) {
|
public void visit(BlockStatement statement) {
|
||||||
outerStatements.add(statement);
|
outerStatements.add(statement);
|
||||||
if (!sequenceEscapes && !escapes(statement.getBody())) {
|
if (!escapes(currentSequence.subList(currentIndex + 1, currentSequence.size()))) {
|
||||||
blockSuccessors.put(statement, currentSequence.subList(currentIndex + 1, currentSequence.size()));
|
blockSuccessors.put(statement, currentSequence.subList(currentIndex + 1, currentSequence.size()));
|
||||||
}
|
}
|
||||||
processSequence(statement.getBody());
|
processSequence(statement.getBody());
|
||||||
|
@ -110,7 +106,6 @@ class BreakEliminator implements StatementVisitor {
|
||||||
currentSequence.addAll(successors);
|
currentSequence.addAll(successors);
|
||||||
successors.clear();
|
successors.clear();
|
||||||
--currentIndex;
|
--currentIndex;
|
||||||
sequenceEscapes = escapes(currentSequence);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,9 +138,9 @@ class BreakEliminator implements StatementVisitor {
|
||||||
outerStatements = new HashSet<>();
|
outerStatements = new HashSet<>();
|
||||||
blockSuccessors = new HashMap<>();
|
blockSuccessors = new HashMap<>();
|
||||||
processSequence(statement.getProtectedBody());
|
processSequence(statement.getProtectedBody());
|
||||||
processSequence(statement.getHandler());
|
|
||||||
outerStatements = oldOuterStatements;
|
outerStatements = oldOuterStatements;
|
||||||
blockSuccessors = oldBlockSuccessors;
|
blockSuccessors = oldBlockSuccessors;
|
||||||
|
processSequence(statement.getHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -161,6 +156,6 @@ class BreakEliminator implements StatementVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean escapes(List<Statement> statements) {
|
private boolean escapes(List<Statement> statements) {
|
||||||
return new EscapingStatementFinder(outerStatements).check(statements);
|
return new EscapingStatementFinder(usageCounter).check(statements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,56 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.javascript;
|
package org.teavm.javascript;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayDeque;
|
||||||
import org.teavm.common.*;
|
import java.util.ArrayList;
|
||||||
import org.teavm.javascript.ast.*;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.teavm.common.Graph;
|
||||||
|
import org.teavm.common.GraphIndexer;
|
||||||
|
import org.teavm.common.Loop;
|
||||||
|
import org.teavm.common.LoopGraph;
|
||||||
|
import org.teavm.common.RangeTree;
|
||||||
|
import org.teavm.javascript.ast.AsyncMethodNode;
|
||||||
|
import org.teavm.javascript.ast.AsyncMethodPart;
|
||||||
|
import org.teavm.javascript.ast.BlockStatement;
|
||||||
|
import org.teavm.javascript.ast.ClassNode;
|
||||||
|
import org.teavm.javascript.ast.FieldNode;
|
||||||
|
import org.teavm.javascript.ast.GotoPartStatement;
|
||||||
|
import org.teavm.javascript.ast.IdentifiedStatement;
|
||||||
|
import org.teavm.javascript.ast.MethodNode;
|
||||||
|
import org.teavm.javascript.ast.NativeMethodNode;
|
||||||
|
import org.teavm.javascript.ast.NodeLocation;
|
||||||
|
import org.teavm.javascript.ast.NodeModifier;
|
||||||
|
import org.teavm.javascript.ast.RegularMethodNode;
|
||||||
|
import org.teavm.javascript.ast.SequentialStatement;
|
||||||
|
import org.teavm.javascript.ast.Statement;
|
||||||
|
import org.teavm.javascript.ast.TryCatchStatement;
|
||||||
|
import org.teavm.javascript.ast.WhileStatement;
|
||||||
import org.teavm.javascript.spi.GeneratedBy;
|
import org.teavm.javascript.spi.GeneratedBy;
|
||||||
import org.teavm.javascript.spi.Generator;
|
import org.teavm.javascript.spi.Generator;
|
||||||
import org.teavm.javascript.spi.InjectedBy;
|
import org.teavm.javascript.spi.InjectedBy;
|
||||||
import org.teavm.model.*;
|
import org.teavm.model.AnnotationHolder;
|
||||||
|
import org.teavm.model.ClassHolder;
|
||||||
|
import org.teavm.model.ClassHolderSource;
|
||||||
|
import org.teavm.model.ElementModifier;
|
||||||
|
import org.teavm.model.FieldHolder;
|
||||||
|
import org.teavm.model.Instruction;
|
||||||
|
import org.teavm.model.InstructionLocation;
|
||||||
|
import org.teavm.model.MethodHolder;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.Program;
|
||||||
|
import org.teavm.model.TryCatchBlock;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.model.Variable;
|
||||||
import org.teavm.model.util.AsyncProgramSplitter;
|
import org.teavm.model.util.AsyncProgramSplitter;
|
||||||
import org.teavm.model.util.ProgramUtils;
|
import org.teavm.model.util.ProgramUtils;
|
||||||
|
|
||||||
|
@ -47,6 +90,9 @@ public class Decompiler {
|
||||||
private MethodNodeCache regularMethodCache;
|
private MethodNodeCache regularMethodCache;
|
||||||
private Set<MethodReference> asyncMethods;
|
private Set<MethodReference> asyncMethods;
|
||||||
private Set<MethodReference> splitMethods = new HashSet<>();
|
private Set<MethodReference> splitMethods = new HashSet<>();
|
||||||
|
private List<TryCatchBookmark> tryCatchBookmarks = new ArrayList<>();
|
||||||
|
private Deque<Block> stack;
|
||||||
|
private Program program;
|
||||||
|
|
||||||
public Decompiler(ClassHolderSource classSource, ClassLoader classLoader, Set<MethodReference> asyncMethods,
|
public Decompiler(ClassHolderSource classSource, ClassLoader classLoader, Set<MethodReference> asyncMethods,
|
||||||
Set<MethodReference> asyncFamilyMethods) {
|
Set<MethodReference> asyncFamilyMethods) {
|
||||||
|
@ -70,10 +116,13 @@ public class Decompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Block {
|
static class Block {
|
||||||
|
public Block parent;
|
||||||
|
public int parentOffset;
|
||||||
public final IdentifiedStatement statement;
|
public final IdentifiedStatement statement;
|
||||||
public final List<Statement> body;
|
public final List<Statement> body;
|
||||||
public final int end;
|
public final int end;
|
||||||
public final int start;
|
public final int start;
|
||||||
|
public final List<TryCatchBookmark> tryCatches = new ArrayList<>();
|
||||||
|
|
||||||
public Block(IdentifiedStatement statement, List<Statement> body, int start, int end) {
|
public Block(IdentifiedStatement statement, List<Statement> body, int start, int end) {
|
||||||
this.statement = statement;
|
this.statement = statement;
|
||||||
|
@ -83,6 +132,14 @@ public class Decompiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class TryCatchBookmark {
|
||||||
|
Block block;
|
||||||
|
int offset;
|
||||||
|
String exceptionType;
|
||||||
|
Integer exceptionVariable;
|
||||||
|
int exceptionHandler;
|
||||||
|
}
|
||||||
|
|
||||||
public List<ClassNode> decompile(Collection<String> classNames) {
|
public List<ClassNode> decompile(Collection<String> classNames) {
|
||||||
List<String> sequence = new ArrayList<>();
|
List<String> sequence = new ArrayList<>();
|
||||||
Set<String> visited = new HashSet<>();
|
Set<String> visited = new HashSet<>();
|
||||||
|
@ -276,17 +333,24 @@ public class Decompiler {
|
||||||
private AsyncMethodPart getRegularMethodStatement(Program program, int[] targetBlocks, boolean async) {
|
private AsyncMethodPart getRegularMethodStatement(Program program, int[] targetBlocks, boolean async) {
|
||||||
AsyncMethodPart result = new AsyncMethodPart();
|
AsyncMethodPart result = new AsyncMethodPart();
|
||||||
lastBlockId = 1;
|
lastBlockId = 1;
|
||||||
graph = ProgramUtils.buildControlFlowGraph(program);
|
graph = ProgramUtils.buildControlFlowGraphWithTryCatch(program);
|
||||||
int[] weights = new int[graph.size()];
|
int[] weights = new int[graph.size()];
|
||||||
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();
|
||||||
blockMap = new Block[program.basicBlockCount() * 2 + 1];
|
blockMap = new Block[program.basicBlockCount() * 2 + 1];
|
||||||
Deque<Block> stack = new ArrayDeque<>();
|
stack = new ArrayDeque<>();
|
||||||
|
this.program = program;
|
||||||
BlockStatement rootStmt = new BlockStatement();
|
BlockStatement rootStmt = new BlockStatement();
|
||||||
rootStmt.setId("root");
|
rootStmt.setId("root");
|
||||||
stack.push(new Block(rootStmt, rootStmt.getBody(), -1, -1));
|
stack.push(new Block(rootStmt, rootStmt.getBody(), -1, -1));
|
||||||
|
@ -299,6 +363,22 @@ public class Decompiler {
|
||||||
currentNode = parentNode.getFirstChild();
|
currentNode = parentNode.getFirstChild();
|
||||||
generator.async = async;
|
generator.async = async;
|
||||||
for (int i = 0; i < this.graph.size(); ++i) {
|
for (int i = 0; i < this.graph.size(); ++i) {
|
||||||
|
int node = i < indexer.size() ? indexer.nodeAt(i) : -1;
|
||||||
|
int next = i + 1;
|
||||||
|
int head = loops[i];
|
||||||
|
if (head != -1 && loopSuccessors[head] == next) {
|
||||||
|
next = head;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node >= 0) {
|
||||||
|
generator.currentBlock = program.basicBlockAt(node);
|
||||||
|
int tmp = indexer.nodeAt(next);
|
||||||
|
generator.nextBlock = tmp >= 0 && next < indexer.size() ? program.basicBlockAt(tmp) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeExpiredBookmarks(generator, generator.currentBlock.getTryCatchBlocks());
|
||||||
|
|
||||||
|
List<TryCatchBookmark> inheritedBookmarks = new ArrayList<>();
|
||||||
Block block = stack.peek();
|
Block block = stack.peek();
|
||||||
while (block.end == i) {
|
while (block.end == i) {
|
||||||
Block oldBlock = block;
|
Block oldBlock = block;
|
||||||
|
@ -310,26 +390,46 @@ public class Decompiler {
|
||||||
blockMap[mappedStart] = block;
|
blockMap[mappedStart] = block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int j = oldBlock.tryCatches.size() - 1; j >= 0; --j) {
|
||||||
|
TryCatchBookmark bookmark = oldBlock.tryCatches.get(j);
|
||||||
|
TryCatchStatement tryCatchStmt = new TryCatchStatement();
|
||||||
|
tryCatchStmt.setExceptionType(bookmark.exceptionType);
|
||||||
|
tryCatchStmt.setExceptionVariable(bookmark.exceptionVariable);
|
||||||
|
tryCatchStmt.getHandler().add(generator.generateJumpStatement(
|
||||||
|
program.basicBlockAt(bookmark.exceptionHandler)));
|
||||||
|
List<Statement> blockPart = oldBlock.body.subList(bookmark.offset, oldBlock.body.size());
|
||||||
|
tryCatchStmt.getProtectedBody().addAll(blockPart);
|
||||||
|
blockPart.clear();
|
||||||
|
if (!tryCatchStmt.getProtectedBody().isEmpty()) {
|
||||||
|
blockPart.add(tryCatchStmt);
|
||||||
|
}
|
||||||
|
inheritedBookmarks.add(bookmark);
|
||||||
|
}
|
||||||
|
oldBlock.tryCatches.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int j = inheritedBookmarks.size() - 1; j >= 0; --j) {
|
||||||
|
TryCatchBookmark bookmark = inheritedBookmarks.get(j);
|
||||||
|
bookmark.block = block;
|
||||||
|
bookmark.offset = block.body.size();
|
||||||
|
block.tryCatches.add(bookmark);
|
||||||
|
}
|
||||||
|
|
||||||
while (parentNode.getEnd() == i) {
|
while (parentNode.getEnd() == i) {
|
||||||
currentNode = parentNode.getNext();
|
currentNode = parentNode.getNext();
|
||||||
parentNode = parentNode.getParent();
|
parentNode = parentNode.getParent();
|
||||||
}
|
}
|
||||||
for (Block newBlock : createBlocks(i)) {
|
for (Block newBlock : createBlocks(i)) {
|
||||||
block.body.add(newBlock.statement);
|
block.body.add(newBlock.statement);
|
||||||
|
newBlock.parent = block;
|
||||||
|
newBlock.parentOffset = block.body.size();
|
||||||
stack.push(newBlock);
|
stack.push(newBlock);
|
||||||
block = newBlock;
|
block = newBlock;
|
||||||
}
|
}
|
||||||
int node = i < indexer.size() ? indexer.nodeAt(i) : -1;
|
createNewBookmarks(generator.currentBlock.getTryCatchBlocks());
|
||||||
int next = i + 1;
|
|
||||||
int head = loops[i];
|
|
||||||
if (head != -1 && loopSuccessors[head] == next) {
|
|
||||||
next = head;
|
|
||||||
}
|
|
||||||
if (node >= 0) {
|
if (node >= 0) {
|
||||||
generator.currentBlock = program.basicBlockAt(node);
|
|
||||||
int tmp = indexer.nodeAt(next);
|
|
||||||
generator.nextBlock = tmp >= 0 && next < indexer.size() ? program.basicBlockAt(tmp) : null;
|
|
||||||
generator.statements.clear();
|
generator.statements.clear();
|
||||||
InstructionLocation lastLocation = null;
|
InstructionLocation lastLocation = null;
|
||||||
NodeLocation nodeLocation = null;
|
NodeLocation nodeLocation = null;
|
||||||
|
@ -351,18 +451,6 @@ public class Decompiler {
|
||||||
generator.statements.add(stmt);
|
generator.statements.add(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TryCatchBlock tryCatch : generator.currentBlock.getTryCatchBlocks()) {
|
|
||||||
TryCatchStatement tryCatchStmt = new TryCatchStatement();
|
|
||||||
tryCatchStmt.setExceptionType(tryCatch.getExceptionType());
|
|
||||||
tryCatchStmt.setExceptionVariable(tryCatch.getExceptionVariable().getIndex());
|
|
||||||
tryCatchStmt.getProtectedBody().addAll(generator.statements);
|
|
||||||
generator.statements.clear();
|
|
||||||
generator.statements.add(tryCatchStmt);
|
|
||||||
Statement handlerStmt = generator.generateJumpStatement(tryCatch.getHandler());
|
|
||||||
if (handlerStmt != null) {
|
|
||||||
tryCatchStmt.getHandler().add(handlerStmt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
block.body.addAll(generator.statements);
|
block.body.addAll(generator.statements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -372,6 +460,77 @@ public class Decompiler {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void closeExpiredBookmarks(StatementGenerator generator, List<TryCatchBlock> tryCatchBlocks) {
|
||||||
|
tryCatchBlocks = new ArrayList<>(tryCatchBlocks);
|
||||||
|
Collections.reverse(tryCatchBlocks);
|
||||||
|
|
||||||
|
// Find which try catch blocks have remained since the previous basic block
|
||||||
|
int sz = Math.min(tryCatchBlocks.size(), tryCatchBookmarks.size());
|
||||||
|
int start;
|
||||||
|
for (start = 0; start < sz; ++start) {
|
||||||
|
TryCatchBlock tryCatch = tryCatchBlocks.get(start);
|
||||||
|
TryCatchBookmark bookmark = tryCatchBookmarks.get(start);
|
||||||
|
if (tryCatch.getHandler().getIndex() != bookmark.exceptionHandler) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!Objects.equals(tryCatch.getExceptionType(), bookmark.exceptionType)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close old bookmarks
|
||||||
|
for (int i = tryCatchBookmarks.size() - 1; i >= start; --i) {
|
||||||
|
TryCatchBookmark bookmark = tryCatchBookmarks.get(i);
|
||||||
|
Block block = stack.peek();
|
||||||
|
while (block != bookmark.block) {
|
||||||
|
TryCatchStatement tryCatchStmt = new TryCatchStatement();
|
||||||
|
tryCatchStmt.setExceptionType(bookmark.exceptionType);
|
||||||
|
tryCatchStmt.setExceptionVariable(bookmark.exceptionVariable);
|
||||||
|
tryCatchStmt.getHandler().add(generator.generateJumpStatement(
|
||||||
|
program.basicBlockAt(bookmark.exceptionHandler)));
|
||||||
|
tryCatchStmt.getProtectedBody().addAll(block.body);
|
||||||
|
block.body.clear();
|
||||||
|
if (!tryCatchStmt.getProtectedBody().isEmpty()) {
|
||||||
|
block.body.add(tryCatchStmt);
|
||||||
|
}
|
||||||
|
block = block.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
TryCatchStatement tryCatchStmt = new TryCatchStatement();
|
||||||
|
tryCatchStmt.setExceptionType(bookmark.exceptionType);
|
||||||
|
tryCatchStmt.setExceptionVariable(bookmark.exceptionVariable);
|
||||||
|
tryCatchStmt.getHandler().add(generator.generateJumpStatement(
|
||||||
|
program.basicBlockAt(bookmark.exceptionHandler)));
|
||||||
|
List<Statement> blockPart = block.body.subList(bookmark.offset, block.body.size());
|
||||||
|
tryCatchStmt.getProtectedBody().addAll(blockPart);
|
||||||
|
blockPart.clear();
|
||||||
|
if (!tryCatchStmt.getProtectedBody().isEmpty()) {
|
||||||
|
blockPart.add(tryCatchStmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
bookmark.block.tryCatches.remove(bookmark);
|
||||||
|
}
|
||||||
|
|
||||||
|
tryCatchBookmarks.subList(start, tryCatchBookmarks.size()).clear();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createNewBookmarks(List<TryCatchBlock> tryCatchBlocks) {
|
||||||
|
// Add new bookmarks
|
||||||
|
for (int i = tryCatchBookmarks.size(); i < tryCatchBlocks.size(); ++i) {
|
||||||
|
TryCatchBlock tryCatch = tryCatchBlocks.get(i);
|
||||||
|
TryCatchBookmark bookmark = new TryCatchBookmark();
|
||||||
|
bookmark.block = stack.peek();
|
||||||
|
bookmark.offset = bookmark.block.body.size();
|
||||||
|
bookmark.exceptionHandler = tryCatch.getHandler().getIndex();
|
||||||
|
bookmark.exceptionType = tryCatch.getExceptionType();
|
||||||
|
bookmark.exceptionVariable = tryCatch.getExceptionVariable() != null ?
|
||||||
|
tryCatch.getExceptionVariable().getIndex() : null;
|
||||||
|
bookmark.block.tryCatches.add(bookmark);
|
||||||
|
tryCatchBookmarks.add(bookmark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Set<NodeModifier> mapModifiers(Set<ElementModifier> modifiers) {
|
private Set<NodeModifier> mapModifiers(Set<ElementModifier> modifiers) {
|
||||||
Set<NodeModifier> result = EnumSet.noneOf(NodeModifier.class);
|
Set<NodeModifier> result = EnumSet.noneOf(NodeModifier.class);
|
||||||
if (modifiers.contains(ElementModifier.STATIC)) {
|
if (modifiers.contains(ElementModifier.STATIC)) {
|
||||||
|
|
|
@ -16,35 +16,55 @@
|
||||||
package org.teavm.javascript;
|
package org.teavm.javascript;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
import org.teavm.javascript.ast.*;
|
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 Set<IdentifiedStatement> outerStatements;
|
|
||||||
|
|
||||||
public EscapingStatementFinder(Set<IdentifiedStatement> nestingStatements) {
|
public EscapingStatementFinder(AllBlocksCountVisitor blockCountVisitor) {
|
||||||
this.outerStatements = nestingStatements;
|
this.blockCountVisitor = blockCountVisitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
if (statements.isEmpty()) {
|
return true;
|
||||||
escaping = true;
|
}
|
||||||
} else {
|
if (statements.isEmpty()) {
|
||||||
statements.get(statements.size() - 1).acceptVisitor(this);
|
escaping = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (int i = statements.size() - 1; i >= 0; --i) {
|
||||||
|
Statement stmt = statements.get(i);
|
||||||
|
if (!isEmpty(stmt)) {
|
||||||
|
stmt.acceptVisitor(this);
|
||||||
|
return escaping;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return escaping;
|
escaping = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(AssignmentStatement statement) {
|
public void visit(AssignmentStatement statement) {
|
||||||
escaping = true;
|
escaping |= true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -61,36 +81,46 @@ class EscapingStatementFinder implements StatementVisitor{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(SwitchStatement statement) {
|
public void visit(SwitchStatement statement) {
|
||||||
outerStatements.add(statement);
|
if (blockCountVisitor.getCount(statement) > 0) {
|
||||||
|
escaping = true;
|
||||||
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(WhileStatement statement) {
|
public void visit(WhileStatement statement) {
|
||||||
escaping = true;
|
if (blockCountVisitor.getCount(statement) > 0) {
|
||||||
|
escaping = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (statement.getCondition() != null && check(statement.getBody())) {
|
||||||
|
escaping = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(BlockStatement statement) {
|
public void visit(BlockStatement statement) {
|
||||||
outerStatements.add(statement);
|
if (blockCountVisitor.getCount(statement) > 0) {
|
||||||
|
escaping = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
check(statement.getBody());
|
check(statement.getBody());
|
||||||
outerStatements.remove(statement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(BreakStatement statement) {
|
public void visit(BreakStatement statement) {
|
||||||
escaping = !outerStatements.contains(statement.getTarget());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ContinueStatement statement) {
|
public void visit(ContinueStatement statement) {
|
||||||
escaping = !outerStatements.contains(statement.getTarget());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -108,8 +138,9 @@ class EscapingStatementFinder implements StatementVisitor{
|
||||||
|
|
||||||
@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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,7 +189,11 @@ public class AsyncProgramSplitter {
|
||||||
copy.createBasicBlock();
|
copy.createBasicBlock();
|
||||||
}
|
}
|
||||||
for (int i = 0; i < program.variableCount(); ++i) {
|
for (int i = 0; i < program.variableCount(); ++i) {
|
||||||
|
Variable var = program.variableAt(i);
|
||||||
copy.createVariable();
|
copy.createVariable();
|
||||||
|
Variable varCopy = copy.variableAt(i);
|
||||||
|
varCopy.setRegister(var.getRegister());
|
||||||
|
varCopy.getDebugNames().addAll(var.getDebugNames());
|
||||||
}
|
}
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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