diff --git a/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java b/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java index 7f45a9b7f..d5cd36aa1 100644 --- a/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java +++ b/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java @@ -151,6 +151,8 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor { private ObjectIntMap labelMap = new ObjectIntHashMap<>(); private Set usedAsBreakTarget = new HashSet<>(); private Set usedAsContinueTarget = new HashSet<>(); + private Map 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"); } diff --git a/core/src/main/java/org/teavm/runtime/ExceptionHandling.java b/core/src/main/java/org/teavm/runtime/ExceptionHandling.java index 57fd506ce..cff031859 100644 --- a/core/src/main/java/org/teavm/runtime/ExceptionHandling.java +++ b/core/src/main/java/org/teavm/runtime/ExceptionHandling.java @@ -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); } diff --git a/core/src/main/resources/org/teavm/backend/c/exceptions.h b/core/src/main/resources/org/teavm/backend/c/exceptions.h index 54ea268f9..cd309f0b2 100644 --- a/core/src/main/resources/org/teavm/backend/c/exceptions.h +++ b/core/src/main/resources/org/teavm/backend/c/exceptions.h @@ -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 diff --git a/core/src/main/resources/org/teavm/backend/c/stack.h b/core/src/main/resources/org/teavm/backend/c/stack.h index fb9984335..21af0f24b 100644 --- a/core/src/main/resources/org/teavm/backend/c/stack.h +++ b/core/src/main/resources/org/teavm/backend/c/stack.h @@ -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;