mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
C: generate '#line' preprocessor directive
This commit is contained in:
parent
7a99258cab
commit
0003ed0bb2
|
@ -144,6 +144,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
private Characteristics characteristics;
|
||||
private Set<MethodReference> asyncMethods;
|
||||
private boolean incremental;
|
||||
private boolean lineNumbersGenerated;
|
||||
private StringPool stringPool;
|
||||
|
||||
public CTarget() {
|
||||
|
@ -162,6 +163,10 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
this.incremental = incremental;
|
||||
}
|
||||
|
||||
public void setLineNumbersGenerated(boolean lineNumbersGenerated) {
|
||||
this.lineNumbersGenerated = lineNumbersGenerated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClassHolderTransformer> getTransformers() {
|
||||
List<ClassHolderTransformer> transformers = new ArrayList<>();
|
||||
|
@ -332,8 +337,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
controller.getDependencyInfo(), stringPool, nameProvider, controller.getDiagnostics(), classes,
|
||||
intrinsics, generators, asyncMethods::contains, buildTarget, incremental);
|
||||
|
||||
BufferedCodeWriter runtimeWriter = new BufferedCodeWriter();
|
||||
BufferedCodeWriter runtimeHeaderWriter = new BufferedCodeWriter();
|
||||
BufferedCodeWriter runtimeWriter = new BufferedCodeWriter(false);
|
||||
BufferedCodeWriter runtimeHeaderWriter = new BufferedCodeWriter(false);
|
||||
emitResource(runtimeWriter, "runtime.c");
|
||||
|
||||
runtimeHeaderWriter.println("#pragma once");
|
||||
|
@ -393,8 +398,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
classGenerator.prepare(classes);
|
||||
|
||||
for (String className : classNames) {
|
||||
BufferedCodeWriter writer = new BufferedCodeWriter();
|
||||
BufferedCodeWriter headerWriter = new BufferedCodeWriter();
|
||||
BufferedCodeWriter writer = new BufferedCodeWriter(lineNumbersGenerated);
|
||||
BufferedCodeWriter headerWriter = new BufferedCodeWriter(false);
|
||||
ClassHolder cls = classes.get(className);
|
||||
if (cls != null) {
|
||||
classGenerator.generateClass(writer, headerWriter, cls);
|
||||
|
@ -408,8 +413,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
if (type instanceof ValueType.Object) {
|
||||
continue;
|
||||
}
|
||||
BufferedCodeWriter writer = new BufferedCodeWriter();
|
||||
BufferedCodeWriter headerWriter = new BufferedCodeWriter();
|
||||
BufferedCodeWriter writer = new BufferedCodeWriter(false);
|
||||
BufferedCodeWriter headerWriter = new BufferedCodeWriter(false);
|
||||
classGenerator.generateType(writer, headerWriter, type);
|
||||
String name = ClassGenerator.fileName(type);
|
||||
OutputFileUtil.write(writer, name + ".c", buildTarget);
|
||||
|
@ -451,8 +456,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
|
||||
private void generateCallSites(BuildTarget buildTarget, GenerationContext context,
|
||||
Collection<? extends String> classNames) throws IOException {
|
||||
BufferedCodeWriter writer = new BufferedCodeWriter();
|
||||
BufferedCodeWriter headerWriter = new BufferedCodeWriter();
|
||||
BufferedCodeWriter writer = new BufferedCodeWriter(false);
|
||||
BufferedCodeWriter headerWriter = new BufferedCodeWriter(false);
|
||||
|
||||
IncludeManager includes = new SimpleIncludeManager(writer);
|
||||
includes.init("callsites.c");
|
||||
|
@ -491,8 +496,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
}
|
||||
|
||||
private void generateStrings(BuildTarget buildTarget, StringPool stringPool) throws IOException {
|
||||
BufferedCodeWriter writer = new BufferedCodeWriter();
|
||||
BufferedCodeWriter headerWriter = new BufferedCodeWriter();
|
||||
BufferedCodeWriter writer = new BufferedCodeWriter(false);
|
||||
BufferedCodeWriter headerWriter = new BufferedCodeWriter(false);
|
||||
|
||||
headerWriter.println("#pragma once");
|
||||
headerWriter.println("#include \"runtime.h\"");
|
||||
|
@ -588,7 +593,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
|
||||
private void generateMainFile(GenerationContext context, ListableClassHolderSource classes,
|
||||
List<? extends ValueType> types, BuildTarget buildTarget) throws IOException {
|
||||
BufferedCodeWriter writer = new BufferedCodeWriter();
|
||||
BufferedCodeWriter writer = new BufferedCodeWriter(false);
|
||||
IncludeManager includes = new SimpleIncludeManager(writer);
|
||||
includes.init("main.c");
|
||||
includes.includePath("runtime.h");
|
||||
|
@ -601,7 +606,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
|
||||
private void generateAllFile(ListableClassHolderSource classes, List<? extends ValueType> types,
|
||||
BuildTarget buildTarget) throws IOException {
|
||||
BufferedCodeWriter writer = new BufferedCodeWriter();
|
||||
BufferedCodeWriter writer = new BufferedCodeWriter(false);
|
||||
IncludeManager includes = new SimpleIncludeManager(writer);
|
||||
includes.init("all.c");
|
||||
includes.includePath("runtime.c");
|
||||
|
|
|
@ -18,18 +18,24 @@ package org.teavm.backend.c.generate;
|
|||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class BufferedCodeWriter extends CodeWriter {
|
||||
private List<Fragment> fragments = new ArrayList<>();
|
||||
private int currentIndent;
|
||||
private int lastIndent;
|
||||
private StringBuilder buffer = new StringBuilder();
|
||||
private boolean lineNumbersEmitted;
|
||||
private String lastFileName;
|
||||
private int lastLineNumber;
|
||||
private boolean locationDirty;
|
||||
|
||||
public BufferedCodeWriter() {
|
||||
public BufferedCodeWriter(boolean lineNumbersEmitted) {
|
||||
this.lineNumbersEmitted = lineNumbersEmitted;
|
||||
}
|
||||
|
||||
public void writeTo(PrintWriter writer) {
|
||||
WriterWithContext writerWithContext = new WriterWithContext(writer);
|
||||
public void writeTo(PrintWriter writer, String fileName) {
|
||||
WriterWithContext writerWithContext = new WriterWithContext(writer, fileName);
|
||||
for (Fragment fragment : fragments) {
|
||||
fragment.writeTo(writerWithContext);
|
||||
}
|
||||
|
@ -38,8 +44,12 @@ public class BufferedCodeWriter extends CodeWriter {
|
|||
@Override
|
||||
public CodeWriter fragment() {
|
||||
flush();
|
||||
BufferedCodeWriter innerWriter = new BufferedCodeWriter();
|
||||
BufferedCodeWriter innerWriter = new BufferedCodeWriter(lineNumbersEmitted);
|
||||
innerWriter.lastFileName = lastFileName;
|
||||
innerWriter.lastLineNumber = lastLineNumber;
|
||||
innerWriter.locationDirty = locationDirty;
|
||||
fragments.add(new InnerWriterFragment(innerWriter.fragments));
|
||||
locationDirty = true;
|
||||
return innerWriter;
|
||||
}
|
||||
|
||||
|
@ -49,6 +59,9 @@ public class BufferedCodeWriter extends CodeWriter {
|
|||
buffer.setLength(0);
|
||||
lastIndent = currentIndent;
|
||||
currentIndent = 0;
|
||||
if (lineNumbersEmitted) {
|
||||
lastLineNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -65,37 +78,123 @@ public class BufferedCodeWriter extends CodeWriter {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void source(String fileName, int lineNumber) {
|
||||
if (!lineNumbersEmitted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Objects.equals(lastFileName, fileName) || lastLineNumber != lineNumber || locationDirty) {
|
||||
flush();
|
||||
fragments.add(new SourceFragment(fileName, lineNumber));
|
||||
lastFileName = fileName;
|
||||
lastLineNumber = lineNumber;
|
||||
locationDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nosource() {
|
||||
source(null, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
fragments.add(new SimpleFragment(false, lastIndent, buffer.toString()));
|
||||
lastIndent = currentIndent;
|
||||
currentIndent = 0;
|
||||
buffer.setLength(0);
|
||||
if (buffer.length() > 0 || lastIndent != 0 || currentIndent != 0) {
|
||||
fragments.add(new SimpleFragment(false, lastIndent, buffer.toString()));
|
||||
lastIndent = currentIndent;
|
||||
currentIndent = 0;
|
||||
buffer.setLength(0);
|
||||
}
|
||||
}
|
||||
|
||||
static class WriterWithContext {
|
||||
PrintWriter writer;
|
||||
boolean isNewLine = true;
|
||||
int indentLevel;
|
||||
String initialFileName;
|
||||
String fileName;
|
||||
int lineNumber;
|
||||
int absLineNumber = 1;
|
||||
String pendingFileName;
|
||||
int pendingLineNumber = -1;
|
||||
|
||||
WriterWithContext(PrintWriter writer) {
|
||||
WriterWithContext(PrintWriter writer, String fileName) {
|
||||
this.writer = writer;
|
||||
this.fileName = fileName;
|
||||
initialFileName = fileName;
|
||||
lineNumber = 1;
|
||||
}
|
||||
|
||||
void append(String text) {
|
||||
if (text.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (isNewLine) {
|
||||
for (int i = 0; i < indentLevel; ++i) {
|
||||
writer.print(" ");
|
||||
if (pendingFileName != null || pendingLineNumber >= 0) {
|
||||
printLineDirective(pendingFileName, pendingLineNumber);
|
||||
pendingLineNumber = -1;
|
||||
pendingFileName = null;
|
||||
}
|
||||
printIndent();
|
||||
isNewLine = false;
|
||||
}
|
||||
writer.print(text);
|
||||
}
|
||||
|
||||
private void printLineDirective(String fileName, int lineNumber) {
|
||||
if (Objects.equals(this.fileName, fileName) && lineNumber == this.lineNumber) {
|
||||
return;
|
||||
}
|
||||
|
||||
printIndent();
|
||||
writer.print("#line ");
|
||||
if (Objects.equals(fileName, initialFileName)) {
|
||||
lineNumber = absLineNumber + 1;
|
||||
}
|
||||
writer.print(lineNumber);
|
||||
if (!Objects.equals(fileName, this.fileName)) {
|
||||
writer.print(" \"");
|
||||
escape(writer, fileName);
|
||||
writer.print("\"");
|
||||
}
|
||||
writer.println();
|
||||
absLineNumber++;
|
||||
this.fileName = fileName;
|
||||
this.lineNumber = lineNumber;
|
||||
}
|
||||
|
||||
void newLine() {
|
||||
lineNumber++;
|
||||
absLineNumber++;
|
||||
writer.println();
|
||||
isNewLine = true;
|
||||
}
|
||||
|
||||
private void printIndent() {
|
||||
for (int i = 0; i < indentLevel; ++i) {
|
||||
writer.print(" ");
|
||||
}
|
||||
}
|
||||
|
||||
void source(String fileName, int lineNumber) {
|
||||
if (fileName == null) {
|
||||
fileName = initialFileName;
|
||||
lineNumber = absLineNumber;
|
||||
}
|
||||
if (!Objects.equals(this.fileName, fileName) || this.lineNumber != lineNumber) {
|
||||
if (isNewLine) {
|
||||
pendingFileName = fileName;
|
||||
pendingLineNumber = lineNumber;
|
||||
} else {
|
||||
this.lineNumber++;
|
||||
absLineNumber++;
|
||||
writer.println();
|
||||
printLineDirective(fileName, lineNumber);
|
||||
isNewLine = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static abstract class Fragment {
|
||||
|
@ -123,6 +222,62 @@ public class BufferedCodeWriter extends CodeWriter {
|
|||
}
|
||||
}
|
||||
|
||||
static class SourceFragment extends Fragment {
|
||||
private String fileName;
|
||||
private int lineNumber;
|
||||
|
||||
SourceFragment(String fileName, int lineNumber) {
|
||||
this.fileName = fileName;
|
||||
this.lineNumber = lineNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeTo(WriterWithContext writer) {
|
||||
writer.source(fileName, lineNumber);
|
||||
}
|
||||
}
|
||||
|
||||
private static void escape(PrintWriter writer, String string) {
|
||||
int chunkSize = 256;
|
||||
for (int i = 0; i < string.length(); i += chunkSize) {
|
||||
int last = Math.min(i + chunkSize, string.length());
|
||||
|
||||
for (int j = i; j < last; ++j) {
|
||||
char c = string.charAt(j);
|
||||
switch (c) {
|
||||
case '\\':
|
||||
writer.print("\\\\");
|
||||
break;
|
||||
case '"':
|
||||
writer.print("\\\"");
|
||||
break;
|
||||
case '\r':
|
||||
writer.print("\\r");
|
||||
break;
|
||||
case '\n':
|
||||
writer.print("\\n");
|
||||
break;
|
||||
case '\t':
|
||||
writer.print("\\t");
|
||||
break;
|
||||
default:
|
||||
if (c < 32) {
|
||||
writer.print("\\0" + Character.forDigit(c >> 3, 8) + Character.forDigit(c & 0x7, 8));
|
||||
} else if (c > 127) {
|
||||
writer.print("\\u"
|
||||
+ Character.forDigit(c >> 12, 16)
|
||||
+ Character.forDigit((c >> 8) & 15, 16)
|
||||
+ Character.forDigit((c >> 4) & 15, 16)
|
||||
+ Character.forDigit(c & 15, 16));
|
||||
} else {
|
||||
writer.print(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class InnerWriterFragment extends Fragment {
|
||||
List<Fragment> fragments;
|
||||
|
||||
|
|
|
@ -22,7 +22,9 @@ import java.nio.FloatBuffer;
|
|||
import java.nio.IntBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -78,6 +80,7 @@ import org.teavm.model.ElementModifier;
|
|||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.TextLocation;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.classes.VirtualTable;
|
||||
import org.teavm.runtime.Allocator;
|
||||
|
@ -116,6 +119,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
private IncludeManager includes;
|
||||
private boolean end;
|
||||
private boolean async;
|
||||
private final Deque<LocationStackEntry> locationStack = new ArrayDeque<>();
|
||||
|
||||
static {
|
||||
BUFFER_TYPES.put(ByteBuffer.class.getName(), "int8_t");
|
||||
|
@ -148,137 +152,143 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(BinaryExpr expr) {
|
||||
switch (expr.getOperation()) {
|
||||
case COMPARE:
|
||||
writer.print("teavm_compare_");
|
||||
switch (expr.getType()) {
|
||||
case INT:
|
||||
writer.print("i32");
|
||||
break;
|
||||
case LONG:
|
||||
writer.print("i64");
|
||||
break;
|
||||
case FLOAT:
|
||||
writer.print("float");
|
||||
break;
|
||||
case DOUBLE:
|
||||
writer.print("double");
|
||||
break;
|
||||
pushLocation(expr.getLocation());
|
||||
try {
|
||||
switch (expr.getOperation()) {
|
||||
case COMPARE:
|
||||
writer.print("teavm_compare_");
|
||||
switch (expr.getType()) {
|
||||
case INT:
|
||||
writer.print("i32");
|
||||
break;
|
||||
case LONG:
|
||||
writer.print("i64");
|
||||
break;
|
||||
case FLOAT:
|
||||
writer.print("float");
|
||||
break;
|
||||
case DOUBLE:
|
||||
writer.print("double");
|
||||
break;
|
||||
}
|
||||
writer.print("(");
|
||||
expr.getFirstOperand().acceptVisitor(this);
|
||||
writer.print(", ");
|
||||
expr.getSecondOperand().acceptVisitor(this);
|
||||
writer.print(")");
|
||||
return;
|
||||
case UNSIGNED_RIGHT_SHIFT: {
|
||||
String type = expr.getType() == OperationType.LONG ? "int64_t" : "int32_t";
|
||||
writer.print("((" + type + ") ((u" + type + ") ");
|
||||
|
||||
expr.getFirstOperand().acceptVisitor(this);
|
||||
writer.print(" >> ");
|
||||
expr.getSecondOperand().acceptVisitor(this);
|
||||
|
||||
writer.print("))");
|
||||
return;
|
||||
}
|
||||
writer.print("(");
|
||||
expr.getFirstOperand().acceptVisitor(this);
|
||||
writer.print(", ");
|
||||
expr.getSecondOperand().acceptVisitor(this);
|
||||
writer.print(")");
|
||||
return;
|
||||
case UNSIGNED_RIGHT_SHIFT: {
|
||||
String type = expr.getType() == OperationType.LONG ? "int64_t" : "int32_t";
|
||||
writer.print("((" + type + ") ((u" + type + ") ");
|
||||
|
||||
expr.getFirstOperand().acceptVisitor(this);
|
||||
writer.print(" >> ");
|
||||
expr.getSecondOperand().acceptVisitor(this);
|
||||
case MODULO: {
|
||||
switch (expr.getType()) {
|
||||
case FLOAT:
|
||||
writer.print("fmodf(");
|
||||
expr.getFirstOperand().acceptVisitor(this);
|
||||
writer.print(", ");
|
||||
expr.getSecondOperand().acceptVisitor(this);
|
||||
writer.print(")");
|
||||
return;
|
||||
case DOUBLE:
|
||||
writer.print("fmod(");
|
||||
expr.getFirstOperand().acceptVisitor(this);
|
||||
writer.print(", ");
|
||||
expr.getSecondOperand().acceptVisitor(this);
|
||||
writer.print(")");
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
writer.print("))");
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
case MODULO: {
|
||||
switch (expr.getType()) {
|
||||
case FLOAT:
|
||||
writer.print("fmodf(");
|
||||
expr.getFirstOperand().acceptVisitor(this);
|
||||
writer.print(", ");
|
||||
expr.getSecondOperand().acceptVisitor(this);
|
||||
writer.print(")");
|
||||
return;
|
||||
case DOUBLE:
|
||||
writer.print("fmod(");
|
||||
expr.getFirstOperand().acceptVisitor(this);
|
||||
writer.print(", ");
|
||||
expr.getSecondOperand().acceptVisitor(this);
|
||||
writer.print(")");
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
writer.print("(");
|
||||
expr.getFirstOperand().acceptVisitor(this);
|
||||
|
||||
String op;
|
||||
switch (expr.getOperation()) {
|
||||
case ADD:
|
||||
op = "+";
|
||||
break;
|
||||
case SUBTRACT:
|
||||
op = "-";
|
||||
break;
|
||||
case MULTIPLY:
|
||||
op = "*";
|
||||
break;
|
||||
case DIVIDE:
|
||||
op = "/";
|
||||
break;
|
||||
case MODULO:
|
||||
op = "%";
|
||||
break;
|
||||
case BITWISE_AND:
|
||||
op = "&";
|
||||
break;
|
||||
case BITWISE_OR:
|
||||
op = "|";
|
||||
break;
|
||||
case BITWISE_XOR:
|
||||
op = "^";
|
||||
break;
|
||||
case LEFT_SHIFT:
|
||||
op = "<<";
|
||||
break;
|
||||
case RIGHT_SHIFT:
|
||||
op = ">>";
|
||||
break;
|
||||
case EQUALS:
|
||||
op = "==";
|
||||
break;
|
||||
case NOT_EQUALS:
|
||||
op = "!=";
|
||||
break;
|
||||
case GREATER:
|
||||
op = ">";
|
||||
break;
|
||||
case GREATER_OR_EQUALS:
|
||||
op = ">=";
|
||||
break;
|
||||
case LESS:
|
||||
op = "<";
|
||||
break;
|
||||
case LESS_OR_EQUALS:
|
||||
op = "<=";
|
||||
break;
|
||||
case AND:
|
||||
op = "&&";
|
||||
break;
|
||||
case OR:
|
||||
op = "||";
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
writer.print(" ").print(op).print(" ");
|
||||
expr.getSecondOperand().acceptVisitor(this);
|
||||
writer.print(")");
|
||||
} finally {
|
||||
popLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
writer.print("(");
|
||||
expr.getFirstOperand().acceptVisitor(this);
|
||||
|
||||
String op;
|
||||
switch (expr.getOperation()) {
|
||||
case ADD:
|
||||
op = "+";
|
||||
break;
|
||||
case SUBTRACT:
|
||||
op = "-";
|
||||
break;
|
||||
case MULTIPLY:
|
||||
op = "*";
|
||||
break;
|
||||
case DIVIDE:
|
||||
op = "/";
|
||||
break;
|
||||
case MODULO:
|
||||
op = "%";
|
||||
break;
|
||||
case BITWISE_AND:
|
||||
op = "&";
|
||||
break;
|
||||
case BITWISE_OR:
|
||||
op = "|";
|
||||
break;
|
||||
case BITWISE_XOR:
|
||||
op = "^";
|
||||
break;
|
||||
case LEFT_SHIFT:
|
||||
op = "<<";
|
||||
break;
|
||||
case RIGHT_SHIFT:
|
||||
op = ">>";
|
||||
break;
|
||||
case EQUALS:
|
||||
op = "==";
|
||||
break;
|
||||
case NOT_EQUALS:
|
||||
op = "!=";
|
||||
break;
|
||||
case GREATER:
|
||||
op = ">";
|
||||
break;
|
||||
case GREATER_OR_EQUALS:
|
||||
op = ">=";
|
||||
break;
|
||||
case LESS:
|
||||
op = "<";
|
||||
break;
|
||||
case LESS_OR_EQUALS:
|
||||
op = "<=";
|
||||
break;
|
||||
case AND:
|
||||
op = "&&";
|
||||
break;
|
||||
case OR:
|
||||
op = "||";
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
writer.print(" ").print(op).print(" ");
|
||||
expr.getSecondOperand().acceptVisitor(this);
|
||||
writer.print(")");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UnaryExpr expr) {
|
||||
pushLocation(expr.getLocation());
|
||||
switch (expr.getOperation()) {
|
||||
case NOT:
|
||||
writer.print("(");
|
||||
|
@ -316,10 +326,12 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
writer.print(")");
|
||||
break;
|
||||
}
|
||||
popLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConditionalExpr expr) {
|
||||
pushLocation(expr.getLocation());
|
||||
writer.print("(");
|
||||
expr.getCondition().acceptVisitor(this);
|
||||
writer.print(" ? ");
|
||||
|
@ -327,34 +339,43 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
writer.print(" : ");
|
||||
expr.getAlternative().acceptVisitor(this);
|
||||
writer.print(")");
|
||||
popLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConstantExpr expr) {
|
||||
pushLocation(expr.getLocation());
|
||||
CodeGeneratorUtil.writeValue(writer, context, includes, expr.getValue());
|
||||
popLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(VariableExpr expr) {
|
||||
pushLocation(expr.getLocation());
|
||||
if (expr.getIndex() == 0) {
|
||||
writer.print("teavm_this_");
|
||||
} else {
|
||||
writer.print("teavm_local_" + expr.getIndex());
|
||||
}
|
||||
popLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SubscriptExpr expr) {
|
||||
pushLocation(expr.getLocation());
|
||||
writer.print("TEAVM_ARRAY_AT(");
|
||||
expr.getArray().acceptVisitor(this);
|
||||
writer.print(", ").print(getArrayType(expr.getType())).print(", ");
|
||||
expr.getIndex().acceptVisitor(this);
|
||||
writer.print(")");
|
||||
popLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UnwrapArrayExpr expr) {
|
||||
pushLocation(expr.getLocation());
|
||||
expr.getArray().acceptVisitor(this);
|
||||
popLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
private static String getArrayType(ArrayType type) {
|
||||
|
@ -393,10 +414,13 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
|
||||
Intrinsic intrinsic = context.getIntrinsic(expr.getMethod());
|
||||
if (intrinsic != null) {
|
||||
pushLocation(expr.getLocation());
|
||||
intrinsic.apply(intrinsicContext, expr);
|
||||
popLocation(expr.getLocation());
|
||||
return;
|
||||
}
|
||||
|
||||
pushLocation(expr.getLocation());
|
||||
switch (expr.getType()) {
|
||||
case CONSTRUCTOR: {
|
||||
String receiver = allocTemporaryVariable(CVariableType.PTR);
|
||||
|
@ -482,6 +506,8 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
popLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
private void generateWrappedNativeCall(MethodReader method, InvocationExpr expr) {
|
||||
|
@ -647,6 +673,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
public void visit(QualificationExpr expr) {
|
||||
FieldReference field = expr.getField();
|
||||
if (isMonitorField(field)) {
|
||||
pushLocation(expr.getLocation());
|
||||
String tmp = allocTemporaryVariable(CVariableType.INT);
|
||||
writer.print("(" + tmp + " = TEAVM_FIELD(");
|
||||
expr.getQualified().acceptVisitor(this);
|
||||
|
@ -654,9 +681,11 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
writer.print(", ").print(names.forClass(field.getClassName()) + ", "
|
||||
+ names.forMemberField(field) + ")");
|
||||
writer.print(", TEAVM_UNPACK_MONITOR(" + tmp + "))");
|
||||
popLocation(expr.getLocation());
|
||||
return;
|
||||
}
|
||||
|
||||
pushLocation(expr.getLocation());
|
||||
includes.includeClass(field.getClassName());
|
||||
if (expr.getQualified() != null) {
|
||||
writer.print("TEAVM_FIELD(");
|
||||
|
@ -665,6 +694,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
} else {
|
||||
writer.print(names.forStaticField(field));
|
||||
}
|
||||
popLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
private boolean isMonitorField(FieldReference field) {
|
||||
|
@ -673,9 +703,11 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(NewExpr expr) {
|
||||
pushLocation(expr.getLocation());
|
||||
includes.includeClass(expr.getConstructedClass());
|
||||
includes.includeClass(ALLOC_METHOD.getClassName());
|
||||
allocObject(expr.getConstructedClass());
|
||||
popLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
private void allocObject(String className) {
|
||||
|
@ -686,6 +718,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(NewArrayExpr expr) {
|
||||
pushLocation(expr.getLocation());
|
||||
ValueType type = ValueType.arrayOf(expr.getType());
|
||||
writer.print(names.forMethod(ALLOC_ARRAY_METHOD)).print("(&")
|
||||
.print(names.forClassInstance(type)).print(", ");
|
||||
|
@ -693,6 +726,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
includes.includeType(type);
|
||||
expr.getLength().acceptVisitor(this);
|
||||
writer.print(")");
|
||||
popLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -714,10 +748,12 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(InstanceOfExpr expr) {
|
||||
pushLocation(expr.getLocation());
|
||||
writer.print("teavm_instanceof(");
|
||||
expr.getExpr().acceptVisitor(this);
|
||||
includes.includeType(expr.getType());
|
||||
writer.print(", ").print(names.forSupertypeFunction(expr.getType())).print(")");
|
||||
popLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -730,14 +766,17 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
return;
|
||||
}
|
||||
}
|
||||
pushLocation(expr.getLocation());
|
||||
writer.print("teavm_checkcast(");
|
||||
expr.getValue().acceptVisitor(this);
|
||||
includes.includeType(expr.getTarget());
|
||||
writer.print(", ").print(names.forSupertypeFunction(expr.getTarget())).print(")");
|
||||
popLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(PrimitiveCastExpr expr) {
|
||||
pushLocation(expr.getLocation());
|
||||
writer.print("((");
|
||||
switch (expr.getTarget()) {
|
||||
case INT:
|
||||
|
@ -756,10 +795,12 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
writer.print(") ");
|
||||
expr.getValue().acceptVisitor(this);
|
||||
writer.print(")");
|
||||
popLocation(expr.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AssignmentStatement statement) {
|
||||
pushLocation(statement.getLocation());
|
||||
if (statement.getLeftValue() != null) {
|
||||
if (statement.getLeftValue() instanceof QualificationExpr) {
|
||||
QualificationExpr qualification = (QualificationExpr) statement.getLeftValue();
|
||||
|
@ -772,6 +813,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
+ names.forMemberField(field) + ") = TEAVM_PACK_MONITOR(");
|
||||
statement.getRightValue().acceptVisitor(this);
|
||||
writer.println(");");
|
||||
popLocation(statement.getLocation());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -785,6 +827,8 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
if (statement.isAsync()) {
|
||||
emitSuspendChecker();
|
||||
}
|
||||
|
||||
popLocation(statement.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -809,9 +853,11 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
@Override
|
||||
public void visit(ConditionalStatement statement) {
|
||||
while (true) {
|
||||
pushLocation(statement.getCondition().getLocation());
|
||||
writer.print("if (");
|
||||
statement.getCondition().acceptVisitor(this);
|
||||
writer.println(") {").indent();
|
||||
popLocation(statement.getCondition().getLocation());
|
||||
|
||||
visitMany(statement.getConsequent());
|
||||
writer.outdent().print("}");
|
||||
|
@ -836,9 +882,11 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(SwitchStatement statement) {
|
||||
pushLocation(statement.getValue().getLocation());
|
||||
writer.print("switch (");
|
||||
statement.getValue().acceptVisitor(this);
|
||||
writer.print(") {").println().indent();
|
||||
popLocation(statement.getValue().getLocation());
|
||||
|
||||
for (SwitchClause clause : statement.getClauses()) {
|
||||
for (int condition : clause.getConditions()) {
|
||||
|
@ -906,44 +954,54 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(BreakStatement statement) {
|
||||
pushLocation(statement.getLocation());
|
||||
if (statement.getTarget() == null || statement.getTarget().getId() == null) {
|
||||
writer.println("break;");
|
||||
} else {
|
||||
writer.println("goto teavm_label_" + statement.getTarget().getId() + ";");
|
||||
}
|
||||
popLocation(statement.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ContinueStatement statement) {
|
||||
pushLocation(statement.getLocation());
|
||||
if (statement.getTarget() == null || statement.getTarget().getId() == null) {
|
||||
writer.println("continue;");
|
||||
} else {
|
||||
writer.println("goto teavm_cnt_" + statement.getTarget().getId() + ";");
|
||||
}
|
||||
popLocation(statement.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ReturnStatement statement) {
|
||||
pushLocation(statement.getLocation());
|
||||
writer.print("return");
|
||||
if (statement.getResult() != null) {
|
||||
writer.print(" ");
|
||||
statement.getResult().acceptVisitor(this);
|
||||
}
|
||||
writer.println(";");
|
||||
popLocation(statement.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ThrowStatement statement) {
|
||||
pushLocation(statement.getLocation());
|
||||
includes.includeClass(THROW_EXCEPTION_METHOD.getClassName());
|
||||
writer.print(names.forMethod(THROW_EXCEPTION_METHOD)).print("(");
|
||||
statement.getException().acceptVisitor(this);
|
||||
writer.println(");");
|
||||
popLocation(statement.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(InitClassStatement statement) {
|
||||
pushLocation(statement.getLocation());
|
||||
includes.includeClass(statement.getClassName());
|
||||
writer.println(names.forClassInitializer(statement.getClassName()) + "();");
|
||||
popLocation(statement.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -956,18 +1014,22 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(MonitorEnterStatement statement) {
|
||||
pushLocation(statement.getLocation());
|
||||
includes.includeClass("java.lang.Object");
|
||||
writer.print(names.forMethod(async ? MONITOR_ENTER : MONITOR_ENTER_SYNC)).print("(");
|
||||
statement.getObjectRef().acceptVisitor(this);
|
||||
writer.println(");");
|
||||
popLocation(statement.getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorExitStatement statement) {
|
||||
pushLocation(statement.getLocation());
|
||||
includes.includeClass("java.lang.Object");
|
||||
writer.print(names.forMethod(async ? MONITOR_EXIT : MONITOR_EXIT_SYNC)).print("(");
|
||||
statement.getObjectRef().acceptVisitor(this);
|
||||
writer.println(");");
|
||||
popLocation(statement.getLocation());
|
||||
}
|
||||
|
||||
public void emitSuspendChecker() {
|
||||
|
@ -1043,4 +1105,46 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
}
|
||||
return CVariableType.PTR;
|
||||
}
|
||||
|
||||
private void pushLocation(TextLocation location) {
|
||||
if (location == null) {
|
||||
return;
|
||||
}
|
||||
LocationStackEntry prevEntry = locationStack.peek();
|
||||
if (prevEntry == null || !location.equals(prevEntry.location)) {
|
||||
if (location.getFileName() == null) {
|
||||
writer.nosource();
|
||||
} else {
|
||||
writer.source(location.getFileName(), location.getLine());
|
||||
}
|
||||
}
|
||||
locationStack.push(new LocationStackEntry(location));
|
||||
}
|
||||
|
||||
private void popLocation(TextLocation location) {
|
||||
if (location == null) {
|
||||
return;
|
||||
}
|
||||
LocationStackEntry prevEntry = locationStack.pop();
|
||||
LocationStackEntry entry = locationStack.peek();
|
||||
if (entry != null) {
|
||||
if (!entry.location.equals(prevEntry.location)) {
|
||||
if (entry.location.getFileName() == null) {
|
||||
writer.nosource();
|
||||
} else {
|
||||
writer.source(entry.location.getFileName(), entry.location.getLine());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
writer.nosource();
|
||||
}
|
||||
}
|
||||
|
||||
static class LocationStackEntry {
|
||||
final TextLocation location;
|
||||
|
||||
LocationStackEntry(TextLocation location) {
|
||||
this.location = location;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,4 +137,8 @@ public abstract class CodeWriter {
|
|||
protected abstract void indentBy(int amount);
|
||||
|
||||
public abstract void flush();
|
||||
|
||||
public abstract void source(String fileName, int lineNumber);
|
||||
|
||||
public abstract void nosource();
|
||||
}
|
||||
|
|
|
@ -92,12 +92,12 @@ class GeneratorContextImpl implements GeneratorContext {
|
|||
|
||||
@Override
|
||||
public FileGenerator createSourceFile(String path) {
|
||||
return createFile(new BufferedCodeWriter(), path);
|
||||
return createFile(new BufferedCodeWriter(false), path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileGenerator createHeaderFile(String path) {
|
||||
BufferedCodeWriter writer = new BufferedCodeWriter();
|
||||
BufferedCodeWriter writer = new BufferedCodeWriter(false);
|
||||
writer.println("#pragma once");
|
||||
return createFile(writer, path);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public final class OutputFileUtil {
|
|||
public static void write(BufferedCodeWriter code, String name, BuildTarget buildTarget) throws IOException {
|
||||
try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(
|
||||
buildTarget.createResource(name), StandardCharsets.UTF_8))) {
|
||||
code.writeTo(writer);
|
||||
code.writeTo(writer, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ public class IncrementalCBuilder {
|
|||
private String mainClass;
|
||||
private String[] classPath;
|
||||
private int minHeapSize = 32;
|
||||
private boolean lineNumbersGenerated;
|
||||
private String targetPath;
|
||||
private String externalTool;
|
||||
private String externalToolWorkingDir;
|
||||
|
@ -107,6 +108,10 @@ public class IncrementalCBuilder {
|
|||
this.minHeapSize = minHeapSize;
|
||||
}
|
||||
|
||||
public void setLineNumbersGenerated(boolean lineNumbersGenerated) {
|
||||
this.lineNumbersGenerated = lineNumbersGenerated;
|
||||
}
|
||||
|
||||
public void setTargetPath(String targetPath) {
|
||||
this.targetPath = targetPath;
|
||||
}
|
||||
|
@ -316,6 +321,7 @@ public class IncrementalCBuilder {
|
|||
|
||||
cTarget.setIncremental(true);
|
||||
cTarget.setMinHeapSize(minHeapSize * 1024 * 1024);
|
||||
cTarget.setLineNumbersGenerated(lineNumbersGenerated);
|
||||
vm.setOptimizationLevel(TeaVMOptimizationLevel.SIMPLE);
|
||||
vm.setCacheStatus(classSource);
|
||||
vm.addVirtualMethods(m -> true);
|
||||
|
|
|
@ -52,6 +52,10 @@ public class TeaVMCBuilderRunner {
|
|||
.withDescription("display more messages on server log")
|
||||
.withLongOpt("verbose")
|
||||
.create('v'));
|
||||
options.addOption(OptionBuilder
|
||||
.withDescription("generate debugger-friendly code")
|
||||
.withLongOpt("debug")
|
||||
.create('g'));
|
||||
options.addOption(OptionBuilder
|
||||
.withLongOpt("min-heap")
|
||||
.withArgName("size")
|
||||
|
@ -103,6 +107,7 @@ public class TeaVMCBuilderRunner {
|
|||
parseExternalTool();
|
||||
|
||||
builder.setLog(new ConsoleTeaVMToolLog(commandLine.hasOption('v')));
|
||||
builder.setLineNumbersGenerated(commandLine.hasOption('g'));
|
||||
|
||||
String[] args = commandLine.getArgs();
|
||||
if (args.length != 1) {
|
||||
|
|
|
@ -321,6 +321,7 @@ public class TeaVMTool {
|
|||
private CTarget prepareCTarget() {
|
||||
cTarget = new CTarget();
|
||||
cTarget.setMinHeapSize(minHeapSize);
|
||||
cTarget.setLineNumbersGenerated(debugInformationGenerated);
|
||||
return cTarget;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user