Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Performance of evalInSandbox

78 views
Skip to first unread message

johnjbarton

unread,
Feb 15, 2011, 5:32:06 PM2/15/11
to
Firebug 1.8 is moving from script tags in browser.xul to require.js
modules loaded dynamically. Our current implementation uses
evalInSandbox with a separate scope for each module (file). This
provides the maximum support for scope isolation.

However we hear of three different potential performance problems:
1) no caching of compiled JS,
2) overhead from creating and preparing each sandbox with its own JS
stuff,
3) run-time overhead from calls between functions defined in
different sandboxes.

The first two are easily solved by moving the loading off the startup
event. The third one concerns me since I don't know how to measure it
in a meaningful way. I suppose we could load all of our modules in to
one sandbox to workaround this, but I don't want to do that unless we
are really solving a problem. Any other information or ideas?

jjb

Andreas Gal

unread,
Feb 15, 2011, 7:09:38 PM2/15/11
to johnjbarton, dev-pl...@lists.mozilla.org

Every sandbox runs in its own compartment, which has some substantial memory overhead. Keep that in mind as well. If you can recycle sandboxes (multiple evals against the same sandbox), I would do that.

Andreas

> _______________________________________________
> dev-platform mailing list
> dev-pl...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-platform

John J Barton

unread,
Feb 15, 2011, 11:14:23 PM2/15/11
to
Andreas Gal wrote:
> Every sandbox runs in its own compartment, which has some substantial memory overhead. Keep that in mind as well. If you can recycle sandboxes (multiple evals against the same sandbox), I would do that.

Any idea on how much memory? Is it fixed or variable size?

It would be helpful if I had some model for what a compartment is.

Or is there any way to erase the global state in a sandbox? Here is what
I am imagining:
create sandbox object,
add some special properties, <------------------------+
run some code, which creates some more properties |
clean ---------------------------------------------- +
Could it be as simple as iterating the sandbox and deleting properties?

jjb

Nicholas Nethercote

unread,
Feb 16, 2011, 12:38:00 AM2/16/11
to John J Barton, dev-pl...@lists.mozilla.org
On Tue, Feb 15, 2011 at 3:14 PM, John J Barton
<johnj...@johnjbarton.com> wrote:
>>
>> Every sandbox runs in its own compartment, which has some substantial
>> memory overhead.
>
> Any idea on how much memory? Is it fixed or variable size?

sizeof(JSCompartments) is 4660 bytes on 32-bit and 8496 bytes on
64-bit, so that's the baseline cost. I don't know about the
variable-sized overheads.

> It would be helpful if I had some model for what a compartment is.

http://andreasgal.wordpress.com/2010/10/13/compartments/ is a nice
write-up on compartments.

Nick

Steven Roussey

unread,
Feb 16, 2011, 2:25:24 AM2/16/11
to
Passing in a new scope to Components.utils.import(file,scope) is not good enough for scope isolation?

johnjbarton

unread,
Feb 16, 2011, 5:47:39 AM2/16/11
to
On 2/15/2011 6:25 PM, Steven Roussey wrote:
> Passing in a new scope to Components.utils.import(file,scope) is not good enough for scope isolation?

The top properties we need is ability to control loading and to
understand the result of loading so we can debug code. Next comes code
isolation so we can use the same technology for content. Then comes
runtime performance. At the bottom is internal scope isolation and
startup performance.

Cu.import has the opposite characteristics for the most part. It has
great startup and runtime performance, but we can't use it for content
and the scope of imported code is funky (maybe the second arg helps I
don't know). But the caching means we can't reload so it's out unless we
could be 100% dead sure there was a way to avoid it.

I'm beginning to think we should have stuck with <script> tags. Our
total investment in this minor module thing is threatening our project.

jjb

Natch

unread,
Feb 17, 2011, 6:29:22 PM2/17/11
to

Cu.import is not exactly as you described. a) the second argument
provided can be used as the global, something like this:

var glob = {};
Cu.import("path-to-script", glob);

All the properties in the script that are exported are then accessible
on glob. Otherwise (e.g. without the second argument) it is imported
into the global object of the running context and is accessible
globally (like any global object).

b) Cu.import caching doesn't work like you seem to think. It caches
the script so that all scripts get it and it only has to compile it
once. Past that, properties changed on the cached script will be
visible to all imports of that script (see the docs for exactly how
this works in general).

I'm not sure why you need to reload scripts so I obviously can't
comment on that. But, if you could use Cu.import just for the chrome
scripts and evalInSandbox for the content scripts I'm sure it would
help some...

johnjbarton

unread,
Feb 18, 2011, 5:50:12 AM2/18/11
to

But what does the outer most scope look like in the debugger? glob? Hey
it could be simple, but do you know?

>
> b) Cu.import caching doesn't work like you seem to think. It caches
> the script so that all scripts get it and it only has to compile it
> once. Past that, properties changed on the cached script will be
> visible to all imports of that script (see the docs for exactly how
> this works in general).

