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

Rewrite script execution on top of ES #401

Merged
merged 3 commits into from
Dec 21, 2015
Merged

Rewrite script execution on top of ES #401

merged 3 commits into from
Dec 21, 2015

Conversation

domenic
Copy link
Member

@domenic domenic commented Dec 14, 2015

This is on top of #373; the first three commits are just that PR. However, I am making a separate PR because the changes here depend on tc39/ecma262#242, so this is not mergeable quite yet. It's ready for review though.


This brings the script execution parts of the spec up to date with the latest changes in ES. Notable changes include:

  • Removed of some generalization to allow non-JavaScript scripting languages (including XML-based ones).
  • Let ES track the execution context stack, and the corresponding stack of scripts; see Layering: track execution contexts' script/module tc39/ecma262#242. This allows us to stop tracking the stack of script settings objects, instead defining entry and incumbent settings objects with reference to ES. This is especially important since our current mechanism, of monkey-patching the SourceElement grammatical construction, no longer works since that grammar production has disappeared. Fixes Unclear distinction between "entry" and "incumbent" settings objects #155.
  • Established a direct correspondence between HTML's "script" concept and ES's Script Record/Module Record concepts. The former is stored in the [[HostDefined]] slot of the latter.
  • The process of parsing and executing scripts, including handling any resulting errors, is now formalized and appropriately calls out to ES's ParseScript and ScriptEvaluation abstract operations.

