ST for debugging : break here: MethodDeclaration(AbstractMethodDeclaration).generateCode(ClassFile) line: 357 MethodDeclaration(AbstractMethodDeclaration).generateCode(ClassScope, ClassFile) line: 281 TypeDeclaration.generateCode(ClassFile) line: 578 TypeDeclaration.generateCode(CompilationUnitScope) line: 648 CompilationUnitDeclaration.generateCode() line: 410 CompilationUnitProblemFinder(Compiler).resolve(CompilationUnitDeclaration, ICompilationUnit, boolean, boolean, boolean) line: 1061 CompilationUnitProblemFinder(Compiler).resolve(ICompilationUnit, boolean, boolean, boolean) line: 1100 CompilationUnitProblemFinder.process(CompilationUnit, SourceElementParser, WorkingCopyOwner, HashMap, boolean, int, IProgressMonitor) line: 280 CompilationUnitProblemFinder.process(CompilationUnit, WorkingCopyOwner, HashMap, boolean, int, IProgressMonitor) line: 346 ReconcileWorkingCopyOperation.makeConsistent(CompilationUnit) line: 193 ReconcileWorkingCopyOperation.executeOperation() line: 94 ReconcileWorkingCopyOperation(JavaModelOperation).run(IProgressMonitor) line: 736 ReconcileWorkingCopyOperation(JavaModelOperation).runOperation(IProgressMonitor) line: 802 CompilationUnit.reconcile(int, int, WorkingCopyOwner, IProgressMonitor) line: 1322 JavaReconcilingStrategy.reconcile(ICompilationUnit, boolean) line: 131 NegativeArraySizeException is thrown. Reproduced. Working on it. I don't know if this is same, but the following code throws an AIOBE when compiling. And making small changes to the code throws a verify error.
public class X {
@SuppressWarnings("preview")
public static void main(String[] args) {
(new X()).bar(switch (0) {
default -> {
try {
break 1;
}
catch (Exception ex) {
break 2;
}
}
});
foo(Day.SUNDAY); // Commenting out this code make the compiler work but throws a VerifyError on running
}
public void bar(int i) {} // if bar() is static, we can both compiler and run the code
public static void foo(Day d) {}
}
enum Day {
SUNDAY, MONDAY;
}
Retargeting to Java13 with the latest spec changes. (In reply to Manoj Palat from comment #0) > Created attachment 277728 [details] > test case Test case further simplified without the custom exception: public class X { @SuppressWarnings("preview") public static void foo(int i) throws Exception { int v = switch (i) { case 0 -> switch (i) { case 0 -> 0; default -> throw new Exception(); }; default -> 0; }; } public static void main(String argv[]) throws Exception { X.foo(0); } } Created attachment 279655 [details]
Debugging Notes
A short description of the analysis so far given below - For the complete detailed information, please refer to the attachment:
For the following code snippet,
public static int foo(int i) throws Exception {
int v = switch (i) {
case 0 -> switch (i) {
case 0 -> 0;
default -> throw new Exception();
};
default -> 0;
};
return v;
}
The code generated is shown below:
// Method descriptor #15 (I)I
// Stack: 3, Locals: 1
public static int foo(int arg0) throws java.lang.Exception;
0 new java.lang.Error [23]
3 dup
4 ldc <String "Unresolved compilation problem: \n"> [25]
6 invokespecial java.lang.Error(java.lang.String) [27]
9 athrow
Line numbers:
[pc: 0, line: 3]
The message at runtime is of course given by the line 4 ldc <String "Unresolved compilation problem: \n"> which is inserted into the code stream by the following st (debug breakpoint):
ClassFile.addProblemMethod(AbstractMethodDeclaration, MethodBinding, CategorizedProblem[]) line: 914
ClassFile.addProblemMethod(AbstractMethodDeclaration, MethodBinding, CategorizedProblem[], int) line: 952
MethodDeclaration(AbstractMethodDeclaration).generateCode(ClassScope, ClassFile) line: 317
TypeDeclaration.generateCode(ClassFile) line: 583
TypeDeclaration.generateCode(CompilationUnitScope) line: 653
CompilationUnitDeclaration.generateCode() line: 410
CompilationUnitResolver.resolve(CompilationUnitDeclaration, ICompilationUnit, NodeSearcher, boolean, boolean, boolean) line: 1249
CompilationUnitResolver.resolve(ICompilationUnit, IJavaProject, List, NodeSearcher, Map, WorkingCopyOwner, int, IProgressMonitor) line: 714
ASTParser.internalCreateAST(IProgressMonitor) line: 1221
ASTParser.createAST(IProgressMonitor) line: 836
CoreASTProvider$1.run() line: 271
at the st:
StackMapFrame.duplicate() line: 129
ClassFile.traverse(MethodBinding, int, byte[], int, int, Map, boolean) line: 5955
ClassFile.generateStackMapTableAttribute(MethodBinding, int, int, int, boolean) line: 4804
ClassFile.completeCodeAttribute(int) line: 1513
MethodDeclaration(AbstractMethodDeclaration).generateCode(ClassFile) line: 357
MethodDeclaration(AbstractMethodDeclaration).generateCode(ClassScope, ClassFile) line: 281
TypeDeclaration.generateCode(ClassFile) line: 583
TypeDeclaration.generateCode(CompilationUnitScope) line: 653
CompilationUnitDeclaration.generateCode() line: 410
length = this.numberOfStackItems;
if (length != 0) {
the length is -1 is here
and an allocation of an array of negative size, causes NegativeArraySizeException which causes the abort pushing all the way up to provide the ldc string of compilation error.
@Olivier: Adding further debugging notes: the length mentioned in the above comment 6 is the stack items ie frame. numberOfStackItems Starting from the expected code to be generated [the following generated by commenting out // frame.numberOfStackItems--; under tableSwitch case in traverse [for debug purpose only]: // Method descriptor #15 (I)I // Stack: 2, Locals: 2 public static int foo(int i) throws java.lang.Exception; 0 iload_0 [i] 1 tableswitch default: 52 case 0: 20 20 iload_0 [i] 21 tableswitch default: 44 case 0: 40 40 iconst_0 41 goto 53 44 new java.lang.Exception [17] 47 dup 48 invokespecial java.lang.Exception() [19] 51 athrow 52 iconst_0 53 istore_1 [v] 54 iload_1 [v] 55 ireturn Line numbers: [pc: 0, line: 4] [pc: 20, line: 5] [pc: 40, line: 6] [pc: 44, line: 7] [pc: 52, line: 9] [pc: 53, line: 4] [pc: 54, line: 11] Local variable table: [pc: 0, pc: 56] local: i index: 0 type: int [pc: 54, pc: 56] local: v index: 1 type: int The stack frame snapshots are each of the opcodes are listed below: 0 iload_0 [i] [pc : -1 locals: 0 stack items: 1 locals: [I,top] stack: [I]] 1 tableswitch default: 52 case 0: 20 [pc : -1 locals: 1 stack items: 0 locals: [I,top] stack: [] ] 20 iload_0 [i] [pc : -1 locals: 1 stack items: 1 locals: [I,top] stack: [I] ] 21 tableswitch default: 44 case 0: 40 [pc : -1 locals: 1 stack items: 0 locals: [I,top] stack: [] ] 40 iconst_0 [pc : -1 locals: 1 stack items: 1 locals: [I,top] stack: [I] ] 41 goto 53 [pc : -1 locals: 1 stack items: 1 locals: [I,top] stack: [I] ] 44 new java.lang.Exception [17] [pc : -1 locals: 1 stack items: 1 locals: [I,top] stack: [uninitialized(java/lang/Exception)] ] 47 dup [pc : -1 locals: 1 stack items: 2 locals: [I,top] stack: [uninitialized(java/lang/Exception),uninitialized(java/lang/Exception)] ] 48 invokespecial java.lang.Exception() [19] [pc : -1 locals: 1 stack items: 1 locals: [I,top] stack: [java/lang/Exception] ] 51 athrow [pc : -1 locals: 1 stack items: 0 locals: [I,top] stack: [] ] And a frame.duplicate() throws NegativeArrayException here when it tries to decrement stack items which is already 0. 52 iconst_0 53 istore_1 [v] 54 iload_1 [v] 55 ireturn ] This points to the decrement of athrow, and for debugging purposes, commenting out the // frame.numberOfStackItems--; Under case Opcodes.OPC_athrow: Of ClassFile.traverse; compilation goes through and the code generated is as follows: // Method descriptor #15 (I)I // Stack: 2, Locals: 2 public static int foo(int i) throws java.lang.Exception; 0 iload_0 [i] 1 tableswitch default: 52 case 0: 20 20 iload_0 [i] 21 tableswitch default: 44 case 0: 40 40 iconst_0 41 goto 53 44 new java.lang.Exception [17] 47 dup 48 invokespecial java.lang.Exception() [19] 51 athrow 52 iconst_0 53 istore_1 [v] 54 iload_1 [v] 55 ireturn Line numbers: [pc: 0, line: 4] [pc: 20, line: 5] [pc: 40, line: 6] [pc: 44, line: 7] [pc: 52, line: 9] [pc: 53, line: 4] [pc: 54, line: 11] Local variable table: [pc: 0, pc: 56] local: i index: 0 type: int [pc: 54, pc: 56] local: v index: 1 type: int Stack map table: number of frames 5 [pc: 20, same] [pc: 40, same] [pc: 44, same] [pc: 52, same] [pc: 53, same_locals_1_stack_item, stack: {int}] Looking at the Stack map table (jdt disassembler output – pc explicitly displayed), this is in complete agreement with the javac generated code as well, the appropriate part extracted below (javap output that of the above identical now) StackMapTable: number_of_entries = 5 frame_type = 20 /* same */ frame_type = 19 /* same */ frame_type = 3 /* same */ frame_type = 7 /* same */ frame_type = 64 /* same_locals_1_stack_item */ stack = [ int ] The program runs and prints zero correctly as well. Random notes/thinking aloud: Though a blanket commenting of decrement is of course wrong, is this pointing to any omission in terms of are we missing any conditional check before decrementing the stack items at athrow in a switch labeled expression rhs? Or any special processing at the flow-analysis/code-gen stage of ThrowStatement within a switch labelled expression enclosed within a switch expression? Further Notes:
public class X {
@SuppressWarnings({ "preview" })
public static int foo(int i) throws Exception {
int v = switch (i) {
case 0 -> switch (i) {
case 0 -> 0;
default-> throw new Exception();
case 3 -> 3;
case 2 -> throw new Exception();
};
default -> 0;
};
return v;
}
public static void main(String argv[]) throws Exception {
System.out.println(X.foo(1));
}
The problem happens only if throw new Exception() is the last case in the switch expression – it can be either a case or the default, just the order , ie just the last one matters – Is the YieldStatement.adjustStackSize() a suspect?
Investigating the issue again. Could not get a fix yet. Continuing to debug the case. I think this is a consequence of optimized goto. New Gerrit change created: https://git.eclipse.org/r/149843 (In reply to Eclipse Genie from comment #10) > New Gerrit change created: https://git.eclipse.org/r/149843 Merge of Olivier's new_stack_map to master via : https://git.eclipse.org/r/#/c/149842 Gerrit change https://git.eclipse.org/r/149843 was merged to [master]. Commit: http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=d629b1096b8cb254d581d898bc8e532a43fadd9d (In reply to Manoj Palat from comment #11) > Merge of Olivier's new_stack_map to master via : > https://git.eclipse.org/r/#/c/149842 Done via commit: https://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=9407f9ff6ccc3c7dccbee9bda158370adbe122c7 Thanks Olivier! New Gerrit change created: https://git.eclipse.org/r/149876 New Gerrit change created: https://git.eclipse.org/r/149878 Gerrit change https://git.eclipse.org/r/149878 was merged to [master]. Commit: http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=42e8e7c7d3c0a2353712025cd77254613c5d31d7 New Gerrit change created: https://git.eclipse.org/r/149881 New Gerrit change created: https://git.eclipse.org/r/149896 A combined stashed change of Olivier's patch alongwith test case changes and dom ast ConverterJCL additions/corrections at https://git.eclipse.org/r/#/c/149902/. Tests are green. This was pushed via commit:https://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=ae3d720efce20459d1d746646153478f03bf3002 Thanks Olivier. Resolving (In reply to Manoj Palat from comment #19) > A combined stashed change of Olivier's patch alongwith test case changes and > dom ast ConverterJCL additions/corrections at > https://git.eclipse.org/r/#/c/149902/. > > Tests are green. > > This was pushed via > commit:https://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/ > ?id=ae3d720efce20459d1d746646153478f03bf3002 > > Thanks Olivier. > > Resolving This one most likely caused a major regression, see bug 551368. New Gerrit change created: https://git.eclipse.org/r/150001 (In reply to Eclipse Genie from comment #21) > New Gerrit change created: https://git.eclipse.org/r/150001 This is a revert for commit ae3d720efce20459d1d746646153478f03bf3002. Gerrit change https://git.eclipse.org/r/150001 was merged to [master]. Commit: http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=d698c9585b5705d5d5c4944bb938bdba566fefdc New Gerrit change created: https://git.eclipse.org/r/150017 (In reply to Eclipse Genie from comment #24) > New Gerrit change created: https://git.eclipse.org/r/150017 New Gerrit change created: https://git.eclipse.org/r/150033 Created a combined gerrit that includes the revert of revert of bug 544943 and then applied the patch of bug 551368 - essentially https://git.eclipse.org/r/#/c/150018/. Request people willing to test this out by spawning Eclipse and doing some sanity test. Gerrit change https://git.eclipse.org/r/150017 was merged to [master]. Commit: http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=4cce8d539640bf79f986bb9a432b2351d6a08608 Fixed via bug 551368. The fix for this issue is a complete rewrite of the stack map frame computation. Instead of trying to keep stack map markers during the code generation, the generated bytecodes are traversed to compute the needed stack map frames. I added the notion of merging existing stack map frames with the current frame at branching locations. This required to have a scope in order to be able to compute type bindings based on the type names stored in the class files. This is required to be able to find the common type between two subtypes. Once the stack map frames are computed, the corresponding entries are added into the .class files by comparing the frames with their previous frame. Verified for 4.14 M1 using build I20191009-1800 This bug contains changes in org.eclipse.jdt.core/.settings/org.eclipse.pde.api.tools.prefs which effectively *turn off* API tools in the IDE. Why?? While this bug has gone through many reverts and revert-reverts, the initial change to these prefs was done via http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=134cb1fd6dd0e0b14cfeaa0ff3d1bb323bc79a00 Wasn't Olivier one of the original authors of API tools? You should know the value of these checks :) (In reply to Stephan Herrmann from comment #30) > This bug contains changes in > org.eclipse.jdt.core/.settings/org.eclipse.pde.api.tools.prefs which > effectively *turn off* API tools in the IDE. > > Why?? I can only think of this to be overlooked. Once Olivier confirm that there were no intended changes for this file, I will revert this particular file. Stephan, out of curiosity, how did you catch this? (In reply to Jay Arthanareeswaran from comment #31) > Stephan, out of curiosity, how did you catch this? Saw it flying by while merging JDT/Core changes into the Object Teams fork. New Gerrit change created: https://git.eclipse.org/r/151998 Can you please track and fix this in a new bug. Thanks. (In reply to Dani Megert from comment #34) > Can you please track and fix this in a new bug. Thanks. Over to bug 553315 (In reply to Jay Arthanareeswaran from comment #31) > Once Olivier confirm that there were no intended changes for this file, I > will revert this particular file. Sorry, overlook this |
Created attachment 277728 [details] test case Run the attached testcase to get : Exception in thread "main" java.lang.Error: Unresolved compilation problem: at X.foo(X.java:3) at X.main(X.java:20)