32
edits
m (Reverted edit of Minglang, changed back to last version by MarkH) |
No edit summary |
||
Line 30: | Line 30: | ||
nsIScriptContext will grow new methods relating to: | nsIScriptContext will grow new methods relating to: | ||
* language specific cleanup and "default language context" type code. For example, nsGlobalWindow.cpp has a number of calls to ::JS_ClearScope/::JS_ClearWatchPointsForObject etc - these need to be hidden behind one of the interfaces. | * language specific cleanup and "default language context" type code. For example, nsGlobalWindow.cpp has a number of calls to ::JS_ClearScope/::JS_ClearWatchPointsForObject etc - these need to be hidden behind one of the interfaces. | ||
* The "WrapNative" process | * The "WrapNative" process (or possibly this can be hidden behind JS 'SetProperty' functions?) | ||
The existing nsIScriptGlobalObject interface will move towards a model where there is a global | The existing nsIScriptGlobalObject interface will move towards a model where there is a global nsIScriptContext per language. GetGlobalJSObject and GetContext would be deprecated, with a new method allowing the desired language to be specified. Thus, nsIScriptGlobalObject may have many nsIScriptContexts associated with it (one per supported and initialized language) | ||
A new 'context stack' will be invented: | |||
* nsIScriptContexts to be used directly on the stack, rather than JSContext (hmm - is this necessary? I guess a "void *" would still work so long as it was associated with the language) | |||
* Contexts for *all* languages are pushed and poped as a single operation - a new context applies to all languages in the environment, not just a single one. This is so when calls cross multiple language boundaries, they always have a correct context, not just the last one that happened to be pushed for their language. | |||
nsDOMClassInfo will be split into a language neutral nsDOMClassInfo, and a JS specific nsIXPCScriptable. The JS specific code in this file will need to be re-written for Python, but this should allow all DOM knowledge to be reused by the Python implementation. | nsDOMClassInfo will need a fair bit of work, and significant help from Mozilla resources. It may be able to be split into a language neutral nsDOMClassInfo, and a JS specific nsIXPCScriptable. The JS specific code in this file will need to be re-written for Python, but this should allow all DOM knowledge to be reused by the Python implementation. | ||
Need to agree on a single "script language ID". nsIProgrammingLanguage defines a set of integers, while nsIScriptElement uses a generic "char *". | Need to agree on a single "script language ID". nsIProgrammingLanguage defines a set of integers, while nsIScriptElement uses a generic "char *". This document assumes an integer. | ||
Below are specific implementation notes: | |||
=== new interface nsIScriptLanguage === | |||
* This is really only a factory for nsIScriptContext objects. The nsIScriptContext itself becomes the factory for the language specific, void * "global object". | |||
=== nsIScriptContext === | === nsIScriptContext === | ||
Line 48: | Line 52: | ||
* Existing JSObject replaced with void | * Existing JSObject replaced with void | ||
* Existing "void *aScopeObject" (ExecuteScript/EvaluateStringWithValue/CompileScript), replaced with nsIScriptGlobalObject. The language impl can then get | * Existing "void *aScopeObject" (ExecuteScript/EvaluateStringWithValue/CompileScript), replaced with nsIScriptGlobalObject. The language impl can then get its "void *" via either sgo->GetLanguageContext() or provide a default via its own private means. | ||
This may require a helper function to return a (temporary?) nsIScriptGlobalObject for a given JSObject - eg, plugin code, nsXBLProtoImplField::InstallMember. | |||
[actually, the above may be gratuitious and cause unnecessary problems] | |||
* Need a "WrapNative" type function | * Need a "WrapNative" type function (or maybe not - this may end up being able to be hidden behind Get/SetProperty functions? | ||
* FinalizeClasses method - JS does the ClearScope/ClearWatchpointsForObject/ClearRegExpStatistics? | * FinalizeClasses method - JS does the ClearScope/ClearWatchpointsForObject/ClearRegExpStatistics? | ||
* Some kind of "SetProperty" function - as needed by nsGlobalWindow - "arguments", "navigator" etc. http://lxr.mozilla.org/seamonkey/source/dom/src/base/nsGlobalWindow.cpp#871 | * Some kind of "SetProperty" function - as needed by nsGlobalWindow - "arguments", "navigator" etc. http://lxr.mozilla.org/seamonkey/source/dom/src/base/nsGlobalWindow.cpp#871 | ||
* SetTerminationFunction needs thinking through - this does *not* seem to be a per-language thing. Maybe could be on the nsIDOMContextStackItem proposed below? Only few callers though. | |||
=== nsIScriptGlobalObject / nsGlobalWindow === | === nsIScriptGlobalObject / nsGlobalWindow === | ||
Line 60: | Line 68: | ||
http://lxr.mozilla.org/seamonkey/source/dom/public/nsIScriptGlobalObject.h | http://lxr.mozilla.org/seamonkey/source/dom/public/nsIScriptGlobalObject.h | ||
nsGlobalWindow is the main implemention of nsIScriptGlobalObject | nsGlobalWindow is the main implemention of nsIScriptGlobalObject, but XUL has one too. | ||
* | * Still need to understand callers of GetNativeContext - they will not be language neutral | ||
* nsIScriptGlobalObject probably needs to remain a single object (ie, not per language). It will move towards keeping a list of "IScriptContext *ctx, void *global" items, one for each language. New method: | * nsIScriptGlobalObject probably needs to remain a single object (ie, not per language). It will move towards keeping a list of "IScriptContext *ctx, void *global" items, one for each language. New method: | ||
nsresult GetLanguageContext( [in] language_id language, [out] nsIScriptContext **retLangContext, [out]void **retLangGlobal); | nsresult GetLanguageContext( [in] language_id language, [out] nsIScriptContext **retLangContext, [out]void **retLangGlobal); | ||
The concept of a single context/global will be deprecated - callers will be encouraged to use the new method. | |||
GetContext()/GetGlobalJSObject() remain for b/w compat. They are equivalent to "GetLanguageContext('js', ...)" | GetContext()/GetGlobalJSObject() remain for b/w compat. They are equivalent to "GetLanguageContext('js', ...)" | ||
* New | * New method to ensure the nsIScriptGlobal is initialized for a specific language. This may be called at any time - whenever someone needs to run a script in a language. | ||
* New method to set and get "properties" - nsGlobalWindow does this for JS. Setting a property should presumably set it in all languages (via the global attached to the context). Getting is tricker - what if the property is in a different language? Or in multiple languages? | * New method to set and get "properties" - nsGlobalWindow does this for JS. Setting a property should presumably set it in all languages (via the global attached to the context). Getting is tricker - what if the property is in a different language? Or in multiple languages? | ||
Line 75: | Line 83: | ||
** Properties fetched seem arbitrary. | ** Properties fetched seem arbitrary. | ||
* | * SetNewArguments will need to be specified as an nsISupports. This trickles down into a number of things, including the concept of "extra args" nsGlobalWindow has. May need to supply *2* nsISupports. | ||
* New method to push all current contexts onto the context stack. | |||
* Serializing scripts? | * Serializing scripts? | ||
Line 84: | Line 94: | ||
// is mis-typed as const char * | // is mis-typed as const char * | ||
sets mJSObject | sets mJSObject | ||
=== nsDOMClassInfo === | |||
Note: Work on nsDOMClassInfo could be done by a Mozilla resource in parallel with this other work. We will not need to use this enhanced class info until we already have Python code being executed and that code trying to work with a "dumb" DOM object. | |||
One radical alternative: Invent a new "nsIDynamicClassInfo" or similar interface that allows the additional class info to be expressed. Modify the JS XPConnect code to also use that new interface is supported regardless of implementor. Python's xpcom code would do likewise. nsIDOMClassInfo is responsible only for implementing this new interface. It is possible this could also subsume your existing IDispatch support. | |||
Notes assuming a less radical evolution of the existing code: | |||
Lots of DOM namespace magic happens here, but it is very JS specific. We will try to split the implementation: | |||
* Create ns(I)DOMClassInfo. It contains all the existing code that works with nsDOMClassInfoData - that includes most of the "tables" defined using macros. | |||
* nsDOMXPC will have all the JS specific code, which is currently implementing nsIXPCScriptable. This is the bulk of the existing nsDOMClassInfo implementation. | |||
This language neutral interface will allow language "helpers" to be explicitly installed, and will then be able to be fetched by the existing nsIClassInfo::GetLanguageHelper() function. Thus, anyone with an nsIDOMClassInfo will still be able to get the JS helper. | |||
The Python language implementation will then need to write an equivalent to the new nsDOMXPC. This will be the magic where attributes are got/set for objects, etc. This Python implementation will need to lean heavily on nsDOMClassInfo. | |||
Decide what to do with the various flags - eg, ALLOW_PROP_MODS_TO_PROTOTYPE. Presumably these will have some meaning to languages other than JS, but they are defined in a JS specific interface (nsIXPCScriptable) | |||
The following "public" functions are problematic: | |||
* nsWindowSH::InvalidateGlobalScopePolluter referenced by nsGlobalWindow. | |||
* GC | |||
* oops - lost the other one! | |||
=== Context Stack === | === Context Stack === | ||
Existing nsIJSContextStack "@mozilla.org/js/xpc/ContextStack;1" service is replaced with language generic ContextStack. This is almost identical to the JS version, but all | Existing nsIJSContextStack "@mozilla.org/js/xpc/ContextStack;1" service is replaced with language generic ContextStack. This is almost identical to the JS version, but all operations work for the entire set of languages in use, not just the language about to be executed. | ||
Probably need a new interface for each language to do their thing. The DOM will simply ask for a new context, and the nsIScriptGlobal will push the context for each language it is initialized with. | |||
Thus, we will have one ContextStack, with each holding an array of nsIScriptContexts - one for each language. You can not push a context for only a single language on the stack. | |||
If a language is initialized even after items are already on the context stack, only new items pushed will include a context item for that language. Once the stack pops back past where a language has no entries, the language will not be able to run (but this should be impossible - there can be no stack entries for that language higher in the context stack, and attempting to start a new script in that language will simply re-push a context entry which will again include the language) | |||
As mentioned above re nsIScriptContext, we may need to handle SetTerminationFunction functionality on this stack. | |||
Tricky: We need to interoperate with code that is not multi-language aware, and may not be for some time. Eg: | |||
http://lxr.mozilla.org/seamonkey/source/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp#216 | |||
http://lxr.mozilla.org/seamonkey/source/extensions/webservices/security/src/nsWebScriptsAccess.cpp#767 - pushes a NULL context? | |||
This probably will mean that the existing JS Context Stack will be a wrapper around the new cross-language one. | |||
Generic "GetCallerDocShell" or similar will avoid some JS specifics - eg, http://lxr.mozilla.org/seamonkey/source/docshell/base/nsDocShell.cpp#5898 | |||
What about http://lxr.mozilla.org/seamonkey/source/dom/public/nsIScriptContext.h#356 - it | What about http://lxr.mozilla.org/seamonkey/source/dom/public/nsIScriptContext.h#356 - it | ||
checks flags. Will there be flags for a single stack entry, or flags for each language in a single stack entry, or both? | checks flags. Will there be flags for a single stack entry, or flags for each language in a single stack entry, or both? | ||
==== New interface - nsIDOMContextStackItem ==== | |||
An item on the context stack - stores one nsIScriptContext for every language initialized for this item. | |||
nsIDOMContextStackItem : nsISupports | |||
{ | |||
nsIScriptContext getLanguageContext(in PRInt32 langId); | |||
void setLanguageContext(in PRInt32 langId, in nsIScriptContext cx); | |||
}; | |||
==== New interface - nsIDOMContextStack ==== | |||
interface nsIDOMContextStack : nsISupports | |||
{ | |||
readonly attribute PRInt32 count; | |||
nsIDOMContextStackItem peek(); | |||
nsIDOMContextStackItem pop(); | |||
void push(in nsIDOMContextStackItem cx); | |||
/* what is a "safe context" anyway??? */ | |||
nsIScriptContext getLanguageSafeContext(in PRInt32 langId); | |||
/* A helper for code that wants the most recent nsIDocShell on | |||
the context stack - any/all languages on the stack can provide it */ | |||
nsIDocShell GetCallerDocShell() | |||
}; | |||
==== Notes on callers of existing JS Context Stack ==== | |||
nsJSConfigTriggers.cpp: pushed and pops its own private JSContext. Not nsIScript* aware at all. | |||
nsWebScriptsAccess.cpp: pushes and pops an explicitly null context | |||
nsXMLHttpRequest.cpp: appears to just push the context from its nsIScriptContext *mScriptContext, and fetch an nsIScriptContext from the context stack - can use the language independent function. In NotifyEventListeners/ChangeState/OnChannelRedirect | |||
nsScriptSecurityManager: Very JS specific already and will probably remain so. | |||
nsDocShell: Use new GetCallerDocShell as described above. | |||
LegacyPlugin.cpp: Does some private magic with context stacks. Filename implies we can ignore this. | |||
ns4xPlugin.cpp: some private js context work. | |||
nsWindowWatcher: Generally looks at the top of the stack to try and locate a dynamic or static script global. Some JS specifics though. | |||
js/src/*: Lots of JS specific stuff as you expect | |||
ProxyClassLoader.cpp: Peeks at the stack to get a context, to get a property. Could use new property fetch functions. | |||
nsProfile.cpp: Calls GetSafeJSContext just to force a GC. | |||
nsContentUtils: See nsContentUtils discussion below. | |||
nsRange.cpp::CreateContextualFragment - seems to push/pop a JS Context, and compares principals and contexts. | |||
// If there's no JS or system JS running, push the current document's context on the JS context stack | |||
What does that mean??? | |||
content/html - a few uses ignored. | |||
nsLocation: Looks for existing context. Some DynamicContext. | |||
::JS_GetContextPrivate ??? | ::JS_GetContextPrivate ??? | ||
=== nsIScriptSecurityManager === | |||
All JSContext* can probably be replaced with nsIScriptContext. Use of simple JObject* may need to be replaced with nsIScriptContext* and matching void*. | |||
=== nsScriptLoader === | === nsScriptLoader === | ||
Line 106: | Line 216: | ||
Presumably will need to become script language aware. eg, scriptAvailable() method has text of the script passed - not much use without also knowing the language. Possibly replace with nsIScriptElement, which does have the language ID | Presumably will need to become script language aware. eg, scriptAvailable() method has text of the script passed - not much use without also knowing the language. Possibly replace with nsIScriptElement, which does have the language ID | ||
=== | === nsXULPrototypeScript === | ||
* Change JSObject *mJSObject -> void *mScriptObject. | |||
* Add language_id reference - caller must provide their own nsIScriptContext. | |||
* | * Deserializing etc needs to support multi-languages. May require serialize/deserialize functions on the context? | ||
=== nsContentUtils === | |||
Uses native JSContext for ReparentContentWrapper | |||
GetDocShellFromCaller/GetDocumentFromCaller - uses JS context stack to get the nsIScriptGlobal | |||
nsCxPusher helper class: Peeks at JSContextStack to determine if a script is running (the simple fact an item is on the stack is all it checks). Pushes and pops a context. | |||
nsContentUtils::NotifyXPCIfExceptionPending(JSContext* aCx) - 2 callers: | |||
* content/xbl/src/nsXBLProtoImplMethod.cpp - nsXBLProtoImplAnonymousMethod::Execute() - very JS specific | |||
* dom/src/base/nsJSEnvironment.cpp | |||
=== | === nsAppShellService === | ||
SetXPConnectSafeContext - seems to create and set the "safe context" for the context stack. | |||
=== Event listeners === | === Event listeners === | ||
Line 132: | Line 247: | ||
* 'context' still comes from ScriptGlobal | * 'context' still comes from ScriptGlobal | ||
* Use of "@mozilla.org/js/xpc/ContextStack;1" needs to be abstracted into the nsIScript interfaces. | * Use of "@mozilla.org/js/xpc/ContextStack;1" needs to be abstracted into the nsIScript interfaces. | ||
=== nsDOMScriptObjectFactory === | |||
nsDOMScriptObjectFactory:::NewScriptContext may be unnecessary - just allow the ScriptGlobalObject to auto-create its own somehow. There are multiple implementations, so may not be reasonable. | |||
=== Exceptions === | === Exceptions === | ||
Line 151: | Line 270: | ||
* WrapNative and what it really means to this | * WrapNative and what it really means to this | ||
* | * Best way to tackle nsDOMClassInfo??? | ||
* nsBindingManager - very JS specific and not using nsIScript interfaces | * nsBindingManager - very JS specific and not using nsIScript interfaces | ||
Line 163: | Line 282: | ||
== Random Notes == | == Random Notes == | ||
Some notes about existing callers of certain | Some notes about existing callers of certain nsIScriptContext. | ||
nsDOMParser: | nsDOMParser: | ||
Line 203: | Line 322: | ||
content/base/src/nsDocument.cpp: | content/base/src/nsDocument.cpp: | ||
Convert nsIScriptContext -> JS Context -> | Convert nsIScriptContext -> JS Context -> CanExecuteScripts | ||
(can | (can CanExecuteScripts take an nsIScriptContext?) | ||
content/base/src/nsScriptLoader.cpp: | content/base/src/nsScriptLoader.cpp: |
edits