Note that we do not use the ECMAScript ScriptEvaluationJob or job queue for our script parsing/evaluation. That setup is overengineered and does not serve the needs of HTML; we hope to remove it from ES eventually. (See tc39/ecma262#240 (comment) for details.) Instead we simply use ParseScript and EvaluateScript directly.

This almost completes https://www.w3.org/Bugs/Public/show_bug.cgi?id=25981, with the remaining work item being to integrate promise jobs and ensure they are run as microtasks.

@domenic domenic added the do not merge yet Pull request must not be merged per rationale in comment label Dec 14, 2015
@domenic domenic force-pushed the es-init branch 2 times, most recently from da503bf to dcfaadc Compare December 15, 2015 15:38
@domenic
Copy link
Member Author

domenic commented Dec 15, 2015

Addressed most review comments, in a separate commit for ease of reviewing. The GitHub UI seems to have lost them so here is the link to the original commit where they were present: da503bf

@annevk
Copy link
Member

annevk commented Dec 15, 2015

(I made the comments on the commit directly as the other commits were not applicable to this PR. But I guess that means they do not get tracked as part of the PR review, which seems sad.)

@@ -77557,6 +77521,9 @@ dictionary <dfn>DragEventInit</dfn> : <span>MouseEventInit</span> {
navigations occur.</p>
</li>

<li><p>Let <var>realm execution context</var> be the <span>JavaScript execution context</span>
created.</p></li>
Copy link
Member

Choose a reason for hiding this comment

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

I realize I suggested this, but looking at it "created" probably makes more sense to appear before the term, don't you think?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's a bit of a weird case; I'm happy to go with whatever. Maybe I should patch ES to return the execution context from InitializeHostDefinedRealm() instead.

@annevk
Copy link
Member

annevk commented Dec 15, 2015

Is it fine to not always write realm as Realm? I think other than that this is okay, though having explicit review from the IDL editors would be great. Not sure if @heycam is on vacation too though.

@domenic
Copy link
Member Author

domenic commented Dec 15, 2015

I opened tc39/ecma262#252 about the capitalization of realm. I think it's an editorial issue with ES and they should not capitalize.

@domenic
Copy link
Member Author

domenic commented Dec 15, 2015

I added an additional commit addressing #193, please take a look. Also it looks like tc39/ecma262#242 is about to be merged so I'm looking for final LGTMs.

@domenic domenic assigned annevk and unassigned domenic Dec 15, 2015
@domenic domenic removed the do not merge yet Pull request must not be merged per rationale in comment label Dec 15, 2015
@domenic
Copy link
Member Author

domenic commented Dec 15, 2015

And I pushed my job queue integration commit into here as well. This finally gives us a normative specification for the fact that promises go on the microtask queue. /cc @bterlson @DigiTec.

@domenic
Copy link
Member Author

domenic commented Dec 15, 2015

OK, I guess ES is using Realm to mean Realm Record, per tc39/ecma262#252. I have capitalized it for the one place it is used in that sense here. The other places are in "realm execution context" where it is an adjective so I left it lowercase.

@domenic
Copy link
Member Author

domenic commented Dec 16, 2015

Newline nit fixed; ready for more review.

<p>If the user agent does not <span>support the scripting language</span> given by <var
data-x="concept-script-type">the script block's type</var> for this <code>script</code> element,
then the user agent must abort these steps at this point. The script is not executed.</p>
<p>Determine whether the <var>the script block's type</var> is a component-wise <span>ASCII
Copy link
Member

Choose a reason for hiding this comment

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

What does component-wise mean? Seems like that can be removed without changing the meaning?

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 idea was to match the previous text (in "support the scripting language"):

if each component of the script block's type is an ASCII case-insensitive match for the corresponding component in the MIME type string of a scripting language that the user agent implements.

I considered other phrasing, like

For each JavaScript MIME type, check whether the script block's type is an ASCII case-insensitive match for the corresponding component in the JavaScript MIME type string. If all such checks fail, then the user agent must abort these steps at this point.

But that seemed verbose and a bit confusing.

Upon reflection I think I agree you can just do a string comparison, so I will amend it as you suggest.

@domenic
Copy link
Member Author

domenic commented Dec 17, 2015

I guess I should add back "do not merge yet" until @bterlson pushes another snapshot for the JS spec. Bah, continuous deployment is so much nicer :).

@domenic domenic added the do not merge yet Pull request must not be merged per rationale in comment label Dec 17, 2015
@annevk
Copy link
Member

annevk commented Dec 17, 2015

I'll just note that what I reviewed looks good. I would be more comfortable with review from the IDL folks, but since @domenic is committed to maintaining this I'm fine with merging this once ECMAScript is ready and then seeking review from IDL folks on the merged text.

@domenic domenic assigned domenic and unassigned annevk Dec 18, 2015
@domenic domenic removed the do not merge yet Pull request must not be merged per rationale in comment label Dec 21, 2015
This brings the script execution parts of the spec up to date with the latest changes in ES. Notable changes include:

- Removed of some generalization to allow non-JavaScript scripting languages (including XML-based ones).
- Let ES track the execution context stack, and the corresponding stack of scripts; see tc39/ecma262#242. This allows us to stop tracking the stack of script settings objects, instead defining entry and incumbent settings objects with reference to ES. This is especially important since our current mechanism, of monkey-patching the SourceElement grammatical construction, no longer works since that grammar production has disappeared. Fixes #155.
- Established a direct correspondence between HTML's "script" concept and ES's Script Record/Module Record concepts. The former is stored in the [[HostDefined]] slot of the latter.
- The process of parsing and executing scripts, including handling any resulting errors, is now formalized and appropriately calls out to ES's ParseScript and ScriptEvaluation abstract operations.

Note that we do *not* use the ECMAScript ScriptEvaluationJob or job queue for our script parsing/evaluation. That setup is overengineered and does not serve the needs of HTML; we hope to remove it from ES eventually. (See tc39/ecma262#240 (comment) for details.) Instead we simply use ParseScript and EvaluateScript directly.

This almost completes https://www.w3.org/Bugs/Public/show_bug.cgi?id=25981, with the remaining work item being to integrate promise jobs and ensure they are run as microtasks.
This fixes #193, which notes that importScripts() previously sent errors down the "report an exception" path instead of rethrowing them. It also makes a slight change of rethrowing any early errors that are not SyntaxErrors, instead of converting early ReferenceErrors into SyntaxErrors.
This integrates with the ES job queue for promise jobs, by overriding ES's EnqueueJob and NextJob to delegate to the microtask queue. This finally gives us a normative specification for how promises interface with the browser event loop.

This approach of monkeypatching ES is necessary for now. See discussions in tc39/ecma262#240 (comment) about how this is the least-bad alternative. We hope to update ES to delegate to the host for those operations in the future, instead of overwriting ES. That possibility is discussed in replies to the linked comment.

Also fixes a few uses of "ECMAScript"; this specification prefers "JavaScript".

This completes https://www.w3.org/Bugs/Public/show_bug.cgi?id=25981.
@bzbarsky
Copy link
Contributor

bzbarsky commented Jan 7, 2016

@domenic The new definition of incumbent settings object seems broken to me.

In particular, I don't see how propagating it across Web IDL callbacks works. Think things like:

setTimeout(someWindow.postMessage.bind(someWindow, stuff), 0);

and what the incumbent settings object will be when postMessage is invoked. What will it be with the spec as it's written right now.

I assume the entry settings object in this case will be something sane-ish, in that it will be associated with the Function that is the return value of bind in this case, right?

@bzbarsky
Copy link
Contributor

bzbarsky commented Jan 7, 2016

Oh, and importantly are there ever JavaScript execution contexts that do not have a script or a module associated with them? If not, why not? What is the ScriptOrModule when the callback function is called in the case above?

@bzbarsky
Copy link
Contributor

bzbarsky commented Jan 7, 2016

Digging into the ES end of this a bit more, builtin functions have [[ScriptOrModule]] set to null, afaict. See https://tc39.github.io/ecma262/#sec-createbuiltinfunction

A bound function isn't even a Function object in terms of the ES spec, afaict. It's created in https://tc39.github.io/ecma262/#sec-boundfunctioncreate and just has a special [[Call]]. So it would not have a [[ScriptOrModule]] of its own. Given that, calling GetActiveScriptOrModule inside that postMessage invocation seems like it would fail the assert in step 5. This happens because https://tc39.github.io/ecma262/#sec-built-in-function-objects-call-thisargument-argumentslist will set the running execution context to the calleeContext, which gets F's [[ScriptOrModule]], which as noted above is null.

@bzbarsky
Copy link
Contributor

bzbarsky commented Jan 7, 2016

@domenic As far as entry settings objects... I'm not sure what "the script corresponding to the running execution context" is in the EnqueueJob section in the HTML spec. Why would there be such a script at all? See builtin functions above.

I'm not quite sure what used to set up entry settings objects for the case of callbacks backed by either builtin functions or worse yet bound builtin functions. And worse yet bound builtin where the bind comes from a different Realm than the builtin. A testcase:

<script>
  onerror = function() { console.log("Parent error"); }
  onload = function() {
    frames[0].onerror = function() { console.log("Child error"); };
    frames[0].setTimeout(document.querySelector.bind(document), 0);
    frames[0].setTimeout(frames[0].Function.prototype.bind.call(document.querySelector, document), 0);
  }
</script>
<iframe></iframe>

I believe the real intent of the spec as it stood before these changes is that this should log "Parent error" followed by "Child error", though it's worth testing what UAs actually do here. At least IE and Firefox and the spec used to agree on the first thing being logged being "Parent error" in this case, last I checked.

domenic added a commit that referenced this pull request May 4, 2016
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.
domenic added a commit that referenced this pull request May 19, 2016
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.
domenic added a commit that referenced this pull request May 20, 2016
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.
domenic added a commit that referenced this pull request Jun 1, 2016
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.
domenic added a commit that referenced this pull request Jun 3, 2016
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.
domenic added a commit that referenced this pull request Jun 14, 2016
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.
domenic added a commit that referenced this pull request Jun 15, 2016
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. However, we
noticed that it does not correctly track the entry settings object; the
previous text, introduced in #1091, incorrectly referred to
job.[[Realm]], which does not exist. The correct fix is unfortunately
not obvious. So we add a warning there for now, with #1426 tracking
further work.
@domenic domenic mentioned this pull request Jun 5, 2020
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

3 participants