Note: This is a discussion from June 2005. For documentation of inner/outer windows, see https://developer.mozilla.org/En/SpiderMonkey/Split_object
We need to split the window object into two objects. See bug 296639 for rationale and such, as well as for the JSExtendedClass note there.
Some fuzzy thoughts on how to do this:
We want to ensure that any time someone actually _asks_ for the window object they get the outer object (since we can't really tell whether they're asking from "inside" the window or not). That is, the mFlatJSObject on the XPCWrappedNative for the window should be the outer object. The inner object should only be relevant in the following cases, I think:
- Global object (or at least outermost scope object) for scripts that execute in the page.
- End of scope chain for all event handlers and such in the page.
- window property on the outermost scope
JS arch questions: Is it possible for script compilation to define properties (eg function compilation needs to) on some object other than the global object for the JSContext? If no, then it seems we have two choices: either have one JSContext per inner window object (and a separate JSContext for the outer? Or what?) or rely on forwarding of sets from the outer object to the inner (in which case we need to switch the inner before compiling any scripts in a newly loading document, which may be ok; we already call SetNewDocument before that point currently).
I'm sort of assuming we want to change as little of the current object graph as possible (say we don't want to add another C++ class sitting between nsDocument and nsGlobalWindow).
GC thoughts: the outer and inner should mark each other as long as the inner is the current inner for the outer. Once that stops being the case, the inner can't be reached from the outer (so no reason to mark in that direction). I think we need to keep marking from inner to outer because making a native method call on the inner needs to end up going to the XPCWrappedNative, hence we need to keep it alive. I guess this is one problem with the XPCWrappedNative's mFlatJSObject being the outer object...
--Bzbarsky 21:16, 4 Jun 2005 (PDT)
Answers to JS arch questions:
1. Yes. The global object of a context is just a convenient association, used by the DOM code in Mozilla classic and modern implementations. What ECMA-262 calls the "variable object" is the last object on the scope chain, which is found from the current frame (activation object). That outermost scope object has no necessary relation to JS_GetGlobalObject(cx).
2. On marking outer and inner: we have to avoid bad paths that lead from an old (back in history) inner to the outer to a different (current) inner. It would be good to find ways to check this with assertions or other kinds of proof aids. Same goes for any bad paths that use JS_GetGlobalObject(cx).
To pull this off it seems like we'd need to do the following (the above in more detail...):
- Create a new JS scope object, i.e. the inner global object. This won't be a native object wrapped by XPConnect, but simply a JSClass (JSExtendedClass) whose private data points to an object that knows the principals and the native global (outer, e.g. nsGlobalWindow). Though this object needs to somehow get all the standard JS classes and the methods etc exposed on the global object by XPConnect.
- Write a JSExtendedClass::equality hook implementation on it (which is fun, since JSExtendedClass doesn't exist on the aviary or 1.7 branches), and make the equality hook on the wrapped native for the outer global do the same (probably mean we need an nsIXPCScriptable::Equality() method).
- Move most of the current nsWindowSH logic to the JSExtendedClass for the inner window.
- Write a new nsWindowSH that does the appropriate security checks and the forwarding of gets/sets to the inner.
- Make all nameable references to the inner window "exterize" the reference, that means a get of the below properties needs to return the outer window. Anyone think of any more of these?
- content (and _content)
- opener (?)
--Jst 17:21, 24 Jun 2005 (PDT)
jst: I was thinking we would make the inner object reuse all of the current window implementation, at first. After getting things working, we could turn security checks into assertions of same origin, etc. The outer window object would be of a new extended class (the inner would want to use the JSExtendedClass support now in XPConnect on the trunk, so we would want more scriptable helpers or something, so it could participate in == and != ops, e.g.).
To handle |this|, we would want to hook JSObjectOps.thisObject up somehow. XPConnect implements JSObjectOps for wrapped natives, so the simplest thing to do is add another scriptable helper that forwards thisObject calls from the JS engine to the nsWindowSH impl.
The other properties can be handled using existing or new getter hooks that "outer-ize" any inner window object reference.