-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Layering: Allow hosts to cleanly specify Promise Job semantics #1597
Conversation
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.
LGTM with nits. Very excited about this, and how it will also help fix whatwg/html#1426. <3 <3 <3
spec.html
Outdated
|
||
<p>HostEnqueuePromiseJob is a host-defined abstract operation that schedules the abstract operation indicated by _job_ to be performed, with the arguments _arguments_, at some future time. The Jobs used with this algorithm are intended to be related to the handling of Promises, or otherwise, to be scheduled with equal priority to Promise handling operations.</p> | ||
|
||
<p>The implementation of HostEnqueuePromiseJob must conform to the requirements in <emu-xref href="#sec-jobs-and-job-queues"></emu-xref>. Additionally, Jobs must be scheduled in FIFO order, with Jobs running in the same order as the HostEnqueuePromiseJob invocations which scheduled them.</p> |
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.
"Jobs must be scheduled in FIFO order" seems like a general requirement that belongs in the previous section (and I think the previous section already contains it, in different words?).
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.
The motivation for putting it in this section was that not all host job hooks will use it. For example, I don't think we want this to apply to WeakRef finalization callbacks. However, we will want it to apply to Atomics.waitAsync.
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.
The above general requirements state
The evaluation of any Jobs enqueueed via this or other host job scheduling algorithms must complete before evaluation of the Job starts.
This seems like the same requirement, applied to all jobs?
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.
I think the above requirement is more about run-to-completion (which applies to all host job hooks), and this requirement is about FIFO ordering (which only applies to some of them).
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.
I think I can see that reading now. Any jobs that have not yet started, don't trigger that clause.
In that case I think that clause should be deleted, since it comes right before an IMO-clearer statement:
Once evaluation of a Job starts, it must run to completion before evaluation of any other Job starts.
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.
OK, deleted; I agree that it's a bit redundant.
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.
This still hasn’t been deleted; is a new diff expected?
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.
What used to be at 6439 was deleted, following @domenic's recommendation.
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.
Does the phrase “in FIFO order” need to appear? It seems redundant with the prose immediately following it.
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.
It's slightly redundant for clarity. FIFO was present in the previous text, and the FIFO ordering was also clear from the RunJobs algorithm, so the wording here is analogous to that. If it's a big deal for you, I could move part of it to a note, but I think it's OK to have a single sentence with words that agree with each other.
The first commit message says:
Where's this annex? |
The annex was removed; you can see it in #735. We can squash this and change the commit message to clarify. |
Why was the annex removed? (I don't see any reasons given here or in #735. Will the June meeting notes have some discussion of it?) Without the Annex, the spec has no invocation of:
and no guidance or restrictions on if/when an implementation should invoke them. There isn't even a sentence to reassure the reader that the lack of invocation isn't a spec bug. I'm also wondering about the normative effect of not having any requirement that these operations ever 'run'; i.e., there's no requirement that the behavior they express ever happens. |
without the Script/Module jobs it isn't entirely clear how one actually runs a script or module. Maybe we should have |
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.
Existing comments imply another diff is impending?
spec.html
Outdated
<emu-clause id="sec-hostenqueuepromisejob" aoid="HostEnqueuePromiseJob"> | ||
<h1>HostEnqueuePromiseJob ( _job_, _arguments_ )</h1> | ||
|
||
<p>HostEnqueuePromiseJob is a host-defined abstract operation that schedules the abstract operation indicated by _job_ to be performed, with the arguments _arguments_, at some future time. The Jobs used with this algorithm are intended to be related to the handling of Promises, or otherwise, to be scheduled with equal priority to Promise handling operations.</p> |
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.
are there no consistent steps needed here? I’d expect, at the least, an assertion about the arguments passed to the abstract operation.
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.
This text follows the pattern of other host hooks in not having algorithm steps--the algorithm is provided by the host. The argument types are documented in this paragraph.
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.
This paragraph does not define the types - there is zero text that explicitly says that job
is a Job, and nothing that indicates that arguments
is a List or an Array (i assume), nor of what (presumably “any ECMAScript value”)
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.
The type of job is given ("the abstract operation indicated by job"). I suppose you could state "with the arguments given by arguments (a List)" if it's not clear enough from context.
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.
The argument name doesn’t guarantee what type it is.
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.
@ljharb: The phrase the abstract operation indicated by _job_
means that the parameter _job_
is (bound to) an abstract operation. Its type is 'abstract operation'. (In the world of this PR, there isn't really a distinct Job type.)
As for _arguments_
, you have to observe that HostEnqueuePromiseJob
is a job-scheduling operation as described in the parent clause, which gives the parameter types of such operations more precisely.
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.
Thanks for the clarification - this seems like a really obscure way to specify things. For example, why not make a Job a record with an abstract operation in a slot, so it’s a reified “thing” with its own type? (not suggesting doing that; it’s just that this approach seems very vague and hand-wavey and hard to understand without the context of how the HTML spec works, which shouldn’t be required in order to understand this spec)
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.
I don't think wrapper types is a good strategy for increasing clarity; it just creates an extra layer of abstraction that makes it less clear what is being operated on.
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.
I'd also point out that the job setup is inherited from the current spec, not something particularly tied to HTML. I agree that the current spec is pretty clear and close to how programming languages operate. E.g., process.nextTick(job)
in Node.js, and similarly function pointers in C/C++.
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.
why not make a Job a record with an abstract operation in a slot, so it’s a reified “thing” with its own type?
In the world of this PR, you can think of that record existing in the host environment, but it's not the spec's job to specify the host environment. (At least, not to that level of detail.)
I agree with @domenic that introducing such a record to this PR (e.g., reinstating PendingJob) would not increase clarity.
this approach seems very vague and hand-wavey
I think some of that is inevitable when the spec talks about the host environment and its interaction with the ES implementation. (On the other hand, I do think this PR could be clearer.)
spec.html
Outdated
|
||
<p>HostEnqueuePromiseJob is a host-defined abstract operation that schedules the abstract operation indicated by _job_ to be performed, with the arguments _arguments_, at some future time. The Jobs used with this algorithm are intended to be related to the handling of Promises, or otherwise, to be scheduled with equal priority to Promise handling operations.</p> | ||
|
||
<p>The implementation of HostEnqueuePromiseJob must conform to the requirements in <emu-xref href="#sec-jobs-and-job-queues"></emu-xref>. Additionally, Jobs must be scheduled in FIFO order, with Jobs running in the same order as the HostEnqueuePromiseJob invocations which scheduled them.</p> |
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.
This still hasn’t been deleted; is a new diff expected?
spec.html
Outdated
@@ -37913,7 +37740,7 @@ <h1>Promise Resolve Functions</h1> | |||
1. Let _thenAction_ be _then_.[[Value]]. | |||
1. If IsCallable(_thenAction_) is *false*, then | |||
1. Return FulfillPromise(_promise_, _resolution_). | |||
1. Perform EnqueueJob(`"PromiseJobs"`, PromiseResolveThenableJob, « _promise_, _resolution_, _thenAction_ »). | |||
1. Perform HostEnqueuePromiseJob(PromiseResolveThenableJob, « _promise_, _resolution_, _thenAction_ »). |
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 this produce an abrupt completion? If so, let’s prefix it with ?; if not, ! (same throughout)
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.
I would be happy to add ! here; any concerns?
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.
Then we should also add a sentence to the specification of HostEnqueuePromiseJob, like "An implementation of HostEnqueuePromiseJob must complete normally in all cases." (copied from HostReportErrors)
@devsnek @jmdyck I think it's a strict improvement that that, instead of a called-by-nothing RunJobs that matches no implementations (and was never required to be called), the world after this CL instead has InitializeHostDefinedRealm/ParseScript/ScriptEvaluation/ParseModule as top-level. Those, at least, have implementation counterparts. We could consider adding an annex (as my original PR did) that gives an example of all the host hooks, as well as an example of initial startup. But I don't think that's necessary for making this patch work, and I think it'd best be done as a follow-up so that it gets its own debate (as RunJobs never did) as to whether the spec is really in the business of providing example hosts. |
Note, the reason I omitted the annex was that people seemed to be objecting to it before. I am fine to add it back in, but I'd like to come to a conclusion here soon. This patch has already been waiting for years due to editorial disagreements. |
To be clear, I'm not disagreeing with that. I'm just saying that I think the spec needs to describe/architect/rationalize that world somewhat better than this PR does.
I'd be okay with that, assuming the spec-without-such-an-annex is understandable. Re example hosts: given the existence of test262, I think it would be useful if TC39 at least outlined an example host that is capable of processing the test suite in the intended manner. (But whether that description appears in ecma262 or test262 is another matter.) |
@jmdyck Interesting idea. Would you be interested in preparing a modification of this PR (e.g., as a PR against it) to draft out such a description? |
If you mean where I said the spec needs to better "describe/architect/rationalize" the world created by this PR, I'm not sure I know enough about implementations + hosts to do so. It feels like what's missing is a description of what a "host" is or does from the perspective of the ES spec (or an ES implementation?). And/or some constraints on when+how the host can invoke (the behavior represented by) the new 'top-level' abstract operations. |
I think what I'm asking for is something roughly like this: To a first approximation, the implementation provides functionality that the host can invoke.
The host can invoke these operations as many times as it likes, in any order, subject only to the constraint that a call to ScriptEvaluation() (with a given Script Record) must necessarily come after the call to ParseScript() that returned that Script Record, which in turn must necessarily come after the call to InitializeHostDefinedRealm() that created the realm passed to ParseScript(). And then all that similarly for the module side of things. But it's not clear to me how Jobs and Job queues and Agents fit into this description. Of course, it's actually far more complicated, because the host can do lots more than just invoke those top-level operations. |
spec.html
Outdated
1. Add _pending_ at the back of the Job Queue named by _queueName_. | ||
1. Return NormalCompletion(~empty~). | ||
</emu-alg> | ||
<p>Jobs are scheduled for execution by ECMAScript host environments with abstract operations such as HostEnqueuePromiseJob. Such operations accept two parameters: _job_, an abstract operation, and _arguments_, a list of ECMAScript values. These abstract operations schedule _job_ to be performed with _arguments_ at some future time. Their implementations must conform to the following requirements:</p> |
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.
"These abstract operations" is initially ambiguous, because both the job-enqueuer and the job itself are abstract operations, and the previous sentence refers to both. Reading further in the sentence resolves the ambiguity, but it would be easier to read if the ambiguity wren't there at all. One way to avoid it would be to introduce a name for the class of job-enqueuing operations.
spec.html
Outdated
<p>Jobs are scheduled for execution by ECMAScript host environments with abstract operations such as HostEnqueuePromiseJob. Such operations accept two parameters: _job_, an abstract operation, and _arguments_, a list of ECMAScript values. These abstract operations schedule _job_ to be performed with _arguments_ at some future time. Their implementations must conform to the following requirements:</p> | ||
|
||
<ul> | ||
<li>At some future point in time, when there is no running execution context and the execution context stack is empty, the implementation must: |
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.
Since the preamble to this <ul>
ends with "Their implementations must conform to the following requirements:", it's tempting to think that "the implementation" here refers to the same thing, i.e. the (host's) implementation of a job-enqueing operation. But it could also mean what it usually means elsewhere in the spec (roughly, the ECMAScript engine).
But neither option entirely makes sense to me.
- The implementation of a job-enqueuing operation is basically just "append this job to a queue". What happens when the jobs runs isn't the responsibility of the enqueuing operation.
- If it's the ECMAScript engine doing the following steps (which, by itself, seems to make sense), how does the job get from a host-maintained queue to the engine? It seems like there needs to be a
RunJob
operation that the host can call to get the engine to do this.
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.
Also, it's unclear how the the execution context stack would ever be empty. Specifically, InitializeHostDefinedRealm pushes an execution context onto the stack; what would ever pop that context from the stack?
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.
The implementation of a job-enqueuing operation is basically just "append this job to a queue". What happens when the jobs runs isn't the responsibility of the enqueuing operation.
This isn't correct. See e.g. https://html.spec.whatwg.org/multipage/webappapis.html#enqueuejob(queuename,-job,-arguments) for what can be involved here. It is not simple at all, and the enqueuing operation is intimately tied to the event loop, which in turn works to give these guarantees.
If you haven't familiarized yourself with @littledan's presentation on this PR, that might be a good way of getting some shared context.
Also, it's unclear how the the execution context stack would ever be empty. Specifically, InitializeHostDefinedRealm pushes an execution context onto the stack; what would ever pop that context from the stack?
In HTML the stack is popped immediately upon creation. The stack-pushing is just a kind of weird way of getting a return value out of InitializeHostDefinedRealm(). See https://html.spec.whatwg.org/multipage/webappapis.html#creating-a-new-javascript-realm.
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.
The implementation of a job-enqueuing operation is basically just "append this job to a queue". What happens when the jobs runs isn't the responsibility of the enqueuing operation.
This isn't correct. See e.g. https://html.spec.whatwg.org/multipage/webappapis.html#enqueuejob(queuename,-job,-arguments) for what can be involved here. It is not simple at all, and the enqueuing operation is intimately tied to the event loop, which in turn works to give these guarantees.
Sorry, yes, the host can make this as complicated as it likes, I was looking at it from the implementation's/engine's point of view. (I think.)
But even so, I'm still not sure which meaning of "the implementation" is intended.
If you haven't familiarized yourself with @littledan's presentation on this PR, that might be a good way of getting some shared context.
Sure. This one?
Also, it's unclear how the the execution context stack would ever be empty. Specifically, InitializeHostDefinedRealm pushes an execution context onto the stack; what would ever pop that context from the stack?
In HTML the stack is popped immediately upon creation.
Sneaky!
The stack-pushing is just a kind of weird way of getting a return value out of InitializeHostDefinedRealm(). See https://html.spec.whatwg.org/multipage/webappapis.html#creating-a-new-javascript-realm.
Ah, so that fits with my suggestion that InitializeHostDefinedRealm() needs to return the Realm Record that it creates.
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.
I've read @littledan's presentation a few times now (assuming I got the right one). I don't think it answers any of the questions I've asked so far, but maybe answers some I haven't asked yet.
Thanks for the HTML links. One thing that hadn't quite clicked for me before was that an HTML user agent can manipulate the ES execution stack. (This feels a bit odd to me, since the ES spec doesn't mention that possibility when it describes the stack.)
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.
I wouldn't mind looking into cleaning up this aspect of layering further in a follow-on PR.
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.
"Clean up" as in refactor the spec so that the host doesn't have to directly manipulate the stack? That'd be nice. (In a follow-on PR, agreed.)
I'd like to echo the sentiments upthread that such additions be pursued as a separate PR after this one lands. We're just trying to implement the committee consensus from the June meeting here. Let's not scope-creep this into something bigger that will require another two-month (or two-year) roundtrip. |
Nit: I wonder if "job" should be de-capitalized throughout? There used to be a Job Record type, and we capitalize record type names, but not the names of abstract concepts, which are now what jobs are. I think "promise" definitely should be lowercased as well. (Example existing usages.) |
I don't see any such sentiments. The closest I see is where you said:
And I said I'd be okay with that, but that was talking about an annex of examples, which is not what I was asking for. Moreover, I was responding to @littledan's invitation to prepare a modification of this PR, so that's counter to the sentiments you refer to.
And I'm just trying to make sure that the resulting spec makes sense.
I'll accept the editors' decision. |
spec.html
Outdated
</ul> | ||
|
||
<emu-clause id="sec-hostenqueuepromisejob" aoid="HostEnqueuePromiseJob"> | ||
<h1>HostEnqueuePromiseJob ( _job_, _arguments_ )</h1> |
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.
So sometime between @littledan's presentation and this PR,
HostEnqueueJob("Foo", _job_, _args_)
got replaced with
HostEnqueueFooJob(_job_, _args_)
(roughly speaking).
Why's that?
It seems like defining a single job-enqueuing operation would be simpler than defining a 'class' of them.
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.
We discussed the two alternatives that the slides presented in the TC39 meeting, and the consensus there (at least shared by me, @domenic, and @erights, if I understood correctly; I don't remember hearing opinions from others) was that hook-per-job is easier to understand and more flexible. This way, we can define different invariants for different hooks. For example, WeakRef finalizer callbacks should not be FIFO but rather considered unordered, whereas Promise-related job hooks should be ordered.
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.
We discussed the two alternatives that the slides presented
(I'm not positive we're talking about the same thing, because I don't see the slides presenting what I'm suggesting. Are you thinking of the "One-off callbacks" alternative? I'm not.)
Anyhow, it seems to me the spec could as easily attach an invariant to a particular argument value as to a particular operation. E.g.: Jobs enqueued with _kind_ = "Promise" must be scheduled in FIFO order.
No difference in flexibility there.
As for the "easier to understand" claim, I don't get it. I mean, I could see it if different kinds of jobs needed to supply different extra information when they were enqueued. But the PR says that every job-enqueuing operation accepts the same two parameters.
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.
Yes, I was talking about PR #735 vs one-off callbacks (this PR). I am not sure what other option you are thinking of.
I agree, we could do that. We discussed these two options in TC39 and settled on one-off callbacks as subjectively simpler. The decision here is editorial, and we can iterate on it over time.
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.
one-off callbacks (this PR)
Well, now I'm really confused, because one-off callbacks ("No use of Jobs") doesn't appear to be what this PR is doing.
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.
So here's what I think you're saying: the consensus was that the presentation's second alternative (one-off callbacks, no use of jobs) was more flexible and easier to understand than the first (HostEnqueueJob
), but rather than adopt one-off callbacks, you moved (for the purposes of this PR) part-way in that direction, from HostEnqueueJob
to HostEnqueueFooJob
. Have I got that right?
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.
If I understand you correctly, yes.
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.
Okay, good. But that still leaves me puzzled on 2 fronts:
-
If one-off callbacks were deemed better, why not just adopt one-off callbacks?
-
I still don't get why it's deemed more flexible and easier to understand.
You gave the example of specifying invariants, and I pointed out that invariants can be attached regardless. Or consider the example of a one-off callback from the presentation; I can imagine defining the operation:
HostCleanupFinalizationGroup(_fg_)
1. Return HostEnqueueJob("whatever", CleanupFinalizationGroup, << _fg_ >>).
If I can "implement" a one-off callback using HostEnqueueJob
, then a one-off callback doesn't seem to be more flexible. (If it's deemed to have expositional benefit, we'd be free to retain it but define it as above. Of course, then it wouldn't be a "Host" operation, so name-change.)
In terms of flexibility, the three approaches look about the same to me.
But in other ways, HostEnqueueJob
seems to me to be better: less to specify, less to understand, and less for downstream specs to have to deal with.
So I'm probably missing something. But what?
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.
-
For Promises, there are several different algorithms that need to be run, scheduled in the same way. So there's still value in passing around an abstract algorithm, while having these callbacks per type of scheduling.
-
Yes, there are other ways of attaching invariants, and we could do it with HostEnqueueJob. We could have a string parameter, and specify the invariants to be related to what the string is. I see this as an extremely minor editorial difference compared to the patch under discussion.Tor me, it feels marginally cleaner to attach invariants to a whole algorithm rather than to the particular string. But we could go the other way; it just isn't a big deal. You probably aren't missing much.
I don't really understand why HostEnqueueJob would be less to specify or understand. There would probably be more lines of spec text, since we'd have to break things up by the queue name on both the JS and host environment side anyway. It would be sort of like, in a computer program, merging a few functions together with a switch statement at the top, so that we have fewer functions that you have to think about.
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.
Re 1: I think I agree.
2. I see this as an extremely minor editorial difference
I agree that it's editorial. But given that it's an interface that downstream specs will probably reference, I don't think it's "extremely minor".
compared to the patch under discussion.To me, it feels marginally cleaner to attach invariants to a whole algorithm rather than to the particular string. But we could go the other way; it just isn't a big deal.
I don't really understand why HostEnqueueJob would be less to specify or understand.
Because it's one operation rather than many.
There would probably be more lines of spec text,
I doubt it. Each new HostEnqueueFooJob operation would have some boilerplate overhead.
since we'd have to break things up by the queue name on both the JS and host environment side anyway.
Not quite sure what you mean.
It would be sort of like, in a computer program, merging a few functions together with a switch statement at the top, so that we have fewer functions that you have to think about.
Sort of.
@jmdyck I would still welcome a PR against this branch for any clarifications you'd like to make. I don't quite understand what issues you see here, so such a PR would be helpful to drive this discussion forward. |
Yeah, but that's tough when I can't (yet) see the June meeting notes. I could spend hours on a PR that (for all I know) goes counter to the committee's consensus. (Which is why I've asked for more information about why this PR is the way it is.)
My main issue is the spec's lack of clarity about the interface/interaction between the ES implementation and the host environment. I know that that's a bigger problem than this PR, and it's not this PR's job to make it all better. But it would be nice if it at least didn't make things worse. I'm not convinced that a PR against this branch would be the best way to move the discussion forward, but I can give it a shot. |
@littledan, could you rebase this branch against master? The anachronisms are causing me some problems. |
@littledan: I mean, I'd be okay with doing the rebase myself, but I don't know if delivering the resulting |
5a0d850
to
a832c38
Compare
Rebased. I think this is ready to land, but nevertheless, I'm looking forward to @jmdyck 's PR if he wants to propose an alternative. |
@jmdyck Can we discuss your possible variant after this patch lands, or should we keep waiting for you to propose it? |
Thanks for rebasing. I've been trying to get other things out of the way before getting back to this PR. I hope to start paging it back in today. In the meantime, do you have any thoughts on my June 25th comment? |
spec.html
Outdated
<ul> | ||
<li>At some future point in time, when there is no running execution context and the execution context stack is empty, the implementation must: | ||
<ol> | ||
<li>Push an execution context onto the execution context stack.</li> |
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.
I think we should describe here how to set up the environment, setting [[ScriptOrModule]] and [[Function]] and such.
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.
The wording here matches wording about execution contexts elsewhere in the specification. I wouldn't be opposed to the broader editorial change, but I think it's a separate issue.
In tc39#1597 (comment) @domenic points out that: > The stack-pushing is just a kind of weird way of getting > a return value out of InitializeHostDefinedRealm(). This PR should simplify https://html.spec.whatwg.org/multipage/webappapis.html#creating-a-new-javascript-realm
I hope we can separate what HTML calls the "entry" realm semantics/layering (which has multiple implementer support and is part of the HTML living standard) from incumbent realm semantics (where I don't know if we have multiple implementer support). Let's focus on the entry realm for now. |
I'll preserve
as oldids to sec-jobs. I'll preserve
to the obvious renames. I'm going to leave out
Because it's probably clearer if they're obviously gone. |
Yeah, let's follow up with incumbents later. It's a more complicated thing and certainly shouldn't block this PR. |
@domenic We have an underspecified corner here. Getting the [[Realm]] of callables is fallible because of handlerless Proxy values. HTML currently doesn't specify what happens if we hit that case. Handlerless Proxy are kinda like |
Amazing... So in this case the job would throw a TypeError, per proxy [[Call]]. I think null will work here, as no author code is run, just the ES-spec-throwing. So our current treatment of null (which is used when the handler is one of the built-in identity or thrower ones) will also work for this case. This also effects Web IDL in general, I think. I will file a separate issue. |
If GetFunctionRealm throws on the handler for a PromiseReactionJob, should that promise be rejected at time of being enqueued (and thus not enqueue a microtask at all), or should a ReactionJob be enqueued as normal, which then rejects the promise when it actually runs? What this PR currently does is reject the promise when the microtask runs, not when enqueued. It swallows the error at enqueues time and enqueue the job in the host with a FWIW Chrome implements this behavior. When V8 can't extract the context from the handler, it'll fall back to the currently entered context and enqueue a microtask on that context. When that microtask runs, the promise is rejected because the Proxy throws on being called. |
That behavior makes sense to me. After all, you could revoke the proxy between the enqueuing and the running of the microtask, so we'll need this check anyway. Any earlier check would just be for catching the issue earlier, which for this kind of edge case, doesn't seem worth it. |
I like this. It is consistent with the proxy still having a (Plus that is the behavior normatively required by ECMA-262 prior to this PR, as far as I can tell.) |
…1597) This layering change retains the PendingJob concept but sends PendingJob records off to the host to be dispatched at the appropriate time, replacing the RunJobs algorithm. The change is expected to help specify the interaction between Promises, WeakRefs and the Web more precisely, while maintaining all current invariants. Co-authored-by: Domenic Denicola <d@domenic.me> Co-authored-by: Daniel Ehrenberg <littledan@chromium.org> Co-authored-by: Shu-yu Guo <syg@chromium.org>
043669d
to
3588286
Compare
…1597) This layering change retains the PendingJob concept but sends PendingJob records off to the host to be dispatched at the appropriate time, replacing the RunJobs algorithm. The change is expected to help specify the interaction between Promises, WeakRefs and the Web more precisely, while maintaining all current invariants. Co-authored-by: Domenic Denicola <d@domenic.me> Co-authored-by: Daniel Ehrenberg <littledan@chromium.org> Co-authored-by: Shu-yu Guo <syg@chromium.org>
3588286
to
c595020
Compare
|
Are the editors planning on making any further editorial changes in follow-on patches, or is this the final version? Do you plan to follow up with changes to whatwg/html#4722 to match the changes here? (Or do you prefer to leave that to me? Either way is fine with me.) |
No other algorithm step creates a record value without some kind of name prefix before the open-brace. (re tc39#1597)
Replace the EnqueueJob abstract operation with a HostEnqueuePromiseJob operation, responsible for asking the host to schedule the PromiseJob, and run it in a way that preserves the run-to-completion nature of JavaScript. As it is a host hook and not an algorithm, the invariants are specified declaratively, rather than imperatively as previously.
This PR implements the conclusion of the discussion in the June 2019 TC39 discussion on Promise scheduling and host layering.
Replaces #735
cc @erights