-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUGFIX release] Avoid re-freezing already frozen objects. #15312
Conversation
@@ -38,6 +38,19 @@ export const UPDATE = symbol('UPDATE'); | |||
|
|||
export { NULL_REFERENCE, UNDEFINED_REFERENCE } from '@glimmer/runtime'; | |||
|
|||
let maybeFreeze = () => {}; | |||
if (DEBUG) { | |||
maybeFreeze = (obj) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a note here regarding intended usage? I notice you're left the if (DEBUG) {
statements even though the function is a noop when !DEBUG
and I presume it is for DCE to do its thing. A note here might help a future traveller from thinking they can rely on the noop in non-debug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. And yes, that is why I left the if guards.
When a helper is invoked we pass in the arguments, those arguments are frozen (via Object.freeze) so that helpers can't mutate them (and cause issues in the rendering engine itself). When a helper doesn't have hash arguments, we use a shared `EMPTY_HASH` empty object to avoid allocating a bunch of empty objects for no reason (we do roughly the same thing when no positional params are passed). Since these objects are shared they are being frozen over and over again (throughout the lifetime of the running application). Turns out that there is what we think is almost certainly a bug in Chrome, where re-freezing the same object many times starts taking significantly more time upon each freeze attempt. This change introduces a guard to ensure we do not re-freeze repeatedly. Thanks to @krisselden for identifying the root cause and reporting the upstream Chrome bug: https://bugs.chromium.org/p/v8/issues/detail?id=6450
@krisselden - thanks for tracing down the root cause - when I posted #15290 I didn't specify which browser we were on - didn't occur to me that the browser itself was the issue (though I guess it was obvious from the profiler...) |
When a helper is invoked we pass in the arguments, those arguments are frozen (via Object.freeze) so that helpers can't mutate them (and cause issues in the rendering engine itself). When a helper doesn't have hash arguments, we use a shared
EMPTY_HASH
empty object to avoid allocating a bunch of empty objects for no reason (we do roughly the same thing when no positional params are passed). Since these objects are shared they are being frozen over and over again (throughout the lifetime of the running application). Turns out that there is what we think is almost certainly a bug in Chrome, where re-freezing the same object many times starts taking significantly more time upon each freeze attempt.This change introduces a guard to ensure we do not re-freeze repeatedly.
Thanks to @krisselden for identifying the root cause.
Fixes #15290