Bug 38839 - org.eclipse.jdt.internal.compiler.parser.Scanner throws thousands of Exceptions
Summary: org.eclipse.jdt.internal.compiler.parser.Scanner throws thousands of Exceptions
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 2.1   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: 3.0 RC1   Edit
Assignee: Kent Johnson CLA
QA Contact:
URL:
Whiteboard:
Keywords: performance
Depends on:
Blocks:
 
Reported: 2003-06-12 11:11 EDT by Christophe Cornu CLA
Modified: 2004-05-28 15:36 EDT (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Christophe Cornu CLA 2003-06-12 11:11:29 EDT
Linux RH9, tested with default locale en_US.UTF8 and the japanese locale
I20030611, hotspot 1.4.1_02

Some methods in the Scanner class generate a significant number of
java.lang.IndexOutOfBoundsException when switching between 2 java editors.

Use case: switch between java editors
.OptimizeIt reports about 17% of the CPU time of the
org.eclipse.jdt.internal.ui.text.JavaReconciler thread is spent throwing
IndexOutOfBoundsException instances. This represents about 9% of the time of all
threads in the main thread group, and appears to be the most significant hotspot
for this use case.
The tool reports these exceptions are generated from the following methods
inside Scanner:
getNextChar, getNextToken, getNextCharAsDigit
.Without OptimizeIt, I instrumented the 2 methods getNextChar to count these
IndexOutOfBoundsException. About 2000 IndexOutOfBoundsException instances were
thrown when switching from one java file to another. The java files I used are
org.eclipse.swt.widgets.Shell and org.eclipse.swt.graphics.Cursor from SWT GTK.

An older version of Eclipse does not throw these exceptions on Windows. This may
be because my Windows box and my Linux box use different encoding or/and that
something has changed in the Scanner code.

If this was not expected and can be fixed, this will contribute to improving the
time taken to switch between java editors.
Comment 1 Rafael Chaves CLA 2003-06-12 11:16:57 EDT
Moving to JDT/Core.
Comment 2 Philipe Mulet CLA 2003-06-12 11:30:52 EDT
The scanner indeed doesn't check for boundaries eagerly and rather rely on the 
fact that there is only one such failure at the end of a unit.

Need to investigate this scenario, since it may occur more than we initially 
thought.
Comment 3 Kent Johnson CLA 2004-05-13 12:05:08 EDT
Ran the following test on 3 separate machines of varying speeds.

Expect to see the break even point between catching an exception & performing 
a bounds check to be between 1000-2500 array accesses.

If you can be sure that your code will throw an IndexOutOfBounds exception 
every few hundred accesses then you should definitely do a bounds check... but 
if its every 5-10,000 accesses or more then catching the exception is more 
efficient.


public class WithException {
  static int LoopSize = 100000;
  public static void main(String[] args) {
    int[] arraySizes = new int[] {500, 1000, 2500, 5000};
    for (int i = 0, l = arraySizes.length; i < l; i++) {
      int[] numbers = new int[arraySizes[i]];
      int numberOfRuns = 3;
      long t = 0;
      for (int n = numberOfRuns; --n >= 0; )
        t += catchException(numbers);
      System.out.println("catchException " + numbers.length + " -> " + t / 
numberOfRuns);
  
      t = 0;
      for (int n = numberOfRuns; --n >= 0; )
        t += performCheck(numbers);
      System.out.println("performCheck " + numbers.length + " -> " + t / 
numberOfRuns);
    }
  }

  public static long catchException(int[] numbers) {
    long t = System.currentTimeMillis();
    for (int i = LoopSize; --i >= 0; ) {
      try {
        for (int j = 0, l = 2 * numbers.length; j < l; j++)
          numbers[j] = 1;
      } catch (IndexOutOfBoundsException ignore) {
        for (int j = 0, l = numbers.length; j < l; j++)
          numbers[j] = 1;
      }
    }
    return System.currentTimeMillis() - t;
  }
  public static long performCheck(int[] numbers) {
    long t = System.currentTimeMillis();
    for (int i = 2 * LoopSize; --i >= 0; )
      for (int j = 0, l = numbers.length; j < l; j++)
        if (j < l)
          numbers[j] = 1;
    return System.currentTimeMillis() - t;
  }
}
Comment 4 Kent Johnson CLA 2004-05-14 13:01:23 EDT
Spawned the CodeStream & ConstantPool (which account for 300 of 341 cases) to 
bug 62131.
Comment 5 Kent Johnson CLA 2004-05-14 17:16:43 EDT
I released some changes to the Scanner so that does bounds checks for the 
common cases.
Comment 6 Olivier Thomann CLA 2004-05-20 21:40:07 EDT
Did you copy the internal scanner inside the PublicScanner?
Comment 7 Kent Johnson CLA 2004-05-25 17:04:55 EDT
Yes the PublicScanner was updated.

Released the remaining changes. The CodeStream & ConstantPool will be taken 
care of by bug 62131.
Comment 8 Olivier Thomann CLA 2004-05-28 15:36:23 EDT
Verified in 200405281200