Skip to content
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

Editorial: refactor PerformPromiseThen to allow no capability #1146

Merged
merged 1 commit into from
Aug 9, 2018

Conversation

ljharb
Copy link
Member

@ljharb ljharb commented Mar 21, 2018

Fixes #694.

I followed @domenic's steps in the linked issue here; I'm not sure if other changes are needed.

Specifically, which PerformPromiseThen calls should now be able to omit a capability?

@domenic
Copy link
Member

domenic commented Mar 21, 2018

Search for "throwawayCapability"

@ljharb ljharb force-pushed the promise_undefined_capability branch from 578f37b to a1234e9 Compare March 21, 2018 16:57
@ljharb
Copy link
Member Author

ljharb commented Mar 21, 2018

@domenic thanks, updated!

@ljharb ljharb force-pushed the promise_undefined_capability branch from a1234e9 to 9a77b53 Compare April 17, 2018 23:07
Copy link
Member

@domenic domenic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few small things missing. Sorry for the massive delay!

spec.html Outdated
1. If _resultCapability_ is present, then
1. Assert: _resultCapability_ is a PromiseCapability Record.
1. Else,
1. Set _resultCapability to *undefined*.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing _

I think maybe you should use "Let" here instead of "Set" since the variable doesn't technically exist yet? (Which might argue for moving the else clause into a single line, so the "block scoping" is less confusing.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable exists because it's in the abstract operation signature, so I think "Set" is correct.

Thanks, I've added the underscore

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I guess that depends on how you interpret "is present", but your way makes sense too.

spec.html Outdated
@@ -38204,7 +38202,7 @@ <h1>AsyncGeneratorRequest Records</h1>
</tr>
<tr>
<td>[[Capability]]</td>
<td>A PromiseCapability record</td>
<td>A PromiseCapability record, or *undefined*</td>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you meant to edit PromiseReaction, not AsyncGeneratorRequest.

spec.html Outdated
@@ -39095,11 +39094,14 @@ <h1>Promise.prototype.then ( _onFulfilled_, _onRejected_ )</h1>

<!-- es6num="25.4.5.3.1" -->
<emu-clause id="sec-performpromisethen" aoid="PerformPromiseThen">
<h1>PerformPromiseThen ( _promise_, _onFulfilled_, _onRejected_, _resultCapability_ )</h1>
<h1>PerformPromiseThen ( _promise_, _onFulfilled_, _onRejected_ [ , _resultCapability_ ] )</h1>
<p>The abstract operation PerformPromiseThen performs the &ldquo;then&rdquo; operation on _promise_ using _onFulfilled_ and _onRejected_ as its settlement actions. The result is _resultCapability_'s promise.</p>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should modify the intro text. Suggestion:

If resultCapability is passed, the result is stored by updating resultCapability's promise. (If it is not passed, then PerformPromiseThen is being called by a specification-internal operation where the result does not matter.)

@ljharb ljharb force-pushed the promise_undefined_capability branch from 9a77b53 to 71e8b85 Compare April 20, 2018 21:31
@ljharb
Copy link
Member Author

ljharb commented Apr 20, 2018

Thanks, updated!

@bterlson bterlson assigned ljharb and unassigned bterlson Jun 4, 2018
@ljharb
Copy link
Member Author

ljharb commented Jun 4, 2018

@anba @domenic @gsathya @msaboff any objections to merging this editorial change into ES2018?

@ljharb ljharb force-pushed the promise_undefined_capability branch from 71e8b85 to 414666d Compare June 4, 2018 18:12
@domenic
Copy link
Member

domenic commented Jun 4, 2018

I don't like spending resources on snapshots, but whatevs...

@littledan
Copy link
Member

@MayaLekova We chatted about this change and it sounded like you might have had some reservations about it. Are any embedding environments depending on the throwaway Promise, based on embedder-specific hooks into the Promise lifecycle, even if it's unobservable without those hooks?

@MayaLekova
Copy link
Contributor

For now it seems we won't fire the promise hooks on the throwawayPromise, don't know if this is the only change. @ak239 - please comment as well!

@alexkozy
Copy link

On DevTools side to implement async stacks we rely on kBefore and kAfter hook calls for throwaway promise:

  • each time when async function is suspended - we capture stack trace at this moment,
  • when async function is resumed next time - we use kBefore and kAfter hooks - between these hooks we use captured async stack as current one.

From implementation point of view I believe we can instrument microtask by itself with inspector-only hooks or we can stop using promise hooks at all by proper instrumentation async function suspended, async function resumed and async function finished. It will work for us but I am not sure about some external developers who relies on promise hooks.

@littledan
Copy link
Member

@ak239 Could you explain more how DevTools currently takes advantage of the kBefore and kAfter events related to the throwawayPromise?

@alexkozy
Copy link

When function is suspended we get instrumentation call with async function promise as argument and record stack trace for this promise.
On await we record mapping between throwaway promise and async function promise and expect that when async function is running next time we will get kBefore hook with throwaway promise before that run and kAfter hook after. We use recorded mapping between throwaway and async function promise here to map these hooks to async function.

As external developer I think that I can use:

  • kInit when throwaway promise is created to capture stack,
  • kBefore and kAfter when async function is resumed to set captured stack as current one.

What we actually would like to have: instrumentation every time when async function suspended, every time when async function is resumed and once when async function finished.

@alexkozy
Copy link

alexkozy commented Jun 26, 2018

On inspector side we can implement required for us instrumentation without using throwawayPromise: PoC. So from inspector point of view this PR looks good to me.

I am not sure how important it is to provide these hooks for developers.

@bmeurer
Copy link

bmeurer commented Jul 10, 2018

@littledan @domenic @ljharb Any other roadblocks left to have this merged?

@ljharb ljharb force-pushed the promise_undefined_capability branch from 414666d to 689a396 Compare July 11, 2018 18:58
@ljharb ljharb assigned bterlson and unassigned ljharb Jul 11, 2018
@ljharb ljharb assigned ljharb and unassigned bterlson Aug 9, 2018
@ljharb ljharb force-pushed the promise_undefined_capability branch from 689a396 to 5e93e1b Compare August 9, 2018 20:03
@ljharb ljharb force-pushed the promise_undefined_capability branch from 5e93e1b to a7139c5 Compare August 9, 2018 20:03
@ljharb ljharb merged commit a7139c5 into tc39:master Aug 9, 2018
@ljharb ljharb deleted the promise_undefined_capability branch August 9, 2018 21:34
peterwmwong pushed a commit to peterwmwong/v8 that referenced this pull request Oct 15, 2018
…o capability".

This implements the editorial change in tc39/ecma262#1146
which removes the need to allocate the throwaway promise in await (the throwaway
promise was not exposed to user JavaScript anyways, but this spec change allows
us to rely on this behavior). Now we still need the throwaway promise for proper
before and after events with both DevTools (which might change) and PromiseHooks.
So if either DevTools or PromiseHooks is on, we call into %AwaitPromisesInit,
which then allocates the throwaway promise and does all the other debugger/hooks
related setup.

This gives around 7% improvement on the doxbee-async-es2017-native and around 1-2%
on the parallel-async-es2017-native benchmarks.

Bug: v8:7253, v8:8285
Ref: tc39/ecma262#1146
Tbr: [email protected]
Change-Id: I972ba0538ec8c00808e95b183603025c7e55a6d3
Cq-Include-Trybots: luci.chromium.try:linux_chromium_headless_rel;luci.chromium.try:linux_chromium_rel_ng;master.tryserver.blink:linux_trusty_blink_rel
Reviewed-on: https://chromium-review.googlesource.com/c/1270798
Commit-Queue: Benedikt Meurer <[email protected]>
Reviewed-by: Benedikt Meurer <[email protected]>
Reviewed-by: Maya Lekova <[email protected]>
Reviewed-by: Sathya Gunasekaran <[email protected]>
Cr-Commit-Position: refs/heads/master@{#56506}
joyeecheung pushed a commit to joyeecheung/v8 that referenced this pull request Oct 25, 2018
This CL introduces a new fast-path for `Promise.all(a)` for the case
that elements in `a` are native promises, and the Promise.prototype
and Promise function itself are intact. If so, we can skip the lookups
of "resolve" on Promise and "then" on the result of invoking "resolve",
which are both quite expensive, and we can instead directly call the
PerformPromiseThen() operation on the element of `a`.

In addition to that we don't need to create and chain a result promise,
since this is only used when either async_hooks or DevTools are enabled.
Otherwise it's a "throwaway promise" only used to satisfy the operation
parameter signature (see tc39/ecma262#1146).

This results in a significant performance improvement on `Promise.all()`
heavy code. For example the parallel-promises-es2015-native test goes
from around 84ms to roughly 68ms, which is almost a 20% improvement.

Bug: v8:7253
Ref: tc39/ecma262#1146
Change-Id: Iab9c57edb26d13a467b0653fd8de6149c382efc6
Reviewed-on: https://chromium-review.googlesource.com/c/1293374
Reviewed-by: Sathya Gunasekaran <[email protected]>
Reviewed-by: Maya Lekova <[email protected]>
Commit-Queue: Benedikt Meurer <[email protected]>
Cr-Commit-Position: refs/heads/master@{#56858}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants