Nashorn (es6) corrupted function scope

Viewed 340

I am currently investigating following issue in Nashorn js scripting engine and I'd appreciate your input. Following code snippet fails execution (code in Kotlin):

fun main() {
    val brokenScript = """
        function fn() {
            const object1 = { "name": "Pepa" };
            print(object1.name);
            const descriptor1 = Object.getOwnPropertyDescriptor(object1, 'name');
            print(descriptor1.configurable);
            print(eval("3+1"));
        }
        fn();
    """.trimIndent()
    NashornScriptEngineFactory()
            .getScriptEngine("--no-deprecation-warning", "--language=es6", "--log=compiler:finest,fields,recompile:fine")
            .let { (it as Compilable).compile(brokenScript) }
            .also { script -> script.eval() }
}

Error:

Exception in thread "main" javax.script.ScriptException: ReferenceError: "descriptor1" is not defined in <eval> at line number 8
    at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.throwAsScriptException(NashornScriptEngine.java:477)
    at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:461)
    at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine$3.eval(NashornScriptEngine.java:517)
    at java.scripting/javax.script.CompiledScript.eval(CompiledScript.java:103)
    at MainKt.main(Main.kt:19)
    at MainKt.main(Main.kt)
Caused by: <eval>:8 ReferenceError: "descriptor1" is not defined
    at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ECMAErrors.error(ECMAErrors.java:57)
    at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ECMAErrors.referenceError(ECMAErrors.java:319)
    at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ECMAErrors.referenceError(ECMAErrors.java:291)
    at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ECMAErrors.referenceError(ECMAErrors.java:278)
    at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.AccessorProperty.checkUndeclared(AccessorProperty.java:571)
...

Observations:

  • issue is influenced by eval function - ommiting it from script helps - also need to be nested in function - works fine at top level
  • issue is influenced by Object.getOwnPropertyDescriptor function - ommiting it from script helps
  • issue is influenced by scoping - changing variable declaration from scoped (const/let) to unscoped var helps
  • output log contains caught RewriteException [pp=3, type=object, value='Pepa')]

Current hypothesis:

Object.getOwnPropertyDescriptor function raises UnwarrantedOptimismException that forces the function to recompile. Scope of recompiled script is corrupted. Usually the scope is manipulated by eval function usage so it can declare variables - maybe this is resolved incorrectly during the runtime recompilation. Accessing scoped variables fails.

What outcome I hope for?(in order of preference)

  • it works just as when executed in node - obviously
  • issue is identified at compile time without turning off es6 features
  • disabling eval function prevents the issue - I tried this by removing eval from Bindings object but script is corrupted at compilation phase and modified Bindings are passed later to script.eval(bindings) - so the script still fails before reaching eval line
  • (this is actually what I try to avoid) bypassing issue by turning off es6 features (removing --language=es6 - this forces the script to fail at compile time due to usage of scoped variables (const/let)

(I am aware that nashorn is deprecated and will be removed.)

1 Answers

We also had similar problem with Nashorn and JDK 9+. It seems like optimistic types causes this problem. Try disabling optimistic types for Nashorn

.getScriptEngine("--no-deprecation-warning", "--language=es6", "--log=compiler:finest,fields,recompile:fine", "--optimistic-types=false")

Ref: https://openjdk.java.net/jeps/196

Related