Bug 143239 - No way to quickly make non-enumerable instance properties
Summary: No way to quickly make non-enumerable instance properties
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-03-30 16:07 PDT by Ryosuke Niwa
Modified: 2015-03-30 18:28 PDT (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ryosuke Niwa 2015-03-30 16:07:45 PDT
I was talking with https://twitter.com/stefanpenner (Ember.js core member) and he told me that they currently work around the fact we can't create a non-enumrerable property fast.

SpiderMonkey bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1088453
V8 bug: https://code.google.com/p/v8/issues/detail?id=3649
Comment 1 Ryosuke Niwa 2015-03-30 16:10:16 PDT
I've manually enabled symbols in JSC and got results on https://jsperf.com/symbol-vs-prop-vs-def-prop:

property       68,907,822 ±0.30%  fastest
non-enumerable 4,093,475 ±0.58%   94% slower
symbol         11,586,795 ±0.36%  83% slower
weakmap        5,361,775 ±2.15%   92% slower
Comment 2 Filip Pizlo 2015-03-30 16:12:43 PDT
That's super interesting.  I think that the main problem is that making a property non-enumerable doesn't involve a cached transition.  This means that if you make something non-enumerable, all accesses to the object go slow after that.

Once we fix that, then the next problem is that the call to make it non-enumerable is not intrinsic.  We should make that call be intrinsic.
Comment 3 Ryosuke Niwa 2015-03-30 16:15:08 PDT
Accessing a property using symbol seems pretty fast (http://jsperf.com/symbol-vs-property/13):

symbol    18,871,149 ±0.94%  28% slower
property  18,106,575 ±0.42%  31% slower
.foo      26,093,814 ±0.53%  fastest

(Chrome results are somewhat misleading because it ran on a much faster results; what's important is the relative perf. of different cases).
Comment 4 Filip Pizlo 2015-03-30 16:15:52 PDT
(In reply to comment #1)
> I've manually enabled symbols in JSC and got results on
> https://jsperf.com/symbol-vs-prop-vs-def-prop:
> 
> property       68,907,822 ±0.30%  fastest
> non-enumerable 4,093,475 ±0.58%   94% slower
> symbol         11,586,795 ±0.36%  83% slower
> weakmap        5,361,775 ±2.15%   92% slower

The best way to benchmark this is to take a medium-sized test that is known to create a lot of objects and access a lot of properties, and modify it to make all of the properties non-enumerable.  Then also make a version that uses symbols.  Then also make a version that uses WeakMap.  That is, uses those things for all of the properties.

I recommend either V8/deltablue or V8/raytrace.  V8/raytrace could be hilarious since in that one we do very aggressive object allocation sinking but we can't do it if you do things we don't optimize (like all of the things you list above).  So, just make three new versions of raytrace:

raytrace-non-enum
raytrace-symbol
raytrace-weakmap

I know it's tedious, but this is what I do when I want to come up with a good story for optimizing a feature.  Like, we have getter-richards for when I was optimizing getters/setters, and now we have deltablue-varargs to help me with my varargs optimization work.
Comment 5 Ryosuke Niwa 2015-03-30 16:16:57 PDT
(In reply to comment #2)
> Once we fix that, then the next problem is that the call to make it
> non-enumerable is not intrinsic.  We should make that call be intrinsic.

Since class methods are non-enumerable (bugs 143181), we should add the intrinsic for defineProperty anyway.
Comment 6 Ryosuke Niwa 2015-03-30 16:18:02 PDT
Oh these are tests made by Ember.js folks. Also see the original bug report by https://twitter.com/stefanpenner at https://code.google.com/p/v8/issues/detail?id=3649 and https://bugzilla.mozilla.org/show_bug.cgi?id=1088453.

I've asked him to file a bug but he's really busy right now so I'm doing it on his behalf.
Comment 7 Filip Pizlo 2015-03-30 16:21:07 PDT
(In reply to comment #3)
> Accessing a property using symbol seems pretty fast
> (http://jsperf.com/symbol-vs-property/13):
> 
> symbol    18,871,149 ±0.94%  28% slower
> property  18,106,575 ±0.42%  31% slower
> .foo      26,093,814 ±0.53%  fastest
> 
> (Chrome results are somewhat misleading because it ran on a much faster
> results; what's important is the relative perf. of different cases).

No.  Relative perf doesn't matter.  It's possible that just adding a symbol-keyed property puts the prototype into a slower mode, in which case this test is bogus.

If Chrome is much faster on basic property accesses in your test then one of the following is happening:

- Our property accesses are completely busted and we should go back to the drawing board.  Unlikely, since we are very competitive on property access tests.

- Putting symbols into an object makes accesses to even normal properties slower, in which case "accessing a property using a symbol seems pretty fast" is an incorrect conclusion.

- jsperf puts each microbenchmark snippet into some kind of bizarro loop, and we're running that loop slowly.  I.e. you're not even testing property access performance but you're just testing the performance of the jsperf harness.

Anyway, it's completely wrong to conclude that something is fast the baseline (accessing .foo) is an order of magnitude slower than Chrome.
Comment 8 Ryosuke Niwa 2015-03-30 18:23:02 PDT
Alright, I've made a slightly better micro benchmark at https://gist.github.com/rniwa/572ed56668366e6542d3

It doesn't seem like defining or accessing symbol properties isn't significantly slower:

Defining string properties: 242 ms 
Accessing string properties: 95 ms 
Defining symbol properties: 271 ms 
Accessing string properties: 143 ms
Comment 9 Ryosuke Niwa 2015-03-30 18:28:33 PDT
(In reply to comment #7)
>
> Anyway, it's completely wrong to conclude that something is fast the
> baseline (accessing .foo) is an order of magnitude slower than Chrome.

I don't think anyone is claiming that here.

This bug is about Ember.js wanting to define and access non-enumerable property without runtime penalty. Either making defineProperty fast or symbols perform as fast as strings would work (although we should really do both!)