WebIDL attribute reflection

David Bruant bruant.d at gmail.com
Sun Dec 30 10:20:19 PST 2012


Le 30/12/2012 07:42, Boris Zbarsky a écrit :
> On 12/29/12 11:08 AM, David Bruant wrote:
>> Boris, what initially triggered my questioning of the inherited accessor
>> setting is in this message:
>> https://mail.mozilla.org/pipermail/es-discuss/2012-December/027435.html
>
> OK, but that's a problem methods can have too, yes?  Not in this 
> particular case, but in plenty of other cases...
Good point, it's a problem for methods too. Since I've posted the point 
about inherited accessors, I've realized that the problem is not about 
accessor, but the prototypal inheritance model.
An idea would be to remove the inherited method and add it back to each 
instance where it's "allowed". I guess the exact same thing can be done 
with getter/setter pairs.
I would say that the difference lies in the fact that properties which 
usually materialize the object state clearly are a per-instance thing 
while object methods usually are stateless functions, so can be thought 
as per-"class". That's a model that's very familiar and widely used by 
JavaScript developers at least.

> Completely revamping how properties are handled to make this one case 
> easier seems a bit extreme.  In my opinion.
There is the |this| check removal and Brandon Benvie made a couple of 
good points on the developer experience at 
https://mail.mozilla.org/pipermail/es-discuss/2012-December/027503.html
The point about debuggers may be very annoying. It can be solved by 
devtools. It would be just more work ;-)

>> Mostly concerns about a mix of API "securability" and convenience. I
>> "demonstrate" that if every attribute is an inherited accessor, then,
>> it's possible to secure the environment, but it can be at the expense of
>> API usability up to asking people to tweak their code (which is an
>> anti-goal when trying to secure your code from, say, an advertiser's 
>> code)
>
> If you're trying to secure your code from an advertiser's code you 
> want to not run the advertiser's code with your origin.  Anything else 
> at best gives you the illusion of security...  Again, in my opinion.
I don't understand your point. I didn't mention anything about origin. 
Can you develop?
Anyway, in a modern browser, the beforescriptexecute event [1] can be of 
great help to sandbox code from any origin apparently 
(e.preventDefault() then evaluate with a sandbox of your own recipe).

>> I'm not sure I'm convinced by "it's more work than right now". If you
>> had told me that there is a fundamental issue that implementors can't
>> work around when exposing own data properties, I would have backed out,
>> but you suggested than it's possible to create "yet another kind of
>> thing internally which is not a proxy so it can be optimized sanely".
>
> This is empirically true, since that's what JavaScriptCore does today, 
> for example.  If I'm not misreading the code, it actually hangs its 
> DOM property getters/setters of the prototype internally, makes them 
> look like own properties on objects when reflected via 
> getOwnPropertyDescriptor, and has magic to make a property lookup 
> return the getter/setter pair internally and have their interpreter 
> and JIT call those.
>
> So in JavaScriptCore there are at least three different kinds of 
> properties (there are more, because they have non-proxy objects with 
> custom getOwnPropertyDescriptor hooks, like Document, but I'm 
> simplifying): accessor properties, value properties, and magic 
> properties that claim to be value properties when reflected but don't 
> have a slot, are actually accessor properties under the hood, and 
> pretend to be on a different object than the object they're really on.
>
> This of course has the interesting side-effect that JavaScriptCore 
> ends up having to claim the properties are non-configurable, because 
> they don't actually live on the objects under the hood, so you have to 
> disallow deleting them.  So this approach, in this particular 
> implementation, doesn't address you "delete .global" issue anyway.  
> Try the testcase:
>
> <script>
>   var h = document.documentElement;
>   alert(h.innerHTML);
>   alert(JSON.stringify(Object.getOwnPropertyDescriptor(h,
> "innerHTML")));
>   delete h.innerHTML;
>   alert(h.innerHTML);
> </script>
Interesting point.
Unrelated, but it's making me realize that innerHTML may stay a 
getter/setter (not sure about inherited or not).
I guess the divide I'd like to put is between object state and what is 
conveniently put as an accessor

>> Out of curiosity, do you have an idea of how much cost the |this| check?
>
> Cost in terms of what?
Time mostly, I guess.

> It depends on your implementation, obviously (e.g. it's really 
> expensive in Gecko's XPConnect bindings from 6 years ago), but in 
> Gecko's WebIDL bindings the cost of the "this" check (which we want to 
> minimize no matter what, because methods have to do it!) is about 
> 15-20 cycles on average last I measured (including whatever cache 
> misses are involved every so often, etc).  It'll get a bit cheaper as 
> we remove some more edge cases it has to deal with right now.  Oh, and 
> in practice we usually only have to do it at JIT-compile time, not at 
> runtime (unless you go out of your way to do .call or .apply on the 
> getter/setter) because the combination of the type inference and 
> guarding the JIT already does means that we'll get the equivalent of 
> an IC miss (it's not quite an IC, but similar concept) if the observed 
> type changes from what it was when the code was compiled.
Thanks for this very enriching answer.
The JIT-compile time point is the kind of thing I was asking for. If I 
understand correctly, it means that for code used very often, the |this| 
check is performed once and never done again (until a .call/apply which 
is rather rare). It basically mean that the |this| cost has been made 
almost inexistent. It remains in cold code, but the perf of cold code 
doesn't matter.
It makes my argument to remove the |this| checks still valid for the 
spec, but it's a very light argument for implementation performance.

On a related thought, I'm always surprised by the tricks in place in 
current JS engines. It looks like in a lot of cases, empirical runtime 
type analysis and optimistic JIT compilation allow crazy performance. 
I'm trying very hard to think of cases where this approach wouldn't be 
enough for hand-written code and I can't find any.

David

[1] 
http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#execute-the-script-block


More information about the es-discuss mailing list