Details

    • Type: Bug Bug
    • Status: Closed Closed
    • Priority: Critical Critical
    • Resolution: Fixed
    • Affects Version/s: JRuby 1.6RC2
    • Fix Version/s: JRuby 1.6.6
    • Component/s: Embedding
    • Labels:
      None
    • Environment:
      WindowsXP, JavaSDK 1.6.0_07; The bug also occurs with JRuby 1.5.0 and 1.5.6
    • Number of attachments :
      0

      Description

      If you use ScriptContext.setAttribute() in combination with compiled JRuby script then JRuby throws an exception:

      java.lang.ArrayIndexOutOfBoundsException: 0
      at org.jruby.runtime.scope.ManyVarsDynamicScope.setValueDepthZero(ManyVarsDynamicScope.java:158)
      at org.jruby.runtime.scope.ManyVarsDynamicScope.setValue(ManyVarsDynamicScope.java:151)
      at org.jruby.embed.variable.VariableInterceptor.inject(VariableInterceptor.java:128)
      at org.jruby.embed.internal.BiVariableMap.inject(BiVariableMap.java:381)
      at org.jruby.embed.internal.EmbedEvalUnitImpl.run(EmbedEvalUnitImpl.java:111)
      at org.jruby.embed.jsr223.JRubyCompiledScript.eval(JRubyCompiledScript.java:87)
      at at.alphagate.mesgateway.NewMain.<init>(NewMain.java:100)

      Test Code:

      System.setProperty("org.jruby.embed.localcontext.scope", "threadsafe");
      System.setProperty("org.jruby.embed.localvariable.behavior", "transient");

      ScriptEngineManager manager = new ScriptEngineManager();
      ScriptEngine rbEngine = manager.getEngineByName("jruby");
      ScriptContext context = new SimpleScriptContext();
      String[] texts = new String[]

      {"ab", "cd"}

      ;

      context.setAttribute("texts", texts, ScriptContext.ENGINE_SCOPE);

      String rbScript =
      " require 'java'\n" +
      " puts 'test script'\n" +
      " puts texts[0]\n";

      rbEngine.eval(rbScript, context); // is OK

      CompiledScript compiledScript = ((Compilable) rbEngine).compile(rbScript);
      compiledScript.eval(context); // throws exception

        Activity

        Hide
        Yoko Harada added a comment -

        Thanks for reporting the bug and helpful code. I could reproduce the exception. I'll have a look.

        Show
        Yoko Harada added a comment - Thanks for reporting the bug and helpful code. I could reproduce the exception. I'll have a look.
        Hide
        Yoko Harada added a comment -

        Hi,
        I fixed the bug in rev. c32ed17, so you won't get ArrayIndexOutOfBoundsException anymore.

        But, Two bugs and your misunderstanding were related to run a given sample code correctly. So, let me explain about these.

        The first bug fix might bother you, but this is the sharing variable policy. Please bear in mind. When a local variable behavior is transient, all local variables should vanish after evaluation. This is to avoid possibilities that lvars in file1.rb are used in file2.rb accidentally. So, you should add it again before the compile method.

        The second bug fix is exactly the culprit of ArrayIndexOutOfBoundsException. I'd like to say thank you for finding the bug.

        At last, you need to set ScriptContext to ScriptEngine before compile method is used. I know this is very hard to understand. JSR223 lacks many features to run Ruby code. If there was compile(script, context) method, you would have used that. Unfortunately, not. JRuby needs to know local variables' presence while parsing. Your code didn't set ScriptContext to JRubyEngine, so you'll get another exception. "rbEngine.eval(rbScript, context);" won't set context to ScriptEgine (JSR2223 spec says so), just use to the evaluation.

        Below is the code run successfully:

         
        System.setProperty("org.jruby.embed.localcontext.scope", "threadsafe");
        System.setProperty("org.jruby.embed.localvariable.behavior", "transient");
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine rbEngine = manager.getEngineByName("jruby");
        ScriptContext context = new SimpleScriptContext();
        String[] texts = new String[] {"ab", "cd"};
        
        context.setAttribute("texts", texts, ScriptContext.ENGINE_SCOPE);
        
        String rbScript =
            " require 'java'\n" +
            " puts 'test script'\n" +
            " puts texts[0]\n";
        
        rbEngine.eval(rbScript, context);
        
        context.setAttribute("texts", texts, ScriptContext.ENGINE_SCOPE); // needs to set again
        rbEngine.setContext(context); // needs set context to engine
        CompiledScript compiledScript = ((Compilable) rbEngine).compile(rbScript);
        compiledScript.eval(context);
        
        Show
        Yoko Harada added a comment - Hi, I fixed the bug in rev. c32ed17, so you won't get ArrayIndexOutOfBoundsException anymore. But, Two bugs and your misunderstanding were related to run a given sample code correctly. So, let me explain about these. The first bug fix might bother you, but this is the sharing variable policy. Please bear in mind. When a local variable behavior is transient, all local variables should vanish after evaluation. This is to avoid possibilities that lvars in file1.rb are used in file2.rb accidentally. So, you should add it again before the compile method. The second bug fix is exactly the culprit of ArrayIndexOutOfBoundsException. I'd like to say thank you for finding the bug. At last, you need to set ScriptContext to ScriptEngine before compile method is used. I know this is very hard to understand. JSR223 lacks many features to run Ruby code. If there was compile(script, context) method, you would have used that. Unfortunately, not. JRuby needs to know local variables' presence while parsing. Your code didn't set ScriptContext to JRubyEngine, so you'll get another exception. "rbEngine.eval(rbScript, context);" won't set context to ScriptEgine (JSR2223 spec says so), just use to the evaluation. Below is the code run successfully: System.setProperty("org.jruby.embed.localcontext.scope", "threadsafe"); System.setProperty("org.jruby.embed.localvariable.behavior", "transient"); ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine rbEngine = manager.getEngineByName("jruby"); ScriptContext context = new SimpleScriptContext(); String[] texts = new String[] {"ab", "cd"}; context.setAttribute("texts", texts, ScriptContext.ENGINE_SCOPE); String rbScript = " require 'java'\n" + " puts 'test script'\n" + " puts texts[0]\n"; rbEngine.eval(rbScript, context); context.setAttribute("texts", texts, ScriptContext.ENGINE_SCOPE); // needs to set again rbEngine.setContext(context); // needs set context to engine CompiledScript compiledScript = ((Compilable) rbEngine).compile(rbScript); compiledScript.eval(context);
        Hide
        Yoko Harada added a comment -

        should be closed. original problem has been solved.

        Show
        Yoko Harada added a comment - should be closed. original problem has been solved.

          People

          • Assignee:
            Yoko Harada
            Reporter:
            Daniel Lang
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: