Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8294560

assertion raised in newBuiltinSwitchPoint

    XMLWordPrintable

Details

    Description

      ADDITIONAL SYSTEM INFORMATION :
      nashorn 15.4 / JDK 17

      A DESCRIPTION OF THE PROBLEM :
      Context.newBuiltinSwitchPoint raises an assertion when trying to access a lazily initialized built-in object like JSON from the Global scope.
      It seems the code is not thread-safe and multiple parallel access during initialization can lead to an assertion error.
      Previous versions of nashorn from JDK 1.8 without lazy global initialization did not have the problem.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the test code and after sometime you get an internal assertion

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Script execution is thread-safe
      ACTUAL -
      ```
      Caused by: java.lang.AssertionError
      at org.openjdk.nashorn.internal.runtime.Context.newBuiltinSwitchPoint(Context.java:1737)
      at org.openjdk.nashorn.internal.objects.Global.tagBuiltinProperties(Global.java:2950)
      at org.openjdk.nashorn.internal.objects.Global.initConstructorAndSwitchPoint(Global.java:2552)
      at org.openjdk.nashorn.internal.objects.Global.getBuiltinJSON(Global.java:2089)
      at org.openjdk.nashorn.internal.objects.Global.getJSON(Global.java:294)
      at org.openjdk.nashorn.internal.scripts.Script$Recompilation$79$17A$\^eval\_.entrypoint(<eval>:3)
      at org.openjdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:648)
      at org.openjdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:513)
      at org.openjdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:520)
      at org.openjdk.nashorn.api.scripting.ScriptObjectMirror.call(ScriptObjectMirror.java:111)
      at org.example.AppTest.lambda$test$0(AppTest.java:46)
      at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
      at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
      at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
      at java.base/java.lang.Thread.run(Thread.java:833)
      ```


      ---------- BEGIN SOURCE ----------
      package org.example;


      import com.fasterxml.jackson.databind.ObjectMapper;
      import java.util.ArrayList;
      import java.util.List;
      import java.util.concurrent.ExecutionException;
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;
      import java.util.concurrent.Future;
      import java.util.concurrent.TimeUnit;
      import javax.script.Bindings;
      import javax.script.CompiledScript;
      import javax.script.ScriptEngineManager;
      import javax.script.ScriptException;
      import org.junit.Test;
      import org.openjdk.nashorn.api.scripting.JSObject;
      import org.openjdk.nashorn.api.scripting.NashornScriptEngine;

      public class AppTest {
          @Test
          public void test() throws InterruptedException, ExecutionException, ScriptException {
              String script1 = """
                      var entrypoint = function(param) {
                      var out = busy(param);
                      return JSON.stringify({"out":out}); };
                      function busy(count) {
                      var j=0;
                      for (i=0;i<count;i++){j++;}
                      return j;
                      }""";

              ExecutorService taskExecutor = Executors.newFixedThreadPool(100);

              while (true) {
                  List<Future<Integer>> futures = new ArrayList<>();
                  ScriptEngineManager manager = new ScriptEngineManager();
                  NashornScriptEngine engine = (NashornScriptEngine) manager.getEngineByName("nashorn");
                  for (int i = 0; i < 10; i++) {
                      CompiledScript compiledScript = engine.compile(script1);
                      for (int j = 0; j < 1000; j++) {
                          futures.add(taskExecutor.submit(() -> {
                              Bindings bindings = compiledScript.getEngine().createBindings();
                              compiledScript.eval(bindings);
                              JSObject jsObject = (JSObject) bindings.get("entrypoint");
                              String jsonResult = (String) jsObject.call(null, 100);
                              return new ObjectMapper().readTree(jsonResult).get("out").intValue();
                          }));
                      }
                  }
                  for (Future<Integer> f : futures) {
                      f.get();
                  }
                  System.out.println(".");
                  TimeUnit.SECONDS.sleep(1);
              }
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      load json in the context after compiling the script and before doing mulithreaded script calls
      compiledScript.getEngine().eval("JSON")

      FREQUENCY : always


      Attachments

        Activity

          People

            attila Attila Szegedi
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: