Closed
Bug 1447362
Opened 7 years ago
Closed 7 years ago
Avoid more AtomizeString calls when binding a bound function
Categories
(Core :: JavaScript: Standard Library, enhancement, P3)
Core
JavaScript: Standard Library
Tracking
()
RESOLVED
FIXED
mozilla61
Tracking | Status | |
---|---|---|
firefox61 | --- | fixed |
People
(Reporter: anba, Assigned: anba)
Details
Attachments
(1 file, 1 obsolete file)
(deleted),
patch
|
anba
:
review+
|
Details | Diff | Splinter Review |
We can avoid even more string atomization calls when binding a bound function (bug 1371593).
The attached patch improves this µ-benchmark from 255ms to 115ms.
---
function f() {
function fn(){}
var t = dateNow();
for (var i = 0; i < 1000000; ++i) {
fn.bind().bind();
}
return dateNow() - t;
}
f()
---
Assignee | ||
Comment 1•7 years ago
|
||
bug 1371593 only improved the case when we repeatedly bind the same bound function. This patch improves the idea from bug 1371593 to store unprefixed (without the "bound " prefix) names for bound functions, so we can also improve the case when we call Function.prototype.bind() for the first time on a bound function.
Function overview:
JSFunction::getBoundFunctionName()
Returns the full name of a bound function, that means including the "bound " prefix. If the HAS_BOUND_FUNCTION_NAME_PREFIX function flag is not set, we compute the full name by counting the number of target bound functions and then appending "bound " that many times.
JSFunction::getUnresolvedName()
JSFunction::infallibleGetUnresolvedName()
This function was modified to no longer atomize the function name when called from fun_resolve(). And parts of it were split into JSFunction::infallibleGetUnresolvedName().
JSFunction::finishBoundFunctionInit()
- If the target function doesn't have a resolved name and if it is a bound function with HAS_BOUND_FUNCTION_NAME_PREFIX set, directly store the name atom. If HAS_BOUND_FUNCTION_NAME_PREFIX is set, we need to eagerly compute the full prefixed name because we can't compute it lazily in JSFunction::getBoundFunctionName().
- If the target function has a resolved name (or is not a JSFunction) and it's not a bound function, we can also just save the name atom. If it is a bound function, we need to compute the full prefixed name.
We need to handle the bound function cases differently because of things like this:
---
// f.atom = "f"
function f() {}
// bf1.atom = "f"
var bf1 = f.bind();
Object.defineProperty(bf1, "name", {value: "g"});
// But bf2.atom = "bound g", because we need to store bf1's name at the time bind() was called, which means we can't restore the name when we're calling JSFunction::getBoundFunctionName().
var bf2 = bf1.bind();
assertEq(bf2.name, "bound g");
---
Which also implies that HAS_BOUND_FUNCTION_NAME_PREFIX is a transitive property, so if the target of a bound function has HAS_BOUND_FUNCTION_NAME_PREFIX set, the bound function also needs to set HAS_BOUND_FUNCTION_NAME_PREFIX.
Attachment #8960696 -
Flags: review?(jdemooij)
Comment 2•7 years ago
|
||
Comment on attachment 8960696 [details] [diff] [review]
bug1447362.patch
Review of attachment 8960696 [details] [diff] [review]:
-----------------------------------------------------------------
Great improvement!
::: js/src/vm/JSFunction.cpp
@@ +1392,5 @@
> + if (name->hasTwoByteChars() && !sb.ensureTwoByteChars())
> + return nullptr;
> +
> + CheckedInt<size_t> len(boundTargets);
> + len *= strlen(boundWithSpaceChars);
GCC/Clang should inline the strlen, not sure about MSVC. To avoid relying on this optimization, it might be nicer to do this:
static constexpr char boundWithSpaceChars[] = "bound ";
static constexpr size_t boundWithSpaceCharsLength = mozilla::ArrayLength(boundWithSpaceChars) - 1; // No trailing '\0'.
This ArrayLength is a constexpr: https://searchfox.org/mozilla-central/rev/b29daa46443b30612415c35be0a3c9c13b9dc5f6/mfbt/ArrayUtils.h#54-59
And then use boundWithSpaceCharsLength instead of strlen (twice).
Attachment #8960696 -
Flags: review?(jdemooij) → review+
Assignee | ||
Comment 3•7 years ago
|
||
Updated per review comments, carrying r+.
Attachment #8960696 -
Attachment is obsolete: true
Attachment #8960975 -
Flags: review+
Assignee | ||
Comment 4•7 years ago
|
||
(In reply to Jan de Mooij [:jandem] from comment #2)
> static constexpr size_t boundWithSpaceCharsLength =
> mozilla::ArrayLength(boundWithSpaceChars) - 1; // No trailing '\0'.
It's a bit sad that std::char_traits::length() is only constexpr starting with c++17, because then we wouldn't need to handle the trailing '\0' case...
Assignee | ||
Comment 5•7 years ago
|
||
Try: https://treeherder.mozilla.org/#/jobs?repo=try&revision=fda78b7e464578358e20764819cee47cb68ccdd7
Keywords: checkin-needed
Pushed by apavel@mozilla.com:
https://hg.mozilla.org/integration/mozilla-inbound/rev/f56e2332d673
Avoid Atomize calls when binding a bound function. r=jandem
Keywords: checkin-needed
Comment 7•7 years ago
|
||
bugherder |
Status: ASSIGNED → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla61
You need to log in
before you can comment on or make changes to this bug.
Description
•