Are frozen Objects faster ?
Frozen and sealed objects are both dramatically slower in most JS engines I've tested. In the ones where they're not dramatically slower they are never faster.
The last time I asked on the mozilla and v8 bug trackers I was informed that there is no plan to optimize for these features and that the design of the respective JS engines would make such optimizations difficult anyway.
(I find this extremely unfortunate.)
Likewise. And unlikely.
Based on history, I suggest that the best way to get this situation fixed is benchmarks. Either create a new benchmark or a variation of an existing benchmark. For example, if someone created a variant of SunSpider in which all objects that don't need to not be frozen were frozen, and posted the measurements, that would help get everyone's attention. The situation might then improve rapidly.
(I find this extremely unfortunate.)
I, on the other hand, find it fortunate. Otherwise, some people would
prematurely freeze objects to gain speed. It would be same
<del>disaster</del> akwardness as v8 did with removing delete
in
favour of = null
.
What are you referring to? What 'delete' was removed?
If someone created a variant of SunSpider in which all objects that don't need to not be frozen were frozen, and posted the measurements, that would help get everyone's attention.
Gulp. Mark, you didn't just suggest using SunSpider as the basis for a future benchmark, did you? My eyes must have tricked me.
It was just an example. Feel free to make an alternative and more informed suggestion ;).
I suggest that the best way to get this situation fixed is benchmarks.
Agreed 100%
Either create a new benchmark or a variation of an existing benchmark.
Choice of the specific benchmark aside, this is a very good idea. This could also be applied to strict mode.
What are you referring to? What 'delete' was removed?
I meant "de facto". People wanting to remove property bar from foo do not write delete foo.bar
anymore; they (at least some significant subset) have learned to write foo.bar = null;
or foo.bar = undefined;
. The reason is perf - delete
deoptimized hidden classes.
And with ES6, those people will hopefully realise that for those cases, using a Map is a cleaner alternative anyway.
No, it is another scenario. If an object is used as a Map, it should degrade to HashMap, it's ok.
The problem is proliferation of foo.bar = null
in "normal" code, where sometimes you want to remove some property (maybe it was an expando, or it is realy not needed any more in the actual phases of the lifecycle). In such cases, doing delete
would degrade your optimized instance into a Hash. Thus, people do foo.bar = null
even if what they want to do is delete foo.bar
.
This is definitely the case. Recent performance guidance from V8 developers strongly discouraged the use of 'delete' so I've gone to some lengths to avoid using it in my own code, mostly through design (trying to avoid scenarios that require the deletion of attributes). If this guidance isn't accurate anymore, I certainly never heard about it. Then again engine developers have said that they intentionally avoid publishing performance guidance since people continue to follow it after it becomes outdated - so I guess this is just support for that policy. :/
Anyway! I spent an hour or so building a simplified real-world benchmark for Object.freeze, by modifying a HTML5 game port to use Object.freeze at construction time for its immutable structured objects. These objects are basically simple tuples of integers/floats that are frequently constructed and passed around - think a Vector2 or Point data structure, etc.
This file has detailed timings from the latest versions of Chrome Canary and Firefox Nightly with the Object.freeze call disabled and enabled, respectively, along with a URL you can hit to run it yourself: dl.dropbox.com/u/1643240/freeze timings.txt
I'm pleased to report that Object.freeze does not seem to cause an enormous performance hit in v8 anymore. Hooray! Unfortunately, the call to Object.freeze itself shows up as a bottleneck in V8 profiles, and the 'freeze enabled' version is slower in both versions (though at least only slightly slower). So, I guess you could start using freeze in applications now if your users are all on latest FF/Chrome, and hope that in the future it will actually make you faster.
Feel free to let me know if you have any questions (though if they're questions about the benchmark, maybe don't spam es-discuss with them :) )
On 14 February 2013 20:56, Herby Vojčík <herby at mailbox.sk> wrote:
The problem is proliferation of
foo.bar = null
in "normal" code, where sometimes you want to remove some property (maybe it was an expando, or it is realy not needed any more in the actual phases of the lifecycle). In such cases, doingdelete
would degrade your optimized instance into a Hash. Thus, people dofoo.bar = null
even if what they want to do isdelete foo.bar
.
By definition, if you want to delete it, it's not a "normal" property. In most languages, you couldn't even do that. The reason that you can in JavaScript is mostly historic. (And fortunately, I don't see a "proliferation" of this in practice.)
On 14 February 2013 21:12, Kevin Gadd <kevin.gadd at gmail.com> wrote:
I'm pleased to report that Object.freeze does not seem to cause an enormous performance hit in v8 anymore. Hooray! Unfortunately, the call to Object.freeze itself shows up as a bottleneck in V8 profiles, and the 'freeze enabled' version is slower in both versions (though at least only slightly slower).
Thanks for doing the benchmark, very interesting!
That freeze bottleneck will hopefully vanish in the foreseeable future.
the delete obj.property
changes the shape of the object, right? so I
think is more a problem of devs using objects as trash bin but this is the
opposite scenario of a frozen object.
I understand ES5 descriptors are an overhead during an object lifecycle but I think a mechanism to make frozen object that fast would be a win while we wait for better options on statically defined types.
"Binary Arrays" are indeed frozen objects, at least in Firefox, and ultra fast: Object.isFrozen(new Float32Array()) // true in Firefox
Since these are ultra fast in Chrome too but not frozen, I believe there is already a way to speed up typed stuff (didn't check how it's done though) so I wonder how come Object.freeze() is not taking similar approach "typizing" behind the scene the object improving all static properties getters (probably dropping those getters where possible unless defined as such)
Will this cost more than now at freeze() time? I understand this might be undesired but think about libraries or modules that do not want to be extended, would like to be as fast as possible, and are loaded once and never again.
Thanks for all thoughts and info already provided, also agreed on some bench. I usually do that on jsPerf 'cause I don't know how to reach those bigger, widely tested, one.
Any hint here appreciated.
On 14 February 2013 21:36, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote:
"Binary Arrays" are indeed frozen objects, at least in Firefox, and ultra fast: Object.isFrozen(new Float32Array()) // true in Firefox
Since these are ultra fast in Chrome too but not frozen, I believe there is already a way to speed up typed stuff (didn't check how it's done though) so I wonder how come Object.freeze() is not taking similar approach "typizing" behind the scene the object improving all static properties getters (probably dropping those getters where possible unless defined as such)
Frozenness is largely irrelevant for typed arrays, since all array accesses are defined by a magic nameless getter/setter pair per the WebIDL spec.
One more thought ... the best scenario ever would be the ability to define a frozen prototype and create already fixed shaped instance at runtime.
I think Object.freeze()
semantic is not the right one to do this, but I am dreaming about something like this:
var MyStaticShapeConstructor = Object.createStaticConstructor(
inheritFrom, // either null or actually not extremely important
descriptors // descriptors we know
);
var instance = new MyStaticShapeConstructor;
We might discuss if the "constructor" property in descriptors should have a handy, exceptional, treatment (ie invoked with arguments)
{
constructor: {
value: function (a, b, c) {
// invoked when new MyStaticShapeConstructor(1,2,3)
}
}
}
or simply encourage the usage of o.init(arg1, ..., argN)
;
I know this is way too much magic behind the scene but it would be straight forward from different points of view, at least for JS users, IMHO, and really easy to polyfill.
Thoughts on this would be much appreciated, thanks.
Apologies if already discussed and I have missed that thread.
I wodner how come Firefox behaves like that then but I don't have tests to compare any difference between these two. I will write some,
Ideally the JIT would, at runtime, just identify the pattern where your constructor ends with an Object.freeze(this) call, and turn it into the equivalent of an immutable, pass-by-value packed struct. IIRC v8 and SpiderMonkey are both able to do some of this already based on looking at your constructor and using shape information...
that is assuming nobody ever call the constructor without new keyword and no inheritance is involved, since the sub constructor would be trapped behind the parent.
That would be even more magic ... I kinda like it, not sure is explicit enough though ... but yeah, if freeze(this) would do that, it would be awesome!
On Thursday, February 14, 2013, Andreas Rossberg wrote:
On 14 February 2013 19:26, Herby Vojčík <herby at mailbox.sk <javascript:;>> wrote:
I meant "de facto". People wanting to remove property bar from foo do not write
delete foo.bar
anymore; they (at least some significant subset) have learned to writefoo.bar = null;
orfoo.bar = undefined;
. The reason is perf -delete
deoptimized hidden classes.And with ES6, those people will hopefully realise that for those cases, using a Map is a cleaner alternative anyway.
I think it's worth noting here that of course older features have seen heavier optimization. I honestly expect that the Map type will start much slower than it will eventually end up being, perhaps not in V8, but elsewhere. But slow and available often beats unavailable and/or non-standard. It's a complicated story to tell end-users, but anything else is misleading.
One hopes that any new feature we that gets wide implementation and is not explicitly performance oriented pays for itself on a semantic basis. Such features find their natural users prior to the optimization foot race kicking off, and there's nothing bad about any of that. The ideal world (that freeze() is now a poster child for) looks roughly like:
// Standard written, implementations arrive (not in that order) // ...time passes... Hooray! New features!
// ...time passes... // Users realize optimization is uneven Boo! They're slow! // Said without any sense of JS perf history
// ...time passes... // Features optimized Yay! They're fast!
Typed Arrays are not frozen on FF, they are not extensible, only new typed_array(nothing) is frozen (just bad luck for your example :-) ).
Reading this thread, it seems that I am not using good practices,
because I am using quite often the object literal indexed with numbers
(var a={};a[1]=something
), and I am using delete
to remove the values
(the object litteral becomes a kind of array with holes), and I really
expect delete to remove the property, not to assign it to null. I find
it convenient (despite of the fact that properties enumeration order in
that case is let to the appreciation of the js engine and can change
depending on what you are doing), is this not correct/impacting a lot
performances?
One day maybe there could be an annex in ES specs about good practices and performances, or does it exist somewhere?
not sure I follow here ... I did ask if Object.freeze was faster and why, if not, 'cause faster is what I would expect after a probably slower operation as freeze could be.
Aymeric yes, that was unfortunate, also I don't understand all these different behaviors but point is, I think you can extend in Chrome, you cannot in Firefox and no idea why this choice (bu tI understand the implementation of static, fixed, type/shape)
So, it looks like is planned, but nobody knows when? Well, that's better than nothing :-)
If not, any particular reason these are not, being immutable and representable similar to a C struct ?
If they could, any idea which engine is planning to optimize and when?
Thanks and Best