Jim Lawless' Blog


Compiling Rhino JavaScript to Java

Originally published on: Sat, 17 Jul 2010

I've been experimenting with a few dynamic languages that run on top of the JVM. I've recently used Clojure, JRuby, and Rhino JavaScript. I am more conversant in JavaScript than I am in Ruby or any dialect of Lisp, so I have been using Rhino more frequently for experimentation.

I had begun to write a stand-alone program in Java when I realized that I could probably write the program more quickly in JavaScript, calling lower-level Java methods as I'd need them. I thought that I'd probably just write the whole thing as a single JavaScript file and would embed the source code as a resource in the JAR.

I accidentally happened upon the fact that the standard Rhino Java distribution will allow one to compile a JavaScript source file into a Java class file. If you take a look here, you'll find the documentation for the Rhino compiler. I decided to give it a try.

The first thing I did was to write a script that added js-14.jar and js.jar to my CLASSPATH environment variable.

Then, I wrote a short JavaScript program. Please note that all of the JavaScript sources below are Copyright 2010 by James K. Lawless under the MIT/ X11 open source license. ( See: http://www.mailsend-online.com/wp/license.php.)

test1.js

Running the above script dynamically generates the output "Heya, world!":

java -jar js.jar test1.js
Heya, world!

To compile the above script into a Java class file, I issued the following command:

java org.mozilla.javascript.tools.jsc.Main test1.js

A clean compile is indicated by an absence of output ... much like the Sun Java command-line compiler.

The file test1.class was properly generated. When I tried to execute it, I received the following output:

java test1
Heya, world!

Next, I wanted to see what kind of code had been generated, so I used the JAD decompiler by Pavel Kouznetsov.

jad test1
Parsing test1... Generating test1.jad

Here are a couple of interesting methods from the decompiled file:

The first method, getEncodedSource(), will return the source of the compiled file in its entirety when invoked. If you read through the documentation provided in the earlier link to the Mozilla, site, you may notice a parameter called -nosource. When adding this parameter to the compile command-line, the getEncodedSource() method is not generated.

The second method, Object_c0, is private in scope. It seems to be the primary method that runs the program that I just compiled.

I next wrote a variant of the first script that used a JavaScript function to wrap the call to System.out.println():

test2.js

java -jar js.jar test2.js
Heya, world!

Now, let's compile and run it.

java org.mozilla.javascript.tools.jsc.Main test2.js

java test2
Heya, world!

Let's decompile it with JAD:

C:\j\rhino>jad test2
Parsing test2... Generating test2.jad
Couldn't fully decompile method call
Couldn't fully decompile method getEncodedSource

Let's take a look at some of the generated methods:

Note that the methods, getEncodedSource() and call() have some low-level JVM code appearing in them. It's possible that I might need a newer version of JAD. If that's not the case, then Rhino is offering some mild JVM obfuscation to the output class file. ( Please see http://www.mailsend-online.com/blog/jruby-as-a-java-obfuscation-utility.html for a look at how JRuby can be used to generate obfuscated Java code. )

I found that the JVM code makes its appearance as soon as I define a function in the source file. Note that the JVM code in call() seems to be dispatching control conditionally to either the method _c0() or the method_c1().

After examining the generated code for each of these two methods, I noted that _c0() appears to be the code generated for the single line:

msg("Heya, world!");

The method _c1() appears to be the code generated from the body of the function msg().

It would appear that in a Rhino JS script, any code that sits outside of a function is bottled up into at least one anonymous function under the hood.

Note that the function names and variable names are all present in the compile class file as String literals. While I wouldn't necessarily want to be the one to try it, I would imagine that someone could manually decompile the generated code back to working JavaScript based on the decompiled class file.

If obfuscation of the JS source was actually something I'd need, I might look into using something like the YUI JavaScript minifier by Yahoo! on the source before compilation.

As I continued to experiment, I tried to compile a JavaScript program that used the load() function to load an external JS source file. I used the example from a prior post ( http://www.mailsend-online.com/blog/directory-traversal-in-rhino-javascript.html ):

dir.js

While the code ran properly after compilation. However, since the load() function executes at runtime, my class file had a dependency on the file spanDir.js. When I renamed spanDir.js to something else, the compiled dir.class threw an exception:

In prior Rhino JavaScript programs that I'd written, I tried to bottle up functions in appropriate library files and would load() them as needed. If I intend to compile my Rhino JavaScript code, I'm going to have to change the way I code. I would prefer to keep using libraries for isolated families of functions, so I will probably devise some sort of preprocessor that will combine the libraries and the main code into a single file before compilation.

Compiling Rhino JS code looks like a viable option for me. The primary benefit that I believe I will attain is that I hope to see higher level of coding productivity.

Unless otherwise noted, all code and text entries are Copyright ©2010 by James K. Lawless



Views expressed in this blog are those of the author and do not necessary reflect those of the author's employer. Views expressed in the comments are those of the responding individual.

stumbleupon Save to StumbleUpon
digg Digg it
reddit Save to Reddit
facebook Share on Facebook
twitter Share on Twitter
aolfav More bookmarks


Previous post: Directory Traversal in Rhino JavaScript
Next post:Rhino JavaScript to EXE with launch4j


About Jim ...


Click **here**
to try out MailWrench;
a command-line SMTP /
SMTPS (Google Gmail)
mailer for Windows.


Follow me on Twitter

http://twitter.com/lawlessGuy


Recent Posts

A JavaScript REPL for Android Devices

MailSend is Free

My Blog Engine

The October 10th Bug

A Review of Kevin Mitnick's Book Ghost in the Wires

Spellbound by Web Programming

Backlinks to my Blog Posts

Play MP3 Files with Python on Windows


Random Posts

Twimmando No More

Safe Scripting with Scroll Lock and Caps Lock

Shrouding CSharp and Java Source Code with AWK

WSH2EXE - The Final Chapter

A JavaScript REPL for Android Devices

Computers I Have Known

Directory Traversal in Rhino JavaScript

We've Moved!

Choose your own Adventure with Sinatra

Checking Shift States with DEBUG


Full List of Posts

http://www.mailsend-online.com/bloglist.htm


Recent Posts from my Other Blog

Remembering Dr. San Guinary

Why Some Web Sites will go Dark on Jan 18th

SNL Superhero Skit

More Ruby Games

My Ruby Game Challenge Entry

Steal this Bookmarklet

Nerd Toys

Learn New Jargon, You Must

Spot the Wiebe

Tech Magazine Glory Days

Book Review : Paull Allen - Idea Man

A 90's Experiment in Online Systems - The U.S. West CommunityLink Service