JDK-8134488 : var statement in if(false) block incorrectly evacuated into enclosing function
  • Type: Bug
  • Component: core-libs
  • Sub-Component: jdk.nashorn
  • Affected Version: 8u60,9
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_8
  • CPU: x86
  • Submitted: 2015-08-22
  • Updated: 2016-02-02
  • Resolved: 2015-09-25
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u72Fixed 9 b84Fixed
Description
FULL PRODUCT VERSION :
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) Client VM (build 25.60-b23, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.3.9600]

A DESCRIPTION OF THE PROBLEM :
There is a bug while executing the following javascript program with Nashorn via command line:
jjs.exe program.js

Probably the dead code elimination corrupts the global scope, hence the Nashorn's predefined "print" function is undefined during runtime.
 

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Save the following javascript program to file (program.js) and run it by CLI:
jjs.exe program.js

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
the expected output would be (as it does in other javascript engines):
string
string
ACTUAL -
the actual output is:
string
run.js:7 TypeError: Cannot call undefined

ERROR MESSAGES/STACK TRACES THAT OCCUR :
run.js:7 TypeError: Cannot call undefined

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
var x = "string";
print(x);

(function () {
	(function () {
		// print is undefined!
		print(x);
	})();

	if (false) {
		(function () {
			var x;
		})();
	}
})();
---------- END SOURCE ----------


Comments
The culprit was actually in FoldConstants. We have code that evacuates VarNodes from the part of if statements identified as dead code, as they still need to be effected as declarations, as they are scoped to the whole function. E.g. this: function f() { x = 1; if (false) { var x = 2; } } is effectively transformed into: function f() { x = 1; var x; } so that "x" is recognized as a local and not global variable. The problem was that the visitor looking for var declarations in dead if branches was also descending into nested functions, so "var x" in the anonymous nested function got evacuated into enclosing function.
25-09-2015

If you run it with -ea it'll actually stop with an assertion. I think FindScopeDepths is the culprit somehow as the RecompilableScriptFunctionData for f1 has no entry for "v1" in its externalScopeDepths map.
24-09-2015

Further analysis shows that: - removing "var x" from the dead function eliminates the problem. - replacing "var x" with "var y" from the dead function also eliminates the problem. - using "--lazy-compilation=false" produces different output (prints "string" and "undefined") So there's definitely something wrong going on there.
26-08-2015

Attached is the test case ran from Command line as : jjs.exe program2.js JDK 8u60 -fail JDK 9eab78 -fail On Commenting out the dead code, it does work as expected. Moving to dev-team for confirming if this is due to dead code elimination and taking further action.
26-08-2015