Skip to content

Commit

Permalink
Fix and expand incumbent settings object definition
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
domenic committed May 4, 2016
1 parent cf02812 commit 353d634
Showing 1 changed file with 103 additions and 7 deletions.
110 changes: 103 additions & 7 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -2894,6 +2894,7 @@ a.setAttribute('href', 'http://example.com/'); // change the content attribute d
<li><dfn data-noexport="" data-x="dfn-callback-this-value" data-x-href="https://heycam.github.io/webidl/#dfn-callback-this-value">Callback this value</dfn>
<li><dfn data-noexport="" data-x="concept-idl-convert" data-x-href="https://heycam.github.io/webidl/#es-type-mapping">Converting</dfn> between WebIDL types and JS types
<li><dfn data-noexport="" data-x="es-invoking-callback-functions" data-x-href="https://heycam.github.io/webidl/#es-invoking-callback-functions">invoke the Web IDL callback function</dfn>
<li><dfn data-noexport="" data-x-href="https://heycam.github.io/webidl/#dfn-callback-context">callback context</dfn>
</ul>

<p>The Web IDL specification also defines the following types that are used in Web IDL fragments
Expand Down Expand Up @@ -87518,12 +87519,12 @@ interface <dfn>NavigatorOnLine</dfn> {
<li><p>Assert: <var>settings</var>'s <span>realm execution context</span> is the <span>running
JavaScript execution context</span>.</p></li>

<li><p>Decrement <var>settings</var>'s <span>realm execution context</span>'s <span>entrance
counter</span> by one.</p></li>

<li><p>Remove <var>settings</var>'s <span>realm execution context</span> from the
<span>JavaScript execution context stack</span>.</p></li>

<li><p>Decrement <var>settings</var>'s <span>realm execution context</span>'s <span>entrance
counter</span> by one.</p></li>

<li><p>If the <span>JavaScript execution context stack</span> is now empty, <span>run the global
script clean-up jobs</span>. (These cannot run scripts.)</p></li>

Expand Down Expand Up @@ -87777,16 +87778,39 @@ interface <dfn>NavigatorOnLine</dfn> {

<h6>Incumbent</h6>

<p>Every <span>event loop</span> has an associated <dfn>backup incumbent settings object
stack</dfn>, initially empty. Roughly speaking, it is used to determine the <span>incumbent
settings object</span> when no author code is on the stack, but author code is responsible for the
current algorithm having been run in some way. When Web IDL is used to <span
data-x="es-invoking-callback-functions">invoke</span> author code, it manipulates this stack. <ref
spec="WEBIDL"/></p>

<p>The <dfn>incumbent settings object</dfn> is determined as follows:</p>

<ol>
<li><p>Let <var>scriptOrModule</var> be the result of JavaScript's <span
data-x="js-GetActiveScriptOrModule">GetActiveScriptOrModule()</span> abstract
operation.</p></li>
<li><p>If <var>scriptOrModule</var> is null, abort these steps; there is no
<span>incumbent settings object</span>.</p></li>
<li><p>Return the <span>settings object</span> of the <span>script</span> in
<var>scriptOrModule</var>'s [[HostDefined]] field.</p></li>

<li><p>If <var>scriptOrModule</var> is not null, return the <span>settings object</span> of the
<span data-x="concept-script">script</span> in <var>scriptOrModule</var>'s [[HostDefined]]
field.</p></li>

<li>
<p>Assert: the <span>backup incumbent settings object stack</span> is not empty.</p>

<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
trigger if you tried to obtain the <span>incumbent settings object</span> inside an algorithm
that ran periodically as part of the <span>event loop</span>, with no involvement of author
code. In such cases the <span data-x="concept-incumbent-everything">incumbent</span> concept
cannot be used.</p>
</li>

<li><p>Return the topmost entry of the <span>backup incumbent settings object
stack</span>.</p></li>
</ol>

<p>Then, the <dfn data-x="concept-incumbent-realm">incumbent Realm</dfn> is the <span
Expand All @@ -87797,6 +87821,78 @@ interface <dfn>NavigatorOnLine</dfn> {
<span data-x="concept-settings-object-global">global object</span> of the <span>incumbent
settings object</span>.</p>

<div class="example">
<p>Consider the following very simple example:</p>

<pre>&lt;!DOCTYPE html>
&lt;script>
new Worker('worker.js');
&lt;/script></pre>

<p>When the <code data-x="dom-Worker">Worker()</code> constructor looks at the <span>incumbent
settings object</span> to use for various parts of its algorithm, <span
data-x="js-GetActiveScriptOrModule">GetActiveScriptOrModule()</span> will return the JavaScript
Script Record corresponding to the <code>script</code> element. The corresponding
<span>JavaScript execution context</span> was pushed as part of <span
data-x="js-ScriptEvaluation">ScriptEvaluation</span> during the <span>run a classic script</span>
algorithm.</p>
</div>

<div class="example">
<p>Consider the following more complicated example:</p>

<pre>&lt;!DOCTYPE html>
&lt;iframe>&lt;/iframe>
&lt;script>
const bound = frames[0].postMessage.bind(frames[0], "some data", "*");
window.setTimeout(bound);
&lt;/script></pre>

<p>There are two interesting <span data-x="environment settings object">environment settings
objects</span> here: that of <code data-x="">window</code>, and that of <code
data-x="">frames[0]</code>. Our concern is: what is the <span>incumbent settings object</span> at
the time that the algorithm for <code data-x="dom-window-postMessage">postMessage()</code>
executes?</p>

<p>It should be that of <code data-x="">window</code>, to capture the intuitive notion that the
author script responsible for causing the algorithm to happen is executing in <code
data-x="">window</code>, not <code data-x="">frames[0]</code>. Another way of capturing the
intuition here is that invoking algorithms asynchronously (in this case via <code
data-x="dom-setTimeout">setTimeout()</code>) should not change the <span
data-x="concept-incumbent-everything">incumbent</span> concept.</p>

<p>Let us now explain how the steps given above give us our intuitively-desired result of <code
data-x="">window</code>'s <span>relevant settings object</span>.</p>

<p>When <code data-x="">bound</code> is converted to a Web IDL callback type, the <span>incumbent
settings object</span> is that corresponding to <code data-x="">window</code> (in the same manner
as in our simple example above). Web IDL stores this as the resulting callback value's
<span>callback context</span>.</p>

<p>When the <span data-x="concept-task">task</span> posted by <code
data-x="dom-setTimeout">setTimeout()</code> executes, the algorithm for that task uses Web IDL to
<span data-x="es-invoking-callback-functions">invoke</span> the stored callback value. This
pushes the stored <span>callback context</span> onto the <span>backup incumbent settings object
stack</span>. Invoking the callback then calls <code data-x="">bound</code>, which in turn calls
the <code data-x="dom-window-postMessage">postMessage()</code> method of <code
data-x="">frames[0]</code>.</p>

<p>Note that since <code data-x="dom-window-postMessage">postMessage()</code> is a built-in
method, the act of calling it does not add any execution contexts to the <span>JavaScript
execution context stack</span> that have a ScriptOrModule component. Thus, when the <code
data-x="dom-window-postMessage">postMessage()</code> algorithm looks up the <span>incumbent
settings object</span>, <span
data-x="js-GetActiveScriptOrModule">GetActiveScriptOrModule()</span> will return null: the
<span>JavaScript execution context</span> stack only contains an execution context corresponding
to <code data-x="dom-window-postMessage">postMessage()</code>, with no <span
data-x="js-ScriptEvaluation">ScriptEvaluation</span> context or similar below it.</p>

<p>This is where we fall back to the <span>backup incumbent settings object stack</span>. Web IDL
set us up so that the stack contains the <span>relevant settings object</span> of <code
data-x="">window</code>, so that is what is used as the <span>incumbent settings object</span>
while executing the <code data-x="dom-window-postMessage">postMessage()</code> algorithm.</p>
</div>

<h6>Current</h6>

<p>The JavaScript specification defines the <span>current Realm Record</span>, sometimes
Expand Down

0 comments on commit 353d634

Please sign in to comment.