Forum Controls
Spotlight Features

The Rich Engineering Heritage Behind Dependency Injection

Andrew McVeigh takes us on a tour of the rich heritage behind dependency injection, what it represents, and tells us why its here to stay.

NetBeans 6: Matisse Updates

NetBeans 6 delivers great updates to the Matisse GUI builder. Spend a few minutes with Roman Strobl and get an expert briefing on what's new and what has changed.

Introduction to Groovy Part 3

In this, the third and final installation of Andres' Introduction to Groovy series, you learn about how Groovy handles variable numbers of arguments, named parameters, currying, and more about Groovy operators. Including, some new operators.

Easier Custom Components with Swing Fuse

Swing Fuse (actually just Fuse), is a framework designed to make it easier to create your own custom desktop components. In this article, Daniel Spiewak shows you how to get started and provides sample source code you can download.

Benchmark Analysis: Guice vs Spring

Willam Louth shows how he uses JXInsight Probes to investigate probable performance issues with code bases that he is not familiar with. He also highlights possible pitfalls in creating a benchmark, as well as in the analysis of results.
Replies: 6 - Pages: 1  
Threads: [ Previous | Next ]
  Click to reply to this thread Reply

Scripting: Compiling Scripts in Java 6

At 1:40 PM on Dec 29, 2006, R.J. Lorimer wrote:

Java 6 introduces scripting engine support in to Java, and this new support provides a link between the Java we all know and hopefully love and the dynamic, delayed binding world of scripting languages.

Rhino (the Mozilla 100% Java Javascript implementation) ships with Sun's Java 6, and is about as full-featured as a Java 6 scripting engine can get. Not only is Rhino a Javascript/ECMAScript 1.6 compliant engine, but it also provides support for the 'compilable' feature of the scripting engine, and provides full access back into Java code - meaning you can use any Java library you want from within a Rhino script (that, however, is a topic for another tip).

Normally, when you want to run a script you would do something like this:

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
Bindings bindings = engine.createBindings();
bindings.put("num", "20");
Object result = engine.eval(
	"fib(num);" +
	"function fib(n) {" +
	"  if(n <= 1) return n; " +
	"  return fib(n-1) + fib(n-2); " +
	"};", 
	bindings);
 
System.out.println(result);

This example simply computes the fibonacci of '20' using Javascript, and then outputs the result (6765) to System.out. This Javascript fibonacci implementation is not anywhere near as fast as Java. The Javscript implementation is at a significant disadvantage, however, as it is being re-parsed every time, re-interpreted every time, and doesn't have the advantage of being run through Java's hotspot compiler (which the Java fibonacci implementation most certainly does). In addition, because of the nature of the scripting implementation, a lot of reflection is involved, and all of the number usage is done with full objects as opposed to stack-based primitives. Because fibonacci calculations are almost completely numerical in nature, the JS implementation inherits a lot of overhead.

While we can't solve all of these problems (some of them are simply the nature of the code being interpreted like this), we can compile the script so that we don't incur the re-parse/re-interpret overhead each time. This allows the Rhino Javascript engine to work it's magic as much as possible.

Compilation is an optional feature of the scripting engine support in Java 6, and it just so happens that Rhino supports compilation. Here is an example:

Map<String, CompiledScript> m = new HashMap<String, CompiledScript>();
// ...
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
CompiledScript script = m.get("fib");
if(script == null) {
	Compilable compilingEngine = (Compilable)engine;
	script = compilingEngine.compile(
			"fib(num);" +
			"function fib(n) {" +
			"  if(n <= 1) return n; " +
			"  return fib(n-1) + fib(n-2); " +
			"};"		
	);
	m.put("fib", script);
}
Bindings bindings = engine.createBindings();
bindings.put("num", "20");
Object result = script.eval(bindings);
System.out.println(result);

In this example, you can see we have a cache of compiled scripts represented by the hashmap 'm'. Everytime the code is run, it will look for the pre-compiled script first, and use it if it is there. Otherwise, the script is compiled and then put in to the map.

Unfortunately, compiled scripts are not, by default, serializable, so they can't be pre-compiled as part of a deployment process, so compilation should be applied at runtime when you know it makes sense. After all, a script being run only once is going to incur more overhead (possibly only a small amount, but more, nonetheless) to be turned into a CompiledScript and then be evaluated than it would simply to be evaluated; in both cases the underlying scripting engine is probably performing a compilation, but there is no intermediate step in the second case, and hence more room for 'one-run' optimizations. The advantage of compilation is only going to show up if you are running a script over and over again.

One other thing to consider if you are working with multiple script implementations is that not all scripts are necessarily compilable. If you need to run a script and are in a situation where you don't know whether or not the engine to execute the script is compilable, you can code more flexibly:

