Dynamically changing of loader global
To clarify: are you asking if an arbitrary object is a valid global object when using a custom loader? If not, then I have a lot of code to rewrite.
I meant, if the answer to your question is "no". =/
Le 24/12/2012 23:37, Brandon Benvie a écrit :
To clarify: are you asking if an arbitrary object is a valid global object when using a custom loader? If not, then I have a lot of code to rewrite.
What I'm asking is: "is the global in the loader the initial or the dynamic value of the "global" option?" If dynamic value, my snippet will log "37". If initial value, my snippet will throw a ReferenceError originating from the eval-ed script (because there is no "a" global in the initial global)
I assume any object can be used as a global in a loader. I see no restriction in the proposal.
For that matter, you've implemented the "initial" solution in continuum [1] because you look at options.global when constructing the loader, but never look at it ever after.
By the way, maybe you should Object-wrap it or throw if it isn't an object? The proposal doesn't say which should occur.
David
[1] Benvie/continuum/blob/6338e3cdfc5a472d0998a6343ed38d5dc31e454c/engine/builtins/%40system.js#L50
Le 24/12/2012 23:37, Brandon Benvie a écrit :
Oh I see more clearly now what you mean. The proposal leaves room for options.global to be dynamically changed and have that reflected in modules, since it's specified as an accessor. My presumption would be that if that were allowed, it wouldn't actually change the global object for modules that loader has already loaded, since they would have already created a Global Environment Record using the global at the time of initialization. But it would allow for newly loaded modules to reference a different global.
I updated my Loader implementation to allow dynamically modifying the options since it seems like a potentially good idea worth investigating, and also seems like it might be indicated as the desired functionality based on global and baseURL being specified as getters. In order to make this work requires storing a reference to the parent as well in order to keep the spirit of deferring to the parent when the loader's options don't specify a global. You can see this in action here Benvie/continuum/blob/gh-pages/engine/builtins/%40system.js#L63 .
For good measure I made this work with most of the options, not just loader and baseURL (the three callbacks).
Unfortunately github has been failing to build the gh-pages for a few days now so until I can diagnose the reason for it randomly deciding to fail these changes aren't reflected in the live debugger demo hosted at github.
Le 25/12/2012 23:01, Brandon Benvie a écrit :
I updated my Loader implementation to allow dynamically modifying the options since it seems like a potentially good idea worth investigating, and also seems like it might be indicated as the desired functionality based on global and baseURL being specified as getters.
That's what I thought too, though a getter may just be for better syntax. A "getGlobal" method would be of bad taste in a post-ES5 world.
In order to make this work requires storing a reference to the parent as well in order to keep the spirit of deferring to the parent when the loader's options don't specify a global. You can see this in action here Benvie/continuum/blob/gh-pages/engine/builtins/%40system.js#L63.
For good measure I made this work with most of the options, not just loader and baseURL (the three callbacks).
Really cool, thanks :-)
On a related note, I had misunderstood document.open on the www-dom thread, so what I suggested here can't be a solution, I think. However, I'm glad it caught your attention enough to think it's a valuable idea :-)
On Dec 24, 2012, at 2:34 PM, David Bruant <bruant.d at gmail.com> wrote:
I've reading the loader API [1] and I was wondering if it was possible to dynamically change the global. I think it is by doing the following, but tell me if I'm wrong:
That wasn't the intention. It probably wasn't written out since the full semantics isn't spelled out yet (though Sam and I have been making good progress working through the details of the semantics), but the idea was that the properties of the options object are read in up-front and stored internally. The getter always returns that internally closed-over value that was obtained when the loader was first created.
In other words, in the global in the loader the initial or the dynamic value of the "global" option?
The initial value. We can look into what it would mean to make it modifiable, but we'd probably not make that the API; we'd probably just have a setter.
If it was the dynamic value, I think it would help a lot in the document.open situation [2]
David
[1] harmony:module_loaders#loader_api [2] lists.w3.org/Archives/Public/www-dom/2012OctDec/0166.html
Thanks, I'll read up on this.
Le 26/12/2012 23:14, David Herman a écrit :
On Dec 24, 2012, at 2:34 PM, David Bruant <bruant.d at gmail.com> wrote:
I've reading the loader API [1] and I was wondering if it was possible to dynamically change the global. I think it is by doing the following, but tell me if I'm wrong: That wasn't the intention. It probably wasn't written out since the full semantics isn't spelled out yet (though Sam and I have been making good progress working through the details of the semantics), but the idea was that the properties of the options object are read in up-front and stored internally. The getter always returns that internally closed-over value that was obtained when the loader was first created.
Ok, thanks for the clarification. The strawman as it was didn't explain the full semantics hence my question.
In other words, in the global in the loader the initial or the dynamic value of the "global" option? The initial value. We can look into what it would mean to make it modifiable, but we'd probably not make that the API; we'd probably just have a setter.
Good point. [Adding MarkM into the mix for this part] I wish to point out a potential security/convenience issue regarding inherited getter/setters. My point is broader than the 'global' loader situation (it includes everything covered by WebIDL for instance), but let's assume a 'global' setter is added to Loader.prototype and I'll draw the general conclusion from this example. If I want to share a single loader instance to someone else, but not provide access to the loader global, I have to delete Loader.prototype.global (otherwise, someone can extract the getter and use the reference to the loader instance to retrieve the global) The problem with deleting Loader.prototype.global is that it's deleted for every single instance which in turns make the code harder to write (because, defensively, one needs to extract the getter/setter pair an then use that instead of the more convenient "myLoader.global" syntax). The opposite way, if freezing Loader.prototype, it becomes impossible to revoke the capability to introspect instances using the inherited getters/setters.
In essence, an inherited accessor means that the choice allowing access to a given property isn't a per-instance choice anymore. It's a per-"class" choice (keep it or remove it for every instance) which is probably fine for most situations, but certainly too coarse for some others.
Since the amount of storage is equivalent anyway (you need some sort of private property to associate the global to the loader instance), I would suggest to go to an own "global" data property for loaders... and I guess to stay away from inherited accessors when describing a per-instance property for the reasons I described.
On Wed, Dec 26, 2012 at 3:03 PM, David Bruant <bruant.d at gmail.com> wrote:
Le 26/12/2012 23:14, David Herman a écrit :
On Dec 24, 2012, at 2:34 PM, David Bruant <bruant.d at gmail.com> wrote:
I've reading the loader API [1] and I was wondering if it was possible to dynamically change the global. I think it is by doing the following, but tell me if I'm wrong:
That wasn't the intention. It probably wasn't written out since the full semantics isn't spelled out yet (though Sam and I have been making good progress working through the details of the semantics), but the idea was that the properties of the options object are read in up-front and stored internally. The getter always returns that internally closed-over value that was obtained when the loader was first created.
Ok, thanks for the clarification. The strawman as it was didn't explain the full semantics hence my question.
In other words, in the global in the loader the initial or the dynamic value of the "global" option?
The initial value. We can look into what it would mean to make it modifiable, but we'd probably not make that the API; we'd probably just have a setter.
Good point. [Adding MarkM into the mix for this part] I wish to point out a potential security/convenience issue regarding inherited getter/setters. My point is broader than the 'global' loader situation (it includes everything covered by WebIDL for instance), but let's assume a 'global' setter is added to Loader.prototype and I'll draw the general conclusion from this example. If I want to share a single loader instance to someone else, but not provide access to the loader global, I have to delete Loader.prototype.global (otherwise, someone can extract the getter and use the reference to the loader instance to retrieve the global) The problem with deleting Loader.prototype.global is that it's deleted for every single instance which in turns make the code harder to write (because, defensively, one needs to extract the getter/setter pair an then use that instead of the more convenient "myLoader.global" syntax). The opposite way, if freezing Loader.prototype, it becomes impossible to revoke the capability to introspect instances using the inherited getters/setters.
In essence, an inherited accessor means that the choice allowing access to a given property isn't a per-instance choice anymore. It's a per-"class" choice (keep it or remove it for every instance) which is probably fine for most situations, but certainly too coarse for some others.
This is a very good point. Is there any reason other than legacy compat why WebIDL specifies inherited accessors rather than own properties?
Le 27/12/2012 20:04, Mark S. Miller a écrit :
This is a very good point. Is there any reason other than legacy compat why WebIDL specifies inherited accessors rather than own properties?
There is no legacy compat issue. Before WebIDL, the ECMAScript representation of DOM objects was an absurd under-specified and consequently non-interoperable mess. We are still in this mess. IE9 is following WebIDL quite closely. I assume IE10 is doing better (I've never had a look, but Microsoft is following a good path, so I assume progress). All other browsers are still very far from WebIDL. Firefox is making fast progress [1]. I don't think I have seen progress in other browsers, but I haven't been following that closely either.
I don't know why inherited accessors were chosen, but I'm very interested in learning if someone has the answer. Since we can decently assume than no web content really relies on WebIDL, there is certainly still time to change WebIDL if necessary
David
It's definitely been my experience that accessors, as found in IE and Firefox, are much more fidgety and error prone than own data properties, as found in WebKit. The fact that it becomes possible to call them on invalid targets and that it's no longer possible for a debugger to simply display own properties exacerbates this fidgetyness. Even worse, the prototypes which the accessors live on are themselves not valid targets, which basically invites errors.
So does anyone know why? Own properties were the obvious choice, so there must have been some reason to choose inherited accessors instead.
The trade-off is not between own data properties and shared prototype-homed accessors.
Rather, it is between own and inherited accessors.
In either case, one needs per-instance state, often stored in a peer-to-JS C++ DOM native data structure that must exist whether there' s a JS reflection.
But with own accessors, one also then needs another slot or pair of slots (for setter and getter).
It's not enough to make a magic data property with code backing it to compute or normalize or commit other effects on get and/or set. We can't model magic own data properties that involve computed get/set in WebIDL or ES5 (or ES6, outside of proxies).
So economics come in, and shared accessors win big-time on efficiency.
The key insight is that the per-instance storage does not change between alternative own vs. inherited accessor scenarios, but own adds extra slots to every instance. That hurts.
Pre-WebIDL DOM bindings cheat by using native code to run on every set and even get, without the own data property reflecting as an accessor. That seems worse than what we have settled on with prototype-homed inherited accessors, no?
On Dec 26, 2012, at 3:03 PM, David Bruant <bruant.d at gmail.com> wrote:
The initial value. We can look into what it would mean to make it modifiable, but we'd probably not make that the API; we'd probably just have a setter. Good point. [Adding MarkM into the mix for this part] I wish to point out a potential security/convenience issue regarding inherited getter/setters. My point is broader than the 'global' loader situation (it includes everything covered by WebIDL for instance), but let's assume a 'global' setter is added to Loader.prototype and I'll draw the general conclusion from this example. If I want to share a single loader instance to someone else, but not provide access to the loader global, I have to delete Loader.prototype.global (otherwise, someone can extract the getter and use the reference to the loader instance to retrieve the global)
Heh, good luck with that. A loader is a very high privilege object. Just removing the getter is not going to help you, when you can easily write
loader.eval("this")
For security, it's much better to treat a loader is a super-powerful object, and completely deny access to it to untrusted code. That's one of the reasons why there's no f.getLoader() or getCurrentLoader() API. The System object is a loader, but when you create a sandbox, you would typically censor or attenuate its power.
I've reading the loader API [1] and I was wondering if it was possible to dynamically change the global. I think it is by doing the following, but tell me if I'm wrong:
In other words, in the global in the loader the initial or the dynamic value of the "global" option? If it was the dynamic value, I think it would help a lot in the document.open situation [2]
David
[1] harmony:module_loaders#loader_api [2] lists.w3.org/Archives/Public/www-dom/2012OctDec/0166.html