Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JDK 1.8.0_92 Nashorn JS engine indexOf behaviour

I am using "nashorn" javascript engine in java8 to evaluate some expressions during runtime. I have a util class for this with method:

    public static String evaluateJavaScriptExpression(String expression) throws ScriptException {
    if (expression == null) {
        return null;
    }
    ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
    ScriptEngine javaScriptEngine = scriptEngineManager.getEngineByName(JAVASCRIPT_ENGINE);
    return String.valueOf(javaScriptEngine.eval(expression));
}

for which I created some unit tests. One of them goes like this:

    String expression = "var arr = [1, 3, 2, 5, 4]; arr.indexOf(0);";
    assertEquals("-1", ExpressionEvaluatorUtil.evaluateJavaScriptExpression(expression));

It worked fine for me while I was using java version "1.8.0_91". But someone who used java version "1.8.0_92" reported that the test is failing. I switched my version to build 92 and it failed for me as well. The actual result for it is "-1.0". Also, i tried the same js code in Chrome console and it is returning "-1" as in build 91.

Does anyone know why there is such difference in results between the two jdk versions? Is this a bug or it was purposely changed?

like image 630
dty Avatar asked Jul 01 '16 08:07

dty


1 Answers

Well, if you know the precise version number of the change, you know where to look: the list of 1.8u92 bugfixes lists some fixes regarding Nashorn, the most interesting being JDK-8144020:

Remove long as an internal numeric type

ECMA defines double as the only number type in JavaScript. In Nashorn, we internally represent numbers as int, long and double. Use of long is problematic because it adds extra precision to the 53 bits provided by double. …

At the first glance, this seems to be an internal change only, but the picture changes, if you realize that your former result stemmed from the fact that previously, eval returned a Long for this code, being formatted to "-1".

Now consider the first sentence of this bug report: “ECMA defines double as the only number type in JavaScript”. This leads to the conclusion that returning a Long was not a specified result type, but an implementation artifact.

So apparently, when long was removed from the internal usage, the possibility to return Long was eliminated and the engine now doesn’t return Integer instead, but Double, as a byproduct of the change.

This explains, why there are other scripts like "var str = 'abcd'; str.indexOf('x');" which still produce an output without fractional digits. The latter script evaluated to Integer and still does. Since the change of the output type was a byproduct of removing internal long usage, not an intentional action to change all non-Double numeric results, places internally using int were not affected.

When comparing the result with Chrome’s engine, you have to consider that you are only comparing formatted output, with the number to string conversion not being part of the script. So the outcome is unspecified. The browser may take the freedom to present all numeric values matching an integer value without fractional digits.

like image 59
Holger Avatar answered Oct 18 '22 01:10

Holger