Map<String, CompiledScript> m = new HashMap<String, CompiledScript>();
// ...
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
Bindings bindings = engine.createBindings();
bindings.put("num", "20");
if(engine instanceof Compilable) {
	CompiledScript script = m.get("fib");
	if(script == null) {
		Compilable compilingEngine = (Compilable)engine;
		script = compilingEngine.compile(
			"fib(num);" +
			"function fib(n) {" +
			"  if(n <= 1) return n; " +
			"  return fib(n-1) + fib(n-2); " +
			"};"		
		);
		m.put("fib", script);
	}
	script.eval(bindings);
}
else {
	engine.eval(r, bindings);
}				

1 . At 7:30 PM on Dec 29, 2006, Ray Cromwell DeveloperZone Top 100 wrote:
  Click to reply to this thread Reply

Re: Scripting: Compiling Scripts in Java 6

RJ,
I haven't looked into the details of the engine, but I think the term "compile" needs to be clarified. Is this "compile" as in Regex Pattern.compile, or "compile" as in, groovyc -> generate Java bytecodes compile. While the API may leave the true definition up to the implementor, I would wondering what it means for Rhino in particular? I have found that even Firefox's native Javascript implementation is slow (compared to Flash or JScript for example) and was curious if this is just a "parse->AST" compile, or a true one.


edit: Nevermind, I found my answer here: http://www.mozilla.org/rhino/jsc.html, it's a true bytecode compile.
2 . At 12:02 PM on Dec 30, 2006, R.J. Lorimer wrote:
  Click to reply to this thread Reply

Re: Scripting: Compiling Scripts in Java 6

Ray,

That's a good question. Rhino as a standalone product does include BCEL; it's not predominately used at this point for generating class files for your JS model, but theoretically it could be. They took that dependency out when they integrated Rhino as the JS engine, and that does have impacts on what Rhino can do; I'm writing another article on Javascript/Java integration that will discuss the implications of removing BCEL.

So, all that being said, currently no, Rhino does not generate any class files. The closest it gets is dynamic proxies for interface implementation at runtime. From everything I have seen and read, compiling with the integrated Rhino is simply pre-building an AST.

That's really why I make the point that the code itself is fairly far removed from Hotspot; ideally for most scripting engines if class files could be built, the 'compiled' script code could benefit from the JIT, which is always a good thing.

The good news is the compilable API is fairly coarsely defined, so it shouldn't be too difficult to add 'true' compilation for most engines. The nice thing is that most open-source scripting engines that are being integrated with Java 6 (such as those at scripting.dev.java.net ) don't limit the dependencies.
Best, R.J. Lorimer
3 . At 1:49 AM on Jan 25, 2007, Sanjay Dasgupta wrote:
  Click to reply to this thread Reply

Class Loading Failure

I can't get JavaScript (in JDK 1.6.0-b105) to load an external class file. The following test code (with a script that tries to load its own class using "java.lang.Class.forName(String)") demonstrates the problem:

import javax.script.*;
public class LoadTest {
  public static void main(String args[]) {
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("js");
    try {
      engine.eval(
        "fn = new java.lang.String(\"LoadTest.class\");\r\n" +
        "f = new java.io.File(fn);\r\n" +
        "println(f.exists());\r\n" +
        "println(java.lang.System.getProperty(\"java.class.path\"));\r\n" +
        "c = java.lang.Class.forName(new java.lang.String(\"LoadTest\"));\r\n"
      );
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}


When run from the command-line (using "java -cp . LoadTest"), it produces the following output (the first two lines containing "true" and "." respectively come from two "println()"s in the script):

true
.
javax.script.ScriptException: sun.org.mozilla.javascript.internal.WrappedExcepti
on: Wrapped java.lang.ClassNotFoundException: LoadTest ( #5) in Unknown source> at line number 5
at com.sun.script.javascript.RhinoScriptEngine.eval(Unknown Source)
at com.sun.script.javascript.RhinoScriptEngine.eval(Unknown Source)
at javax.script.AbstractScriptEngine.eval(Unknown Source)
at LoadTest.main(LoadTest.java:9)
4 . At 2:54 PM on Jan 28, 2007, !vS_ wrote:
  Click to reply to this thread Reply

Re: Scripting: Compiling Scripts in Java 6

So this means we can write JS stuff in Java?
Planet Java
5 . At 6:25 AM on Mar 19, 2007, Israr Ahmed wrote:
  Click to reply to this thread Reply

Re: Scripting: Compiling Scripts in Java 6

Can we write and read JS statements in Java.
There certainly have been performance issues with Java. We've been working really hard on them. The primary way we've attacked the problem is with advanced virtual machines. The performance has been getting very nice. --James Gosling, 1999.
6 . At 2:06 AM on Oct 3, 2007, harivital wrote:
  Click to reply to this thread Reply

Re: Scripting: Compiling Scripts in Java 6

how can we import js from internet (using url) and also how can we create document and window objects in java

thread.rss_message