Bug 11431 - Stepping from one case statement's break ends up in next case
Summary: Stepping from one case statement's break ends up in next case
Status: RESOLVED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 2.0   Edit
Hardware: PC Windows 2000
: P2 normal (vote)
Target Milestone: 2.0 M5   Edit
Assignee: Olivier Thomann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2002-03-15 01:22 EST by Nick Edgar CLA
Modified: 2002-03-27 10:19 EST (History)
1 user (show)

See Also:


Attachments
Snap.gif (147.93 KB, image/gif)
2002-03-15 01:22 EST, Nick Edgar CLA
no flags Details
export.jar containing .java and .class files for the tasklist view (131.77 KB, application/octet-stream)
2002-03-15 01:25 EST, Nick Edgar CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Nick Edgar CLA 2002-03-15 01:22:00 EST
Build 20020214

I was stepping through the following code in 
org.eclipse.ui.views.tasklist.TaskListContentProvider:

int[] getMarkerCounts(List markers) {
	int numTasks = 0;
	int numErrors = 0, numWarnings = 0, numInfos = 0;
	for (Iterator i = markers.iterator(); i.hasNext();) {
		IMarker marker = (IMarker) i.next();
		if (MarkerUtil.isMarkerType(marker, IMarker.PROBLEM)) {
			int sev = MarkerUtil.getSeverity(marker);
			switch (sev) {
				case IMarker.SEVERITY_ERROR:
					++numErrors;
					break;
				case IMarker.SEVERITY_WARNING:
					++numWarnings;
					break;
				case IMarker.SEVERITY_INFO:
					++numInfos;
					break;
			}
		}
		else if (MarkerUtil.isMarkerType(marker, IMarker.TASK)) {
			++numTasks;
		}
	}
	return new int[] { numTasks, numErrors, numWarnings, numInfos };
}

All the markers have severity IMarker.SEVERITY_WARNING in this case.
When I stepped from this case's break statement, the debugger ended up 
highlighting the case for IMarker.SEVERITY_INFO.
Although ++numInfos was highlighed, stepping again had no effect (correct).

Suspect problems with the debug attributes.
I've attached the current sources and the corresponding .class files for the 
whole task list, and a screen shot showing the bogus state.
In the screen shot, notice that sev=1 (SEVERITY_WARNING, not SEVERITY_INFO).
Comment 1 Nick Edgar CLA 2002-03-15 01:22:34 EST
Created attachment 483 [details]
Snap.gif
Comment 2 Nick Edgar CLA 2002-03-15 01:25:34 EST
Created attachment 484 [details]
export.jar containing .java and .class files for the tasklist view
Comment 3 Olivier Thomann CLA 2002-03-15 11:54:40 EST
It seems that it is missing a line number entry in the debug attribute.
For the switch in the 
getMarkerCounts method the bytecodes are:
 0xAA           /*53  : tableswitch*/
 0x00 /*padding with 0-3 
0x00*/ 0x00
 0x0000002A /* default goto 95*/
 0x00000000 /* from 0 to 2 */ 0x00000002
 
0x00000027 /* for 0 goto 92 */
 0x00000021 /* for 1 goto 86 */
 0x0000001B /* for 2 goto 80 */
 0x84 
0x03 0x01 /*80  : iinc local variable 3 with const 1 */
 0xA7 0x00 0x0C /*83  : goto pc 95 : offset 12 
*/
 0x84 0x04 0x01 /*86  : iinc local variable 4 with const 1 */
 0xA7 0x00 0x06 /*89  : goto pc 95 : 
offset 6 */
 0x84 0x05 0x01 /*92  : iinc local variable 5 with const 1 */
 0xA7 0x00 0x11 /*95  : goto 
pc 112 : offset 17 */

And the line number attributes are:
 0x0050 /*pc 80 <--> 229 line number*/ 
0x00E5
 0x0053 /*pc 83 <--> 230 line number*/ 0x00E6
 0x0056 /*pc 86 <--> 232 line number*/ 0x00E8
 
0x0059 /*pc 89 <--> 233 line number*/ 0x00E9
 0x005C /*pc 92 <--> 235 line number*/ 0x00EB
 0x0062 
/*pc 98 <--> 239 line number*/ 0x00EF

