• hessian
  • quercus/php
  • resin 3.0
  • resin 3.1
  • resin 3.2

  • changes
  • configuration
  • examples
  • installing
  • overview
  • starting

  • guide: admin
  • admin
  • amber
  • bam
  • caching
  • clustering
  • comet
  • database
  • deployment
  • ejb 3.0
  • embedding
  • filters
  • ioc
  • jsf
  • jsp
  • logging
  • messaging
  • quercus
  • remoting
  • security
  • resources
  • servlets
  • third-party
  • troubleshooting
  • virtual host
  • watchdog
  • webapp
  • HOME
  • ABOUT
  • BLOG
  • BUGS
  • FORUM
  • MAIL-LIST
  • PRESS
  • PRODUCTS
  • STORE
  • WIKI
compiles JavaScript to Java bytecodes and uses the Java virtual machine to execute its code. The primary benefit of direct compilation is speed. Interpreters are slow. Interpreting JavaScript in Java would be deadly slow. The compilation to Java bytecodes allows the generated code to be compiled by any JIT compiler.

And, to be honest, writing Java bytecodes is cooler and more fun to implement. (Although tracing down verifier errors can be a huge headache.) Although Caucho Technology is primarily focused on providing robust and bug-sparse products to its customers, the engineers need to play, too.

JavaScript's great strength is in its object model, using prototype-based inheritance to retrieve fields. Essentially this means that objects are inheritable hashtables, rather than Java fields. This gives greater flexibility and makes it simpler to use properties; they never have to be declared. var a = obj.foo var b = obj["f" + "oo"] static ESId C1_foo = ESId.intern("foo"); static ESString C2_f = new ESString("f"); static ESString C3_oo = new ESString("oo"); ... ESBase a = obj.getProperty(C1_foo); ESBase t1 = C2_f.ecmaPlus(C2_oo); ESBase b = obj.getProperty(ref);

JavaScript's function calls differ dramatically from Java's calls. JavaScript functions are first-class objects; Java functions are bound to an object. JavaScript functions can be assigned to variables and put in arrays. They even have properties of their own. In addition, they take a variable number of arguments. This flexibility does come at a price, although a careful implementation can minimize the performance cost.

call2 is responsible for looking up the function concat in obj, putting "a" and "b" on the call stack, and calling the function. resin® has predefined functions for calls up to 3 arguments. Beyond that, the generated code must put the extra arguments on the call stack by itself. obj.concat("a", "b") static ESId C1_concat = ESId.intern("concat"); static ESString C2_a = new ESString("a"); static ESString C3_b = new ESString("b"); ... ESBase t1 = Call.call2(obj, C1_concat, call, 0, C2_a, C3_b);

Function local variables are much faster than global variables. resin® can usually put local variables and declared function arguments into Java local variables, so variable access is as fast as Java.

Global variables must remain in the global hashtable. Scouring the ECMAScript spec over and over again has shown no way of getting around this. For example, global variables can be watched with the watch call. So a global variable access will always require a function call.

I said that resin® can usually put local variables into Java variables. Using eval, the with statement, or function closures forces local variables into a hashtable. resin® makes eval a keyword to distinguish between the two cases. In strict ECMA-262, eval is just a function. If resin® strictly followed ECMA-262, it could not make this optimization because it could never detect an eval

For the same reason, resin® doesn't implement some of the obscure JavaScript 1.2 extensions, i.e. those allowing a function call access to its caller's local variables. That's not possible in Java without degrading to a hashtable.

resin® imports Java objects and classes by creating a wrapper around them. Essentially, it compiles a Java class to make the Java object appear as a JavaScript object. Properties and calls are then Java calls, not introspection calls. Introspection calls are slow.

JavaScript property accessing translates to field references and method calls. getLength becomes a property reference of length.

Function calls can only overload based on length because JavaScript is not strongly typed. For example, resin® can't overload like the PrintStream class, because it cannot distinguish between integers and doubles.

A library provider can get around this by creating an interface class, similar to a BeanInfo class, that describes the binding in detail. For example, the InputStream class uses this technique to write strings and provide printf to scripts.

The primary benefit of compiling to Java bytecodes is performance. Now, admittedly, performance isn't everything. People use scripting for the flexibility and rapid prototyping availability, not the speed. That's all the more reason for an implementation of a scripting language to be fast. Scripters shouldn't worry about performance. A fast scripting language lets the scripter concentrate on writing cool applications, instead of worrying about speed.

A JPython implementation paper.

  • HOME |
  • CONTACT US |
  • DOCUMENTATION |
  • SALES |
  • WIKI
Copyright (c) 1998-2008 Caucho Technology, Inc. All rights reserved.
resin® and quercus® are registered trademarks, and Ambertm is a trademark of Caucho Technology, Inc.