2

I'm experimenting with multi-threaded scripts loading and evaluation in Nashorn and get kind of shocking behavior:

// having some object o loaded in another thread
print(o.constructor === o.constructor); // false
print(o.constructor === Object); // false as well
print(o.foo === o.foo); // true - OK

How can this be possible within single script engine? o above is just an object created using object literal notation (in another thread). Printing o.constructor gives usual function Object() { [native code] };.

At the same time:

print({}.constructor === {}.constructor); // true

Any ideas?

Update

It turned out this was unrelated to multi-threading at all. See my answer below for details.

Tvaroh
  • 6,645
  • 4
  • 51
  • 55
  • 1
    Each thread probably has its own copy of the Object constructor? Kind of like different windows in a browser? That is `window.frames[0].Object !== window.Object` – Ruan Mendes Dec 05 '14 at 21:37
  • @JuanMendes I bet that's exactly what it is. Except ... well, if it's a reference to an "alien" object, I'm not sure how it works at all. It'd help to know more about what the OP has set up; like, is it one ScriptEngine or multiple? – Pointy Dec 05 '14 at 21:38
  • Does it explain why o.constructor is not equal to itself? – Tvaroh Dec 05 '14 at 21:40
  • 1
    @Tvaroh I don't know; it seems strange. – Pointy Dec 05 '14 at 21:40
  • @Pointy this is just one script engine. – Tvaroh Dec 05 '14 at 21:41
  • So different threads are sharing a reference to a single ScriptEngine instance and making calls into the JavaScript code? Wow. – Pointy Dec 05 '14 at 21:44
  • @Tvaroh No it doesn't explain `o.constructor === o.constructor` being false. That is really weird – Ruan Mendes Dec 05 '14 at 21:47
  • Yep, but the code itself is thread-safe. I'm just evaluating one file then pass the result to a function being evaluated in another thread. – Tvaroh Dec 05 '14 at 21:47
  • @JuanMendes furthermore according to this http://stackoverflow.com/questions/27032656/does-it-make-sense-to-load-scripts-concurrently-in-java-8-nashorn-javascript-eng Nashorn is not thread-safe so it shouldn't create different globals (like Object constructor) for different threads. – Tvaroh Dec 05 '14 at 21:50
  • In fact, I doubt this is threading-related. I tried setting my thread pool size to 1 and nothing changed. – Tvaroh Dec 05 '14 at 21:56
  • Maybe `o.constructor` is `NaN` :) :) – Pointy Dec 05 '14 at 22:13
  • @Pointy As I mentioned in the question, it's not. I will try to create a minimal reproducible sample. – Tvaroh Dec 05 '14 at 22:22

1 Answers1

1

It turned out this does not relate to multi-threading at all. Here is a simple Scala program which reproduces the problem:

object Test extends App {
  val engine = new ScriptEngineManager().getEngineByName("nashorn")
  var o = engine.eval("({ foo: 'bar' })")
  var result = engine.eval("(o.constructor === o.constructor)", new SimpleBindings() {
    put("o", o)
  })
  print(result) // false
}

I was using bindings parameter incorrectly. Instead, I should take existing bindings and update 'em in-place. I'm still not convinced this should result in o.constructor === o.constructor to be false, but at least it works now. Corrected version:

object Test extends App {
  val engine = new ScriptEngineManager().getEngineByName("nashorn")
  var o = engine.eval("({ foo: 'bar' })")

  val bindings =  engine.getBindings(ScriptContext.ENGINE_SCOPE)
  bindings.put("o", o)

  var result = engine.eval("(o.constructor === o.constructor)", bindings)
  print(result) // true
}
Tvaroh
  • 6,645
  • 4
  • 51
  • 55
  • 1
    Whether this is expected behavior or not, it's certainly not intuitive, nor clearly documented. There's nothing I've found about Nashorn that explains why evaluating an object in a new bindings would behave differently than using the engine bindings. Good catch, though. – Steve B. Dec 06 '14 at 23:30