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;
|
||||
|
||||
public JCLComparisonVisitor(ClassReaderSource classSource, Map<String, JCLPackage> packageMap) {
|
||||
super(Opcodes.ASM4);
|
||||
super(Opcodes.ASM5);
|
||||
this.classSource = classSource;
|
||||
this.packageMap = packageMap;
|
||||
}
|
||||
|
|
|
@ -240,13 +240,14 @@ public class TDataInputStream extends TFilterInputStream implements TDataInput {
|
|||
int a;
|
||||
while (count < utfSize) {
|
||||
char ch = (char)buf[offset + count++];
|
||||
out[s] = ch;
|
||||
if (ch < '\u0080') {
|
||||
out[s++] = ch;
|
||||
s++;
|
||||
} else if (((a = out[s]) & 0xe0) == 0xc0) {
|
||||
if (count >= utfSize) {
|
||||
throw new TUTFDataFormatException(TString.wrap("End of stream reached"));
|
||||
}
|
||||
int b = buf[count++];
|
||||
int b = buf[offset + count++];
|
||||
if ((b & 0xC0) != 0x80) {
|
||||
throw new TUTFDataFormatException(TString.wrap("Malformed UTF-8 sequence"));
|
||||
}
|
||||
|
@ -255,8 +256,8 @@ public class TDataInputStream extends TFilterInputStream implements TDataInput {
|
|||
if (count + 1 >= utfSize) {
|
||||
throw new TUTFDataFormatException(TString.wrap("Malformed UTF-8 sequence"));
|
||||
}
|
||||
int b = buf[count++];
|
||||
int c = buf[count++];
|
||||
int b = buf[offset + count++];
|
||||
int c = buf[offset + count++];
|
||||
if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) {
|
||||
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 int round(float a) {
|
||||
return (int)(a + 1.5f);
|
||||
return (int)(a + 0.5f);
|
||||
}
|
||||
|
||||
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(){
|
||||
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()));
|
||||
}
|
||||
|
||||
@Rename("getStackTrace")
|
||||
public TStackTraceElement[] getStackTrace0() {
|
||||
return new TStackTraceElement[0];
|
||||
}
|
||||
|
||||
public void setStackTrace(@SuppressWarnings("unused") TStackTraceElement[] stackTrace) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Rename("getSuppressed")
|
||||
public final TThrowable[] getSuppressed0() {
|
||||
return TArrays.copyOf(suppressed, suppressed.length);
|
||||
|
|
|
@ -93,13 +93,13 @@ public final class TeaVMRunner {
|
|||
.create('c'));
|
||||
options.addOption(OptionBuilder
|
||||
.withDescription("Wait for command after compilation, in order to enable hot recompilation")
|
||||
.withLongOpt("--wait")
|
||||
.withLongOpt("wait")
|
||||
.create('w'));
|
||||
options.addOption(OptionBuilder
|
||||
.withArgName("classpath")
|
||||
.hasArgs()
|
||||
.withDescription("Additional classpath that will be reloaded by TeaVM each time in wait mode")
|
||||
.withLongOpt("--classpath")
|
||||
.withLongOpt("classpath")
|
||||
.create('p'));
|
||||
|
||||
if (args.length == 0) {
|
||||
|
|
|
@ -37,11 +37,14 @@ public class GraphIndexer {
|
|||
private DominatorTree domTree;
|
||||
private int lastIndex;
|
||||
private int[] weights;
|
||||
private int[] priorities;
|
||||
|
||||
public GraphIndexer(Graph graph, int[] weights) {
|
||||
public GraphIndexer(Graph graph, int[] weights, int[] priorities) {
|
||||
int sz = graph.size();
|
||||
this.weights = weights;
|
||||
propagateWeights(graph, weights);
|
||||
this.weights = weights.clone();
|
||||
propagateWeights(graph, this.weights);
|
||||
this.priorities = priorities.clone();
|
||||
propagatePriorities(graph, this.priorities);
|
||||
indexToNode = new int[sz + 1];
|
||||
nodeToIndex = new int[sz + 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) {
|
||||
int sz = graph.size();
|
||||
byte[] state = new byte[sz];
|
||||
|
@ -128,7 +164,7 @@ public class GraphIndexer {
|
|||
IntSet loopNodes = IntOpenHashSet.from(findNaturalLoop(node, terminalNodes.getAll()));
|
||||
for (int succ : successors) {
|
||||
if (loopNodes.contains(succ)) {
|
||||
succList.add(new WeightedNode(succ, weights[succ]));
|
||||
succList.add(new WeightedNode(succ, priorities[succ], weights[succ]));
|
||||
}
|
||||
}
|
||||
Collections.sort(succList);
|
||||
|
@ -142,7 +178,7 @@ public class GraphIndexer {
|
|||
for (int succ : graph.outgoingEdges(loopNode.value)) {
|
||||
if (!loopNodes.contains(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 {
|
||||
for (int succ : successors) {
|
||||
succList.add(new WeightedNode(succ, weights[succ]));
|
||||
succList.add(new WeightedNode(succ, priorities[succ], weights[succ]));
|
||||
}
|
||||
Collections.sort(succList);
|
||||
for (WeightedNode wnode : succList) {
|
||||
|
@ -209,15 +245,21 @@ public class GraphIndexer {
|
|||
|
||||
static class WeightedNode implements Comparable<WeightedNode> {
|
||||
int index;
|
||||
int priority;
|
||||
int weight;
|
||||
|
||||
public WeightedNode(int index, int weight) {
|
||||
public WeightedNode(int index, int priority, int weight) {
|
||||
this.index = index;
|
||||
this.priority = priority;
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(WeightedNode o) {
|
||||
int r = Integer.compare(priority, o.priority);
|
||||
if (r != 0) {
|
||||
return r;
|
||||
}
|
||||
return Integer.compare(weight, o.weight);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,14 +27,24 @@ import org.teavm.javascript.ast.*;
|
|||
class AllBlocksCountVisitor implements StatementVisitor {
|
||||
private Map<IdentifiedStatement, Integer> blocksCount = new HashMap<>();
|
||||
private IdentifiedStatement currentBlock;
|
||||
private boolean last = true;
|
||||
|
||||
public void visit(List<Statement> statements) {
|
||||
if (statements == null) {
|
||||
return;
|
||||
}
|
||||
for (Statement part : statements) {
|
||||
part.acceptVisitor(this);
|
||||
if (statements.isEmpty()) {
|
||||
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) {
|
||||
|
@ -44,6 +54,9 @@ class AllBlocksCountVisitor implements StatementVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(AssignmentStatement statement) {
|
||||
if (last) {
|
||||
incrementCurrentBlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,6 +79,9 @@ class AllBlocksCountVisitor implements StatementVisitor {
|
|||
}
|
||||
visit(statement.getDefaultClause());
|
||||
currentBlock = oldCurrentBlock;
|
||||
if (last && blocksCount.containsKey(statement)) {
|
||||
incrementCurrentBlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -74,6 +90,9 @@ class AllBlocksCountVisitor implements StatementVisitor {
|
|||
currentBlock = statement;
|
||||
visit(statement.getBody());
|
||||
currentBlock = oldCurrentBlock;
|
||||
if (last && (statement.getCondition() != null || blocksCount.containsKey(statement))) {
|
||||
incrementCurrentBlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,6 +101,9 @@ class AllBlocksCountVisitor implements StatementVisitor {
|
|||
currentBlock = statement;
|
||||
visit(statement.getBody());
|
||||
currentBlock = oldCurrentBlock;
|
||||
if (last && blocksCount.containsKey(statement)) {
|
||||
incrementCurrentBlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -90,7 +112,7 @@ class AllBlocksCountVisitor implements StatementVisitor {
|
|||
if (target == null) {
|
||||
target = currentBlock;
|
||||
}
|
||||
blocksCount.put(target, getCount(target) + 1);
|
||||
incrementBlock(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -99,7 +121,17 @@ class AllBlocksCountVisitor implements StatementVisitor {
|
|||
if (target == null) {
|
||||
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
|
||||
|
@ -126,9 +158,15 @@ class AllBlocksCountVisitor implements StatementVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(MonitorEnterStatement statement) {
|
||||
if (last) {
|
||||
incrementCurrentBlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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 Set<IdentifiedStatement> outerStatements = new HashSet<>();
|
||||
private List<Statement> currentSequence;
|
||||
private boolean sequenceEscapes;
|
||||
private int currentIndex;
|
||||
private AllBlocksCountVisitor usageCounter;
|
||||
|
||||
|
@ -39,15 +38,12 @@ class BreakEliminator implements StatementVisitor {
|
|||
private void processSequence(List<Statement> statements) {
|
||||
List<Statement> oldSequence = currentSequence;
|
||||
int oldIndex = currentIndex;
|
||||
boolean oldEscapes = sequenceEscapes;
|
||||
|
||||
sequenceEscapes = escapes(statements);
|
||||
currentSequence = statements;
|
||||
for (currentIndex = 0; currentIndex < currentSequence.size(); ++currentIndex) {
|
||||
statements.get(currentIndex).acceptVisitor(this);
|
||||
}
|
||||
|
||||
sequenceEscapes = oldEscapes;
|
||||
currentIndex = oldIndex;
|
||||
currentSequence = oldSequence;
|
||||
}
|
||||
|
@ -93,7 +89,7 @@ class BreakEliminator implements StatementVisitor {
|
|||
@Override
|
||||
public void visit(BlockStatement 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()));
|
||||
}
|
||||
processSequence(statement.getBody());
|
||||
|
@ -110,7 +106,6 @@ class BreakEliminator implements StatementVisitor {
|
|||
currentSequence.addAll(successors);
|
||||
successors.clear();
|
||||
--currentIndex;
|
||||
sequenceEscapes = escapes(currentSequence);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -143,9 +138,9 @@ class BreakEliminator implements StatementVisitor {
|
|||
outerStatements = new HashSet<>();
|
||||
blockSuccessors = new HashMap<>();
|
||||
processSequence(statement.getProtectedBody());
|
||||
processSequence(statement.getHandler());
|
||||
outerStatements = oldOuterStatements;
|
||||
blockSuccessors = oldBlockSuccessors;
|
||||
processSequence(statement.getHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -161,6 +156,6 @@ class BreakEliminator implements StatementVisitor {
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
import java.util.*;
|
||||
import org.teavm.common.*;
|
||||
import org.teavm.javascript.ast.*;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
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.Generator;
|
||||
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.ProgramUtils;
|
||||
|
||||
|
@ -47,6 +90,9 @@ public class Decompiler {
|
|||
private MethodNodeCache regularMethodCache;
|
||||
private Set<MethodReference> asyncMethods;
|
||||
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,
|
||||
Set<MethodReference> asyncFamilyMethods) {
|
||||
|
@ -70,10 +116,13 @@ public class Decompiler {
|
|||
}
|
||||
|
||||
static class Block {
|
||||
public Block parent;
|
||||
public int parentOffset;
|
||||
public final IdentifiedStatement statement;
|
||||
public final List<Statement> body;
|
||||
public final int end;
|
||||
public final int start;
|
||||
public final List<TryCatchBookmark> tryCatches = new ArrayList<>();
|
||||
|
||||
public Block(IdentifiedStatement statement, List<Statement> body, int start, int end) {
|
||||
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) {
|
||||
List<String> sequence = new ArrayList<>();
|
||||
Set<String> visited = new HashSet<>();
|
||||
|
@ -276,17 +333,24 @@ public class Decompiler {
|
|||
private AsyncMethodPart getRegularMethodStatement(Program program, int[] targetBlocks, boolean async) {
|
||||
AsyncMethodPart result = new AsyncMethodPart();
|
||||
lastBlockId = 1;
|
||||
graph = ProgramUtils.buildControlFlowGraph(program);
|
||||
graph = ProgramUtils.buildControlFlowGraphWithTryCatch(program);
|
||||
int[] weights = new int[graph.size()];
|
||||
for (int i = 0; i < weights.length; ++i) {
|
||||
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();
|
||||
loopGraph = new LoopGraph(this.graph);
|
||||
unflatCode();
|
||||
blockMap = new Block[program.basicBlockCount() * 2 + 1];
|
||||
Deque<Block> stack = new ArrayDeque<>();
|
||||
stack = new ArrayDeque<>();
|
||||
this.program = program;
|
||||
BlockStatement rootStmt = new BlockStatement();
|
||||
rootStmt.setId("root");
|
||||
stack.push(new Block(rootStmt, rootStmt.getBody(), -1, -1));
|
||||
|
@ -299,6 +363,22 @@ public class Decompiler {
|
|||
currentNode = parentNode.getFirstChild();
|
||||
generator.async = async;
|
||||
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();
|
||||
while (block.end == i) {
|
||||
Block oldBlock = block;
|
||||
|
@ -310,26 +390,46 @@ public class Decompiler {
|
|||
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) {
|
||||
currentNode = parentNode.getNext();
|
||||
parentNode = parentNode.getParent();
|
||||
}
|
||||
for (Block newBlock : createBlocks(i)) {
|
||||
block.body.add(newBlock.statement);
|
||||
newBlock.parent = block;
|
||||
newBlock.parentOffset = block.body.size();
|
||||
stack.push(newBlock);
|
||||
block = newBlock;
|
||||
}
|
||||
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;
|
||||
}
|
||||
createNewBookmarks(generator.currentBlock.getTryCatchBlocks());
|
||||
|
||||
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();
|
||||
InstructionLocation lastLocation = null;
|
||||
NodeLocation nodeLocation = null;
|
||||
|
@ -351,18 +451,6 @@ public class Decompiler {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
@ -372,6 +460,77 @@ public class Decompiler {
|
|||
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) {
|
||||
Set<NodeModifier> result = EnumSet.noneOf(NodeModifier.class);
|
||||
if (modifiers.contains(ElementModifier.STATIC)) {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package org.teavm.javascript;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.teavm.javascript.ast.*;
|
||||
|
||||
/**
|
||||
|
@ -24,27 +23,48 @@ import org.teavm.javascript.ast.*;
|
|||
* @author Alexey Andreev
|
||||
*/
|
||||
class EscapingStatementFinder implements StatementVisitor {
|
||||
AllBlocksCountVisitor blockCountVisitor;
|
||||
public boolean escaping;
|
||||
private Set<IdentifiedStatement> outerStatements;
|
||||
|
||||
public EscapingStatementFinder(Set<IdentifiedStatement> nestingStatements) {
|
||||
this.outerStatements = nestingStatements;
|
||||
public EscapingStatementFinder(AllBlocksCountVisitor blockCountVisitor) {
|
||||
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) {
|
||||
if (!escaping) {
|
||||
if (escaping) {
|
||||
return true;
|
||||
}
|
||||
if (statements.isEmpty()) {
|
||||
escaping = true;
|
||||
} else {
|
||||
statements.get(statements.size() - 1).acceptVisitor(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
for (int i = statements.size() - 1; i >= 0; --i) {
|
||||
Statement stmt = statements.get(i);
|
||||
if (!isEmpty(stmt)) {
|
||||
stmt.acceptVisitor(this);
|
||||
return escaping;
|
||||
}
|
||||
}
|
||||
escaping = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AssignmentStatement statement) {
|
||||
escaping = true;
|
||||
escaping |= true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -61,36 +81,46 @@ class EscapingStatementFinder implements StatementVisitor{
|
|||
|
||||
@Override
|
||||
public void visit(SwitchStatement statement) {
|
||||
outerStatements.add(statement);
|
||||
if (blockCountVisitor.getCount(statement) > 0) {
|
||||
escaping = true;
|
||||
return;
|
||||
}
|
||||
for (SwitchClause clause : statement.getClauses()) {
|
||||
if (check(clause.getBody())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!escaping) {
|
||||
check(statement.getDefaultClause());
|
||||
outerStatements.remove(statement);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WhileStatement statement) {
|
||||
if (blockCountVisitor.getCount(statement) > 0) {
|
||||
escaping = true;
|
||||
return;
|
||||
}
|
||||
if (statement.getCondition() != null && check(statement.getBody())) {
|
||||
escaping = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BlockStatement statement) {
|
||||
outerStatements.add(statement);
|
||||
if (blockCountVisitor.getCount(statement) > 0) {
|
||||
escaping = true;
|
||||
return;
|
||||
}
|
||||
check(statement.getBody());
|
||||
outerStatements.remove(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BreakStatement statement) {
|
||||
escaping = !outerStatements.contains(statement.getTarget());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ContinueStatement statement) {
|
||||
escaping = !outerStatements.contains(statement.getTarget());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -108,9 +138,10 @@ class EscapingStatementFinder implements StatementVisitor{
|
|||
|
||||
@Override
|
||||
public void visit(TryCatchStatement statement) {
|
||||
check(statement.getProtectedBody());
|
||||
if (!check(statement.getProtectedBody())) {
|
||||
check(statement.getHandler());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(GotoPartStatement statement) {
|
||||
|
|
|
@ -67,6 +67,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
private Map<String, String> blockIdMap = new HashMap<>();
|
||||
private List<Set<String>> debugNames = new ArrayList<>();
|
||||
private List<String> cachedVariableNames = new ArrayList<>();
|
||||
private boolean end;
|
||||
private int currentPart;
|
||||
|
||||
private static class OperatorPrecedence {
|
||||
Priority priority;
|
||||
|
@ -657,6 +659,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
}
|
||||
writer.append(";").softNewLine();
|
||||
}
|
||||
end = true;
|
||||
currentPart = 0;
|
||||
method.getBody().acceptVisitor(Renderer.this);
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
|
@ -743,6 +747,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
emitSuspendChecker();
|
||||
}
|
||||
AsyncMethodPart part = methodNode.getBody().get(i);
|
||||
end = true;
|
||||
currentPart = i;
|
||||
part.getStatement().acceptVisitor(Renderer.this);
|
||||
writer.outdent();
|
||||
}
|
||||
|
@ -901,9 +907,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
|
||||
@Override
|
||||
public void visit(SequentialStatement statement) {
|
||||
for (Statement part : statement.getSequence()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
visitStatements(statement.getSequence());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -924,9 +928,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
}
|
||||
debugEmitter.emitCallSite();
|
||||
writer.append(")").ws().append("{").softNewLine().indent();
|
||||
for (Statement part : statement.getConsequent()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
visitStatements(statement.getConsequent());
|
||||
if (!statement.getAlternative().isEmpty()) {
|
||||
writer.outdent().append("}").ws();
|
||||
if (statement.getAlternative().size() == 1 &&
|
||||
|
@ -936,9 +938,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
continue;
|
||||
}
|
||||
writer.append("else").ws().append("{").indent().softNewLine();
|
||||
for (Statement part : statement.getAlternative()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
visitStatements(statement.getAlternative());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -973,16 +973,22 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
writer.append("case ").append(condition).append(":").softNewLine();
|
||||
}
|
||||
writer.indent();
|
||||
boolean oldEnd = end;
|
||||
for (Statement part : clause.getBody()) {
|
||||
end = false;
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
end = oldEnd;
|
||||
writer.outdent();
|
||||
}
|
||||
if (statement.getDefaultClause() != null) {
|
||||
writer.append("default:").softNewLine().indent();
|
||||
boolean oldEnd = end;
|
||||
for (Statement part : statement.getDefaultClause()) {
|
||||
end = false;
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
end = oldEnd;
|
||||
writer.outdent();
|
||||
}
|
||||
writer.outdent().append("}").softNewLine();
|
||||
|
@ -1015,9 +1021,12 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
writer.append("true");
|
||||
}
|
||||
writer.append(")").ws().append("{").softNewLine().indent();
|
||||
boolean oldEnd = end;
|
||||
for (Statement part : statement.getBody()) {
|
||||
end = false;
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
end = oldEnd;
|
||||
writer.outdent().append("}").softNewLine();
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
|
@ -1047,9 +1056,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
public void visit(BlockStatement statement) {
|
||||
try {
|
||||
writer.append(mapBlockId(statement.getId())).append(":").ws().append("{").softNewLine().indent();
|
||||
for (Statement part : statement.getBody()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
visitStatements(statement.getBody());
|
||||
writer.outdent().append("}").softNewLine();
|
||||
} catch (IOException 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
|
||||
public void visit(TryCatchStatement statement) {
|
||||
try {
|
||||
|
@ -2031,9 +2049,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
sequence.add(nextStatement);
|
||||
protectedBody = nextStatement.getProtectedBody();
|
||||
}
|
||||
for (Statement part : protectedBody) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
visitStatements(protectedBody);
|
||||
writer.outdent().append("}").ws().append("catch").ws().append("($e)")
|
||||
.ws().append("{").indent().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()
|
||||
.append("$je;").softNewLine();
|
||||
}
|
||||
for (Statement part : catchClause.getHandler()) {
|
||||
part.acceptVisitor(this);
|
||||
}
|
||||
visitStatements(catchClause.getHandler());
|
||||
writer.outdent().append("}").ws().append("else ");
|
||||
}
|
||||
writer.append("{").indent().softNewLine();
|
||||
|
@ -2065,9 +2079,13 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
@Override
|
||||
public void visit(GotoPartStatement statement) {
|
||||
try {
|
||||
if (statement.getPart() != currentPart) {
|
||||
writer.append(pointerName()).ws().append("=").ws().append(statement.getPart()).append(";")
|
||||
.softNewLine();
|
||||
}
|
||||
if (!end || statement.getPart() != currentPart + 1) {
|
||||
writer.append("continue ").append(mainLoopName()).append(";").softNewLine();
|
||||
}
|
||||
} catch (IOException ex){
|
||||
throw new RenderingException("IO error occured", ex);
|
||||
}
|
||||
|
|
|
@ -189,7 +189,11 @@ public class AsyncProgramSplitter {
|
|||
copy.createBasicBlock();
|
||||
}
|
||||
for (int i = 0; i < program.variableCount(); ++i) {
|
||||
Variable var = program.variableAt(i);
|
||||
copy.createVariable();
|
||||
Variable varCopy = copy.variableAt(i);
|
||||
varCopy.setRegister(var.getRegister());
|
||||
varCopy.getDebugNames().addAll(var.getDebugNames());
|
||||
}
|
||||
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)
|
||||
private MethodVisitor methodVisitor = new MethodVisitor(Opcodes.ASM4) {
|
||||
private MethodVisitor methodVisitor = new MethodVisitor(Opcodes.ASM5) {
|
||||
@Override
|
||||
public void visitVarInsn(int opcode, int local) {
|
||||
switch (opcode) {
|
||||
|
@ -485,7 +485,12 @@ public class ProgramParser implements VariableDebugInformation {
|
|||
}
|
||||
|
||||
@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) {
|
||||
case Opcodes.INVOKEINTERFACE:
|
||||
case Opcodes.INVOKEVIRTUAL:
|
||||
|
|
|
@ -250,6 +250,14 @@ function $rt_createByteMultiArray(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) {
|
||||
var arrays = new Array($rt_primitiveArrayCount(dimensions));
|
||||
var firstDim = dimensions[0] | 0;
|
||||
|
|
|
@ -35,5 +35,6 @@
|
|||
<module>teavm-samples-storage</module>
|
||||
<module>teavm-samples-video</module>
|
||||
<module>teavm-samples-async</module>
|
||||
<module>teavm-samples-kotlin</module>
|
||||
</modules>
|
||||
</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