C: fix behaviour of nested try/catch statements

This commit is contained in:
Alexey Andreev 2021-04-15 20:55:52 +03:00
parent 73bd139b7e
commit 220537d984
4 changed files with 53 additions and 23 deletions

View File

@ -151,6 +151,8 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
private ObjectIntMap<IdentifiedStatement> labelMap = new ObjectIntHashMap<>();
private Set<IdentifiedStatement> usedAsBreakTarget = new HashSet<>();
private Set<IdentifiedStatement> usedAsContinueTarget = new HashSet<>();
private Map<IdentifiedStatement, Integer> tryDepthByStatements = new HashMap<>();
private int tryDepth;
static {
BUFFER_TYPES.put(ByteBuffer.class.getName(), "int8_t");
@ -1197,8 +1199,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
IdentifiedStatement oldDefaultBreakTarget = defaultBreakTarget;
defaultBreakTarget = statement;
int statementId = labelMap.size() + 1;
labelMap.put(statement, statementId);
int statementId = registerIdentifiedStatement(statement);
pushLocation(statement.getValue().getLocation());
writer.print("switch (");
@ -1243,8 +1244,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
defaultBreakTarget = statement;
defaultContinueTarget = statement;
int statementId = labelMap.size() + 1;
labelMap.put(statement, statementId);
int statementId = registerIdentifiedStatement(statement);
writer.print("while (");
if (statement.getCondition() != null) {
@ -1276,8 +1276,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
@Override
public void visit(BlockStatement statement) {
int statementId = labelMap.size() + 1;
labelMap.put(statement, statementId);
int statementId = registerIdentifiedStatement(statement);
visitMany(statement.getBody());
@ -1293,8 +1292,7 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
if (target == null) {
target = defaultBreakTarget;
}
int id = labelMap.get(target);
writer.println("goto teavm_label_" + id + ";");
jumpToTarget(target, "teavm_label_");
usedAsBreakTarget.add(target);
popLocation(statement.getLocation());
}
@ -1306,12 +1304,28 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
if (target == null) {
target = defaultContinueTarget;
}
int id = labelMap.get(target);
writer.println("goto teavm_cnt_" + id + ";");
jumpToTarget(target, "teavm_cnt_");
usedAsContinueTarget.add(target);
popLocation(statement.getLocation());
}
private int registerIdentifiedStatement(IdentifiedStatement statement) {
tryDepthByStatements.put(statement, tryDepth);
int statementId = labelMap.size() + 1;
labelMap.put(statement, statementId);
return statementId;
}
private void jumpToTarget(IdentifiedStatement target, String prefix) {
int targetDepth = tryDepthByStatements.get(target);
while (targetDepth < tryDepth) {
targetDepth++;
writer.println("TEAVM_RESTORE_JUMP_BUFFER;");
}
int id = labelMap.get(target);
writer.println("goto " + prefix + id + ";");
}
@Override
public void visit(ReturnStatement statement) {
pushLocation(statement.getLocation());
@ -1398,7 +1412,10 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
}
writer.println("TEAVM_TRY").indent();
tryDepth++;
visitMany(statement.getProtectedBody());
tryDepth--;
handlers.subList(firstId, handlers.size()).clear();
writer.outdent().println("TEAVM_CATCH").indent();
for (int i = tryCatchStatements.size() - 1; i >= 0; --i) {
@ -1421,8 +1438,6 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
writer.outdent().println("}");
}
handlers.subList(firstId, handlers.size()).clear();
writer.outdent().println("TEAVM_END_TRY");
}

View File

@ -108,13 +108,17 @@ public final class ExceptionHandling {
while (handler != null) {
if (handler.exceptionClass == null || handler.exceptionClass.isSupertypeOf.apply(exceptionClass)) {
handlerId = handler.id;
ShadowStack.setExceptionHandlerId(stackFrame, handler.id);
if (!isJumpSupported()) {
ShadowStack.setExceptionHandlerId(stackFrame, handlerId);
}
break stackLoop;
}
handler = handler.next;
}
ShadowStack.setExceptionHandlerId(stackFrame, callSiteId - 1);
if (!isJumpSupported()) {
ShadowStack.setExceptionHandlerId(stackFrame, callSiteId - 1);
}
}
stackFrame = ShadowStack.getNextStackFrame(stackFrame);
}

View File

@ -10,21 +10,25 @@
#if TEAVM_USE_SETJMP
#define TEAVM_JUMP_SUPPORTED 1
#define TEAVM_RESTORE_JUMP_BUFFER \
teavm_shadowStack.header.jmpTarget = teavm_shadowStack.header.jmpTarget->previous
#define TEAVM_TRY \
do { \
jmp_buf teavm_tryBuffer; \
jmp_buf* teavm_oldTryBuffer = teavm_shadowStack.header.jmpTarget; \
teavm_shadowStack.header.jmpTarget = &teavm_tryBuffer; \
int teavm_exceptionHandler = setjmp(teavm_tryBuffer); \
TeaVM_LongjmpDesc teavm_longJmpdesc; \
teavm_longJmpdesc.previous = teavm_shadowStack.header.jmpTarget; \
teavm_shadowStack.header.jmpTarget = &teavm_longJmpdesc; \
int teavm_exceptionHandler = setjmp(teavm_longJmpdesc.buffer); \
if (teavm_exceptionHandler == 0) {
#define TEAVM_CATCH \
teavm_shadowStack.header.jmpTarget = teavm_oldTryBuffer; \
TEAVM_RESTORE_JUMP_BUFFER; \
} else { \
teavm_shadowStack.header.jmpTarget = teavm_oldTryBuffer; \
TEAVM_RESTORE_JUMP_BUFFER; \
switch (teavm_exceptionHandler) {
#define TEAVM_END_TRY \
default: \
longjmp(*teavm_oldTryBuffer, teavm_exceptionHandler); \
longjmp(teavm_shadowStack.header.jmpTarget->buffer, teavm_exceptionHandler); \
break; \
} \
} \
@ -32,7 +36,7 @@
#define TEAVM_JUMP_TO_FRAME(frame, id) \
teavm_stackTop = (TeaVM_StackFrame*) (frame); \
longjmp(*teavm_stackTop->jmpTarget, id)
longjmp(teavm_stackTop->jmpTarget->buffer, id)
#if TEAVM_UNIX

View File

@ -35,13 +35,20 @@ typedef struct TeaVM_CallSite {
TeaVM_CallSiteLocation* location;
} TeaVM_CallSite;
#if TEAVM_USE_SETJMP
typedef struct TeaVM_LongjmpDesc {
jmp_buf buffer;
struct TeaVM_LongjmpDesc* previous;
} TeaVM_LongjmpDesc;
#endif
typedef struct TeaVM_StackFrame {
struct TeaVM_StackFrame* next;
#if TEAVM_INCREMENTAL
TeaVM_CallSite* callSites;
#endif
#if TEAVM_USE_SETJMP
jmp_buf* jmpTarget;
TeaVM_LongjmpDesc* jmpTarget;
#endif
int32_t size;
int32_t callSiteId;