Rhino 1.5R5

Table of contents

  1. Wrapping of JavaScript functions as Java interfaces
  2. uneval() and toSource()
  3. seal() and changes in semantic of sealed objects
  4. Exception changes
  5. Compiled scripts are scope independent
  6. Callable interface
  7. No static caching
  8. API for compiling scripts into class files
  9. API for Context sealing
  10. Optimizer generates only one class per script
  11. Improved support for huge scripts
  12. Resolved Bugzilla reports

This is a log of significant changes in Rhino 1.5 Release 5.

Wrapping of JavaScript functions as Java interfaces

Rhino allows to pass a JavaScript function to a Java method expecting an interface which either has a single method or all its methods have the same number of parameters and each corresponding parameter has the same type. The JavaScript function will be called whenever interface’s method is called from Java. The function will receive all Java arguments properly converted into JS types and as the last parameter Rhino will pass interface method’s name.

The feature allows to simplify code that previously had to create explicit JavaAdapter objects. For example, one can write now:

    var button = new javax.swing.JButton("My Button");
    button.addActionListener(function(e) {
        java.lang.System.out.println("Button click:"+e);
    });
    var frame = new javax.swing.JFrame("My Frame");
    frame.addWindowListener(function(e, methodName) {
        java.lang.System.out.println("Window event:"+e);
        if (methodName == "windowClosing") {
            java.lang.System.exit(0);
        }
    });

instead of

    var button = new javax.swing.JButton("My Button");
    button.addActionListener(new java.awt.event.WindowListener({
        windowClosing : function(e) {
            java.lang.System.out.println("Window event:"+e);
            java.lang.System.exit(0);
        },
        windowActivated : function(e) {
            java.lang.System.out.println("Window event:"+e);
        },
        // similar code for the rest of WindowListener methods
    });
    var frame = new javax.swing.JFrame("My Frame");
    frame.addWindowListener(function(e, methodName) {

which was necessary in the previous version of Rhino. See Bugzilla 223435](https://bugzilla.mozilla.org/show_bug.cgi?id=).

uneval() and toSource()

Rhino fully supports uneval() function and toSource() method which are extensions to ECMAScript available in SpiderMonkey. They return a string that can be passed to the eval() function to reconstruct the original value when possible. It is guaranteed that uneval(eval(uneval(x))) == uneval(x) and in many cases more useful notion eval(uneval(x)) == deep_copy_of_x holds.

For example, here is an extract from a Rhino shell session:

js> var x = { a: 1, b: 2, c: [1,2,3,4,5], f: function test() { return 1; }, o: { property1: "Test", proeprty2: new Date()}}
js> uneval(x)
({c:[1, 2, 3, 4, 5], o:{property1:"Test", proeprty2:(new Date(1076585338601))}, f:(function test() {return 1;}), a:1, b:2})
js> x.toSource()
({c:[1, 2, 3, 4, 5], o:{property1:"Test", proeprty2:(new Date(1076585338601))}, f:(function test() {return 1;}), a:1, b:2})
js> uneval(x.propertyThatDoesNotExist)
undefined

See Bugzilla 225465.

seal() and changes in semantic of sealed objects

Rhino supports seal(object) function which is another ECMAScript extension from SpiderMonkey. The function makes the object immune to changes and any attempt to add, modify or delete a property of such object will throw an exception. Previously sealing was only possible through the Java sealObject() method in org.mozilla.javascript.ScriptableObject and before Rhino 1.5R5 it was possible to modify existing properties of sealed objects.

See Bugzilla 203013.

Exception changes

In Rhino 1.5R5 all exceptions generated during execution of a script provide information about script’s source name and line number that triggered the exception. The exception class org.mozilla.javascript.JavaScriptException is used now only to represent exceptions explicitly thrown by the JavaScript throw statement, it never wraps exceptions thrown in a Java method invoked by the script. Such exceptions are always wrapped as (org.mozilla.javascript.WrappedException)[https://javadoc.io/doc/org.mozilla/rhino/latest/org/mozilla/javascript/WrappedException.html].

See Bugzilla 217584, Bugzilla 219055 and Bugzilla 225817

Compiled scripts are scope independent

Previously Rhino required a scope object in the compileReader method of org.mozilla.javascript.Context to compile a script into org.mozilla.javascript.Script instances. Under some circumstances it was possible that the scope object would be stored in the compiled form of the script. It made impossible in such cases to reuse of the compiled form to execute the script against different scopes and lead to potential memory leaks.

Rhino 1.5R5 fixes such misbehavior and compileReader and newly introduced compileString no longer take the scope argument. For compatibility the old form of compileReader is kept as a deprecated method. See Bugzilla 218440.

Callable interface

All org.mozilla.javascript.Script and org.mozilla.javascript.Function instances in Rhino now implement the new interface org.mozilla.javascript.Callable which together with the new call method in org.mozilla.javascript.Context gives a simple way to call scripts and functions without explicit calls to Context.enter() and Context.exit().

The Callable interface allows to set the value of JavaScript this during script execution to arbitrary org.mozilla.javascript.Scriptable instance overriding default behaviour of using the scope object for the value of this.

Rhino interpreter uses Callable to pass references to scripts and functions to org.mozilla.javascript.SecurityController directly without wrapping script code into an additional proxy Script object. It allows to optimize an implementation of callWithDomain method in org.mozilla.javascript.SecurityController.

For compatibility applications extending the previous version of SecurityController are fully supported but the new applications should override callWithDomain method, not execWithDomain.

No static caching

Rhino no longer caches generated classes and information about reflected Java classes in static objects. Instead such caches are stored in a top scope object and initialized by default during call to initStandardObjects of org.mozilla.javascript.Context. This can be overridden with the explicit call to the associate method of org.mozilla.javascript.ClassCache if cache sharing is desired.

The cached objects no longer holds references to scope objects so even an application using multiple calls to Context.initStandardObjects and single shared ClassCache instance would not leak references to runtime library instantiations as it was the case with the previous Rhino for all applications.

The change allows to instantiate multiple Rhino runtime instances which would not interfere with each other and prevents memory leaks through ever growing caches.

API for compiling scripts into class files

The new class org.mozilla.javascript.optimizer.ClassCompiler provides a simple API to compile JavaScript source into set of Java class files with the given set of compilation options. JavaScript Compiler was upgraded to use new API and the old API were deprecated.

API for Context sealing

The new methods seal(Object), unseal(Object) and isSealed() in org.mozilla.javascript.Context allows to make Context instances immune from changes. Rhino embeddings that needs to run potentially untrusted scripts may use the new functionality to proprly implement the sandbox for such scripts without too restrictive org.mozilla.javascript.ClassShutter implementation.

See Bugzilla 236117.

Optimizer generates only one class per script

In Rhino 1.5R5 the default optimization mode generates only one Java class for script and all its functions while previously the optimizer generated additional class for each function definition in the script. It improves loading time for scripts and decreases memory usage especially for scripts with many function definitions.

See Bugzilla 198086.

Improved support for huge scripts

The interpreted mode contains significantly less restrictions on size and complexity of the scripts and if the remaining restrictions are not satisfied, Rhino will report an exception instead of generating corrupted internal byte code for interpreting.

See Bugzilla 225831.

Resolved Bugzilla reports

The full list of Bugzilla reports addressed in Rhino 1.5R5 can be obtained with the following Bugzilla query which searches bugzilla.mozilla.org for all resolved or verified bugs with the product set to Rhino and the target milestone set to 1.5R5.