Re: [Rhino in Java] compiling .js to class file gives "bad local" error
Date:
Wed, 31 Jan 2001 09:41:45 +0100
From:
"Sylvia E. Schleutermann" <ses@h-m-s.com>
Organization:
.hms Health Management Systems
Newsgroups:
netscape.public.mozilla.jseng
References:
1 , 2
I have found out some more. Looking really quickly over the JVM specs, I
found that
indeed the astore-command requires that the variables index be below 128.
However,
the book also said that if more index space is needed, a "wide" command can
be used to
be able to address up to 65xxx variables.
Question: is there a possibility to integrate this "wide"-command into the
class compiler?
Some option, that can be set? Or am I on the wrong tracks?
Please help, since I want to avoid spreading the script over many classes to
avoid the
size limitation. Cheers, Sylvia
Sylvia E. Schleutermann <ses@h-m-s.com> wrote in message
news:956sv9$9g53@secnews.netscape.com...
> I have found out that it is definitely the number of variables.
> I removed all variables and then the script compiled into class files
> with one base class and inner classes for each function in the script.
>
> What is the limitation exactly, i.e. does anyone know how many (global)
> variables
> I can use? Or is there some other kind of work around?
>
> Cheers, Sylvia
>
>
> Sylvia E. Schleutermann <ses@h-m-s.com> wrote in message
> news:956qtv$6kh3@secnews.netscape.com...
> > Hello,
> > when compiling a *.js file to class file, I get a "bad local" runtime
> > exception.
> > Stepping through the source, the following happens in reverse order:
> >
> > Codegen.xstore (75, 58, 209)
> > -> in the switch - default case, there is a comparison
> > for local (=209), which is compared to Byte.MAX_VALUE (=127).
> > When greater, the above exception is thrown.
> >
> > Codegen.astore (209)
> > -> calls Codegen.xstore (ByteCode.ASTORE_0, ByteCode.ASTORE, 209)
> >
> > Codegen.generatePrologue (<context>, <tree>, true, -1) // -1 is
> > directParameterCount
> > -> sets itsZeroArgArray = getNewWordLocal(); // here, the 209 is
> > produced
> > -> calls astore (itsZeroArgArray)
> >
> > From what I can read from the source code, the 209 seems to be a counter
> for
> > "locals", perhaps
> > local variables?? The function that is being compiled does initialize
many
> > variables - would it help
> > to move the initialize code out of the function into separate code
blocks?
> >
> > The function looks like this
> >
> > function rule_Disclaimer()
> > {
> > try { VAR1 = <init code 1>;} catch (exception) { VAR1 = <default
init
> > code 1>; }
> > try { VAR2 = <init code 2>;} catch (exception) { VAR2 = <default
init
> > code 2>;}
> > ... (about 58 such variables)
> >
> > var cond = true;
> >
> > < rest of code>
> > }
> >
> > When I compile the script for interpreted mode, all works well. The
> > variables VAR1 to VAR58 are to be global
> > variables (global to the whole script).
> >
> > I appreciate any help! Thanks, Sylvia
> >
> >
>
>
expressions. The method "prefix" on a RegExp behaves exactly the same
as the "exec" method except it returns "undefined" if the match failed
because there was an insufficient number of characters in the
input. E.g.
/^foo/.prefix("foo") => ["foo"] (just like exec)
/^foo/.prefix("fox") => null (just like exec)
/^foo/.prefix("fo") => undefined (whereas exec returns null)
Subject:
[Rhino] Question
Date:
Tue, 30 Jan 2001 20:18:21 +0900
From:
"get21" <get21@secsm.org>
Organization:
Another Netscape Collabra Server User
Newsgroups:
netscape.public.mozilla.jseng
I found something unusual to me when I hacking the Rhino source code.
In tagify method of NativeString Class,
When it adds tag to its string(this.string), it does not use quotation
marks.
For example, the result of tagify("A HREF", "A", value) in
jsFunction_link(String value) is
<A HREF=Some Value>Original String Value</A>
Not,
<A HREF="Some Value">Original String Value</A>
This question might sound silly, but I'm curious why.
Thanks in advance,
Nam
--
email : get21@secsm.org
home : http://get21.secsm.org
phone : 011-9092-1802
- Optimize compile (parse+emit) operation to generate code for each top-level
statement or function in turn, recycling JSParseNodes as we go for greatly
reduced "long linear script" footprint.
- Fix O(n**2) growth problems in bytecode and srcnote generation.
- Add js_ParseTokenStream entry point to compiler, for tree-generation without
code-generation. Move JSOP_EVAL instruction selection from code-generator to
parser, to match other such specializations and enable js_ParseTokenStream.
- Fix js_CompileTokenStream (and get it right in new js_ParseTokenStream) to
respect JSOPTION_VAROBJFIX.
- Clean up bracing, multi-line conditions, and overlong lines.
Some other small fixes are included. Here is the list...
- Make nsIJSID::id [noscript] because xpconnect automatically builds a nsIJSID
wrapper around nsid values. However, xpconnect does not maintain a table of
those wrappers. So, given the same id twice it will make two nsIJSID wrappers.
This means that property walking could get foo.id.id.id... and not detect that
the different objects represent the same id. nsIJSID already exposes 'number'
so that JS can get the stringified value of the nsid. The nsid struct returned
by 'id' is useful for C++, but only causes problems for JS.
- Fix the nsIXPCScriptable 'IGNORE' handler for GetAttributes to not fail
silently.
- Add 'Components' to global objects as a non-enumerable property for backwards
compatibility and to avoid additional work in property enumeration (esp. in
win.toSource!)
- Expose toSource on wrapped native JSObjects. This just returns an empty object
string: '{}'. It can be overridden by an interface method if present.
- Expose toString on wrapped native JSObjects. It can be overridden by an
interface method if present. Previously we only did this as part of the
Convert op. Now someWrapper.toString will return a callable function.
- Extend the toString behaviour to also print the address of the wrapper in
DEBUG builds only: e.g. "xpconnect wrapped nsIFoo @ 0x12345678". mccabe
convinced me this would be useful. Release build behaviour is unchanged - we
worried that exposing addresses might contribute to possible security exploits.
- Have wrapped native JSObjects use Object.prototype as their proto rather than
have a null proto. Originally this was going to allow delegation to
Object.prototype.toSource, but even without that, this seems like a good thing.
This is implemented by getting Object.prototype from the global object each
time we create a wrapper to allow for spify JS dynamic craziness.
- Use 16bit values in wrappednative property descriptors to save space. It was
only possible to use 16 bits of the pointer-sized ints in the structs anyway.
- Do a security check at enumeration time and only expose those properties that
the caller can actually 'Get'. This fixes the toSource security exception
problem.
- Add a big comment about the problem of reporting uncaught exceptions.
- Fix crashing bug for case where object has no enumerable properties and
xpconnect failed to fill in the zero count.
- Fix NewInstanceJSObject to dig in and find the 'ultimate' parent when
parenting new wrapper JSObject. The old scheme was ending up with hugely
long parent chains in some cases.
r=jst, sr=brendan
- Optimize integer ++ and -- to avoid double-to-int, which is quite costly for
some compilers (ftol on Windows with MSVC).
- Optimized arguments[i] and arguments.length references to use bytecodes that
avoid creating an arguments object for the current frame. This entailed
simplifying the compiler to avoid flagging functions and scripts that set
arguments, since we have code in jsfun.c to catch such sets at runtime.
- The code generator now eliminates useless expression statements, giving a
strict warning about them.
- Rationalized jsemit.c's LookupArgOrVar to have well-defined results in *pn.
Eliminate bytecode specializations for argument and local variable gets and
sets from jsparse.c -- these precede jsemit.c's LookupArgOrVar and frustrate
it, by setting pn_slot non-negative too early.
- Code generation errors set report->filename and report->lineno, rather than
hacking "{0}, line {1}: " into the localized message.
- Bogus JSFRAME_VAROBJBUG removed, JSOPTION_VAROBJFIX is sufficient.
- Spruce up jsinterp.c macros to use JS_BEGIN/END_MACRO brackets if possible.
- Avoid calling JS_PropertyStub. The call is too costly compared to a branch
in the caller.
- Optimize integer ++ and -- to avoid double-to-int, which is quite costly for
some compilers (ftol on Windows with MSVC).
- Optimized arguments[i] and arguments.length references to use bytecodes that
avoid creating an arguments object for the current frame. This entailed
simplifying the compiler to avoid flagging functions and scripts that set
arguments, since we have code in jsfun.c to catch such sets at runtime.
- The code generator now eliminates useless expression statements, giving a
strict warning about them.
- Rationalized jsemit.c's LookupArgOrVar to have well-defined results in *pn.
- Code generation errors set report->filename and report->lineno, rather than
hacking "{0}, line {1}: " into the localized message.
- Bogus JSFRAME_VAROBJBUG removed, JSOPTION_VAROBJFIX is sufficient.
- Spruce up jsinterp.c macros to use JS_BEGIN/END_MACRO brackets if possible.
- Avoid calling JS_PropertyStub. The call is too costly compared to a branch
in the caller.
Subject:
minor Rhino bug
Date:
Tue, 23 Jan 2001 13:14:51 -0800
From:
dave russo <d-russo@ti.com>
To:
nboyd@atg.com
CC:
d-russo@ti.com
Norris,
While using the new Rhino debugger (from the latest tip) I started to get "No
Context associated with current Thread" exceptions when expanding host objects
in the "Context:" debugger window.
In looking at the code, I discovered that NativeObject.toString seems to assume
that Context.getContext() may return null. In fact, getContext() always returns
a non-null context or throws an exception.
I changed NativeObject.toString to never throw an exception (see below) and this
eliminated the problem I was seeing (of course).
It would be nice to incorporate this in a future Rhino tip or, if this change is
inappropriate, any guidance would be appreciated. Thanks in advance.
I changed NativeObject.toString to:
public String toString() {
try {
Context cx = Context.getContext();
return jsFunction_toString(cx, this, null, null);
}
catch (Exception e) {
return "[object " + getClassName() + "]";
}
}
from:
public String toString() {
Context cx = Context.getContext();
if (cx != null)
return jsFunction_toString(cx, this, null, null);
else
return "[object " + getClassName() + "]";
}
Re: Small usage simplification for Rhino
Date:
Tue, 23 Jan 2001 16:01:42 +0100
From:
Igor Bukanov <igor@icesoft.no>
To:
Norris Boyd <nboyd@atg.com>
References:
1 , 2 , 3 , 4
Norris Boyd wrote:
> Thanks. I've patched in your changes and checked it into CVS.
I also looked at other places with similar pattern of few lines of
common code to construct error messages. The following was occurred too
often not to avoid temptations to move it to a separated function:
NativeGlobal.constructError(
Context.getContext(), "TypeError",
ScriptRuntime.getMessage1("msg.default.value", arg),
this)
It can be replaced by
NativeGlobal.typeError1("msg.default.value", arg, this)
There are other similar usages but they are not to frequent to bother
with code reduction because even the above replacement saves just 200
bytes in uncompressed jars (it is expensive to introduce new methods in
Java).
In any case, if you think it makes any sense, patches are attached. They
are made via
diff -cbB javascript.orig javascript > patch_context
diff -bB javascript.orig javascript > patch_std
from org/mozilla directory.
Regards, Igor
Subject:
Recent rhino broke security support
Date:
Tue, 23 Jan 2001 08:07:45 -0500
From:
"Kurt Westerfeld" <kurt@managedobjects.com>
To:
"Norris Boyd" <nboyd@atg.com>
Norris.....I like the changes made to FunctionObject to do method invocation
much faster. Very slick.
Problem tho: this mechanism does not veer into the security support plugin
on context for defining a class. This is crucial do creating event adapter
code later in applet environments.
I'm going to look into this, but perhaps you could probably make the changes
faster than I.
Unfortunately for us, we found this problem yesterday at a customer site.
:-( Shame on us.
________________________________________________________________________
Kurt Westerfeld
Senior Software Architect
Managed Objects
mailto:kwester@ManagedObjects.com
703.770.7225
http://www.ManagedObjects.com
Managed Objects: manage technology > rule business
Backing out Brendan's previous checkin for bug #65553 (jsapi.c, jsdbgapi.c, jsemit.c, jsinterp.c, jsinterp.h, jsobj.c, and jsscript.c), so we can get smoke tests going.
r=attinasi@netscape.com (sheriff)
[Fwd: My Mistake in ScriptRuntime method]]]
Date:
Tue, 16 Jan 2001 15:48:26 +0100
From:
Igor Bukanov <igor@icesoft.no>
To:
Norris Boyd <nboyd@atg.com>
Hi, Norris!
With my previous patch to fix in
org/mozilla/javascript/ScriptRuntime.java Integer.MIN_VALUE as index
problem I also added a bug to the unrelated code: I tried to minimize
object creation and unfortunately that untested "optimization" slippet
into my patch as well.
I replaced the lines 290, 291 in toNumber(String s) method from
String sub = s.substring(start, end+1);
if (sub.equals("Infinity"))
to
if (s.regionMatches(start, "Infinity", 0, 8))
But that should be
if (start + 7 == end && s.regionMatches(start, "Infinity", 0, 8))
Sory for troubles, Igor
290c290
< if (s.regionMatches(start, "Infinity", 0, 8))
---
> if (start + 7 == end && s.regionMatches(start, "Infinity", 0, 8))
Re: Debugger problem
Date:
Mon, 08 Jan 2001 14:16:30 -0800
From:
Christopher Oliver <coliver@mminternet.com>
Organization:
Primary Interface LLC
To:
Kurt Westerfeld <kurt@ManagedObjects.com>
CC:
Norris Boyd <nboyd@atg.com>
References:
1 , 2 , 3
Kurt, Norris,
Yes, with the change to the shell this should be possible. The problem before
was that if you loaded the same file with different relative path names, two
different windows in the debugger were created because everything (windows,
breakpoints, etc) is keyed off the source name.
The attached file contains the fix (and includes the workaround for
Desktop.getSelectedFrame).
There are still some bugs in transferring focus between the windows in the
Desktop. I haven't had time to track down the problem or a solution.
Chris
Kurt Westerfeld wrote:
> I would point out that "Source Name" of a script isn't necessarily a
> filename. In our system, scripts are run remotely from a script library
> that has no file system backing. Canonicalizing the file names is really
> unnecessary.
>
> Can't you just modify JSDebugger to not care what the name of the file is?
> If access to the original script is unavailable except through the file
> system, I'd be surprised.
>
> ----- Original Message -----
> From: Christopher Oliver <coliver@mminternet.com>
> To: Kurt Westerfeld <kurt@ManagedObjects.com>
> Cc: Norris Boyd <nboyd@atg.com>
> Sent: Sunday, January 07, 2001 2:23 AM
> Subject: Re: Debugger problem
>
> > Hi Kurt,
> >
> > I rather would say that it is a problem with the processFile method in the
> > shell's Main class. If you change the current working directory or the
> value
> > of the System property "user.dir" after compiling a script, relative path
> names
> > can become ambiguous. Norris, would it be ok to modify the shell to
> > "canonicalize" the names of files it compiles? That way the source name
> that
> > shows up in the stack and in DebuggableScript will always be unique. For
> > example:
> >
> > public static void processFile(Context cx, Scriptable scope,
> > String filename)
> > {
> > Reader in = null;
> > try {
> > in = new PushbackReader(new FileReader(filename));
> > int c = in.read();
> > // Support the executable script #! syntax: If
> > // the first line begins with a '#', treat the whole
> > // line as a comment.
> > if (c == '#') {
> > while ((c = in.read()) != -1) {
> > if (c == '\n' || c == '\r')
> > break;
> > }
> > ((PushbackReader) in).unread(c);
> > } else {
> > // No '#' line, just reopen the file and forget it
> > // ever happened. OPT closing and reopening
> > // undoubtedly carries some cost. Is this faster
> > // or slower than leaving the PushbackReader
> > // around?
> > in.close();
> > in = new FileReader(filename);
> > }
> > filename = new java.io.File(filename).getCanonicalPath();
> > <<<====== Add this
> > }
> > catch (FileNotFoundException ex) {
> > Context.reportError(ToolErrorReporter.getMessage(
> > "msg.couldnt.open",
> > filename));
> > exitCode = EXITCODE_FILE_NOT_FOUND;
> > return;
> > } catch (IOException ioe) {
> > globalState.getErr().println(ioe.toString());
> > }
> >
> > // Here we evalute the entire contents of the file as
> > // a script. Text is printed only if the print() function
> > // is called.
> > evaluateReader(cx, scope, in, filename, 1);
> > }
> >
> >
> > Attached is *my* latest version of the debugger code. Norris, have you
> made
> > any progress on cvs commit priveledges? The attached version fixes a
> number of
> > GUI bugs:
> >
> > 1) If you undocked the Variables window and popped up the Context
> combo-box and
> > then closed the window with the system menu, the Context pop-up was not
> cleaned
> > up properly.
> > 2) The first time you minimize a file window it appeared to dissappear
> when you
> > tried to restore it. This was due to the fact that I forgot to "pack" its
> > contents and as a result its requested size was 0x0.
> >
> > I also added a menu item to toggle whether to break on exceptions and one
> which
> > allows you to open (and compile) a JavaScript file without actually
> executing
> > it.
> >
> > I have also attached a Word document with some basic documentation for the
> > Debugger.
> >
> > Note that this version also includes all the changes to support debugging
> > scripts in the AWT dispatch thread.
> >
> > Chris
> >
> > Kurt Westerfeld wrote:
> >
> > > Hello. I ran into a null pointer exception in JSDebugger tonight, and I
> > > thought I'd drop you a note.
> > >
> > > The problem line is 2336, where a breakpoint is hit. To simulate, load
> the
> > > debugger using the command line syntax on a file that has not been
> resolved
> > > to cannonical path.
> > >
> > > Example,
> > >
> > > jshell -debug -f \myfile.fs
> > >
> > > At any rate, the "handleCompilationDone" routine takes \myfile.fs and
> turns
> > > it into a canonical path. If you hit a breakpoint in this file and say
> > > "go", when the breakpoint hits the file is not found, because the same
> > > canonical path resolution is not done. The resolution seems dubious,
> since
> > > it is only done in the compilation done callback, but I don't know the
> best
> > > way to suggest a fix since it seems that code had some purpose.
> > >
> > > Anyway, thought you'd wanna know.
> > >
> > > ________________________________________________________________________
> > > Kurt Westerfeld
> > > Senior Software Architect
> > > Managed Objects
> > > mailto:kwester@ManagedObjects.com
> > > 703.770.7225
> > > http://www.ManagedObjects.com
> > >
> > > Managed Objects: manage technology > rule business
> >
JSDebugger.java
Name:
JSDebugger.java
Type:
Java Class File (java/*)
Encoding:
base64
* Make use of DebuggableEngine interface to keep Context API smaller
* Change org.mozilla.javascript.debug.Frame to DebugFrame to avoid
confusion with java.awt.Frame
Subject:
Re: Rhino bug - Wrapper ??
Date:
Fri, 05 Jan 2001 03:46:11 +0530
From:
Mukund Balasubramanian <mukund@cs.stanford.edu>
Organization:
Another Netscape Collabra Server User
Newsgroups:
netscape.public.mozilla.jseng
References:
1 , 2 , 3 , 4 , 5 , 6
That works too,
Should I assume that this would be a part of the next tip ? I agree with the
part about
overloading code too.
Anyways, thanks a load for your help and just tell me if I could be of any
help in any other
respects of the rhino project.
ThanX,
Mukund Balasubaramanian
Norris Boyd wrote:
> Actually, I was considering removing the unwrapping code from
NativeJavaConstructor. I was
> suprised that it was there. The code dates from before we implemented proper
method and
> constructor overloading in Rhino. It's the overloading code that should have
the responsibility
> for unwrapping.
>
> Does this patch work for you:
>
> Index: NativeJavaObject.java
> ===================================================================
> RCS file:
/cvsroot/mozilla/js/rhino/org/mozilla/javascript/NativeJavaObject.java
> ,v
> retrieving revision 1.29
> diff -u -r1.29 NativeJavaObject.java
> --- NativeJavaObject.java 2000/11/13 22:10:32 1.29
> +++ NativeJavaObject.java 2001/01/04 21:33:55
> @@ -673,6 +673,12 @@
>
> return Result;
> }
> + else if (value instanceof Wrapper) {
> + value = ((Wrapper)value).unwrap();
> + if (type.isInstance(value))
> + return value;
> + reportConversionError(value, type);
> + }
> else {
> reportConversionError(value, type);
> }
>
> This handles the case where the object is both a Scriptable and a Wrapper.
>
> --N
>
> Mukund Balasubramanian wrote:
>
> > Yes they do implement Scriptable.
> > From my preliminary inspection of the code, findFunction seems to be
preceediong the
> > coerceType call and I presume findFunction call is going to fail if the
arguments are
> > wrapped (bad types mismatching signature).
> > The constructor case DOES go through an explicit unwrapping stage as
shown by the cut
> > and paste code. My question is whether the same preamble in NativeJavaMethod
is a valid bug
> > fix.
> >
> > ThanX,
> >
> > Mukund Balasubramanian
> >
> > Norris Boyd wrote:
> >
> > > Do your objects that implement Wrapper also implement Scriptable? From
simple inspection
> > > of the code I'd think that both the constructor and method cases would go
through
> > > NativeJavaMethod.coerceType, which should unwrap. However, Scriptable
objects are picked
> > > off and handled before any unwrapping is considered.
> > >
> > > --N
> > >
> > > Mukund Balasubramanian wrote:
> > >
> > > > Yup,
> > > > Here it is - Line numbers 173-178 are cut and paste from
> > > > NativeJavaConstructor.java inside NativeJavaMethod.java
> > > >
> > > > /*** Call in NativeJavaMethod.java
> > > > public Object call(Context cx, Scriptable scope, Scriptable thisObj,
> > > > Object[] args)
> > > > throws JavaScriptException
> > > > {
> > > > // Eliminate useless args[0] and unwrap if required
> > > > for (int i = 0; i < args.length; i++) {
> > > > if (args[i] instanceof Wrapper) {
> > > > args[i] = ((Wrapper)args[i]).unwrap();
> > > > }
> > > > }
> > > >
> > > > // Find a method that matches the types given.
> > > > if (methods.length == 0) {
> > > > ****/
> > > >
> > > > Is this correct ? I presume it is because of the fact that the
constructor
> > > > does this.
> > > >
> > > > Any luck with my other question regarding generalizing the WrapHandler
to all
> > > > objects (including those returned by scriptable) and not only those
returned
> > > > through nativeJava***
> > > >
> > > > ThanX,
> > > >
> > > > Mukund Balasubramanian
> > > >
> > > > Norris Boyd wrote:
> > > >
> > > > > Could you post your proposed patch?
> > > > >
> > > > > Thanks,
> > > > > Norris
> > > > >
> > > > > Mukund Balasubramanian wrote:
> > > > >
> > > > > > Hi all,
> > > > > > I am trying to play around with writing a custom WrapHandler for
my
> > > > > > Java objects in Rhino. I found WrapHandler very useful.
> > > > > > Now I am stuck at a point where, even though my wrappers
implement
> > > > > > "Wrapper", they get unwrapped only on calles to Constructors using
> > > > > > Liveconnect. Normal methods dont seem to be doing any unwrapping.
> > > > > > Managed to build rhino with a bug fix (cut and paste code from
> > > > > > NativeJavaConstructor to NativeJavamethod), and it works.
> > > > > > Just wanted to verify if it is a known bug (while I wait for
> > > > > > bugzilla to mail me a passwd).
> > > > > >
> > > > > > BTW, also found something interesting, WrapHandler gets called only
when
> > > > > > the object is returned from NativeJava***, not ANY Object. Is that
the
> > > > > > way it is supposed to work ??
> > > > > >
> > > > > > ThanX for any help,
> > > > > >
> > > > > > Mukund Balasubramanian
Subject:
[Rhino] Script compiler bug?
Date:
Tue, 12 Dec 2000 22:08:23 GMT
From:
dave russo <d-russo@ti.com>
Organization:
Deja.com
Newsgroups:
netscape.public.mozilla.jseng
The following script does not seem to compile properly (using Rhino
1.5R1):
test.js:
var test = {};
test.foo = function () { print('foo')}
test.bar = function () { print('bar')}
After compiling test.js ("java org.mozilla.javascript.tools.jsc.Main
test.js"):
js> loadClass('test')
js> test.foo()
bar
js> load('test.js')
js> test.foo()
foo
Note that changing test.js to read:
var test = {};
test.foo = function foo() { print('foo')}
test.bar = function bar() { print('bar')}
Works around the problem. Is there a problem with anonymous functions?
Sent via Deja.com
http://www.deja.com/
Along the way, Patrick also fixed a bug that's been with the JS engine on the mac for more than three years; used to be that Mac dates throughout the year were displayed according to the machine's *current* daylight savings time setting; now they display properly and all is well with the world.
Dependent on recent checkin fixing 61577, adding needed time library to the mac build.X
r=mccabe
especially to jband for his great stress-test setup and particularly helpful
(in terms of reproducing bugs in draft patches) MP and laptop machines.
- Radical(*) object (scope) locking optimization: don't lock if a scope is
accessed on the context that exclusively owns it (initially, the context
on which the scope was created). Once a scope becomes shared among more
than one owner-context, give it the usual thin or fat lock, per existing
jslock.c code.
I did this at the memory cost of another word per JSScope, ownercx, which
raised scope size from 12 to 13 words if !DEBUG. I also added a linked
list head pointer, rt->scopeSharingTodo, and a scopeSharingDone condition
variable to JSRuntime, and a scopeToShare pointer to JSContext that's
necessary for deadlock avoidance.
The rt->scopeSharingTodo list links JSScopes through the scope->u.link
union arm, which overlays the pre-existing scope->count (now u.count)
member. This list holds scopes still exclusively owned by a context, but
wanted by js_LockScope calls active on other threads. Those calls wait
on the rt->scopeSharingDone condition, which is notified every time an
owner-context ends the request running on it, in which code active on
that context may be using scope freely until end of request.
The code that waits on rt->scopeSharingDone must first suspend any and
all requests active on the calling context, and resume those contexts
after the wait is notified. This means a GC could happen while the
thread locking a scope owned by another thread's context blocks; all
calls to JS_LOCK_OBJ must therefore first home fp->sp above any live
operands, e.g. The interpreter takes care to do that already.
To avoid AB-BA deadlocks, if a js_LockScope attempt on one context finds
that the owner-context of the scope is already waiting on a scope owned
by the current context (or indirectly depending on such a scope lock),
the attempt converts the scope from lock-free exclusive ownership to
shared ownership (thin or fat lock).
- Fix js_SetupLocks and the js_LockGlobal/js_UnlockGlobal code to avoid
divmod instruction costs, strength-reducing to bit-mask instructions.
- The radical lock-free scope change required care in handling the 0=>1
and 1=>0 transitions of cx->requestDepth, which was till now thread-local
because part of the JSContext not manipulated by other threads. It's
still updated only by cx's thread, but it is read by other threads in
the course of attempting to claim exclusive ownership of a scope for more
lock-free JS object operations.
- The JS_SuspendRequest and JS_ResumeRequest APIs have changed incompatibly
to require their caller to save and restore the requestCount found when
JS_SuspendRequest is called. This is necessary to avoid deadlock; sorry
for the incompatible change.
- Fixed various nits in jslock.[ch], including using Init/Finish rather
than New/Destroy for the methods that take a JSThinLock and initialize
and finish/free its members. Another example: JS_ATOMIC_ADDREF is now
JS_ATOMIC_INCREMENT and JS_ATOMIC_DECREMENT, so the two cases can be
mapped to PR_AtomicIncrement and PR_AtomicDecrement. This entailed
changing jsrefcount from jsword to int32 (PRInt32).
- No need to use JS_ATOMIC_INCREMENT on JSScopeProperty.nrefs, as it is
always and everywhere protected by the property's JSScope.lock.
- Cleaned up gratuitous casts in jscntxt.c by using &cx->links, etc.
- The lock used for mutual exclusion around both request begin and end vs.
GC synchronization is rt->gcLock, and this lock now also protects all
scope->ownercx pointer changes from non-null (exclusive) to null (shared),
the rt->scopeSharingTodo/scope->u.link list operations, and of course the
rt->scopeSharingDone condition.
But this means that js_GC cannot hold rt->gcLock across the bulk of its
body, in particular the mark phase, during which JS_GetPrivate calls,
e.g., may need to "promote" scope locks from lock-free to thin or fat,
because doing so would double-trip. There never was any good reason to
hold rt->gcLock so long, of course -- locks are for mutual exclusion, not
for waiting or notifying a thread -- those operations require a condition,
rt->gcDone, which we already use along with rt->gcLevel to keep racing GC
attempts at bay.
So now that rt->gcLock does not protect the mark phase, the enumeration
of rt->gcRootsHash can race badly with JS_RemoveRootRT, an API that may
legitimately be called outside of a request, without even a context. It
turns out that people may be cheating on the request model even with
JS_AddRoot, JS_AddNamedRoot, and JS_RemoveRoot calls, so we must make
all of those interlock with the GC using gcLevel and gcDone, unless they
are called on the gcThread.
Also, since bug 49816 was fixed, there has been no need for a separate
finalize phase, or for rt->gcFinalVec. Finalizers can no longer allocate
newborn GC-things that might be swept (because unmarked), or double-trip
on rt->gcLock (which is no longer held). So js_GC finalizes as it sweeps,
just as it did in days of old.
- I added comments to jslock.h making it plain that callers of JS_LOCK_OBJ
and JS_UNLOCK_OBJ must either be implementations of js_ObjectOps hooks,
or code reachable only from those hooks; or else must be predicated on
OBJ_IS_NATIVE tests. It turns out jsinterp.c's CACHED_GET and CACHED_SET
macros neglected to do such tests, limiting the ability of JS embeddings
to implement JSObjectOps with their own non-JSScope JSObjectMap subclass.
Fixed, small performance hit that the lock-free optimization should more
than make up for.
- jslock.c now gives a #error if you try to compile it on a platform that
lacks a compare-and-swap instruction. The #error says to use NSPR locks.
Before this change, some platforms would emulate compare-and-swap using
a global PRLock, which is always worse in runtime than using per-scope
PRLocks.