Actually we replaced all our uses of XPCOM components with Cu.imports
last year some time, so I'm familiar with it. (The docs don't include
the entire story, see https://bugzilla.mozilla.org/show_bug.cgi?id=531886)

>
> I'm not sure why you need to reload scripts so I obviously can't
> comment on that.

So edits on source can be loaded without restarting the browser.

> But, if you could use Cu.import just for the chrome
> scripts and evalInSandbox for the content scripts I'm sure it would
> help some...

Yes, thanks, I appreciate all the information we can get about this
stuff. So I want to explain why I'm listening but not taking action ;-)

Optimization, by it nature, needs to focus on the most critical
resource. In our case it's developer time. So if something works, the
alternative needs to be really compelling. There are more issue with
evalInSandbox than I knew about, so the case is stronger. If someone
else wants to work through the issues and show Cu.import is better in
Firebug, great, I'm all for it. But if we can't get Firebug up on
multiprocess, being a bit faster on startup or a smaller memory won't
matter.

jjb

Neil

unread,
Feb 18, 2011, 9:35:31 AM2/18/11
to
johnjbarton wrote:

> Cu.import has the opposite characteristics for the most part. It has
> great startup and runtime performance, but we can't use it for content
> and the scope of imported code is funky

Not sure what you mean there. Cu.import simply copies the exported
symbols from the scope in which the module was compiled into the scope
passed as the second parameter (or the scope in which Components was
defined if no scope was provided). It's like a website with a frame in
it and script in the frame has var foo = parent.foo; foo(); to call a
function defined in the parent frame.

--
Warning: May contain traces of nuts.

johnjbarton

unread,
Feb 18, 2011, 4:13:33 PM2/18/11
to

What I find 'funky' is the result of:
var scope = frame.scope;
while(scope.jsParent)
scope = scope.jsParent;
for the stack frame of Cu.import compiles. For script tags, evals, and
such in an nsIDOMWindow, the |scope| will be the nsIDOMWindow. In the
Cu.imports case it looks like some kind of dumping ground. (If you run
Chromebug, it's the content of the DOM panel for the BackstagePass
context. To be sure I'm a little unclear whether this |scope| is related
to the Cu.import or perhaps it's from an xpcom component that issues
Cu.import?

If I set a breakpoint in a function compiled in browser.xul and single
step into a Cu.import which does not use the second argument, the outer
most scope (BackstagePass Scope) looks like the file-scope for the
imported file. This makes sense to me. I don't understand how to get
this object at the compile point.

jjb

Steven Roussey

unread,
Feb 18, 2011, 7:20:44 PM2/18/11
to
>> I'm not sure why you need to reload scripts so I obviously can't
>> comment on that.
>
> So edits on source can be loaded without restarting the browser.

There is a bugzilla entry for that (though not the one you posted). So yeah, Cu.import wouldn't be ideal while developing. Now I understand. Still, end users are not editing firebug code, so I don't think we need them to go through slowness. But the two different environments does mean testing two times. Maybe the fix will be in by the time we ship 1.8, and the point will be moot. In the mean time we use evalInSandbox. It will be nice to change the firebug code and not have to restart Firefox!


> for the stack frame of Cu.import compiles. For script tags, evals, and
> such in an nsIDOMWindow, the |scope| will be the nsIDOMWindow.

Wouldn't this be the same:
Cu.import(sciptfile, |window|);
?

Or better (but untested):
var scope = {window: |window|};
Cu.import(scriptfile, scope);

So now I think we ought to keep the evalInSandbox until Cu.import is improved to do what we want it to do. Do we have bugzilla entries for what we want out of Cu.import? Do we want something like import(file, scope, topwindow, reload?)? Something else?

-steve--

Neil

unread,
Feb 21, 2011, 9:42:23 AM2/21/11
to
johnjbarton wrote:

> What I find 'funky' is the result of:
> var scope = frame.scope;
> while(scope.jsParent)
> scope = scope.jsParent;
> for the stack frame of Cu.import compiles. For script tags, evals, and
> such in an nsIDOMWindow, the |scope| will be the nsIDOMWindow. In the
> Cu.imports case it looks like some kind of dumping ground. (If you run
> Chromebug, it's the content of the DOM panel for the BackstagePass
> context. To be sure I'm a little unclear whether this |scope| is
> related to the Cu.import or perhaps it's from an xpcom component that
> issues Cu.import?

Just as each JS-based XPCOM component has its own BackstagePass global
scope, so does each JS module. The only difference lies in the way that
the code is accessed from other script; in the case of a module, you
import the exported symbols; in the case of a component, you get a
service/create an instance of it.

johnjbarton

unread,
Feb 21, 2011, 3:49:28 PM2/21/11
to
Good, that is what I thought. (The content of that scope is still a
mystery).

So in the end there are two differences between Cu.import and XPCOM
components on the one side and Cu.sandbox/evalInSandbox on the other:
1) A new set of JavaScript globals is created for each sandbox,
2) Unless you turn off wrappers, evalInSandbox wraps everything.
(The first one isn't in the docs as I recall, the second one is in the
docs "backwards", the description makes me think the result is opposite
of what it actually is.

jjb

0 new messages