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
Save to del.icio.us
Save to StumbleUpon
Digg it
Save to Reddit
Share on Facebook
Share on Twitter
More bookmarks
| Previous post: | Directory Traversal in Rhino JavaScript |
|---|---|
| Next post: | Rhino JavaScript to EXE with launch4j |
Subscribe!
Auto Save Clipboard Images Redux
Extending SpiderMonkey JavaScript on Windows
Rhino JavaScript to EXE with launch4j
Compiling Rhino JavaScript to Java
Directory Traversal in Rhino JavaScript
A Command-Line MP3 Player for Windows
Auto Save Images from the Clipboard
Java in a Windows EXE with launch4j
An Interview with Tom Zimmer: Forth System Developer
Setting Windows Console Text Colors in C
Scrolling GIF Banners with PerlMagick
Jim Butterfield : The Commodore Guru
Preserving my Favorite HN Links
BPL: Batch Programming Language Interpreter
MicroISV on a Shoestring
DadHacker
The Bottom Feeder
Writin' That Code!
The Recursive ISV
The Thomsen Blog
Prototypically Speaking
The Reinvigorated Programmer