Scope leaked between contexts/optimization bug starting in Java 9

Ryan Berdeen rberdeen at hubspot.com
Mon Aug 19 20:48:20 UTC 2019


I've encountered what seems like bug introduced in Java 9 where variables
can be leaked by the engine across separate contexts. I've extracted this
minimal reproduction out of service I'm running in projection in Java 8.
Gist: https://gist.github.com/also/412ce859f10f0b501bbfc43d15342dfc

Given this script

var x;
function test() {
  x = 1;
  print(++test.calls);
  eval('');
}
test.calls = 0;
test();

Repeatedly running it with a new context in the same engine works fine in
Java 8 (it will print "1" forever), but in Java 9+, things get weird. I
tested on macOS in openjdk 12.0.2 2019-07-16 from Oracle.

    ScriptEngine engine = new
ScriptEngineManager().getEngineByName("nashorn");

    for (int i = 0; i < 20; i++) {
      SimpleScriptContext context = new SimpleScriptContext();
      Bindings bindings = engine.createBindings();
      context.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
      engine.eval(script, context);
    }


This logs
1
2
3
4
...

If you add a second `engine.eval(script, context);` to the loop, it starts
to look like an optimization bug:

1
1
2
NaN
1
1
2
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
1
2
1
2
1
2
1

It seems to stabilize on 2, 1 after the 18th iteration. With a third call
to "engine.eval(script, context);" in the loop, it settles sooner:

1
1
1
2
NaN
NaN
1
1
1
1
1
1

It works as expected if you omit `context` in the calls to `engine.eval()`,
if you omit the `x = 1;` or `eval('');` lines in the `test` function, if
you call `print(++test.calls);` before `x = 1;`, or when using the
"graal.js" engine.

I know GraalVM JS is probably the way forward here, but was hoping I'd be
able to upgrade to Java 12 before making the switch.


More information about the nashorn-dev mailing list