C: generate '#line' preprocessor directive

This commit is contained in:
Alexey Andreev 2019-05-16 11:12:35 +03:00
parent 7a99258cab
commit 0003ed0bb2
9 changed files with 425 additions and 145 deletions

View File

@ -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");

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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) {

View File

@ -321,6 +321,7 @@ public class TeaVMTool {
private CTarget prepareCTarget() {
cTarget = new CTarget();
cTarget.setMinHeapSize(minHeapSize);
cTarget.setLineNumbersGenerated(debugInformationGenerated);
return cTarget;
}