United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6853701 : Scalar replacement (escape analysis) fails for simple test case

Details
Type:
Enhancement
Submit Date:
2009-06-22
Status:
Open
Updated Date:
2014-06-17
Project Name:
JDK
Resolved Date:
Component:
hotspot
OS:
linux
Sub-Component:
compiler
CPU:
x86
Priority:
P4
Resolution:
Unresolved
Affected Versions:
6u14
Targeted Versions:

Related Reports
Relates:
Relates:

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.6.0_14-ea"
Java(TM) SE Runtime Environment (build 1.6.0_14-ea-b06)
Java HotSpot(TM) 64-Bit Server VM (build 14.0-b15, mixed mode)

"java version "1.7.0-ea"
Java(TM) SE Runtime Environment (build 1.7.0-ea-b59)
Java HotSpot(TM) 64-Bit Server VM (build 16.0-b03, mixed mode)


FULL OS VERSION :
Linux 2.6.28-13-generic #44-Ubuntu SMP Tue Jun 2 07:55:09 UTC 2009 x86_64 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
Scalar replacement doesn't work for a situation in which the object reference clearly doesn't escape.
Please take a look at the attached test case.
If you run the test case as pasted below with "java -Xmx64M -server -verbose:gc -XX:+DoEscapeAnalysis Vector3Test" you'll find the following:
The methods escapeAnalysisWorks and escapeAnalysisFails perform the same (silly) computation and print the same output.
There's at most one gc log messages for the escapeAnalysisWorks.
There are tons of gc log messages for the escapeAnalysisFails.
The performance (if this can be concluded from such a microbenchmark) for escapeAnalysisWorks is much better due to scalar replacement.

It seems as if escape analysis incorrectly assumes that result object reference escapes from escapeAnalysisFails (which is only true for the basic block containing the for-loop, but not for the escapeAnalysisFails method).

THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: No

THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Yes

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class Vector3Test {
	
	public static class Vector3 {
		public double x,y,z;

		public Vector3(double x, double y, double z) {
			this.x = x;
			this.y = y;
			this.z = z;
		}
		
		public Vector3 madd(double val, Vector3 other) {
			return new Vector3(val*other.x+x,val*other.y+y,val*other.z+z);
		}
	}
	
	public static void main(String[] args) {
		System.out.println("Escape analysis works");
		escapeAnalysisWorks(10000);
		escapeAnalysisWorks(1000000);
		escapeAnalysisWorks(10000000);
		System.out.println("Escape analysis doesn't work");
		escapeAnalysisFails(10000);
		escapeAnalysisFails(1000000);
		escapeAnalysisFails(10000000);
	}

	public static void escapeAnalysisWorks(int count) {
		System.out.println("starting test where escape analysis works");
		long t1 = System.nanoTime();
		double x = 0;
		double y = 0;
		double z = 0;
		
		for (int i=0;i<count;i++)
		{
			Vector3 last = new Vector3(x,y,z);
			Vector3 result = last.madd(i / (double)count, new Vector3(i/(double)count,1.0-1/(double)count,1.0-1/(double)count));
			x = result.x;
			y = result.y;
			z = result.z;
		}
		long t2 = System.nanoTime();
		System.out.format("result = %f,%f,%f\n", x, y, z);
		System.out.println("duration: "+(t2-t1)/1000.0/1000.0+" msecs\n");
	}

	public static void escapeAnalysisFails(int count) {
		System.out.println("starting test where escape analysis fails");
		long t1 = System.nanoTime();
		Vector3 result = new Vector3(0,0,0);
		for (int i=0;i<count;i++)
		{
			result = result.madd(i / (double)count, new Vector3(i/(double)count,1.0-1/(double)count,1.0-1/(double)count));
		}
		long t2 = System.nanoTime();
		System.out.format("result = %f,%f,%f\n", result.x, result.y, result.z);
		System.out.println("duration: "+(t2-t1)/1000.0/1000.0+" msecs\n");
	}
}

---------- END SOURCE ----------

                                    

Comments
Should be fixed as part of 8012974 changes.
                                     
2014-01-21
Not critical for JDK7 or earlier. Moving to tbd_minor for future investigation by Dev team. Maybe this is no longer an issue
                                     
2014-01-20
It is still the issue but definitely not for  jdk7. Assigning back to me.
                                     
2014-01-20
EVALUATION

The test case shows limitation of the current EA implementation.
Objects will not be eliminated if there is merge point in which it is undefined which object is referenced.
In escapeAnalysisFails() there are references to object fields after the loop and an object could be eigther
the one created before loop (when passed count==0) or one created inside loop (result of madd() )

	public static void escapeAnalysisFails(int count) {
		System.out.println("starting test where escape analysis fails");
		long t1 = System.nanoTime();
		Vector3 result = new Vector3(0,0,0);
		for (int i=0;i<count;i++)
		{
			result = result.madd(i / (double)count, new Vector3(i/(double)count,1.0-1/(double)count,1.0-1/(double)count));
		}
		long t2 = System.nanoTime();
		System.out.format("result = %f,%f,%f\n", result.x, result.y, result.z);
		System.out.println("duration: "+(t2-t1)/1000.0/1000.0+" msecs\n");
	}
                                     
2009-07-24



Hardware and Software, Engineered to Work Together