So the pc 89 is mapped to the line 233 (break;). This is fine. 
But the pc 95 has not entry in the line number attribute table. It should be mapped to line 223 (the 
for loop).
I need to investigate why we missed this entry. Right now pc 95 is mapped at the same 
location than pc 92 which is line 235 (++numInfos; of the next case).
Comment 4 Olivier Thomann CLA 2002-03-15 12:40:56 EST
Without the "else if", everything is fine.
Comment 5 Olivier Thomann CLA 2002-03-19 16:34:46 EST
I checked what javac provides in this case. Javac had an extra line number attribute which points 
to the last break statement of the switch statement. This is a little bit confusing as well. The 
ideal solution would be to point to the line of the increment of the for statement.
Comment 6 Olivier Thomann CLA 2002-03-19 16:36:11 EST
The test case I am using is:

import java.util.ArrayList;
import 
java.util.Iterator;
import java.util.List;

public class Test {

	static int[] 
getMarkerCounts(List markers) {
		int numTasks = 0;
		int numErrors = 0, numWarnings = 0, 
numInfos = 0;
		for (Iterator i = markers.iterator(); i.hasNext();) {
			Marker marker = 
(Marker) i.next();
			if (marker.getType() == Marker.PROBLEM) {
				int sev = 
marker.getSeverity();
				switch (sev) {
					case Marker.SEVERITY_ERROR 
:
						++numErrors;
						break;
					case Marker.SEVERITY_WARNING 
:
						++numWarnings;
						break;
					case Marker.SEVERITY_INFO 
:
						++numInfos;
						break;
				}
			} else if (marker.getType() == 
Marker.TASK) {
				++numTasks;
			}
		}
		return new int[] { numTasks, numErrors, 
numWarnings, numInfos };
	}
	public static void main(String[] args) {
		ArrayList l = new 
ArrayList();
		l.add(new Marker(Marker.SEVERITY_ERROR));
		l.add(new 
Marker(Marker.SEVERITY_WARNING));
		l.add(new 
Marker(Marker.SEVERITY_WARNING));
		l.add(new 
Marker(Marker.SEVERITY_INFO));
		getMarkerCounts(l);
	}
}

class Marker 
{
	public static final int PROBLEM = 0;
	public static final int TASK = 1;
	public static 
final int SEVERITY_ERROR = 1;
	public static final int SEVERITY_WARNING = 2;
	public static 
final int SEVERITY_INFO = 3;
	
	private int sev;
	Marker(int k) {
		this.sev = 
k;
	}
	
	public int getSeverity() {
		return this.sev;
	}
	
	public int getType() 
{
		return PROBLEM;
	}
	
}
Comment 7 Olivier Thomann CLA 2002-03-19 17:01:15 EST
This is a side-effect of removing a goto to the next bytecode in the CodeStream. We might reconsider 
this optimization with latest VMs. It might not be relevant anymore. If this optimization is 
removed, the compiler ends up doing exactly what javac does.
Comment 8 Olivier Thomann CLA 2002-03-19 17:09:08 EST
If the last "break" is removed, javac has exactly the same bug. So I don't know if it worth fixing it. 
We might simply comment this in the release notes.
Comment 9 Philipe Mulet CLA 2002-03-20 13:01:35 EST
Inlining the switch gotos would solve this problem
Comment 10 Olivier Thomann CLA 2002-03-20 13:05:28 EST
We could try several optimizations.
1) Optimizing gotos to a goto. This is quite risky now.
2) 
When we place the falseLabel of a if statement, we check if the thenStatement is a switch statement 
or if it is a block which has a switch statement for the last statement. If this is the case, we can 
copy all the forward references from the switch's break label to the false label. Then when the 
false label is placed, it will override the gotos from the switch statements.
Need to be 
investigate and intensively tested.
Comment 11 Olivier Thomann CLA 2002-03-20 18:47:13 EST
In fact it is the endif label and not the falseLabel that needs to get the forward references of the 
switch statement break label.
Comment 12 Nick Edgar CLA 2002-03-25 23:15:34 EST
If it's that complicated, I don't feel this is a critical bug for 2.0.
Feel free to lower priority or defer.
Comment 13 Olivier Thomann CLA 2002-03-26 10:52:17 EST
We have a fix for this problem. I will release it soon even if I need to see if 
there are other patterns that could lead to the same stepping problem. With the 
fix the stepping looks natural again.
Comment 14 Olivier Thomann CLA 2002-03-27 10:19:49 EST
Fixed and released in HEAD. We might want to use PR 3426 to report further problems in debugger 
highlights.