-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Fix and expand incumbent settings object definition #1189
Conversation
</div> | ||
|
||
<div class="example"> | ||
<p>Consider the following more complicated example:</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.
I would group these divs into one and start this paragraph with "Now".
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.
They're separate examples though...
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.
Yeah never mind.
Ping @bzbarsky to review if possible :) |
This is totally on my list to review, but likely not happening until tomorrow or Friday. |
<p class="note">This assert would fail if you try to obtain the <span>incumbent settings | ||
object</span> from inside an algorithm that was triggered neither by <a | ||
href="#calling-scripts">calling scripts</a> nor by Web IDL <span | ||
data-x="es-invoking-callback-functions">invoking</span> a callback. For example, it would |
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.
Aren't Promise jobs an example of something that is not triggered by either one of those? Again, if we think this incumbent thing is needed we need to make it play nice with Promise jobs too...
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.
You're right. But, good news: handling this turned out to be easier than I thought. I've pushed a second commit which I think takes care of the issue. I'd appreciate a review.
This generally looks great, thanks! |
Oh, and we presumably still need IDL changes here too, right, to push/pop stuff onto this stack? |
353d634
to
f6cd609
Compare
Yeah, that's still needed. Hoping to land the entry stuff first, then do incumbent as a follow-up. |
f6cd609
to
2508c60
Compare
Ping @bzbarsky to review again now that I think I've fixed promise jobs as well.
If you prefer the diff there are two separate commits. |
Thank you. So I was reading through this again carefully... and I'm not sure it works as we have it now. Consider the case when script in document A adds a bound builtin function as an event listener to a node. Then script in document B calls Per proposed spec, what will happen? The EnqueueJob bits look ok, except for the obvious problem of being a monkeypatch. :( I'm not sure what we can do about that, though, short of the ES spec admitting that someone else might be managing the job queue. |
2508c60
to
6168b4a
Compare
Sorry for the delay! TC39 week and subsequent recovery is my excuse. For the record I translated your prose into an example, which I'll dump here for reference: <!-- a.html -->
<!DOCTYPE html>
<button>click me</button>
<script>
const bound = window.postMessage.bind(window, "some data", "*");
document.querySelector("button").addEventListener("click", bound);
</script>
<!-- b.html -->
<!DOCTYPE html>
<iframe src="a.html"></iframe>
<script>
const iframe = document.querySelector("iframe");
iframe.onload = () => {
iframe.contentWindow.document.querySelector("button").click();
};
</script> I agree that the spec in this PR will set the incumbent settings object while Of course I'm not arguing that we should change implementations' concept of incumbent settings object to match my intuition; since we're considering it largely legacy anyway, I just want to match what was in place before. So, assuming document B is not what implementations do, could you give any suggestions for better intuition? Perhaps even suggested algorithms, based on what Firefox does?
I've actually talked about this with the editor, and he's amenable to that. It just hasn't been too high priority to fix yet. So there's hope :) |
It's incorrect if we want the "you can't change what incumbent a function to some other code that is not you merely by running it async through some platform API" invariant.
The thing that takes the place of Note that "legacy" is not a useful argument here because I think only Gecko actually implements the invariant I describe above. Again, that invariant is an absolute must-have if the incumbent global is ever used for anything security-related. If it's not, then it probably doesn't matter very much what the incumbent global actually is in various edge cases... What Firefox does is the following:
|
When are things pushed/popped onto the incumbent settings stack? Is it equivalent to the spec's backup incumbent settings object stack, i.e. it's manipulated by Web IDL invoking things? |
When Web IDL callbacks are invoked. Each Web IDL callback stores the incumbent settings object from its creation and pushes it onto the incumbent settings stack before running. So yes, I think it's equivalent to the backup incumbent settings stack. |
OK, great. With that in mind, here's my draft for how to just copy Firefox's approach. I can't imagine anything we come up with will be substantially better so that seems like a good idea. Add incumbent counter to code evaluation state for every execution context (not just realm execution contexts), initially zero. Add operation: set up for invoking a callback callback with environment settings object settings
Add operation: clean up after invoking a callback callback with environment settings object settings
Then, change Web IDL's current usage of "Prepare to run script with settings" and "clean up after running script with settings" usage inside its four invoke-callback algorithms to use these instead. Also, the PromiseReactionJob patch would need to add similar steps to manage the incumbent counter. I guess we'd then delete GetActiveScriptOrModule() from ES as it's no longer used. Let me know what you think of the above draft. If it makes sense to you, I'll work on turning it into a real pull request this week. |
That, plus changes to how the actual incumbent settings is determined, makes sense. When popping off the backup incumbent settings object stack, we should be able to assert that the topmost thing is the callback's callback context.... |
Oh, right, of course, I forgot that part. Is this correct? Seems a little sketchy...
(Maybe "incumbent counter" is not great, since it's used to determine whether it's not the incumbent... suggestions appreciated.)
That sounds like a good tweak. I'll replace step 4 of the cleanup with
|
3ed7d2f
to
8f57009
Compare
OK, so, I think I've got this all written up. Rendered versions: I've also submitted a Web IDL pull request at whatwg/webidl#128. (There's no real order in which to land or review the two; they basically need to be landed at the same time.) You can view the rendered version of that as well. If you follow the dfn.js popups starting at callback context you should see all the changes. |
Ping @bzbarsky to review this and whatwg/webidl#128. |
Sorry for the lag on this. :( The incumbent section looks good to me. The In terms of the actual behavior we want here, by the way, I would think we want the entry settings to be the same when
In the first case, the entry settings corresponds to the Realm of Oh, and the
followed by resolving somePromise, then we have to start digging into what Realm we're in when we resolve the promise that is the return value of the first |
Oh, dang, that's obviously wrong; thank you. We should be able to ignore PendingJobs, and their problematic [[Realm]] fields, entirely. So the problem is we don't have the proper settings with which to "prepare to run a script", in order to make entry settings work. But this is solvable. We just want to do the thing analogous to what Web IDL does, which is grab the realm of the callback. EnqueueJob doesn't have that information right now, it's true. But we can patch ES to give it to us. I'm not sure exactly how to do this, however:
These problems feel very similar to those faced by the I guess the attraction of the PendingJob [[Realm]] is that it basically just grabs the current realm and bypasses all this heartache, but as you said that leads to some weird scenarios. |
For I'm pretty sure that's what Gecko does: take the actual callable we plan to invoke, and use it to get the entry settings. For
Yes, but that comes from I think the only real headache with promises is whether we can land in a promise resolve function somehow without already having an entry settings on the stack. I hope not, because it does a |
The problem is you could invoke either, or both. Consider this more in-depth example: class SubPromise extends Promise {
constructor(executor) {
super((builtInResolve, builtInReject) => {
executor(
function a(x) {
console.log("a");
resolve(x + 1); // (*)
},
function b(x) {
console.log("b");
reject(x - 1);
}
);
});
}
}
const p1 = SubPromise.resolve(5).then(function c() { throw new Error("argh"); });
const p2 = SubPromise.resolve(5).then(undefined); In both cases, PromiseReactionJob is enqueued at (*). For the p1 case, reaction.[[Handler]] is Do you think it's OK to just use
Oh, you're right. OK, that's nice...
I don't believe you can, as long as we plug the gaps in EnqueueJob. (Promise resolve functions are the default [[Resolve]] of a promise capability object, so if we don't, we're in trouble.) |
In Gecko right now, I believe we invoke In the new setup being worked on that moves Promises out of Gecko and into SpiderMonkey... I'm not actually sure. I'll check....
It's possible to resolve promises not off a job, right? I mean, in specs that are not ES that are using Promises. |
Yeah, this would be hard to do from a spec point of view :(. Curious what your investigations turn up for the SpiderMonkey version...
Ugh, I think you are right. In most cases they are being resolved with newly-created objects, not ones that could have |
That code is still being reviewed, but it looks to me that in the new setup's proposed patch at https://bug911216.bmoattachments.org/attachment.cgi?id=8761429 |
As discussed in #473, starting especially from around #473 (comment), the definition of incumbent introduced in #401 falls down in certain important cases. In order to fix this, we introduce several new concepts, which takes care of these trickier examples. These examples are now included in the spec, and spell out exactly how exactly incumbent settings object calculation works in increasingly-complex scenarios. The new algorithms "prepare to run a callback" and "clean up after running a callback" will be used by Web IDL, similarly to how it already uses "prepare to run script" and "clean up after running script." Another notable change is that EnqueueJob now correctly tracks the necessary goings-on in order to make the incumbent settings object work correctly when promises are used to schedule callbacks.
8f57009
to
9c25103
Compare
OK, so in the interests of moving this forward, I've changed it to the following:
I think that should be enough to make incremental progress, and merge this and the counterpart Web IDL PR. Let me know if you disagree. |
That seems fine, but we should have a followup issue for sorting Jobs out. |
fwiw v8 tracks the Realm the promise constructor came from that was used to create the promise |
As discussed in #473, starting especially from around
#473 (comment), the
definition of incumbent introduced in #401 falls down in certain
important cases. In order to fix this, we introduce the "backup
incumbent settings object stack", which takes care of these trickier
cases. This commit also adds a few examples of how exactly incumbent
settings object calculation works, especially in the case where the
backup incumbent settings object stack ends up mattering.
For this story to be fully coherent, we will also need the minor fixes
found in tc39/ecma262#556, as well as further revisions to Web IDL to
update it for this new framework. This commit is the first step,
however.
@bzbarsky review appreciated!!