I think there's a small problem with Igor's changes. The modifed Interpreter.java
seems to create unnecessary activation objects for InterpretedScripts. You can
see this in the debugger (local variables are present even for top level scripts).
I believe the attached change will fix the problem.
Regards,
Chris
VariableModel.java:220:30:220:40: Caution: This try block cannot throw a "checked exception" (JLS section 14.7) that can be caught here. You may have intended to catch a RuntimeException instead of an Exception.
Changes to omj.tools.debugger are mostly due to renames and refactoring, the new code is limited to ContextData class which contains simplified version of the code for DebugFrame stack from the current DebuggableEngineImplementation and FrameHelper class implementing DebugFrame.
...
The idea is to make Debugger responsible for creation of DebugFrame in
Interpreter.interpret which gives simple way for a Debugger implementation to
observe function enter/exit while completely removing the need to have code
for debug frame stack in the Rhino core as the Debugger implementation can
easily support this on its own when necessary. So I suggest to have:
public interface Debugger { ... }
and
public interface DebugFrame { ... }
which eliminates omj.InterpreterFrame and as DebuggableEngine shrinks down to
3 methods set/getDebugger and getDebuggerContextData, I simply moved them to
Context. The 3rd method is useful to refer to per Context debug data from a
Debugger implementation, but it can be removed as well as the same effect can
be achieved via Context.set/getThreadLocal.
non-ScriptableObject implementations of Scriptable.
I checked in fixes for the problems of serializing objects with FunctionObjects or
GetterSlots. With Foo.class in the current directory, I can now do:
[rhino] java -classpath 'build/rhino1_5R4pre/js.jar;.' org.mozilla.javascript.tools.shell.Main
Rhino 1.5 release 4 0000 00 00 (in progress)
js> defineClass("Foo")
js> f = new Foo
[object Foo]
js> print(f.counter)
0
js> print(f.counter)
1
js> serialize(f, "f.ser")
js> quit()
[rhino] java -classpath 'build/rhino1_5R4pre/js.jar;.' org.mozilla.javascript.tools.shell.Main
Rhino 1.5 release 4 0000 00 00 (in progress)
js> f = deserialize("f.ser")
[object Foo]
js> f.counter
2
js> f.counter
3
Hi Norris,
I encountered the following exception with the below script in compiled
mode with RhinoLatest.zip:
java.lang.NullPointerException
at
org.mozilla.javascript.optimizer.Codegen.visitCall(Codegen.java:1790)
at
org.mozilla.javascript.optimizer.Codegen.generateCodeFromNode(Codegen.java:567)
at
org.mozilla.javascript.optimizer.Codegen.visitReturn(Codegen.java:2283)
at
org.mozilla.javascript.optimizer.Codegen.generateCodeFromNode(Codegen.java:592)
at
org.mozilla.javascript.optimizer.Codegen.generateCodeFromNode(Codegen.java:546)
at
org.mozilla.javascript.optimizer.Codegen.generateCodeFromNode(Codegen.java:546)
at
org.mozilla.javascript.optimizer.Codegen.generateCodeFromNode(Codegen.java:546)
at
org.mozilla.javascript.optimizer.Codegen.generateCode(Codegen.java:497)
at
org.mozilla.javascript.optimizer.Codegen.generateFunctionInits(Codegen.java:1292)
at
org.mozilla.javascript.optimizer.Codegen.generateInit(Codegen.java:1186)
at
org.mozilla.javascript.optimizer.Codegen.generateCode(Codegen.java:481)
at org.mozilla.javascript.optimizer.Codegen.compile(Codegen.java:88)
at org.mozilla.javascript.Context.compile(Context.java:1965)
at org.mozilla.javascript.Context.compile(Context.java:1874)
at org.mozilla.javascript.Context.compileReader(Context.java:895)
at org.mozilla.javascript.Context.evaluateReader(Context.java:813)
at
org.mozilla.javascript.tools.shell.Main.evaluateReader(Main.java:318)
at org.mozilla.javascript.tools.shell.Main.processFile(Main.java:309)
at org.mozilla.javascript.tools.shell.Main.processSource(Main.java:248)
at org.mozilla.javascript.tools.shell.Main.exec(Main.java:95)
at org.mozilla.javascript.tools.shell.Main.main(Main.java:68)
Exception in thread "main"
function tak(x, y, z, k) {
if (!(y < x)) {
return k(z);
} else {
return tak(x - 1,
y,
z,
function(v1) {
return tak(y - 1,
z,
x,
function(v2) {
return tak(z - 1,
x,
y,
function(v3) {
return tak(v1, v2, v3, k);
});
});
});
}
}
function cpstak(x, y, z) {
return tak(x, y, z, function(a) {return a;});
}
//;;; call: (cpstak 18 12 6)
//(run-benchmark "CPSTAK" (lambda () (cpstak 18 12 6)))
var start = new Date();
var res = cpstak(18, 12, 6);
var end = new Date();
print(res +": elapsed: " + (end - start));
Hi Norris,
Would you mind checking in the attached changes to the debugger. The
attached files include the following changes:
1) Use ScriptableObject.getAllIds to obtain an object's properties (if
the object extends ScriptableObject). This makes non-enumerable
properties visible in the debugger for ScriptableObject's.
2) Made the coding style more consistent with the rest of Rhino.
3) Better support for displaying and stepping through eval-ed code.
As Igor suggested to me once, it might be a good idea to define a new
interface to similarly support debugging host objects that don't extend
ScriptableObject, something like the following:
public interface Debuggable extends Scriptable {
public Object[] getAllIds();
}
The debugger could check for this interface and if a host object chose
to implement it, the debugger would be able to display its
non-enumerable properties.
Chris
I think recent Christopher suggestions about tail call elimination is worth
to consider, as it would allow to cut invocation cost of script functions
quite nicely in many cases. Plus I am thinking of not creating Object[] array
to pass arguments to callee if it is another interpreted function as it can
directly access the caller stack. But first I decided to make some
preparation work to simplify an implementation of these features later. The
attached patch includes:
1. Moving all code to setup scope from
InterpretedFunction.call/InterpretedFunction.call to Interpreter.interpret so
the call method simply calls Interpreter.interpret. It would make tail call
elimination code much simple. I also hope this simplifies changes Christopher
needs for the continuations support (but I have strong reservation about
possibility to implement it corectly).
2. Moving all declaration of temporary variables used only during processing
of the single ICODE to the case blocks.
3. Interpreter loop termination only in RETURN icodes, not when pc exceeds
icode size, so there is no need to check for this condition on each icode.
(Scripts are handled via the special END_ICODE token).
...
>I did some tinkering and found there are pure java.lang.Object
>instantiations deep inside all the "standard objects" added to the
>ImporterTopLevel with Context.initStandardObject(). This is what is keeping
>it from serializing.
This is due to presence of Scriptable.NOT_FOUND and IdScriptable.NULL_VALUE tags in the data to serialize.
I replaced the type for the tags from Object to UniqueTag which is serializable ad knows how to make restored tags the same objects as Scriptable.NOT_FOUND and IdScriptable.NULL_VALUE.
Similarly Undefined was made serializable and to restore to Undefined.instance upon reading.
While looking into optimizing the modifications I've
made, I noticed that one of the bottlenecks seemed to be calls to the Java
instanceof operator, particularly if the class argument to instanceof isn't
final. Based on this observation I tweaked ScriptRuntime.java to attempt to avoid
some of the many "instanceof Scriptable" calls in it (which I've attached). In
particular I optimized the comparison operators for the case where the arguments
are Number's. This seems to provide some significant performance improvement in
many cases particularly in compiled mode. See below (note the tests were
performed with today's rhinoLatest.zip code patched with the attached
ScriptRuntime.java and didn't include any of my other modifications).
dan
Reflect new JSPD_* defines, make jsd_GetValueProperty degrade gracefully instead of fail outright when we run into a problem fetching the property value.
2. ObjToIntMap.clear and UintMap.clear now do not discard internal buffers, but clears references to external objects to match behavior of Java Vector.clear and Hashtable.clear.
If I have a Java class with a normal method that throws an exception, Rhino
(1.5pre4) will let JavaScript catch the exception. If the Java class has a
getter method, Rhino will NOT let JavaScript catch the exception. Very
disturbing.
Here's a console dump to show you what I'm talking about:
D:\jsSandbox>cat GIJoe.java
public class GIJoe
{
// Getter
public static int getYoJoe()
throws Exception
{
throw new Exception("Please catch me!");
}
// Normal
public static int rebel()
throws Exception
{
throw new Exception("Please catch me too!");
}
}
D:\jsSandbox>javac GIJoe.java
D:\jsSandbox>cat gi.js
var gi = new Packages.GIJoe();
try
{
var i = gi.rebel();
java.lang.System.err.println("rebel(): uncaught");
}
catch(e1)
{
java.lang.System.err.println("rebel(): caught");
}
try
{
var i = gi.yoJoe;
java.lang.System.err.println("yoJoe: uncaught");
}
catch(e2)
{
java.lang.System.err.println("yoJoe: caught");
}
D:\jsSandbox>java -cp .;e:\javas\rhino1_5R4pre\js.jar
org.mozilla.javascript.too
ls.shell.Main
js> load("gi.js");
rebel(): caught
java.lang.Exception: Please catch me!
org.mozilla.javascript.WrappedException: WrappedException of Please catch
me!
at org.mozilla.javascript.JavaMembers.get(JavaMembers.java:105)
at
org.mozilla.javascript.NativeJavaObject.get(NativeJavaObject.java:93)
at
org.mozilla.javascript.ScriptRuntime.getProp(ScriptRuntime.java:691)
at
org.mozilla.javascript.Interpreter.interpret(Interpreter.java:1591)
at
org.mozilla.javascript.InterpretedScript.call(InterpretedScript.java:
63)
at
org.mozilla.javascript.InterpretedScript.exec(InterpretedScript.java:
54)
at org.mozilla.javascript.Context.evaluateReader(Context.java:741)
at
org.mozilla.javascript.tools.shell.Main.evaluateReader(Main.java:347)
at
org.mozilla.javascript.tools.shell.Main.processSource(Main.java:336)
at org.mozilla.javascript.tools.shell.Global.load(Global.java:169)
at java.lang.reflect.Method.invoke(Native Method)
at
org.mozilla.javascript.FunctionObject.callVarargs(FunctionObject.java
:586)
at
org.mozilla.javascript.FunctionObject.call(FunctionObject.java:460)
at
org.mozilla.javascript.ScriptRuntime.call(ScriptRuntime.java:1216)
at
org.mozilla.javascript.Interpreter.interpret(Interpreter.java:1679)
at
org.mozilla.javascript.InterpretedScript.call(InterpretedScript.java:
63)
at
org.mozilla.javascript.InterpretedScript.exec(InterpretedScript.java:
54)
at org.mozilla.javascript.Context.evaluateReader(Context.java:741)
at
org.mozilla.javascript.tools.shell.Main.evaluateReader(Main.java:347)
at
org.mozilla.javascript.tools.shell.Main.processSource(Main.java:284)
at org.mozilla.javascript.tools.shell.Main.exec(Main.java:146)
at org.mozilla.javascript.tools.shell.Main.main(Main.java:74)
js>
Due to a lack of an "uncaught" statement in the output, we see that the
exception from GIJoe::getYoJoe() was indeed thrown, but not caught by the
JavaScript.
Do any nightly builds past 1.5pre4 address this issue?
Todd Trimmer
simple HAVE_LOCALTIME_R test. -DHAVE_LOCALTIME_R has been added to the
js/src/config/<platform>.mks as necessary.
bug #128556 r=brendan sr=shaver a=asa
tweaks. Patches from Mark Crichton <crichton@gimp.org>, Russell King
<rmk@arm.linux.org>, Jeroen Dobbelaere <jeroen.dobbelaere@acunia.com>.
r=brendan on jsnum.h, sr=shaver, a=asa for trunk and branch.