Inspired by Norris' recent remark about low hanging fruit in the Rhino
garden I've started to experiment with mapping individual JS Objects
directly to Java classes with property access implemented by auto-
generated bytecode. I've created a project on github with some initial
proof-of-concept code:

http://github.com/hns/rhino-8

I called it rhino-8 because I started out on the idea of native JS
property access implemented by Google's V8 engine described here:

http://code.google.com/apis/v8/design.html#prop_access

Obviously, the JVM poses some restrictions on what you can do (for
example, to invoke a method or access a field in a class from Java
bytecode, the target interface or class must be "baked" into the local
class so it can't really be generated on the fly). So I went for a
more conservative approach which has the benefit of also being more
compatible with the Rhino script runtime.

What I am currently doing is to generate a Java class implementing
Rhino's Scriptable interface for each individual set of properties,
store property values in a dense object array, and generate switch
statements in the get(), put(), has(), and delete() methods similar to
those created by the IdSwitch tool to directly map the object's
properties into the value array *). When put() is called with an
unknown property id, it throws an UnknownFieldError that is caught by
a wrapper which transparently "morphes" the object to a newly
generated class that includes the new property id.

*) Note: I previously used individual native Java fields to store
property values but changed to the array representation for easier
transition between classes. I may go back to individual fields if it
benefits performance.

In other words, I'm providing a faster implementation of Scriptable by
implementing property access methods using a switch statement for a
well-known set of properties similar to the one used for NativeObject,
NativeString, NativeArray etc. prototypes instead of the generic slot
hashing implemented by ScriptableObject.

The code for this is in the org.mozilla.javascript.adaptive package:

http://github.com/hns/rhino-8/tree/master/src/org/mozilla/javascript/adaptive

You can use the Rhino shell's defineClass() function to play with it:

js> defineClass(org.mozilla.javascript.adaptive.AdaptiveObject);
js> a = new AdaptiveObject();

On initial benchmarks, this yields something like 30% - 50%
improvement in property access time compared to the current
ScriptableObject property implementation (quite a bit when using the
server HotSpot VM, which obviously does its own optimization magic on
ScriptableObject). Of course the approach won't work for all
situations. If you create an object and subsequently add properties to
it, a new Java class is generated in each step, and the object is
"morphed" to the new class in each step. So this isn't a magic pill
that will bring Rhino performance on par with V8 (not even close), but
I think it's an approach worth following. The good thing is that it
should be relatively easy to use different object implementations for
different situations, or switch between them as needed.

For example, one area where this would most probably make immediate
sense is object literals. Object literals have a set of properties
that is known beforehand, and they are often read-only and used over
and over again, so creating an optimized Java class for them should be
worth the overhead most of the time. Other ideas I'm playing with may
be to initially use a hashed object and watch usage patterns to decide
when and if to switch to compiled, "switched" state, or more simply to
delay class generation until the first invocation of get(), which
might work well for many common JS programming patterns.

Unfortunately, a lot of Rhino code currently assumes things to be
ScriptableObject instances, so it's not easy to test other object
implementations "in the wild". For example, Object.defineProperty
assumes not only the target object to be an instance of
ScriptableObject, but also the property descriptor argument. So one of
the next steps will be to factor the "advanced" property access
methods implemented by ScriptableObject into a new sub-interface of
Scriptable (I'll probably call it
org.mozilla.javascript.ExtendedScriptable - any other suggestions?)
and use that wherever ScriptableObject is used. That won't be fun, so
maybe as a short-term hack I'll just extend ScriptableObject in
AdaptiveObject and override the required methods.

I'm looking forward to your feedback and suggestions!

Hannes
_______________________________________________
dev-tech-js-engine-rhino mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-tech-js-engine-rhino

Reply via email to