From 354abed0b67500998b20bf2d07c356cc807bfb8b Mon Sep 17 00:00:00 2001
From: Arno Unkrig
Date: Fri, 21 Feb 2020 17:04:11 +0100
Subject: [PATCH] FINALLY is no longer implemented with JSR-RET. (Java 6+
.class files forbid JSR and RET). Another step towards Java 7+ .class files!
---
.../java/org/codehaus/janino/CodeContext.java | 5 +-
.../main/java/org/codehaus/janino/Java.java | 6 -
.../main/java/org/codehaus/janino/Opcode.java | 16 +-
.../org/codehaus/janino/UnitCompiler.java | 354 +++++++-----------
4 files changed, 158 insertions(+), 223 deletions(-)
diff --git a/janino/src/main/java/org/codehaus/janino/CodeContext.java b/janino/src/main/java/org/codehaus/janino/CodeContext.java
index b9adf0562..6b38cb289 100644
--- a/janino/src/main/java/org/codehaus/janino/CodeContext.java
+++ b/janino/src/main/java/org/codehaus/janino/CodeContext.java
@@ -629,6 +629,7 @@ class Branch extends Relocatable {
}
int offset = this.destination.offset - this.source.offset;
+ @SuppressWarnings("deprecation") final int opcodeJsr = Opcode.JSR;
if (!this.expanded && (offset > Short.MAX_VALUE || offset < Short.MIN_VALUE)) {
//we want to insert the data without skewing our source position,
//so we will cache it and then restore it later.
@@ -637,7 +638,7 @@ class Branch extends Relocatable {
{
// Promotion to a wide instruction only requires 2 extra bytes. Everything else requires a new
// GOTO_W instruction after a negated if (5 extra bytes).
- CodeContext.this.makeSpace(this.opcode == Opcode.GOTO || this.opcode == Opcode.JSR ? 2 : 5);
+ CodeContext.this.makeSpace(this.opcode == Opcode.GOTO || this.opcode == opcodeJsr ? 2 : 5);
}
CodeContext.this.popInserter();
this.source.offset = pos;
@@ -650,7 +651,7 @@ class Branch extends Relocatable {
//we fit in a 16-bit jump
ba = new byte[] { (byte) this.opcode, (byte) (offset >> 8), (byte) offset };
} else {
- if (this.opcode == Opcode.GOTO || this.opcode == Opcode.JSR) {
+ if (this.opcode == Opcode.GOTO || this.opcode == opcodeJsr) {
ba = new byte[] {
(byte) (this.opcode + 33), // GOTO => GOTO_W; JSR => JSR_W
(byte) (offset >> 24),
diff --git a/janino/src/main/java/org/codehaus/janino/Java.java b/janino/src/main/java/org/codehaus/janino/Java.java
index 386052ea3..599c24c11 100644
--- a/janino/src/main/java/org/codehaus/janino/Java.java
+++ b/janino/src/main/java/org/codehaus/janino/Java.java
@@ -3565,12 +3565,6 @@ class VariableAccessResource extends Resource {
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitTryStatement(this); }
-
- /**
- * This one's created iff the TRY statement has a FINALLY clause when the compilation of the TRY statement
- * begins.
- */
- @Nullable CodeContext.Offset finallyOffset;
}
/**
diff --git a/janino/src/main/java/org/codehaus/janino/Opcode.java b/janino/src/main/java/org/codehaus/janino/Opcode.java
index 398373b1f..2279443ab 100644
--- a/janino/src/main/java/org/codehaus/janino/Opcode.java
+++ b/janino/src/main/java/org/codehaus/janino/Opcode.java
@@ -34,7 +34,7 @@ private Opcode() {}
// Symbolic JVM opcodes, in alphabetical order.
- // SUPPRESS CHECKSTYLE JavadocVariable:205
+ // SUPPRESS CHECKSTYLE JavadocVariable:216
public static final int AALOAD = 50;
public static final int AASTORE = 83;
public static final int ACONST_NULL = 1;
@@ -186,7 +186,12 @@ private Opcode() {}
public static final int ISUB = 100;
public static final int IUSHR = 124;
public static final int IXOR = 130;
- public static final int JSR = 168;
+
+ /**
+ * @deprecated Only allowed until .class file version 50.0 (Java 6) JVMS 4.10.2.5
+ */
+ @Deprecated public static final int JSR = 168;
+
public static final int JSR_W = 201;
public static final int L2D = 138;
public static final int L2F = 137;
@@ -233,7 +238,12 @@ private Opcode() {}
public static final int POP2 = 88;
public static final int PUTFIELD = 181;
public static final int PUTSTATIC = 179;
- public static final int RET = 169;
+
+ /**
+ * @deprecated Only allowed until .class file version 50.0 (Java 6) JVMS 4.10.2.5
+ */
+ @Deprecated public static final int RET = 169;
+
public static final int RETURN = 177;
public static final int SALOAD = 53;
public static final int SASTORE = 86;
diff --git a/janino/src/main/java/org/codehaus/janino/UnitCompiler.java b/janino/src/main/java/org/codehaus/janino/UnitCompiler.java
index ed1c731fd..31d400241 100644
--- a/janino/src/main/java/org/codehaus/janino/UnitCompiler.java
+++ b/janino/src/main/java/org/codehaus/janino/UnitCompiler.java
@@ -2224,9 +2224,8 @@ private enum SwitchKind { INT, ENUM, STRING }
}
this.leaveStatements(
- bs.getEnclosingScope(), // from
- brokenStatement.getEnclosingScope(), // to
- null // stackValueType
+ bs.getEnclosingScope(), // from
+ brokenStatement.getEnclosingScope() // to
);
this.gotO(bs, this.getWhereToBreak(brokenStatement));
return false;
@@ -2293,9 +2292,8 @@ private enum SwitchKind { INT, ENUM, STRING }
}
this.leaveStatements(
- cs.getEnclosingScope(), // from
- continuedStatement.getEnclosingScope(), // to
- null // stackValueType
+ cs.getEnclosingScope(), // from
+ continuedStatement.getEnclosingScope() // to
);
this.gotO(cs, wtc);
@@ -2651,8 +2649,7 @@ private enum SwitchKind { INT, ENUM, STRING }
if (orv != null) this.compileError("Method must not return a value", rs.getLocation());
this.leaveStatements(
rs.getEnclosingScope(), // from
- enclosingFunction, // to
- null // stackValueType
+ enclosingFunction // to
);
this.returN(rs);
@@ -2673,8 +2670,7 @@ private enum SwitchKind { INT, ENUM, STRING }
this.leaveStatements(
rs.getEnclosingScope(), // from
- enclosingFunction, // to
- returnType // stackValueType
+ enclosingFunction // to
);
this.xreturn(rs, returnType);
return false;
@@ -2722,13 +2718,13 @@ private enum SwitchKind { INT, ENUM, STRING }
null // catchTypeFD
);
this.getCodeContext().pushObjectOperand(Descriptor.JAVA_LANG_THROWABLE);
- this.leave(ss, this.iClassLoader.TYPE_java_lang_Throwable);
+ this.leave(ss);
this.athrow(ss);
// Unlock monitor object.
if (canCompleteNormally) {
monitorExitOffset.set();
- this.leave(ss, null);
+ this.leave(ss);
}
} finally {
this.getCodeContext().restoreLocalVariables();
@@ -2782,9 +2778,8 @@ interface Compilable2 { boolean compile() throws CompileException; }
@Nullable final Block finallY
) throws CompileException {
+ // Short-circuit for zero resources.
if (resources.isEmpty()) {
-
- // Short-circuit for zero resources.
return this.compileTryCatchFinally(ts, compileBody, finallY);
}
@@ -2942,6 +2937,7 @@ interface Compilable2 { boolean compile() throws CompileException; }
);
f.setEnclosingScope(ts);
+ // Recurse with one resource less.
return this.compileTryCatchFinally(
ts, // tryStatement
new Compilable2() { // compileBody
@@ -2970,105 +2966,78 @@ interface Compilable2 { boolean compile() throws CompileException; }
*/
private boolean
compileTryCatchFinally(
- final TryStatement ts,
- final Compilable2 compileBody,
- @Nullable BlockStatement finallY
+ final TryStatement ts,
+ final Compilable2 compileBody,
+ @Nullable final BlockStatement finallY
) throws CompileException {
- final CodeContext.Offset beginningOfBody = this.getCodeContext().newOffset();
- final CodeContext.Offset afterStatement = this.getCodeContext().new Offset();
-
- boolean canCompleteNormally;
-
if (finallY == null) {
- canCompleteNormally = this.compileTryCatch(ts, compileBody, beginningOfBody, afterStatement);
- } else {
+ final CodeContext.Offset beginningOfBody = this.getCodeContext().newOffset();
+ final CodeContext.Offset afterStatement = this.getCodeContext().new Offset();
- // Compile a TRY statement *with* a FINALLY clause.
+ boolean canCompleteNormally = this.compileTryCatch(ts, compileBody, beginningOfBody, afterStatement);
+ afterStatement.set();
+ return canCompleteNormally;
+ }
- this.getCodeContext().saveLocalVariables();
- try {
+ // Compile a TRY statement *with* a FINALLY clause.
- final Offset fo = (ts.finallyOffset = this.getCodeContext().new Offset());
+ final CodeContext.Offset afterStatement = this.getCodeContext().new Offset();
+ boolean canCompleteNormally;
- // Allocate a LV for the JSR of the FINALLY clause.
- //
- // Notice:
- // For unclear reasons, this variable must not overlap with any of the body's variables (although the
- // body's variables are out of scope when it comes to the FINALLY clause!?), otherwise you get
- // java.lang.VerifyError: ... Accessing value from uninitialized local variable 4
- // See bug #56.
- final short pcLvIndex = this.getCodeContext().allocateLocalVariable((short) 1);
+ this.getCodeContext().saveLocalVariables();
+ try {
- canCompleteNormally = this.compileTryCatch(ts, new Compilable2() {
+ final CodeContext.Offset beginningOfBody = this.getCodeContext().newOffset();
+ canCompleteNormally = this.compileTryCatch(ts, compileBody, beginningOfBody, afterStatement);
- @Override public boolean
- compile() throws CompileException {
- boolean canCompleteNormally = compileBody.compile();
- if (canCompleteNormally) {
- UnitCompiler.this.jsr(ts, fo);
- }
- return canCompleteNormally;
- }
- }, beginningOfBody, afterStatement);
+ // Generate the "catch (Throwable) {" clause that invokes the FINALLY subroutine.
+ this.getCodeContext().saveLocalVariables();
+ try {
- // Generate the "catch (Throwable) {" clause that invokes the FINALLY subroutine.
- this.getCodeContext().saveLocalVariables();
- try {
+ CodeContext.Offset here = this.getCodeContext().newOffset();
+ this.getCodeContext().addExceptionTableEntry(
+ beginningOfBody, // startPC
+ here, // endPC
+ here, // handlerPC
+ null // catchTypeFD
+ );
- CodeContext.Offset here = this.getCodeContext().newOffset();
- this.getCodeContext().addExceptionTableEntry(
- beginningOfBody, // startPC
- here, // endPC
- here, // handlerPC
- null // catchTypeFD
- );
+ // Push the exception on the operand stack.
+ this.getCodeContext().pushObjectOperand(Descriptor.JAVA_LANG_THROWABLE);
- // Push the exception on the operand stack.
- this.getCodeContext().pushObjectOperand(Descriptor.JAVA_LANG_THROWABLE);
+ // Save the exception object in an anonymous local variable.
+ short evi = this.getCodeContext().allocateLocalVariable((short) 1);
+ this.store(
+ finallY, // locatable
+ this.iClassLoader.TYPE_java_lang_Object, // lvType
+ evi // lvIndex
+ );
+
+ if (this.compile(finallY)) {
- // Save the exception object in an anonymous local variable.
- short evi = this.getCodeContext().allocateLocalVariable((short) 1);
- this.store(
- finallY, // locatable
- this.iClassLoader.TYPE_java_lang_Object, // lvType
- evi // lvIndex
- );
- this.jsr(finallY, fo);
this.load(
finallY, // locatable
this.iClassLoader.TYPE_java_lang_Object, // type
evi // index
);
this.athrow(finallY);
-
- // Generate the "finally" subroutine.
- this.getCodeContext().pushTopOperand();
- fo.set();
- ts.finallyOffset = null;
-
- this.store(
- finallY, // locatable
- this.iClassLoader.TYPE_java_lang_Object, // lvType
- pcLvIndex // lvIndex
- );
- if (this.compile(finallY)) {
- this.ret(finallY, pcLvIndex);
- }
- } finally {
-
- // The exception object local variable allocated above MUST NOT BE RELEASED until after the FINALLY
- // block is compiled, for otherwise you get
- // java.lang.VerifyError: ... Accessing value from uninitialized register 7
- this.getCodeContext().restoreLocalVariables();
}
} finally {
+
+ // The exception object local variable allocated above MUST NOT BE RELEASED until after the FINALLY
+ // block is compiled, for otherwise you get
+ // java.lang.VerifyError: ... Accessing value from uninitialized register 7
this.getCodeContext().restoreLocalVariables();
}
+ } finally {
+ this.getCodeContext().restoreLocalVariables();
}
afterStatement.set();
-// if (canCompleteNormally) this.leave(ts, null);
+
+ if (canCompleteNormally) canCompleteNormally = UnitCompiler.this.compile(finallY);
+
return canCompleteNormally;
}
@@ -3103,81 +3072,75 @@ interface Compilable2 { boolean compile() throws CompileException; }
StackMap smBeforeBody = this.getCodeContext().currentInserter().getStackMap();
- boolean canCompleteNormally = compileBody.compile();
+ boolean tryCatchCcn = compileBody.compile();
CodeContext.Offset afterBody = this.getCodeContext().newOffset();
- if (canCompleteNormally) {
+ if (tryCatchCcn) {
this.gotO(tryStatement, afterStatement);
}
if (beginningOfBody.offset != afterBody.offset) { // Avoid zero-length exception table entries.
- this.getCodeContext().saveLocalVariables();
- try {
- for (int i = 0; i < tryStatement.catchClauses.size(); ++i) {
- try {
- this.getCodeContext().currentInserter().setStackMap(smBeforeBody);
+ for (int i = 0; i < tryStatement.catchClauses.size(); ++i) {
+ this.getCodeContext().currentInserter().setStackMap(smBeforeBody);
- this.getCodeContext().saveLocalVariables();
+ this.getCodeContext().saveLocalVariables();
+ try {
- CatchClause catchClause = (CatchClause) tryStatement.catchClauses.get(i);
+ CatchClause catchClause = (CatchClause) tryStatement.catchClauses.get(i);
- if (catchClause.catchParameter.types.length != 1) {
- throw UnitCompiler.compileException(catchClause, "Multi-type CATCH parameter NYI");
- }
- IClass caughtExceptionType = this.getType(catchClause.catchParameter.types[0]);
+ if (catchClause.catchParameter.types.length != 1) {
+ throw UnitCompiler.compileException(catchClause, "Multi-type CATCH parameter NYI");
+ }
+ IClass caughtExceptionType = this.getType(catchClause.catchParameter.types[0]);
- // Verify that the CATCH clause is reachable.
- if (!catchClause.reachable) {
- this.compileError("Catch clause is unreachable", catchClause.getLocation());
- }
+ // Verify that the CATCH clause is reachable.
+ if (!catchClause.reachable) {
+ this.compileError("Catch clause is unreachable", catchClause.getLocation());
+ }
- // Push the exception on the operand stack.
- this.getCodeContext().pushObjectOperand(caughtExceptionType.getDescriptor());
+ // Push the exception on the operand stack.
+ this.getCodeContext().pushObjectOperand(caughtExceptionType.getDescriptor());
- // Allocate the "exception variable".
- LocalVariableSlot exceptionVarSlot = this.getCodeContext().allocateLocalVariable(
- (short) 1,
- catchClause.catchParameter.name,
- caughtExceptionType
- );
- final short evi = exceptionVarSlot.getSlotIndex();
+ // Allocate the "exception variable".
+ LocalVariableSlot exceptionVarSlot = this.getCodeContext().allocateLocalVariable(
+ (short) 1,
+ catchClause.catchParameter.name,
+ caughtExceptionType
+ );
+ final short evi = exceptionVarSlot.getSlotIndex();
- // Kludge: Treat the exception variable like a local variable of the catch clause body.
- this.getLocalVariable(catchClause.catchParameter).setSlot(exceptionVarSlot);
+ // Kludge: Treat the exception variable like a local variable of the catch clause body.
+ this.getLocalVariable(catchClause.catchParameter).setSlot(exceptionVarSlot);
- this.getCodeContext().addExceptionTableEntry(
- beginningOfBody, // startPC
- afterBody, // endPC
- this.getCodeContext().newOffset(), // handlerPC
- caughtExceptionType.getDescriptor() // catchTypeFD
- );
- this.store(
- catchClause, // locatable
- caughtExceptionType, // lvType
- evi // lvIndex
- );
+ this.getCodeContext().addExceptionTableEntry(
+ beginningOfBody, // startPC
+ afterBody, // endPC
+ this.getCodeContext().newOffset(), // handlerPC
+ caughtExceptionType.getDescriptor() // catchTypeFD
+ );
+ this.store(
+ catchClause, // locatable
+ caughtExceptionType, // lvType
+ evi // lvIndex
+ );
- if (this.compile(catchClause.body)) {
- canCompleteNormally = true;
- if (tryStatement.finallyOffset != null) {
- this.jsr(tryStatement, tryStatement.finallyOffset);
- }
- if (
- i < tryStatement.catchClauses.size() - 1
- || tryStatement.finallyOffset != null
- ) this.gotO(catchClause, afterStatement);
+ if (this.compile(catchClause.body)) {
+
+ if (tryStatement.finallY == null || this.compile(tryStatement.finallY)) {
+ tryCatchCcn = true;
+ this.gotO(catchClause, afterStatement);
}
- } finally {
- this.getCodeContext().restoreLocalVariables();
}
+ } finally {
+ this.getCodeContext().restoreLocalVariables();
}
- } finally {
- this.getCodeContext().restoreLocalVariables();
}
}
- return canCompleteNormally;
+ this.getCodeContext().currentInserter().setStackMap(smBeforeBody);
+
+ return tryCatchCcn;
}
// ------------ FunctionDeclarator.compile() -------------
@@ -6316,76 +6279,57 @@ interface Compilable2 { boolean compile() throws CompileException; }
* Statements like {@code return}, {@code break}, {@code continue} must call this method for all the statements
* they terminate.
*
- *
- * Notice: If stackValueType is {@code null}, then the operand stack is empty; otherwise
- * exactly one operand with that type is on the stack. This information is vital to implementations of {@link
- * #leave(BlockStatement, IClass)} that require a specific operand stack state (e.g. an empty operand stack for
- * JSR).
- *
*/
private void
- leave(BlockStatement bs, @Nullable final IClass stackValueType) {
- BlockStatementVisitor bsv = new BlockStatementVisitor() {
+ leave(BlockStatement bs) throws CompileException {
+ BlockStatementVisitor bsv = new BlockStatementVisitor() {
// SUPPRESS CHECKSTYLE LineLengthCheck:23
- @Override @Nullable public Void visitInitializer(Initializer i) { UnitCompiler.this.leave2(i, stackValueType); return null; }
- @Override @Nullable public Void visitFieldDeclaration(FieldDeclaration fd) { UnitCompiler.this.leave2(fd, stackValueType); return null; }
- @Override @Nullable public Void visitLabeledStatement(LabeledStatement ls) { UnitCompiler.this.leave2(ls, stackValueType); return null; }
- @Override @Nullable public Void visitBlock(Block b) { UnitCompiler.this.leave2(b, stackValueType); return null; }
- @Override @Nullable public Void visitExpressionStatement(ExpressionStatement es) { UnitCompiler.this.leave2(es, stackValueType); return null; }
- @Override @Nullable public Void visitIfStatement(IfStatement is) { UnitCompiler.this.leave2(is, stackValueType); return null; }
- @Override @Nullable public Void visitForStatement(ForStatement fs) { UnitCompiler.this.leave2(fs, stackValueType); return null; }
- @Override @Nullable public Void visitForEachStatement(ForEachStatement fes) { UnitCompiler.this.leave2(fes, stackValueType); return null; }
- @Override @Nullable public Void visitWhileStatement(WhileStatement ws) { UnitCompiler.this.leave2(ws, stackValueType); return null; }
- @Override @Nullable public Void visitTryStatement(TryStatement ts) { UnitCompiler.this.leave2(ts, stackValueType); return null; }
- @Override @Nullable public Void visitSwitchStatement(SwitchStatement ss) { UnitCompiler.this.leave2(ss, stackValueType); return null; }
- @Override @Nullable public Void visitSynchronizedStatement(SynchronizedStatement ss) { UnitCompiler.this.leave2(ss, stackValueType); return null; }
- @Override @Nullable public Void visitDoStatement(DoStatement ds) { UnitCompiler.this.leave2(ds, stackValueType); return null; }
- @Override @Nullable public Void visitLocalVariableDeclarationStatement(LocalVariableDeclarationStatement lvds) { UnitCompiler.this.leave2(lvds, stackValueType); return null; }
- @Override @Nullable public Void visitReturnStatement(ReturnStatement rs) { UnitCompiler.this.leave2(rs, stackValueType); return null; }
- @Override @Nullable public Void visitThrowStatement(ThrowStatement ts) { UnitCompiler.this.leave2(ts, stackValueType); return null; }
- @Override @Nullable public Void visitBreakStatement(BreakStatement bs) { UnitCompiler.this.leave2(bs, stackValueType); return null; }
- @Override @Nullable public Void visitContinueStatement(ContinueStatement cs) { UnitCompiler.this.leave2(cs, stackValueType); return null; }
- @Override @Nullable public Void visitAssertStatement(AssertStatement as) { UnitCompiler.this.leave2(as, stackValueType); return null; }
- @Override @Nullable public Void visitEmptyStatement(EmptyStatement es) { UnitCompiler.this.leave2(es, stackValueType); return null; }
- @Override @Nullable public Void visitLocalClassDeclarationStatement(LocalClassDeclarationStatement lcds) { UnitCompiler.this.leave2(lcds, stackValueType); return null; }
- @Override @Nullable public Void visitAlternateConstructorInvocation(AlternateConstructorInvocation aci) { UnitCompiler.this.leave2(aci, stackValueType); return null; }
- @Override @Nullable public Void visitSuperConstructorInvocation(SuperConstructorInvocation sci) { UnitCompiler.this.leave2(sci, stackValueType); return null; }
+ @Override @Nullable public Void visitInitializer(Initializer i) { UnitCompiler.this.leave2(i); return null; }
+ @Override @Nullable public Void visitFieldDeclaration(FieldDeclaration fd) { UnitCompiler.this.leave2(fd); return null; }
+ @Override @Nullable public Void visitLabeledStatement(LabeledStatement ls) { UnitCompiler.this.leave2(ls); return null; }
+ @Override @Nullable public Void visitBlock(Block b) { UnitCompiler.this.leave2(b); return null; }
+ @Override @Nullable public Void visitExpressionStatement(ExpressionStatement es) { UnitCompiler.this.leave2(es); return null; }
+ @Override @Nullable public Void visitIfStatement(IfStatement is) { UnitCompiler.this.leave2(is); return null; }
+ @Override @Nullable public Void visitForStatement(ForStatement fs) { UnitCompiler.this.leave2(fs); return null; }
+ @Override @Nullable public Void visitForEachStatement(ForEachStatement fes) { UnitCompiler.this.leave2(fes); return null; }
+ @Override @Nullable public Void visitWhileStatement(WhileStatement ws) { UnitCompiler.this.leave2(ws); return null; }
+ @Override @Nullable public Void visitTryStatement(TryStatement ts) throws CompileException { UnitCompiler.this.leave2(ts); return null; }
+ @Override @Nullable public Void visitSwitchStatement(SwitchStatement ss) { UnitCompiler.this.leave2(ss); return null; }
+ @Override @Nullable public Void visitSynchronizedStatement(SynchronizedStatement ss) { UnitCompiler.this.leave2(ss); return null; }
+ @Override @Nullable public Void visitDoStatement(DoStatement ds) { UnitCompiler.this.leave2(ds); return null; }
+ @Override @Nullable public Void visitLocalVariableDeclarationStatement(LocalVariableDeclarationStatement lvds) { UnitCompiler.this.leave2(lvds); return null; }
+ @Override @Nullable public Void visitReturnStatement(ReturnStatement rs) { UnitCompiler.this.leave2(rs); return null; }
+ @Override @Nullable public Void visitThrowStatement(ThrowStatement ts) { UnitCompiler.this.leave2(ts); return null; }
+ @Override @Nullable public Void visitBreakStatement(BreakStatement bs) { UnitCompiler.this.leave2(bs); return null; }
+ @Override @Nullable public Void visitContinueStatement(ContinueStatement cs) { UnitCompiler.this.leave2(cs); return null; }
+ @Override @Nullable public Void visitAssertStatement(AssertStatement as) { UnitCompiler.this.leave2(as); return null; }
+ @Override @Nullable public Void visitEmptyStatement(EmptyStatement es) { UnitCompiler.this.leave2(es); return null; }
+ @Override @Nullable public Void visitLocalClassDeclarationStatement(LocalClassDeclarationStatement lcds) { UnitCompiler.this.leave2(lcds); return null; }
+ @Override @Nullable public Void visitAlternateConstructorInvocation(AlternateConstructorInvocation aci) { UnitCompiler.this.leave2(aci); return null; }
+ @Override @Nullable public Void visitSuperConstructorInvocation(SuperConstructorInvocation sci) { UnitCompiler.this.leave2(sci); return null; }
};
bs.accept(bsv);
}
private void
- leave2(BlockStatement bs, @Nullable IClass stackValueType) {}
+ leave2(BlockStatement bs) {}
private void
- leave2(SynchronizedStatement ss, @Nullable IClass stackValueType) {
+ leave2(SynchronizedStatement ss) {
this.load(ss, this.iClassLoader.TYPE_java_lang_Object, ss.monitorLvIndex);
this.monitorexit(ss);
}
private void
- leave2(TryStatement ts, @Nullable IClass stackValueType) {
+ leave2(TryStatement ts) throws CompileException {
- Offset fo = ts.finallyOffset;
- if (fo == null) return;
+ Block f = ts.finallY;
+ if (f == null) return;
this.getCodeContext().saveLocalVariables();
try {
- short sv = 0;
-
- // Obviously, JSR must always be executed with the operand stack being empty; otherwise we get
- // "java.lang.VerifyError: Inconsistent stack height 1 != 2"
- if (stackValueType != null) {
- sv = this.getCodeContext().allocateLocalVariable(Descriptor.size(stackValueType.getDescriptor()));
- this.store(ts, stackValueType, sv);
- }
-
- this.jsr(ts, fo);
-
- if (stackValueType != null) {
- this.load(ts, stackValueType, sv);
- }
+ if (this.compile(f)) return;
} finally {
this.getCodeContext().restoreLocalVariables();
}
@@ -7657,11 +7601,16 @@ interface Compilable2 { boolean compile() throws CompileException; }
* executed.
*/
private void
- leaveStatements(Scope from, Scope to, @Nullable IClass stackValueType) {
+ leaveStatements(Scope from, Scope to) throws CompileException {
+ Scope prev = null;
for (Scope s = from; s != to; s = s.getEnclosingScope()) {
- if (s instanceof BlockStatement) {
- this.leave((BlockStatement) s, stackValueType);
+ if (
+ s instanceof BlockStatement
+ && !(s instanceof TryStatement && ((TryStatement) s).finallY == prev)
+ ) {
+ this.leave((BlockStatement) s);
}
+ prev = s;
}
}
@@ -12069,12 +12018,6 @@ interface Compilable { void compile() throws CompileException; }
}
}
- private void
- jsr(Locatable locatable, CodeContext.Offset dst) {
- this.getCodeContext().writeBranch(Opcode.JSR, dst);
- dst.setStackMap(this.getCodeContext().currentInserter().getStackMap().pushOperand(StackMapTableAttribute.TOP_VARIABLE_INFO));
- }
-
private void
l2i(Locatable locatable) {
this.addLineNumberOffset(locatable);
@@ -12250,19 +12193,6 @@ interface Compilable { void compile() throws CompileException; }
);
}
- private void
- ret(Locatable locatable, int lvIndex) {
- this.addLineNumberOffset(locatable);
- if (lvIndex > 255) {
- this.write(Opcode.WIDE);
- this.write(Opcode.RET);
- this.writeShort(lvIndex);
- } else {
- this.write(Opcode.RET);
- this.writeByte(lvIndex);
- }
- }
-
private void
returN(Locatable locatable) {
this.addLineNumberOffset(locatable);