Changing behavior of sealed objects to throw an exception on any attempt to modify them including changing values of existing properties. In the same time making object sealed does not affect read-only status of its properties which allows to override properties of objects with a sealed object as a prototype.
Rhino shell now accepts -sealedlib option to seal all standard objects.
In setBySetter when start != this setters with delegators and setters without one if start is not an instance of this class are not invoked on start. Instead the standard JS rules applies so x.a = 1 would not change a in x.__proto__ if a in x.__proto__ is controlled by setter.
New helper class JIFunction for easy implementation of JS functions in Java without using reflection and its usage in ImporterTopLevel and NativeJavaPackage
While you are messing arround with JavaScriptException, is it possible to add
if(value instanceof Throwable) {
initCause((Throwable) value);
}
I know it's a Java 1.4 feature and not directly connected to this bug and don't
know what's the Rhino's policy of supported Java versions, but it in the end it
could be done with method.invoke() or something similar.
This would help debugging a lot.
Using (x instanceof Wrapper) instead of (x instanceof NativeJavaObject) which replaces the previous fix of unwrapping NativeJavaObject.call arguments for the custom wrappers problem.
1. Reorganization of BaseFunction.construct to always call createObject to avoid the need to re-implement construct in IdFunction and FunctionObject when much simpler code for subclassing createObject will do the job.
2. Throwing TypeError in IdFunction.createObject if it is not marked explicitly as constructor to satisfy EcmaScript standard:
first page of ECMAScript Edition 3, chapter 15: "None of the built-in
functions described in this section shall implement the internal
[[Construct]] method unless otherwise specified ...."
For more details, see http://bugzilla.mozilla.org/show_bug.cgi?id=202019
To fix the issue I moved away from generateCodeFromNode code to merge boolean
checks and conditional jumps into separated generateIfJump method that tries to
apply this optimization and if it is not possible, it calls
generateCodeFromNode and adds a generic jump.
The static type argument to toObject is effectively never used since it always assumes that instances of String, Number and Boolean represent primitive JS values and handled via ScriptRuntime.newObject and in the rest of cases static type was not checked by WrapFactory.
Such optimization wins very little with modern JVMs if cast succeeds and produces very big overhead if cast fails. Moreover, it may prevent jits from doing more aggressive optimizations and makes class files bigger.
The change also made code in many places smaller since insanceof check take ensure that object is not null as well and with ClassCastException such check had to be done explicitly.
1. Disable invoker optimization for methods with variable number of arguments since currently to call optimized invoker a new argument array has to be allocated in any case which makes the optimization irrelevant.
2. Never modify elements of the args array in constructor, instead avoid allocation of the new argument array iff all js argument can be passed to java without type conversion.
I added Context.getApplicationClassLoader() that is now used in all
cases as a parent loader for generated classes and as the default class loader
for NativeJavaPackage. The default implementation tries to use
Thread.getContextClassLoader, but only when it is available and if Rhino
classes is available through it. Otherwise the loader for Context instance is
used. In this way if Rhino is loaded through a custom loader, it will be used,
and if Rhino classes are placed in lib/ext, Thread.getContextClassLoader still
give the application loader.
And if this default policy would not work in a particular application,
Context.getApplicationClassLoader() can be overridden to in that application.
use IdFunction.initAsConstructor to initialize Error constructors in
NativeGlobal.init and remove setFunctionType and corresponding getFunctionType in IdFunction and use a simple private boolean field there to mark functions that can be called as constructors since NativeGlobal.init was the only place that used that.
Use toObject() in ScriptRuntime.delete to convert non-Scriptable delete target to Object which required to pass Context and scope to the method and update Interpreter and optimizer/Codegen accordingly.
if (val != null && val != Undefined.instance && val instanceof Scriptable) ...
by code to generate:
if (val instanceof Scriptable && val != Undefined.instance) ...
since (val instanceof Scriptable) => (val != null)
I removed deprecated since 1.5R3 omj.ClassOutput and moved some of code from omj/ClassNameHelper.java to omj/optimizer/OptClassNameHelper so if one does not need the optimizer package, the jar will be smaller.
Initialize invoker in FunctionObject constructor, not during first call and catch possible SecurityException. In this way initialization will happen without script code on java stack which may not have permissions to create class loaders.
2. Hashtable is replaced by ObjToIntMap or UintMap to minimize memory usage.
3. Converting of strings to utf8 encoding is coded explicitly to avoid overhead of creating many objects.
2. Removal of Codegen.superClassSlashName field since Codegen.superSlashName since it is never used as a part of a signature and ClassFileWriter converts . into / in type name automatically.
Attempts to access/modify properties of null or undefined are explicitly checked to include in error messages the property name so it would be possible on error in x.y.z to know if it is x or y that was undefined or null.
Inspired by suggestion from Russell Gold.
I also added explicit flags to Parser: languageVersion and allowMemberExprAsFunctionName and set them from Context. In this way Parser can be used without Context which is useful for debugging.
1. It is not passed as a parameter to Interpreter/Codegen, instead Codegen access it directly when necessary.
2. ClassNameHelper.reset method is removed as inherently thread unsafe and data that should be used during compilation of single script is stored in Codegen itself.
3. Instead of a special DefaultClassRepository null is used to indicate that generated classes should not be stored and JavaAdapter is modified to take ClassRepository as a parameter, not ClassNameHelper.
PreorderNodeIterator iter = new PreorderNodeIterator();
for (iter.start(tree); !iter.done(); iter.next()) {
Node node = iter.getCurrent();
...
}
instead of
PreorderNodeIterator iter = tree.getPreorderIterator();
Node node;
while ((node = iter.nextNode()) != null) {
}
to allow for more flexible usage and added PreorderNodeIterator.nextSkipSubtree to skip iteration of the last visited node subtree which allows to have simple code in Optimizer.buildStatementList when iterating over statements.
The bug caused by a missed check in StmtNodeIterator.nextNode for a possible null result of findFirstInterestingNode inside the search loop which made search to stop preliminary with non-empty stack.
The changes fixe this and integrate StmtNodeIterator into
Optimizer.buildStatementList as StmtNodeIterator was used only by
buildStatementList and the new version is simpler.
The reason for the bug was that omj/optimizer/Optimizer.java when optimizing code for this[name] (see GETELEM switch, line 665) assumed a number context for GETELEM index node unconditionally which is wrong.
The fix uses number context only if [] argument is known for sure to be a number.
The bug was caused by a double call to Codegen.addNumberConstant, the first
time correctly from Codegen.visitLiteral and the second time wrongfully from
the loop in emitConstantDudeInitializers where loop index should be used
instead of calling addNumberConstant. As addNumberConstant would return the
same index for same numbers, the bug surfaces only with NaN as
addNumberConstant does not recognizes already added NaN. The bug also visible
only with optimization set to 1 or higher since only then constant folding can
produce NaN literal.
The fix removes the second call to addNumberConstant and uses
ScriptRuntime.NaNobj for NaNs.
The reason for the bug is that emitDirectConstructor generates code to call
setPrototype twice instead of setPrototype/setParentScope pair during new JS
object construction. The fix replaces that setup by a single call to
BaseFunction.createObject which is used by Interpreter as well.
Integration of LineBuffer into TokenStream code which now uses a special buffer for unreading of several chars to follow SM more closely. In this way there is no problem with a possible backtracking of 3 chars on failed attempt to match <!-- at the last minus.
TokenStream is also modified to accept a string with a source directly which avoids the need to construct intermediate StringReader in Context and allows to remove DebugReader class which is replaced by a simple function to read all Reader data into string.
Codegen.visitRegularCall should not try to apply the simple call optimization
when firstArgDone is true indicating directly called function. The patch also
replaces generation of code to call new Object[0] by loading the
ScripRuntime.emptyArgs field.
I just noticed that the changes introduced with
v1.29 of Main.java broke the ability to do hot
reloads of scripts. To be more explicit, the script
is actually reloaded but the source in the debugger
is not updated to reflect the newly loaded code.
...
Attached is a patch that restores the original behavior.
The refactorings are preserved but the handling of
previously loaded SourceInfo objects is restored and the
check for previously loaded ScriptItem instances
removed.
Have you considered adding a "Go" method to Main.java with
public visibility (same behavior as pressing the "Go" button in the debugger UI).
This would be a big help in a system where the debugger has been
embedded. Being able to close the debugger and ensure that any
breakpoints were removed and any blocked threads notified would
be a nice feature. Without this, closing the debugger can either
a) halt the application or b) destroy the debugger leaving blocked
threads in a permanent wait state. Note that the debugger is
not actually destroyed in this case because the waiting threads
prevent it from being wholly GCed.
This looks like a simple case of using the Hashtable key
instead of the value...
public void clearAllBreakpoints() {
// Igor - Use of keys() is inappropriate here. It produces
// a ClassCastException on the assignment below. The
// keys are String instances, not SourceInfo instances...
//
//Enumeration e = sourceNames.keys();
Enumeration e = sourceNames.elements();
...
}
For that I added new method createClasssLoader to Context, which by default returns new instance of DefiningClassLoader and changed the code to use this method instead of creating DefiningClassLoader directly. I moved DefiningClassLoader to org.mozilla.javascript package so core Rhino classes would not depend on org.mozilla.classfile package. I also changed SecurityController.createClasssLoader to take additional parentLoader argument to explicitly specify which class loader should be parent for generated code.
From my mail to Norris Boyd:
When considering http://bugzilla.mozilla.org/show_bug.cgi?id=166530 I realized that my 2 years old suggestion to use Thread.getContextClassLoader() in org.mozilla.classfile.DefiningClassLoader was wrong, as it does not follow class loader chain pattern Rhino embeddings can use. Moreover, it is wrong to use Thread.getContextClassLoader() when searching for Rhino classes as if Rhino is available via the system class loader and an application uses its copy from another loader, Thread.getContextClassLoader() would return incompatible class while simple Class.forName() would do proper job of loading the requested class from a loader of Class.forName() caller.
The only place where Thread.getContextClassLoader() can be useful is when searching for classes in NativeJavaPackage, but even there with a new option to use Package with an explicit class loader argument it is not necessary as one can write in a script
Packages(java.lang.Thread.contextClassLoader) to get necessary behavior.
The new SecurityController in its current form does not allow to define more then one generated class class in the same class loader effectively preventing to use optimizer which needs to define classes that refer each other and should be defined in the same loader.
To fix this I replaced the defineClass method in SecurityController by
public GeneratedClassLoader createClassLoader(Object securityDomain);
which returns instance of the new GeneratedClassLoader interface which can be used to define several classes. I also made DefiningClassLoader to implement this interface to simplify code in JavaAdapter.java and optimizer/Codegen.java.
The change removes the need to have instances of NativeFunction representing nested functions constructed before they are needed as a part of script execution.
I made ScriptRuntime.escapeString to escape \ and remove code to escape single quote ' as it is unreachable due to if (' ' <= c && c <= '~' && c != '"' && c != '\\') check as ' should not be escaped.
Patch from Marcus Crafter:
...
After speaking with Christopher Oliver, the problem seems to be a general JDK
1.4 bug that caches selected values in JComboBox, even after removeAllItems() is
called. Since its a general defect Christopher and I thought we'd report and get
it fixed in the main CVS tree.
...
Now caching of the last access slot covers GetterSlot instances as well and getter is always called for such slots
2. Fixing a potential race condition in setBySetter when a setter slot becomes an ordinary slot in response to a setter returning a value.
During execution of setBySetter a different thread can see initial null value in slot.value instead of the result of setter call as it is possible that JVM will first update slot.flags and only then slot.value for that thread. The fix replaces the old getter slot by an ordinary one under synchronized block for that I added new getSlotPosition method and updated the rest of code accordingly.
It allows to implement the DebuggableScript interface only by omj/InterpreterData instead of 2 identical implementations by InterpretedFunction and InterpretedScript.
Allow to use char sequences exceeding 64K when storing source for decompilation
The current 64K limit for string literals comes from omj/Parser.java where it constructs the internal script presentation for future decompilation. The patch extends this form to allow string sequences with more then 64K characters and modifes decompilation code in omj/NativeFunction.java accordingly.
TokenStream.java: third octal digit is a part of the octal escape in strings only if the result is <= 0377.
resources/Messages.properties: removal of unused msg.oct.esc.too.large
The change also allows with simple modifications of Context.getCurrentContext and Context.setThreadContext to use java.lang.ThreadLocal from JDK 1.2 to remove any synchronization on global data structures during Context.enter/Context.exit/Context.getCurrentContext.