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.