mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Adds debugging information file generation
This commit is contained in:
parent
3b939d0853
commit
94b9b001cd
|
@ -57,6 +57,10 @@ public class TeaVMRunner {
|
|||
options.addOption(OptionBuilder
|
||||
.withDescription("causes TeaVM to log bytecode")
|
||||
.create("logbytecode"));
|
||||
options.addOption(OptionBuilder
|
||||
.withDescription("Generate debug information")
|
||||
.withLongOpt("debug")
|
||||
.create('D'));
|
||||
options.addOption(OptionBuilder
|
||||
.withArgName("number")
|
||||
.hasArg()
|
||||
|
@ -119,6 +123,9 @@ public class TeaVMRunner {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (commandLine.hasOption('D')) {
|
||||
tool.setDebugInformation(new File(tool.getTargetDirectory(), tool.getTargetFileName() + ".teavmdbg"));
|
||||
}
|
||||
args = commandLine.getArgs();
|
||||
if (args.length > 1) {
|
||||
System.err.println("Unexpected arguments");
|
||||
|
|
|
@ -15,7 +15,13 @@
|
|||
*/
|
||||
package org.teavm.debugging;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
/**
|
||||
|
@ -92,6 +98,11 @@ public class DebugInformation {
|
|||
return index >= 0 ? index : -index - 2;
|
||||
}
|
||||
|
||||
public void write(OutputStream output) throws IOException {
|
||||
DebugInformationWriter writer = new DebugInformationWriter(new DataOutputStream(output));
|
||||
writer.write(this);
|
||||
}
|
||||
|
||||
static class FileDescription {
|
||||
GeneratedLocation[][] generatedLocations;
|
||||
MethodReference[] methodMap;
|
||||
|
|
|
@ -49,6 +49,7 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
|||
|
||||
@Override
|
||||
public void emitLocation(String fileName, int line) {
|
||||
debugInformation = null;
|
||||
Integer fileIndex;
|
||||
if (fileName != null) {
|
||||
fileIndex = fileNameMap.get(fileName);
|
||||
|
@ -76,6 +77,7 @@ public class DebugInformationBuilder implements DebugInformationEmitter {
|
|||
|
||||
@Override
|
||||
public void emitMethod(MethodReference method) {
|
||||
debugInformation = null;
|
||||
currentMethod = method;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.teavm.debugging;
|
||||
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.teavm.common.IntegerArray;
|
||||
import org.teavm.debugging.DebugInformation.FileDescription;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class DebugInformationWriter {
|
||||
private DataOutput output;
|
||||
private int lastNumber;
|
||||
|
||||
public DebugInformationWriter(DataOutput output) {
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
public void write(DebugInformation debugInfo) throws IOException {
|
||||
writeNumber(debugInfo.fileNames.length);
|
||||
for (int i = 0; i < debugInfo.fileNames.length; ++i) {
|
||||
String fileName = debugInfo.fileNames[i];
|
||||
writeString(fileName);
|
||||
writeMethods(debugInfo.fileDescriptions[i]);
|
||||
}
|
||||
|
||||
writeNumber(debugInfo.fileNameKeys.length);
|
||||
resetRelativeNumber();
|
||||
for (int i = 0; i < debugInfo.fileNameKeys.length; ++i) {
|
||||
writeRelativeNumber(debugInfo.fileNameKeys[i].getLine());
|
||||
}
|
||||
resetRelativeNumber();
|
||||
for (int i = 0; i < debugInfo.fileNameKeys.length; ++i) {
|
||||
writeRelativeNumber(debugInfo.fileNameKeys[i].getColumn());
|
||||
}
|
||||
resetRelativeNumber();
|
||||
for (int i = 0; i < debugInfo.fileNameValues.length; ++i) {
|
||||
writeRelativeNumber(debugInfo.fileNameValues[i]);
|
||||
}
|
||||
|
||||
writeNumber(debugInfo.lineNumberKeys.length);
|
||||
resetRelativeNumber();
|
||||
resetRelativeNumber();
|
||||
for (int i = 0; i < debugInfo.lineNumberKeys.length; ++i) {
|
||||
writeRelativeNumber(debugInfo.lineNumberKeys[i].getLine());
|
||||
}
|
||||
resetRelativeNumber();
|
||||
for (int i = 0; i < debugInfo.lineNumberKeys.length; ++i) {
|
||||
writeRelativeNumber(debugInfo.lineNumberKeys[i].getColumn());
|
||||
}
|
||||
resetRelativeNumber();
|
||||
for (int i = 0; i < debugInfo.fileNameValues.length; ++i) {
|
||||
writeRelativeNumber(debugInfo.lineNumberValues[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeMethods(FileDescription fileDesc) throws IOException {
|
||||
Map<MethodReference, IntegerArray> methodLineMap = new HashMap<>();
|
||||
for (int i = 0; i < fileDesc.methodMap.length; ++i) {
|
||||
MethodReference method = fileDesc.methodMap[i];
|
||||
if (method == null) {
|
||||
continue;
|
||||
}
|
||||
IntegerArray lines = methodLineMap.get(method);
|
||||
if (lines == null) {
|
||||
lines = new IntegerArray(1);
|
||||
methodLineMap.put(method, lines);
|
||||
}
|
||||
lines.add(i);
|
||||
}
|
||||
writeNumber(methodLineMap.size());
|
||||
for (MethodReference method : methodLineMap.keySet()) {
|
||||
writeString(method.toString());
|
||||
int[] lines = methodLineMap.get(method).getAll();
|
||||
Arrays.sort(lines);
|
||||
for (int i = 0; i < lines.length;) {
|
||||
writeRelativeNumber(i);
|
||||
int j = i;
|
||||
int last = lines[i];
|
||||
++i;
|
||||
while (i < lines.length && lines[i] == last + 1) {
|
||||
++i;
|
||||
++last;
|
||||
}
|
||||
writeNumber(i - j);
|
||||
}
|
||||
writeRelativeNumber(-1);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeNumber(int number) throws IOException {
|
||||
do {
|
||||
number = (number << 1) | (number >>> 31);
|
||||
byte b = (byte)(number & 0x7F);
|
||||
if ((number & 0xFFFFFF80) != 0) {
|
||||
b |= 0x80;
|
||||
}
|
||||
number >>>= 7;
|
||||
output.writeByte(b);
|
||||
} while (number != 0);
|
||||
}
|
||||
|
||||
private void writeRelativeNumber(int number) throws IOException {
|
||||
writeNumber(number - lastNumber);
|
||||
lastNumber = number;
|
||||
}
|
||||
|
||||
private void resetRelativeNumber() {
|
||||
lastNumber = 0;
|
||||
}
|
||||
|
||||
private void writeString(String str) throws IOException {
|
||||
writeNumber(str.length());
|
||||
output.write(str.getBytes("UTF-8"));
|
||||
}
|
||||
}
|
|
@ -212,6 +212,10 @@ class DependencyGraphBuilder {
|
|||
}
|
||||
|
||||
private InstructionReader reader = new InstructionReader() {
|
||||
@Override
|
||||
public void location(InstructionLocation location) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nop() {
|
||||
}
|
||||
|
|
|
@ -88,6 +88,7 @@ class BreakToContinueReplacer implements StatementVisitor {
|
|||
if (statement.getTarget() == replacedBreak) {
|
||||
replaceBy = new ContinueStatement();
|
||||
replaceBy.setTarget(replacement);
|
||||
replaceBy.setLocation(statement.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -229,7 +229,16 @@ public class Decompiler {
|
|||
int tmp = indexer.nodeAt(next);
|
||||
generator.nextBlock = next < indexer.size() ? program.basicBlockAt(tmp) : null;
|
||||
generator.statements.clear();
|
||||
InstructionLocation lastLocation = null;
|
||||
NodeLocation nodeLocation = null;
|
||||
for (Instruction insn : generator.currentBlock.getInstructions()) {
|
||||
if (lastLocation != insn.getLocation()) {
|
||||
lastLocation = insn.getLocation();
|
||||
nodeLocation = new NodeLocation(lastLocation.getFileName(), lastLocation.getLine());
|
||||
}
|
||||
if (insn.getLocation() != null) {
|
||||
generator.setCurrentLocation(nodeLocation);
|
||||
}
|
||||
insn.acceptVisitor(generator);
|
||||
}
|
||||
for (TryCatchBlock tryCatch : generator.currentBlock.getTryCatchBlocks()) {
|
||||
|
|
|
@ -37,21 +37,21 @@ final class ExprOptimizer {
|
|||
Expr b = binary.getSecondOperand();
|
||||
switch (binary.getOperation()) {
|
||||
case EQUALS:
|
||||
return Expr.binary(BinaryOperation.NOT_EQUALS, a, b);
|
||||
return Expr.binary(BinaryOperation.NOT_EQUALS, a, b, expr.getLocation());
|
||||
case NOT_EQUALS:
|
||||
return Expr.binary(BinaryOperation.EQUALS, a, b);
|
||||
return Expr.binary(BinaryOperation.EQUALS, a, b, expr.getLocation());
|
||||
case LESS:
|
||||
return Expr.binary(BinaryOperation.GREATER_OR_EQUALS, a, b);
|
||||
return Expr.binary(BinaryOperation.GREATER_OR_EQUALS, a, b, expr.getLocation());
|
||||
case LESS_OR_EQUALS:
|
||||
return Expr.binary(BinaryOperation.GREATER, a, b);
|
||||
case GREATER:
|
||||
return Expr.binary(BinaryOperation.LESS_OR_EQUALS, a, b);
|
||||
return Expr.binary(BinaryOperation.LESS_OR_EQUALS, a, b, expr.getLocation());
|
||||
case GREATER_OR_EQUALS:
|
||||
return Expr.binary(BinaryOperation.LESS, a, b);
|
||||
return Expr.binary(BinaryOperation.LESS, a, b, expr.getLocation());
|
||||
case STRICT_EQUALS:
|
||||
return Expr.binary(BinaryOperation.STRICT_NOT_EQUALS, a, b);
|
||||
return Expr.binary(BinaryOperation.STRICT_NOT_EQUALS, a, b, expr.getLocation());
|
||||
case STRICT_NOT_EQUALS:
|
||||
return Expr.binary(BinaryOperation.STRICT_EQUALS, a, b);
|
||||
return Expr.binary(BinaryOperation.STRICT_EQUALS, a, b, expr.getLocation());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -33,13 +33,11 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
|
||||
private static boolean isZero(Expr expr) {
|
||||
return expr instanceof ConstantExpr &&
|
||||
Integer.valueOf(0).equals(((ConstantExpr)expr).getValue());
|
||||
return expr instanceof ConstantExpr && Integer.valueOf(0).equals(((ConstantExpr)expr).getValue());
|
||||
}
|
||||
|
||||
private static boolean isComparison(Expr expr) {
|
||||
return expr instanceof BinaryExpr &&
|
||||
((BinaryExpr)expr).getOperation() == BinaryOperation.COMPARE;
|
||||
return expr instanceof BinaryExpr && ((BinaryExpr)expr).getOperation() == BinaryOperation.COMPARE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -76,6 +74,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
BinaryExpr comparison = (BinaryExpr)p;
|
||||
Expr result = BinaryExpr.binary(expr.getOperation(),
|
||||
comparison.getFirstOperand(), comparison.getSecondOperand());
|
||||
result.setLocation(comparison.getLocation());
|
||||
if (invert) {
|
||||
result = ExprOptimizer.invert(result);
|
||||
}
|
||||
|
@ -139,6 +138,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
VariableExpr var = (VariableExpr)assignment.getLeftValue();
|
||||
if (var.getIndex() == index) {
|
||||
resultSequence.remove(resultSequence.size() - 1);
|
||||
assignment.getRightValue().setLocation(assignment.getLocation());
|
||||
assignment.getRightValue().acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
@ -207,7 +207,9 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
Expr[] args = expr.getArguments().toArray(new Expr[0]);
|
||||
args = Arrays.copyOfRange(args, 1, args.length);
|
||||
assignment.setRightValue(Expr.constructObject(expr.getMethod(), args));
|
||||
Expr constructrExpr = Expr.constructObject(expr.getMethod(), args);
|
||||
constructrExpr.setLocation(expr.getLocation());
|
||||
assignment.setRightValue(constructrExpr);
|
||||
stats.reads[var.getIndex()]--;
|
||||
return true;
|
||||
}
|
||||
|
@ -259,8 +261,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
public void visit(AssignmentStatement statement) {
|
||||
if (statement.getLeftValue() == null) {
|
||||
statement.getRightValue().acceptVisitor(this);
|
||||
if (resultExpr instanceof InvocationExpr &&
|
||||
tryApplyConstructor((InvocationExpr)resultExpr)) {
|
||||
if (resultExpr instanceof InvocationExpr && tryApplyConstructor((InvocationExpr)resultExpr)) {
|
||||
resultStmt = new SequentialStatement();
|
||||
} else {
|
||||
statement.setRightValue(resultExpr);
|
||||
|
|
|
@ -23,6 +23,8 @@ import org.teavm.codegen.NamingException;
|
|||
import org.teavm.codegen.NamingStrategy;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.common.ServiceRepository;
|
||||
import org.teavm.debugging.DebugInformationEmitter;
|
||||
import org.teavm.debugging.DummyDebugInformationEmitter;
|
||||
import org.teavm.javascript.ast.*;
|
||||
import org.teavm.javascript.ni.GeneratorContext;
|
||||
import org.teavm.javascript.ni.InjectedBy;
|
||||
|
@ -46,6 +48,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
private List<String> stringPool = new ArrayList<>();
|
||||
private Properties properties = new Properties();
|
||||
private ServiceRepository services;
|
||||
private DebugInformationEmitter debugEmitter = new DummyDebugInformationEmitter();
|
||||
private Deque<NodeLocation> locationStack = new ArrayDeque<>();
|
||||
|
||||
private static class InjectorHolder {
|
||||
public final Injector injector;
|
||||
|
@ -102,6 +106,14 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
return new Properties(properties);
|
||||
}
|
||||
|
||||
public DebugInformationEmitter getDebugEmitter() {
|
||||
return debugEmitter;
|
||||
}
|
||||
|
||||
public void setDebugEmitter(DebugInformationEmitter debugEmitter) {
|
||||
this.debugEmitter = debugEmitter;
|
||||
}
|
||||
|
||||
public void setProperties(Properties properties) {
|
||||
this.properties.clear();
|
||||
this.properties.putAll(properties);
|
||||
|
@ -462,6 +474,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
|
||||
public void renderBody(MethodNode method, boolean inner) throws IOException {
|
||||
MethodReference ref = method.getReference();
|
||||
debugEmitter.emitMethod(ref);
|
||||
if (inner) {
|
||||
writer.appendMethodBody(ref).ws().append("=").ws().append("function(");
|
||||
} else {
|
||||
|
@ -480,6 +493,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
writer.append(")").ws().append("{").softNewLine().indent();
|
||||
method.acceptVisitor(new MethodBodyRenderer());
|
||||
writer.outdent().append("}").newLine();
|
||||
debugEmitter.emitMethod(null);
|
||||
}
|
||||
|
||||
private class MethodBodyRenderer implements MethodNodeVisitor, GeneratorContext {
|
||||
|
@ -545,15 +559,40 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
}
|
||||
}
|
||||
|
||||
private void pushLocation(NodeLocation location) {
|
||||
locationStack.push(location);
|
||||
if (location != null) {
|
||||
debugEmitter.emitLocation(location.getFileName(), location.getLine());
|
||||
} else {
|
||||
debugEmitter.emitLocation(null, -1);
|
||||
}
|
||||
}
|
||||
|
||||
private void popLocation() {
|
||||
locationStack.pop();
|
||||
NodeLocation location = locationStack.peek();
|
||||
if (location != null) {
|
||||
debugEmitter.emitLocation(location.getFileName(), location.getLine());
|
||||
} else {
|
||||
debugEmitter.emitLocation(null, -1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AssignmentStatement statement) throws RenderingException {
|
||||
try {
|
||||
if (statement.getLocation() != null) {
|
||||
pushLocation(statement.getLocation());
|
||||
}
|
||||
if (statement.getLeftValue() != null) {
|
||||
statement.getLeftValue().acceptVisitor(this);
|
||||
writer.ws().append("=").ws();
|
||||
}
|
||||
statement.getRightValue().acceptVisitor(this);
|
||||
writer.append(";").softNewLine();
|
||||
if (statement.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
@ -672,11 +711,17 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
@Override
|
||||
public void visit(BreakStatement statement) {
|
||||
try {
|
||||
if (statement.getLocation() != null) {
|
||||
pushLocation(statement.getLocation());
|
||||
}
|
||||
writer.append("break");
|
||||
if (statement.getTarget() != null) {
|
||||
writer.append(' ').append(statement.getTarget().getId());
|
||||
}
|
||||
writer.append(";").softNewLine();
|
||||
if (statement.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
@ -685,11 +730,17 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
@Override
|
||||
public void visit(ContinueStatement statement) {
|
||||
try {
|
||||
if (statement.getLocation() != null) {
|
||||
pushLocation(statement.getLocation());
|
||||
}
|
||||
writer.append("continue");
|
||||
if (statement.getTarget() != null) {
|
||||
writer.append(' ').append(statement.getTarget().getId());
|
||||
}
|
||||
writer.append(";").softNewLine();
|
||||
if (statement.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
@ -698,12 +749,18 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
@Override
|
||||
public void visit(ReturnStatement statement) {
|
||||
try {
|
||||
if (statement.getLocation() != null) {
|
||||
pushLocation(statement.getLocation());
|
||||
}
|
||||
writer.append("return");
|
||||
if (statement.getResult() != null) {
|
||||
writer.append(' ');
|
||||
statement.getResult().acceptVisitor(this);
|
||||
}
|
||||
writer.append(";").softNewLine();
|
||||
if (statement.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
@ -712,9 +769,15 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
@Override
|
||||
public void visit(ThrowStatement statement) {
|
||||
try {
|
||||
if (statement.getLocation() != null) {
|
||||
pushLocation(statement.getLocation());
|
||||
}
|
||||
writer.append("$rt_throw(");
|
||||
statement.getException().acceptVisitor(this);
|
||||
writer.append(");").softNewLine();
|
||||
if (statement.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
@ -746,7 +809,13 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
@Override
|
||||
public void visit(InitClassStatement statement) {
|
||||
try {
|
||||
if (statement.getLocation() != null) {
|
||||
pushLocation(statement.getLocation());
|
||||
}
|
||||
writer.appendClass(statement.getClassName()).append("_$clinit();").softNewLine();
|
||||
if (statement.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
@ -767,11 +836,17 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
|
||||
private void visitBinary(BinaryExpr expr, String op) {
|
||||
try {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
writer.append('(');
|
||||
expr.getFirstOperand().acceptVisitor(this);
|
||||
writer.ws().append(op).ws();
|
||||
expr.getSecondOperand().acceptVisitor(this);
|
||||
writer.append(')');
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
@ -779,12 +854,18 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
|
||||
private void visitBinaryFunction(BinaryExpr expr, String function) {
|
||||
try {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
writer.append(function);
|
||||
writer.append('(');
|
||||
expr.getFirstOperand().acceptVisitor(this);
|
||||
writer.append(",").ws();
|
||||
expr.getSecondOperand().acceptVisitor(this);
|
||||
writer.append(')');
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
@ -900,6 +981,9 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
|
||||
@Override
|
||||
public void visit(UnaryExpr expr) {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
try {
|
||||
switch (expr.getOperation()) {
|
||||
case NOT:
|
||||
|
@ -964,11 +1048,17 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConditionalExpr expr) {
|
||||
try {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
writer.append('(');
|
||||
expr.getCondition().acceptVisitor(this);
|
||||
writer.ws().append("?").ws();
|
||||
|
@ -976,6 +1066,9 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
writer.ws().append(":").ws();
|
||||
expr.getAlternative().acceptVisitor(this);
|
||||
writer.append(')');
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
@ -984,7 +1077,13 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
@Override
|
||||
public void visit(ConstantExpr expr) {
|
||||
try {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
writer.append(constantToString(expr.getValue()));
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
@ -1113,7 +1212,13 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
@Override
|
||||
public void visit(VariableExpr expr) {
|
||||
try {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
writer.append(variableName(expr.getIndex()));
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
@ -1122,10 +1227,16 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
@Override
|
||||
public void visit(SubscriptExpr expr) {
|
||||
try {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
expr.getArray().acceptVisitor(this);
|
||||
writer.append('[');
|
||||
expr.getIndex().acceptVisitor(this);
|
||||
writer.append(']');
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
@ -1134,8 +1245,14 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
@Override
|
||||
public void visit(UnwrapArrayExpr expr) {
|
||||
try {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
expr.getArray().acceptVisitor(this);
|
||||
writer.append(".data");
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
@ -1144,55 +1261,61 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
@Override
|
||||
public void visit(InvocationExpr expr) {
|
||||
try {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
Injector injector = getInjector(expr.getMethod());
|
||||
if (injector != null) {
|
||||
injector.generate(new InjectorContextImpl(expr.getArguments()), expr.getMethod());
|
||||
return;
|
||||
} else {
|
||||
String className = naming.getNameFor(expr.getMethod().getClassName());
|
||||
String name = naming.getNameFor(expr.getMethod());
|
||||
String fullName = naming.getFullNameFor(expr.getMethod());
|
||||
switch (expr.getType()) {
|
||||
case STATIC:
|
||||
writer.append(fullName).append("(");
|
||||
for (int i = 0; i < expr.getArguments().size(); ++i) {
|
||||
if (i > 0) {
|
||||
writer.append(",").ws();
|
||||
}
|
||||
expr.getArguments().get(i).acceptVisitor(this);
|
||||
}
|
||||
writer.append(')');
|
||||
break;
|
||||
case SPECIAL:
|
||||
writer.append(fullName).append("(");
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
for (int i = 1; i < expr.getArguments().size(); ++i) {
|
||||
writer.append(",").ws();
|
||||
expr.getArguments().get(i).acceptVisitor(this);
|
||||
}
|
||||
writer.append(")");
|
||||
break;
|
||||
case DYNAMIC:
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
writer.append(".").append(name).append("(");
|
||||
for (int i = 1; i < expr.getArguments().size(); ++i) {
|
||||
if (i > 1) {
|
||||
writer.append(",").ws();
|
||||
}
|
||||
expr.getArguments().get(i).acceptVisitor(this);
|
||||
}
|
||||
writer.append(')');
|
||||
break;
|
||||
case CONSTRUCTOR:
|
||||
writer.append(className).append(".").append(name).append("(");
|
||||
for (int i = 0; i < expr.getArguments().size(); ++i) {
|
||||
if (i > 0) {
|
||||
writer.append(",").ws();
|
||||
}
|
||||
expr.getArguments().get(i).acceptVisitor(this);
|
||||
}
|
||||
writer.append(')');
|
||||
break;
|
||||
}
|
||||
}
|
||||
String className = naming.getNameFor(expr.getMethod().getClassName());
|
||||
String name = naming.getNameFor(expr.getMethod());
|
||||
String fullName = naming.getFullNameFor(expr.getMethod());
|
||||
switch (expr.getType()) {
|
||||
case STATIC:
|
||||
writer.append(fullName).append("(");
|
||||
for (int i = 0; i < expr.getArguments().size(); ++i) {
|
||||
if (i > 0) {
|
||||
writer.append(",").ws();
|
||||
}
|
||||
expr.getArguments().get(i).acceptVisitor(this);
|
||||
}
|
||||
writer.append(')');
|
||||
break;
|
||||
case SPECIAL:
|
||||
writer.append(fullName).append("(");
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
for (int i = 1; i < expr.getArguments().size(); ++i) {
|
||||
writer.append(",").ws();
|
||||
expr.getArguments().get(i).acceptVisitor(this);
|
||||
}
|
||||
writer.append(")");
|
||||
break;
|
||||
case DYNAMIC:
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
writer.append(".").append(name).append("(");
|
||||
for (int i = 1; i < expr.getArguments().size(); ++i) {
|
||||
if (i > 1) {
|
||||
writer.append(",").ws();
|
||||
}
|
||||
expr.getArguments().get(i).acceptVisitor(this);
|
||||
}
|
||||
writer.append(')');
|
||||
break;
|
||||
case CONSTRUCTOR:
|
||||
writer.append(className).append(".").append(name).append("(");
|
||||
for (int i = 0; i < expr.getArguments().size(); ++i) {
|
||||
if (i > 0) {
|
||||
writer.append(",").ws();
|
||||
}
|
||||
expr.getArguments().get(i).acceptVisitor(this);
|
||||
}
|
||||
writer.append(')');
|
||||
break;
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
|
@ -1202,8 +1325,14 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
@Override
|
||||
public void visit(QualificationExpr expr) {
|
||||
try {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
expr.getQualified().acceptVisitor(this);
|
||||
writer.append('.').appendField(expr.getField());
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
@ -1212,7 +1341,13 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
@Override
|
||||
public void visit(NewExpr expr) {
|
||||
try {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
writer.append("new ").append(naming.getNameFor(expr.getConstructedClass())).append("()");
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
@ -1220,6 +1355,9 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
|
||||
@Override
|
||||
public void visit(NewArrayExpr expr) {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
try {
|
||||
ValueType type = expr.getType();
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
|
@ -1273,10 +1411,16 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewMultiArrayExpr expr) {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
try {
|
||||
ValueType type = expr.getType();
|
||||
for (int i = 0; i < expr.getDimensions().size(); ++i) {
|
||||
|
@ -1328,10 +1472,16 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(InstanceOfExpr expr) {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
try {
|
||||
if (expr.getType() instanceof ValueType.Object) {
|
||||
String clsName = ((ValueType.Object)expr.getType()).getClassName();
|
||||
|
@ -1349,15 +1499,24 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(StaticClassExpr expr) {
|
||||
if (expr.getLocation() != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
}
|
||||
try {
|
||||
writer.append(typeToClsString(naming, expr.getType()));
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
if (expr.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -36,6 +36,11 @@ class StatementGenerator implements InstructionVisitor {
|
|||
Decompiler.Block[] blockMap;
|
||||
Program program;
|
||||
ClassHolderSource classSource;
|
||||
private NodeLocation currentLocation;
|
||||
|
||||
public void setCurrentLocation(NodeLocation currentLocation) {
|
||||
this.currentLocation = currentLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(EmptyInstruction insn) {
|
||||
|
@ -237,8 +242,10 @@ class StatementGenerator implements InstructionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(AssignInstruction insn) {
|
||||
statements.add(Statement.assign(Expr.var(insn.getReceiver().getIndex()),
|
||||
Expr.var(insn.getAssignee().getIndex())));
|
||||
AssignmentStatement stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()),
|
||||
Expr.var(insn.getAssignee().getIndex()));
|
||||
stmt.setLocation(currentLocation);
|
||||
statements.add(stmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -365,21 +372,29 @@ class StatementGenerator implements InstructionVisitor {
|
|||
BasicBlock alternative = insn.getAlternative();
|
||||
switch (insn.getCondition()) {
|
||||
case EQUAL:
|
||||
branch(Expr.binary(BinaryOperation.EQUALS, Expr.var(a), Expr.var(b)), consequent, alternative);
|
||||
branch(withLocation(Expr.binary(BinaryOperation.EQUALS, Expr.var(a), Expr.var(b))),
|
||||
consequent, alternative);
|
||||
break;
|
||||
case REFERENCE_EQUAL:
|
||||
branch(Expr.binary(BinaryOperation.STRICT_EQUALS, Expr.var(a), Expr.var(b)), consequent, alternative);
|
||||
branch(withLocation(Expr.binary(BinaryOperation.STRICT_EQUALS, Expr.var(a), Expr.var(b))),
|
||||
consequent, alternative);
|
||||
break;
|
||||
case NOT_EQUAL:
|
||||
branch(Expr.binary(BinaryOperation.NOT_EQUALS, Expr.var(a), Expr.var(b)), consequent, alternative);
|
||||
branch(withLocation(Expr.binary(BinaryOperation.NOT_EQUALS, Expr.var(a), Expr.var(b))),
|
||||
consequent, alternative);
|
||||
break;
|
||||
case REFERENCE_NOT_EQUAL:
|
||||
branch(Expr.binary(BinaryOperation.STRICT_NOT_EQUALS, Expr.var(a), Expr.var(b)),
|
||||
branch(withLocation(Expr.binary(BinaryOperation.STRICT_NOT_EQUALS, Expr.var(a), Expr.var(b))),
|
||||
consequent, alternative);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private Expr withLocation(Expr expr) {
|
||||
expr.setLocation(currentLocation);
|
||||
return expr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(JumpInstruction insn) {
|
||||
Statement stmt = generateJumpStatement(insn.getTarget());
|
||||
|
@ -428,13 +443,16 @@ class StatementGenerator implements InstructionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(ExitInstruction insn) {
|
||||
statements.add(Statement.exitFunction(insn.getValueToReturn() != null ?
|
||||
Expr.var(insn.getValueToReturn().getIndex()) : null));
|
||||
ReturnStatement stmt = Statement.exitFunction(insn.getValueToReturn() != null ?
|
||||
Expr.var(insn.getValueToReturn().getIndex()) : null);
|
||||
stmt.setLocation(currentLocation);
|
||||
statements.add(stmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RaiseInstruction insn) {
|
||||
ThrowStatement stmt = new ThrowStatement();
|
||||
stmt.setLocation(currentLocation);
|
||||
stmt.setException(Expr.var(insn.getException().getIndex()));
|
||||
statements.add(stmt);
|
||||
}
|
||||
|
@ -462,24 +480,27 @@ class StatementGenerator implements InstructionVisitor {
|
|||
@Override
|
||||
public void visit(GetFieldInstruction insn) {
|
||||
if (insn.getInstance() != null) {
|
||||
statements.add(Statement.assign(Expr.var(insn.getReceiver().getIndex()),
|
||||
Expr.qualify(Expr.var(insn.getInstance().getIndex()), insn.getField())));
|
||||
AssignmentStatement stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()),
|
||||
Expr.qualify(Expr.var(insn.getInstance().getIndex()), insn.getField()));
|
||||
stmt.setLocation(currentLocation);
|
||||
statements.add(stmt);
|
||||
} else {
|
||||
Expr fieldExpr = Expr.qualify(Expr.staticClass(ValueType.object(insn.getField().getClassName())),
|
||||
insn.getField());
|
||||
statements.add(Statement.assign(Expr.var(insn.getReceiver().getIndex()), fieldExpr));
|
||||
AssignmentStatement stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()), fieldExpr);
|
||||
stmt.setLocation(currentLocation);
|
||||
statements.add(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(PutFieldInstruction insn) {
|
||||
if (insn.getInstance() != null) {
|
||||
statements.add(Statement.assign(Expr.qualify(Expr.var(insn.getInstance().getIndex()), insn.getField()),
|
||||
Expr.var(insn.getValue().getIndex())));
|
||||
assign(Expr.qualify(Expr.var(insn.getInstance().getIndex()), insn.getField()), insn.getValue().getIndex());
|
||||
} else {
|
||||
Expr fieldExpr = Expr.qualify(Expr.staticClass(ValueType.object(insn.getField().getClassName())),
|
||||
insn.getField());
|
||||
statements.add(Statement.assign(fieldExpr, Expr.var(insn.getValue().getIndex())));
|
||||
assign(fieldExpr, insn.getValue().getIndex());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -511,8 +532,10 @@ class StatementGenerator implements InstructionVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(PutElementInstruction insn) {
|
||||
statements.add(Statement.assign(Expr.subscript(Expr.var(insn.getArray().getIndex()),
|
||||
Expr.var(insn.getIndex().getIndex())), Expr.var(insn.getValue().getIndex())));
|
||||
AssignmentStatement stmt = Statement.assign(Expr.subscript(Expr.var(insn.getArray().getIndex()),
|
||||
Expr.var(insn.getIndex().getIndex())), Expr.var(insn.getValue().getIndex()));
|
||||
stmt.setLocation(currentLocation);
|
||||
statements.add(stmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -535,7 +558,9 @@ class StatementGenerator implements InstructionVisitor {
|
|||
if (insn.getReceiver() != null) {
|
||||
assign(invocationExpr, insn.getReceiver().getIndex());
|
||||
} else {
|
||||
statements.add(Statement.assign(null, invocationExpr));
|
||||
AssignmentStatement stmt = Statement.assign(null, invocationExpr);
|
||||
stmt.setLocation(currentLocation);
|
||||
statements.add(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -546,7 +571,9 @@ class StatementGenerator implements InstructionVisitor {
|
|||
}
|
||||
|
||||
private void assign(Expr source, int target) {
|
||||
statements.add(Statement.assign(Expr.var(target), source));
|
||||
AssignmentStatement stmt = Statement.assign(Expr.var(target), source);
|
||||
stmt.setLocation(currentLocation);
|
||||
statements.add(stmt);
|
||||
}
|
||||
|
||||
private Expr castToInteger(Expr value) {
|
||||
|
@ -584,10 +611,12 @@ class StatementGenerator implements InstructionVisitor {
|
|||
Decompiler.Block block = blockMap[target.getIndex()];
|
||||
if (target.getIndex() == indexer.nodeAt(block.end)) {
|
||||
BreakStatement breakStmt = new BreakStatement();
|
||||
breakStmt.setLocation(currentLocation);
|
||||
breakStmt.setTarget(block.statement);
|
||||
return breakStmt;
|
||||
} else {
|
||||
ContinueStatement contStmt = new ContinueStatement();
|
||||
contStmt.setLocation(currentLocation);
|
||||
contStmt.setTarget(block.statement);
|
||||
return contStmt;
|
||||
}
|
||||
|
@ -601,6 +630,7 @@ class StatementGenerator implements InstructionVisitor {
|
|||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
private void branch(Expr condition, BasicBlock consequentBlock, BasicBlock alternativeBlock) {
|
||||
Statement consequent = generateJumpStatement(consequentBlock);
|
||||
Statement alternative = generateJumpStatement(alternativeBlock);
|
||||
|
@ -610,12 +640,16 @@ class StatementGenerator implements InstructionVisitor {
|
|||
}
|
||||
|
||||
private Expr compare(BinaryOperation op, Variable value) {
|
||||
return Expr.binary(op, Expr.var(value.getIndex()), Expr.constant(0));
|
||||
Expr expr = Expr.binary(op, Expr.var(value.getIndex()), Expr.constant(0));
|
||||
expr.setLocation(currentLocation);
|
||||
return expr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(InitClassInstruction insn) {
|
||||
statements.add(Statement.initClass(insn.getClassName()));
|
||||
InitClassStatement stmt = Statement.initClass(insn.getClassName());
|
||||
stmt.setLocation(currentLocation);
|
||||
statements.add(stmt);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -56,6 +56,12 @@ public abstract class Expr implements Cloneable {
|
|||
return expr;
|
||||
}
|
||||
|
||||
public static Expr binary(BinaryOperation op, Expr first, Expr second, NodeLocation loc) {
|
||||
Expr expr = binary(op, first, second);
|
||||
expr.setLocation(loc);
|
||||
return expr;
|
||||
}
|
||||
|
||||
public static Expr unary(UnaryOperation op, Expr arg) {
|
||||
UnaryExpr expr = new UnaryExpr();
|
||||
expr.setOperand(arg);
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.teavm.javascript.ast;
|
|||
* @author Alexey Andreev
|
||||
*/
|
||||
public class InitClassStatement extends Statement {
|
||||
private NodeLocation location;
|
||||
private String className;
|
||||
|
||||
public String getClassName() {
|
||||
|
@ -30,6 +31,14 @@ public class InitClassStatement extends Statement {
|
|||
this.className = className;
|
||||
}
|
||||
|
||||
public NodeLocation getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(NodeLocation location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(StatementVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
|
|
|
@ -15,32 +15,24 @@
|
|||
*/
|
||||
package org.teavm.javascript.ast;
|
||||
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class NodeLocation {
|
||||
private String className;
|
||||
private MethodDescriptor method;
|
||||
private int lineNumber;
|
||||
private String fileName;
|
||||
private int line;
|
||||
|
||||
public NodeLocation(String className, MethodDescriptor method, int lineNumber) {
|
||||
this.className = className;
|
||||
this.method = method;
|
||||
this.lineNumber = lineNumber;
|
||||
public NodeLocation(String fileName, int line) {
|
||||
this.fileName = fileName;
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public MethodDescriptor getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public int getLineNumber() {
|
||||
return lineNumber;
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,26 +29,26 @@ public abstract class Statement {
|
|||
return new SequentialStatement();
|
||||
}
|
||||
|
||||
public static Statement assign(Expr left, Expr right) {
|
||||
public static AssignmentStatement assign(Expr left, Expr right) {
|
||||
AssignmentStatement stmt = new AssignmentStatement();
|
||||
stmt.setLeftValue(left);
|
||||
stmt.setRightValue(right);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
public static Statement exitFunction(Expr result) {
|
||||
public static ReturnStatement exitFunction(Expr result) {
|
||||
ReturnStatement stmt = new ReturnStatement();
|
||||
stmt.setResult(result);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
public static Statement raiseException(Expr exception) {
|
||||
public static ThrowStatement raiseException(Expr exception) {
|
||||
ThrowStatement stmt = new ThrowStatement();
|
||||
stmt.setException(exception);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
public static Statement increment(int var, int amount) {
|
||||
public static IncrementStatement increment(int var, int amount) {
|
||||
IncrementStatement stmt = new IncrementStatement();
|
||||
stmt.setVar(var);
|
||||
stmt.setAmount(amount);
|
||||
|
@ -67,7 +67,7 @@ public abstract class Statement {
|
|||
return cond(predicate, consequent, Collections.<Statement>emptyList());
|
||||
}
|
||||
|
||||
public static Statement initClass(String className) {
|
||||
public static InitClassStatement initClass(String className) {
|
||||
InitClassStatement stmt = new InitClassStatement();
|
||||
stmt.setClassName(className);
|
||||
return stmt;
|
||||
|
|
|
@ -20,19 +20,19 @@ package org.teavm.model;
|
|||
* @author Alexey Andreev
|
||||
*/
|
||||
public class InstructionLocation {
|
||||
private String className;
|
||||
private MethodDescriptor method;
|
||||
private int lineNumber = -1;
|
||||
private String fileName;
|
||||
private int line = -1;
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
public InstructionLocation(String fileName, int line) {
|
||||
this.fileName = fileName;
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
public MethodDescriptor getMethod() {
|
||||
return method;
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public int getLineNumber() {
|
||||
return lineNumber;
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ import org.teavm.model.*;
|
|||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface InstructionReader {
|
||||
void location(InstructionLocation location);
|
||||
|
||||
void nop();
|
||||
|
||||
void classConstant(VariableReader receiver, ValueType cst);
|
||||
|
|
|
@ -24,12 +24,26 @@ import org.teavm.model.instructions.*;
|
|||
* @author Alexey Andreev
|
||||
*/
|
||||
public class InstructionStringifier implements InstructionReader {
|
||||
private InstructionLocation location;
|
||||
private StringBuilder sb;
|
||||
|
||||
public InstructionStringifier(StringBuilder sb) {
|
||||
this.sb = sb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void location(InstructionLocation location) {
|
||||
if (this.location != location) {
|
||||
if (location != null) {
|
||||
sb.append("at " + (location.getFileName() != null ? location.getFileName() : "<unknown>") + ":" +
|
||||
(location.getLine() >= 0 ? String.valueOf(location.getLine()) : "<unknown>"));
|
||||
} else {
|
||||
sb.append("<unkwnown>");
|
||||
}
|
||||
this.location = location;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nop() {
|
||||
sb.append("nop");
|
||||
|
|
|
@ -110,6 +110,12 @@ public final class ProgramUtils {
|
|||
private static class InstructionCopyReader implements InstructionReader {
|
||||
Instruction copy;
|
||||
Program programCopy;
|
||||
InstructionLocation location;
|
||||
|
||||
@Override
|
||||
public void location(InstructionLocation location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
private Variable copyVar(VariableReader var) {
|
||||
return programCopy.variableAt(var.getIndex());
|
||||
|
@ -122,6 +128,7 @@ public final class ProgramUtils {
|
|||
@Override
|
||||
public void nop() {
|
||||
copy = new EmptyInstruction();
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -130,6 +137,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setConstant(cst);
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -137,6 +145,7 @@ public final class ProgramUtils {
|
|||
NullConstantInstruction insnCopy = new NullConstantInstruction();
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -145,6 +154,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setConstant(cst);
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -153,6 +163,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setConstant(cst);
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -161,6 +172,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setConstant(cst);
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -169,6 +181,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setConstant(cst);
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -177,6 +190,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setConstant(cst);
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -187,6 +201,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setSecondOperand(copyVar(second));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -195,6 +210,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setOperand(copyVar(operand));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -203,6 +219,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setAssignee(copyVar(assignee));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -212,6 +229,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setReceiver(copyVar(receiver));
|
||||
insnCopy.setTargetType(targetType);
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -221,6 +239,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setValue(copyVar(value));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -230,6 +249,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setValue(copyVar(value));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -240,6 +260,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setConsequent(copyBlock(consequent));
|
||||
insnCopy.setAlternative(copyBlock(alternative));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -251,6 +272,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setConsequent(copyBlock(consequent));
|
||||
insnCopy.setAlternative(copyBlock(alternative));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -258,6 +280,7 @@ public final class ProgramUtils {
|
|||
JumpInstruction insnCopy = new JumpInstruction();
|
||||
insnCopy.setTarget(copyBlock(target));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -273,6 +296,7 @@ public final class ProgramUtils {
|
|||
insnCopy.getEntries().add(entryCopy);
|
||||
}
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -280,6 +304,7 @@ public final class ProgramUtils {
|
|||
ExitInstruction insnCopy = new ExitInstruction();
|
||||
insnCopy.setValueToReturn(valueToReturn != null ? copyVar(valueToReturn) : null);
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -287,6 +312,7 @@ public final class ProgramUtils {
|
|||
RaiseInstruction insnCopy = new RaiseInstruction();
|
||||
insnCopy.setException(copyVar(exception));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -296,6 +322,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setSize(copyVar(size));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -308,6 +335,7 @@ public final class ProgramUtils {
|
|||
insnCopy.getDimensions().add(copyVar(dim));
|
||||
}
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -316,6 +344,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setType(type);
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -327,6 +356,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -336,6 +366,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setInstance(instance != null ? copyVar(instance) : null);
|
||||
insnCopy.setValue(copyVar(value));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -344,6 +375,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setArray(copyVar(array));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -352,6 +384,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setArray(copyVar(array));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -360,6 +393,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setArray(copyVar(array));
|
||||
insnCopy.setReceiver(copyVar(receiver));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -369,6 +403,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setReceiver(copyVar(receiver));
|
||||
insnCopy.setIndex(copyVar(index));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -378,6 +413,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setValue(copyVar(value));
|
||||
insnCopy.setIndex(copyVar(index));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -392,6 +428,7 @@ public final class ProgramUtils {
|
|||
insnCopy.getArguments().add(copyVar(arg));
|
||||
}
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -401,6 +438,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setReceiver(copyVar(receiver));
|
||||
insnCopy.setType(type);
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -408,6 +446,7 @@ public final class ProgramUtils {
|
|||
InitClassInstruction insnCopy = new InitClassInstruction();
|
||||
insnCopy.setClassName(className);
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -416,6 +455,7 @@ public final class ProgramUtils {
|
|||
insnCopy.setReceiver(copyVar(receiver));
|
||||
insnCopy.setValue(copyVar(value));
|
||||
copy = insnCopy;
|
||||
copy.setLocation(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,11 +31,12 @@ public final class Parser {
|
|||
private Parser() {
|
||||
}
|
||||
|
||||
public static MethodHolder parseMethod(MethodNode node, String className) {
|
||||
public static MethodHolder parseMethod(MethodNode node, String className, String fileName) {
|
||||
ValueType[] signature = MethodDescriptor.parseSignature(node.desc);
|
||||
MethodHolder method = new MethodHolder(node.name, signature);
|
||||
parseModifiers(node.access, method);
|
||||
ProgramParser programParser = new ProgramParser();
|
||||
programParser.setFileName(fileName);
|
||||
Program program = programParser.parse(node, className);
|
||||
new UnreachableBasicBlockEliminator().optimize(program);
|
||||
SSATransformer ssaProducer = new SSATransformer();
|
||||
|
@ -65,7 +66,7 @@ public final class Parser {
|
|||
}
|
||||
for (Object obj : node.methods) {
|
||||
MethodNode methodNode = (MethodNode)obj;
|
||||
cls.addMethod(parseMethod(methodNode, node.name));
|
||||
cls.addMethod(parseMethod(methodNode, node.name, node.sourceFile));
|
||||
}
|
||||
if (node.outerClass != null) {
|
||||
cls.setOwnerName(node.outerClass.replace('/', '.'));
|
||||
|
|
|
@ -31,18 +31,23 @@ public class ProgramParser {
|
|||
static final byte SINGLE = 1;
|
||||
static final byte DOUBLE_FIRST_HALF = 2;
|
||||
static final byte DOUBLE_SECOND_HALF = 3;
|
||||
private String fileName;
|
||||
private StackFrame[] stackBefore;
|
||||
private StackFrame[] stackAfter;
|
||||
private StackFrame stack;
|
||||
private int index;
|
||||
private int[] nextIndexes;
|
||||
private Map<Label, Integer> labelIndexes;
|
||||
private Map<Label, Integer> lineNumbers;
|
||||
private List<List<Instruction>> targetInstructions;
|
||||
private List<Instruction> builder = new ArrayList<>();
|
||||
private List<BasicBlock> basicBlocks = new ArrayList<>();
|
||||
private int minLocal;
|
||||
private Program program;
|
||||
private String currentClassName;
|
||||
private int currentLineNumber;
|
||||
private boolean lineNumberChanged;
|
||||
private InstructionLocation lastInsnLocation;
|
||||
|
||||
private static class Step {
|
||||
public final int source;
|
||||
|
@ -72,7 +77,17 @@ public class ProgramParser {
|
|||
}
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public Program parse(MethodNode method, String className) {
|
||||
currentLineNumber = -1;
|
||||
lineNumberChanged = true;
|
||||
program = new Program();
|
||||
this.currentClassName = className;
|
||||
InsnList instructions = method.instructions;
|
||||
|
@ -151,11 +166,16 @@ public class ProgramParser {
|
|||
minLocal = 1;
|
||||
}
|
||||
labelIndexes = new HashMap<>();
|
||||
lineNumbers = new HashMap<>();
|
||||
for (int i = 0; i < instructions.size(); ++i) {
|
||||
AbstractInsnNode node = instructions.get(i);
|
||||
if (node instanceof LabelNode) {
|
||||
labelIndexes.put(((LabelNode)node).getLabel(), i);
|
||||
}
|
||||
if (node instanceof LineNumberNode) {
|
||||
LineNumberNode lineNumberNode = (LineNumberNode)node;
|
||||
lineNumbers.put(lineNumberNode.start.getLabel(), lineNumberNode.line);
|
||||
}
|
||||
}
|
||||
targetInstructions = new ArrayList<>(instructions.size());
|
||||
targetInstructions.addAll(Collections.<List<Instruction>>nCopies(instructions.size(), null));
|
||||
|
@ -289,6 +309,15 @@ public class ProgramParser {
|
|||
AssignInstruction insn = new AssignInstruction();
|
||||
insn.setAssignee(getVariable(source));
|
||||
insn.setReceiver(getVariable(target));
|
||||
addInstruction(insn);
|
||||
}
|
||||
|
||||
private void addInstruction(Instruction insn) {
|
||||
if (lineNumberChanged) {
|
||||
lastInsnLocation = new InstructionLocation(fileName, currentLineNumber);
|
||||
lineNumberChanged = false;
|
||||
}
|
||||
insn.setLocation(lastInsnLocation);
|
||||
builder.add(insn);
|
||||
}
|
||||
|
||||
|
@ -338,7 +367,7 @@ public class ProgramParser {
|
|||
ConstructInstruction insn = new ConstructInstruction();
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
insn.setType(cls);
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
case Opcodes.ANEWARRAY: {
|
||||
|
@ -347,7 +376,7 @@ public class ProgramParser {
|
|||
insn.setSize(getVariable(popSingle()));
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
insn.setItemType(valueType);
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
case Opcodes.INSTANCEOF: {
|
||||
|
@ -355,7 +384,7 @@ public class ProgramParser {
|
|||
insn.setValue(getVariable(popSingle()));
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
insn.setType(parseType(type));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
case Opcodes.CHECKCAST: {
|
||||
|
@ -363,7 +392,7 @@ public class ProgramParser {
|
|||
insn.setValue(getVariable(popSingle()));
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
insn.setTargetType(parseType(type));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -389,15 +418,14 @@ public class ProgramParser {
|
|||
SwitchInstruction insn = new SwitchInstruction();
|
||||
insn.setCondition(getVariable(popSingle()));
|
||||
insn.getEntries().addAll(Arrays.asList(table));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
int defaultIndex = labelIndexes.get(dflt);
|
||||
insn.setDefaultTarget(getBasicBlock(defaultIndex));
|
||||
nextIndexes[labels.length] = defaultIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitParameterAnnotation(int parameter, String desc,
|
||||
boolean visible) {
|
||||
public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -412,7 +440,7 @@ public class ProgramParser {
|
|||
insn.setItemType(arrayType);
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
insn.getDimensions().addAll(Arrays.asList(dimensions));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -428,7 +456,7 @@ public class ProgramParser {
|
|||
CloneArrayInstruction insn = new CloneArrayInstruction();
|
||||
insn.setArray(getVariable(popSingle()));
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
ownerCls = "java.lang.Object";
|
||||
|
@ -458,7 +486,7 @@ public class ProgramParser {
|
|||
insn.setReceiver(getVariable(result));
|
||||
}
|
||||
insn.getArguments().addAll(Arrays.asList(args));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
} else {
|
||||
InvokeInstruction insn = new InvokeInstruction();
|
||||
if (opcode == Opcodes.INVOKESPECIAL) {
|
||||
|
@ -472,7 +500,7 @@ public class ProgramParser {
|
|||
}
|
||||
insn.setInstance(getVariable(instance));
|
||||
insn.getArguments().addAll(Arrays.asList(args));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -499,15 +527,14 @@ public class ProgramParser {
|
|||
SwitchInstruction insn = new SwitchInstruction();
|
||||
insn.setCondition(getVariable(popSingle()));
|
||||
insn.getEntries().addAll(Arrays.asList(table));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
int defaultTarget = labelIndexes.get(dflt);
|
||||
insn.setDefaultTarget(getBasicBlock(defaultTarget));
|
||||
nextIndexes[labels.length] = labelIndexes.get(dflt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(String name, String desc, String signature, Label start,
|
||||
Label end, int index) {
|
||||
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -528,12 +555,12 @@ public class ProgramParser {
|
|||
StringConstantInstruction insn = new StringConstantInstruction();
|
||||
insn.setConstant((String)cst);
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
} else if (cst instanceof Type) {
|
||||
ClassConstantInstruction insn = new ClassConstantInstruction();
|
||||
insn.setConstant(ValueType.parse(((Type)cst).getDescriptor()));
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
@ -541,6 +568,11 @@ public class ProgramParser {
|
|||
|
||||
@Override
|
||||
public void visitLabel(Label label) {
|
||||
Integer lineNumber = lineNumbers.get(label);
|
||||
if (lineNumber != null) {
|
||||
currentLineNumber = lineNumber;
|
||||
lineNumberChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void emitBranching(BranchingCondition condition, int value, int target) {
|
||||
|
@ -548,7 +580,7 @@ public class ProgramParser {
|
|||
insn.setOperand(getVariable(value));
|
||||
insn.setConsequent(getBasicBlock(target));
|
||||
insn.setAlternative(getBasicBlock(index + 1));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
}
|
||||
|
||||
private void emitBranching(BinaryBranchingCondition condition, int first, int second,
|
||||
|
@ -558,7 +590,7 @@ public class ProgramParser {
|
|||
insn.setSecondOperand(getVariable(second));
|
||||
insn.setConsequent(getBasicBlock(target));
|
||||
insn.setAlternative(getBasicBlock(index + 1));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
}
|
||||
|
||||
private void emitBinary(BinaryOperation operation, NumericOperandType operandType,
|
||||
|
@ -567,21 +599,21 @@ public class ProgramParser {
|
|||
insn.setFirstOperand(getVariable(first));
|
||||
insn.setSecondOperand(getVariable(second));
|
||||
insn.setReceiver(getVariable(receiver));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
}
|
||||
|
||||
private void emitNeg(NumericOperandType operandType, int operand, int receiver) {
|
||||
NegateInstruction insn = new NegateInstruction(operandType);
|
||||
insn.setOperand(getVariable(operand));
|
||||
insn.setReceiver(getVariable(receiver));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
}
|
||||
|
||||
private void emitNumberCast(NumericOperandType source, NumericOperandType target, int value, int result) {
|
||||
CastNumberInstruction insn = new CastNumberInstruction(source, target);
|
||||
insn.setReceiver(getVariable(result));
|
||||
insn.setValue(getVariable(value));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -669,7 +701,7 @@ public class ProgramParser {
|
|||
case Opcodes.GOTO: {
|
||||
JumpInstruction insn = new JumpInstruction();
|
||||
insn.setTarget(getBasicBlock(target));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
nextIndexes = new int[] { labelIndexes.get(label) };
|
||||
return;
|
||||
}
|
||||
|
@ -686,14 +718,14 @@ public class ProgramParser {
|
|||
IntegerConstantInstruction insn = new IntegerConstantInstruction();
|
||||
insn.setConstant(operand);
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
case Opcodes.SIPUSH: {
|
||||
IntegerConstantInstruction insn = new IntegerConstantInstruction();
|
||||
insn.setConstant(operand);
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
case Opcodes.NEWARRAY: {
|
||||
|
@ -730,7 +762,7 @@ public class ProgramParser {
|
|||
insn.setSize(getVariable(popSingle()));
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
insn.setItemType(itemType);
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -740,28 +772,28 @@ public class ProgramParser {
|
|||
IntegerConstantInstruction insn = new IntegerConstantInstruction();
|
||||
insn.setConstant(value);
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
}
|
||||
|
||||
private void pushConstant(long value) {
|
||||
LongConstantInstruction insn = new LongConstantInstruction();
|
||||
insn.setConstant(value);
|
||||
insn.setReceiver(getVariable(pushDouble()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
}
|
||||
|
||||
private void pushConstant(double value) {
|
||||
DoubleConstantInstruction insn = new DoubleConstantInstruction();
|
||||
insn.setConstant(value);
|
||||
insn.setReceiver(getVariable(pushDouble()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
}
|
||||
|
||||
private void pushConstant(float value) {
|
||||
FloatConstantInstruction insn = new FloatConstantInstruction();
|
||||
insn.setConstant(value);
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
}
|
||||
|
||||
private void loadArrayElement(int sz, ArrayElementType type) {
|
||||
|
@ -771,12 +803,12 @@ public class ProgramParser {
|
|||
UnwrapArrayInstruction unwrapInsn = new UnwrapArrayInstruction(type);
|
||||
unwrapInsn.setArray(getVariable(array));
|
||||
unwrapInsn.setReceiver(unwrapInsn.getArray());
|
||||
builder.add(unwrapInsn);
|
||||
addInstruction(unwrapInsn);
|
||||
GetElementInstruction insn = new GetElementInstruction();
|
||||
insn.setArray(getVariable(array));
|
||||
insn.setIndex(getVariable(arrIndex));
|
||||
insn.setReceiver(getVariable(var));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
}
|
||||
|
||||
private void storeArrayElement(int sz, ArrayElementType type) {
|
||||
|
@ -786,12 +818,12 @@ public class ProgramParser {
|
|||
UnwrapArrayInstruction unwrapInsn = new UnwrapArrayInstruction(type);
|
||||
unwrapInsn.setArray(getVariable(array));
|
||||
unwrapInsn.setReceiver(unwrapInsn.getArray());
|
||||
builder.add(unwrapInsn);
|
||||
addInstruction(unwrapInsn);
|
||||
PutElementInstruction insn = new PutElementInstruction();
|
||||
insn.setArray(getVariable(array));
|
||||
insn.setIndex(getVariable(arrIndex));
|
||||
insn.setValue(getVariable(value));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -800,7 +832,7 @@ public class ProgramParser {
|
|||
case Opcodes.ACONST_NULL: {
|
||||
NullConstantInstruction insn = new NullConstantInstruction();
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
case Opcodes.ICONST_M1:
|
||||
|
@ -851,7 +883,7 @@ public class ProgramParser {
|
|||
CastIntegerDirection.TO_INTEGER);
|
||||
insn.setValue(getVariable(popSingle()));
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
case Opcodes.IALOAD:
|
||||
|
@ -866,7 +898,7 @@ public class ProgramParser {
|
|||
CastIntegerDirection.TO_INTEGER);
|
||||
insn.setValue(getVariable(popSingle()));
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
case Opcodes.CALOAD: {
|
||||
|
@ -875,7 +907,7 @@ public class ProgramParser {
|
|||
CastIntegerDirection.TO_INTEGER);
|
||||
insn.setValue(getVariable(popSingle()));
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
case Opcodes.AALOAD:
|
||||
|
@ -1353,7 +1385,7 @@ public class ProgramParser {
|
|||
CastIntegerDirection.FROM_INTEGER);
|
||||
insn.setValue(getVariable(popSingle()));
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
case Opcodes.I2C: {
|
||||
|
@ -1361,7 +1393,7 @@ public class ProgramParser {
|
|||
CastIntegerDirection.FROM_INTEGER);
|
||||
insn.setValue(getVariable(popSingle()));
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
case Opcodes.I2S: {
|
||||
|
@ -1369,7 +1401,7 @@ public class ProgramParser {
|
|||
CastIntegerDirection.FROM_INTEGER);
|
||||
insn.setValue(getVariable(popSingle()));
|
||||
insn.setReceiver(getVariable(pushSingle()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
case Opcodes.I2F: {
|
||||
|
@ -1449,7 +1481,7 @@ public class ProgramParser {
|
|||
case Opcodes.ARETURN: {
|
||||
ExitInstruction insn = new ExitInstruction();
|
||||
insn.setValueToReturn(getVariable(popSingle()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
nextIndexes = new int[0];
|
||||
return;
|
||||
}
|
||||
|
@ -1457,13 +1489,13 @@ public class ProgramParser {
|
|||
case Opcodes.DRETURN: {
|
||||
ExitInstruction insn = new ExitInstruction();
|
||||
insn.setValueToReturn(getVariable(popDouble()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
nextIndexes = new int[0];
|
||||
return;
|
||||
}
|
||||
case Opcodes.RETURN: {
|
||||
ExitInstruction insn = new ExitInstruction();
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
nextIndexes = new int[0];
|
||||
return;
|
||||
}
|
||||
|
@ -1473,17 +1505,17 @@ public class ProgramParser {
|
|||
UnwrapArrayInstruction unwrapInsn = new UnwrapArrayInstruction(ArrayElementType.OBJECT);
|
||||
unwrapInsn.setArray(getVariable(a));
|
||||
unwrapInsn.setReceiver(getVariable(r));
|
||||
builder.add(unwrapInsn);
|
||||
addInstruction(unwrapInsn);
|
||||
ArrayLengthInstruction insn = new ArrayLengthInstruction();
|
||||
insn.setArray(getVariable(a));
|
||||
insn.setReceiver(getVariable(r));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
case Opcodes.ATHROW: {
|
||||
RaiseInstruction insn = new RaiseInstruction();
|
||||
insn.setException(getVariable(popSingle()));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
nextIndexes = new int[0];
|
||||
return;
|
||||
}
|
||||
|
@ -1502,7 +1534,7 @@ public class ProgramParser {
|
|||
IntegerConstantInstruction intInsn = new IntegerConstantInstruction();
|
||||
intInsn.setConstant(increment);
|
||||
intInsn.setReceiver(getVariable(tmp));
|
||||
builder.add(intInsn);
|
||||
addInstruction(intInsn);
|
||||
emitBinary(BinaryOperation.ADD, NumericOperandType.INT, var, tmp, var);
|
||||
}
|
||||
|
||||
|
@ -1523,7 +1555,7 @@ public class ProgramParser {
|
|||
insn.setField(new FieldReference(ownerCls, name));
|
||||
insn.setFieldType(type);
|
||||
insn.setReceiver(getVariable(value));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
case Opcodes.PUTFIELD: {
|
||||
|
@ -1533,7 +1565,7 @@ public class ProgramParser {
|
|||
insn.setInstance(getVariable(instance));
|
||||
insn.setField(new FieldReference(ownerCls, name));
|
||||
insn.setValue(getVariable(value));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
case Opcodes.GETSTATIC: {
|
||||
|
@ -1542,26 +1574,26 @@ public class ProgramParser {
|
|||
if (!owner.equals(currentClassName)) {
|
||||
InitClassInstruction initInsn = new InitClassInstruction();
|
||||
initInsn.setClassName(ownerCls);
|
||||
builder.add(initInsn);
|
||||
addInstruction(initInsn);
|
||||
}
|
||||
GetFieldInstruction insn = new GetFieldInstruction();
|
||||
insn.setField(new FieldReference(ownerCls, name));
|
||||
insn.setFieldType(type);
|
||||
insn.setReceiver(getVariable(value));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
case Opcodes.PUTSTATIC: {
|
||||
if (!owner.equals(currentClassName)) {
|
||||
InitClassInstruction initInsn = new InitClassInstruction();
|
||||
initInsn.setClassName(ownerCls);
|
||||
builder.add(initInsn);
|
||||
addInstruction(initInsn);
|
||||
}
|
||||
int value = desc.equals("D") || desc.equals("J") ? popDouble() : popSingle();
|
||||
PutFieldInstruction insn = new PutFieldInstruction();
|
||||
insn.setField(new FieldReference(ownerCls, name));
|
||||
insn.setValue(getVariable(value));
|
||||
builder.add(insn);
|
||||
addInstruction(insn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.List;
|
|||
import java.util.Properties;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.teavm.common.ThreadPoolFiniteExecutor;
|
||||
import org.teavm.debugging.DebugInformationBuilder;
|
||||
import org.teavm.javascript.RenderingContext;
|
||||
import org.teavm.model.ClassHolderTransformer;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
|
@ -43,6 +44,7 @@ public class TeaVMTool {
|
|||
private Properties properties = new Properties();
|
||||
private boolean mainPageIncluded;
|
||||
private boolean bytecodeLogging;
|
||||
private File debugInformation;
|
||||
private int numThreads = 1;
|
||||
private List<ClassHolderTransformer> transformers = new ArrayList<>();
|
||||
private List<ClassAlias> classAliases = new ArrayList<>();
|
||||
|
@ -106,6 +108,14 @@ public class TeaVMTool {
|
|||
this.bytecodeLogging = bytecodeLogging;
|
||||
}
|
||||
|
||||
public File getDebugInformation() {
|
||||
return debugInformation;
|
||||
}
|
||||
|
||||
public void setDebugInformation(File debugInformation) {
|
||||
this.debugInformation = debugInformation;
|
||||
}
|
||||
|
||||
public int getNumThreads() {
|
||||
return numThreads;
|
||||
}
|
||||
|
@ -166,6 +176,8 @@ public class TeaVMTool {
|
|||
vm.setMinifying(minifying);
|
||||
vm.setBytecodeLogging(bytecodeLogging);
|
||||
vm.setProperties(properties);
|
||||
DebugInformationBuilder debugEmitter = debugInformation != null ? new DebugInformationBuilder() : null;
|
||||
vm.setDebugEmitter(debugEmitter);
|
||||
vm.installPlugins();
|
||||
for (ClassHolderTransformer transformer : transformers) {
|
||||
vm.add(transformer);
|
||||
|
@ -205,6 +217,12 @@ public class TeaVMTool {
|
|||
vm.build(writer, new DirectoryBuildTarget(targetDirectory));
|
||||
vm.checkForMissingItems();
|
||||
log.info("JavaScript file successfully built");
|
||||
if (debugInformation != null) {
|
||||
try (OutputStream debugInfoOut = new FileOutputStream(debugInformation)) {
|
||||
debugEmitter.getDebugInformation().write(debugInfoOut);
|
||||
}
|
||||
log.info("Debug information successfully written");
|
||||
}
|
||||
}
|
||||
if (runtime == RuntimeCopyOperation.SEPARATE) {
|
||||
resourceToFile("org/teavm/javascript/runtime.js", "runtime.js");
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.*;
|
|||
import org.teavm.codegen.*;
|
||||
import org.teavm.common.FiniteExecutor;
|
||||
import org.teavm.common.ServiceRepository;
|
||||
import org.teavm.debugging.DebugInformationEmitter;
|
||||
import org.teavm.dependency.*;
|
||||
import org.teavm.javascript.Decompiler;
|
||||
import org.teavm.javascript.Renderer;
|
||||
|
@ -81,6 +82,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
private List<RendererListener> rendererListeners = new ArrayList<>();
|
||||
private Map<Class<?>, Object> services = new HashMap<>();
|
||||
private Properties properties = new Properties();
|
||||
private DebugInformationEmitter debugEmitter;
|
||||
|
||||
TeaVM(ClassReaderSource classSource, ClassLoader classLoader, FiniteExecutor executor) {
|
||||
this.classSource = classSource;
|
||||
|
@ -267,6 +269,14 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
dependencyChecker.checkForMissingItems();
|
||||
}
|
||||
|
||||
public DebugInformationEmitter getDebugEmitter() {
|
||||
return debugEmitter;
|
||||
}
|
||||
|
||||
public void setDebugEmitter(DebugInformationEmitter debugEmitter) {
|
||||
this.debugEmitter = debugEmitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Does actual build. Call this method after TeaVM is fully configured and all entry points
|
||||
* are specified. This method may fail if there are items (classes, methods and fields)
|
||||
|
@ -338,6 +348,9 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
builder.setMinified(minifying);
|
||||
SourceWriter sourceWriter = builder.build(writer);
|
||||
Renderer renderer = new Renderer(sourceWriter, classSet, classLoader, this);
|
||||
if (debugEmitter != null) {
|
||||
renderer.setDebugEmitter(debugEmitter);
|
||||
}
|
||||
for (Map.Entry<MethodReference, Injector> entry : methodInjectors.entrySet()) {
|
||||
renderer.addInjector(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
|
|
@ -74,6 +74,12 @@ public class BuildJavascriptMojo extends AbstractMojo {
|
|||
@Parameter
|
||||
private boolean bytecodeLogging;
|
||||
|
||||
@Parameter
|
||||
private boolean debugInformationGenerated;
|
||||
|
||||
@Parameter
|
||||
private File debugInformationFile;
|
||||
|
||||
@Parameter(required = false)
|
||||
private int numThreads = 1;
|
||||
|
||||
|
@ -144,6 +150,22 @@ public class BuildJavascriptMojo extends AbstractMojo {
|
|||
this.methodAliases = methodAliases;
|
||||
}
|
||||
|
||||
public boolean isDebugInformationGenerated() {
|
||||
return debugInformationGenerated;
|
||||
}
|
||||
|
||||
public void setDebugInformationGenerated(boolean debugInformationGenerated) {
|
||||
this.debugInformationGenerated = debugInformationGenerated;
|
||||
}
|
||||
|
||||
public File getDebugInformationFile() {
|
||||
return debugInformationFile;
|
||||
}
|
||||
|
||||
public void setDebugInformationFile(File debugInformationFile) {
|
||||
this.debugInformationFile = debugInformationFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws MojoExecutionException {
|
||||
Log log = getLog();
|
||||
|
@ -169,6 +191,10 @@ public class BuildJavascriptMojo extends AbstractMojo {
|
|||
if (properties != null) {
|
||||
tool.getProperties().putAll(properties);
|
||||
}
|
||||
if (isDebugInformationGenerated()) {
|
||||
tool.setDebugInformation(debugInformationFile != null ? debugInformationFile :
|
||||
new File(targetDirectory, targetFileName + ".teavmdbg"));
|
||||
}
|
||||
tool.generate();
|
||||
} catch (RuntimeException e) {
|
||||
throw new MojoExecutionException("Unexpected error occured", e);
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
<minifying>false</minifying>
|
||||
<mainClass>org.teavm.samples.HelloWorld</mainClass>
|
||||
<mainPageIncluded>true</mainPageIncluded>
|
||||
<debugInformationGenerated>true</debugInformationGenerated>
|
||||
<targetDirectory>${project.build.directory}/javascript/hello</targetDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
@ -73,6 +74,7 @@
|
|||
<minifying>false</minifying>
|
||||
<mainClass>org.teavm.samples.MatrixMultiplication</mainClass>
|
||||
<mainPageIncluded>true</mainPageIncluded>
|
||||
<debugInformationGenerated>true</debugInformationGenerated>
|
||||
<targetDirectory>${project.build.directory}/javascript/matrix</targetDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
@ -86,6 +88,7 @@
|
|||
<minifying>false</minifying>
|
||||
<mainClass>org.teavm.samples.DateTime</mainClass>
|
||||
<targetDirectory>${project.build.directory}/javascript/datetime</targetDirectory>
|
||||
<debugInformationGenerated>true</debugInformationGenerated>
|
||||
<properties>
|
||||
<java.util.Locale.available>en_US,en_GB,ru_RU,ru_UA,nl_NL,nl_BE</java.util.Locale.available>
|
||||
</properties>
|
||||
|
|
Loading…
Reference in New Issue
Block a user