<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[237477] branches/safari-606-branch</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/237477">237477</a></dd>
<dt>Author</dt> <dd>mark.lam@apple.com</dd>
<dt>Date</dt> <dd>2018-10-26 12:10:25 -0700 (Fri, 26 Oct 2018)</dd>
</dl>

<h3>Log Message</h3>
<pre>Cherry-pick <a href="http://trac.webkit.org/projects/webkit/changeset/237469">r237469</a>. rdar://problem/45363534

    2018-10-26  Mark Lam  <mark.lam@apple.com>

    Fix missing edge cases with JSGlobalObjects having a bad time.
    https://bugs.webkit.org/show_bug.cgi?id=189028
    <rdar://problem/45204939>

    Reviewed by Saam Barati.

JSTests:

    * stress/regress-189028.js: Added.

Source/JavaScriptCore:

    Consider the following scenario:

        let object O1 (of global G1) have an indexing type that is not SlowPut.
        let global G2 have a bad time.
        let object O2 (of global G2) be set as the prototype of O1.
        let object O3 (of global G2) have indexed accessors.

    In the existing code, if we set O3 as O2's prototype, we'll have a bug where
    O1 will not be made aware that that there are indexed accessors in its prototype
    chain.

    In this patch, we solve this issue by introducing a new invariant:

        A prototype chain is considered to possibly have indexed accessors if any
        object in the chain belongs to a global object that is having a bad time.

    We apply this invariant as follows:

    1. Enhance JSGlobalObject::haveABadTime() to also check if other global objects are
       affected by it having a bad time.  If so, it also ensures that those affected
       global objects have a bad time.

       The original code for JSGlobalObject::haveABadTime() uses a ObjectsWithBrokenIndexingFinder
       to find all objects affected by the global object having a bad time.  We enhance
       ObjectsWithBrokenIndexingFinder to also check for the possibility that any global
       objects may be affected by other global objects having a bad time i.e.

            let g1 = global1
            let g2 = global2
            let o1 = an object in g1
            let o2 = an object in g2

            let g1 have a bad time
            g2 is affected if
                o1 is in the prototype chain of o2,
                and o2 may be a prototype.

       If the ObjectsWithBrokenIndexingFinder does find the possibility of other global
       objects being affected, it will abort its heap scan and let haveABadTime() take
       a slow path to do a more complete multi global object scan.

       The slow path works as follows:

       1. Iterate the heap and record the graph of all global object dependencies.

          For each global object, record the list of other global objects that are
          affected by it.

       2. Compute a list of global objects that need to have a bad time using the
          current global object dependency graph.

       3. For each global object in the list of affected global objects, fire their
          HaveABadTime watchpoint and convert all their array structures to the
          SlowPut alternatives.

       4. Re-run ObjectsWithBrokenIndexingFinder to find all objects that are affected
          by any of the globals in the list from (2).

    2. Enhance Structure::mayInterceptIndexedAccesses() to also return true if the
       structure's global object is having a bad time.

    Note: there are 3 scenarios that we need to consider:

        let g1 = global1
        let g2 = global2
        let o1 = an object in g1
        let o2 = an object in g2

        Scenario 1: o2 is a prototype, and
                    g1 has a bad time after o1 is inserted into the o2's prototype chain.

        Scenario 2: o2 is a prototype, and
                    o1 is inserted into the o2's prototype chain after g1 has a bad time.

        Scenario 3: o2 is NOT a prototype, and
                    o1 is inserted into the o2's prototype chain after g1 has a bad time.

        For scenario 1, when g1 has a bad time, we need to also make sure g2 has
        a bad time.  This is handled by enhancement 1 above.

        For scenario 2, when o1 is inserted into o2's prototype chain, we need to check
        if o1's global object has a bad time.  If so, then we need to make sure o2's
        global also has a bad time (because o2 is a prototype) and convert o2's
        storage type to SlowPut.  This is handled by enhancement 2 above in conjunction
        with JSObject::setPrototypeDirect().

        For scenario 3, when o1 is inserted into o2's prototype chain, we need to check
        if o1's global object has a bad time.  If so, then we only need to convert o2's
        storage type to SlowPut (because o2 is NOT a prototype).  This is handled by
        enhancement 2 above.

    3. Also add $vm.isHavingABadTime(), $vm.createGlobalObject() to enable us to
       write some tests for this issue.

    * runtime/JSGlobalObject.cpp:
    (JSC::JSGlobalObject::fireWatchpointAndMakeAllArrayStructuresSlowPut):
    (JSC::JSGlobalObject::haveABadTime):
    * runtime/JSGlobalObject.h:
    * runtime/JSObject.h:
    (JSC::JSObject::mayInterceptIndexedAccesses): Deleted.
    * runtime/JSObjectInlines.h:
    (JSC::JSObject::mayInterceptIndexedAccesses):
    * runtime/Structure.h:
    * runtime/StructureInlines.h:
    (JSC::Structure::mayInterceptIndexedAccesses const):
    * tools/JSDollarVM.cpp:
    (JSC::functionHaveABadTime):
    (JSC::functionIsHavingABadTime):
    (JSC::functionCreateGlobalObject):
    (JSC::JSDollarVM::finishCreation):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branchessafari606branchJSTestsChangeLog">branches/safari-606-branch/JSTests/ChangeLog</a></li>
<li><a href="#branchessafari606branchSourceJavaScriptCoreChangeLog">branches/safari-606-branch/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#branchessafari606branchSourceJavaScriptCoreruntimeJSGlobalObjectcpp">branches/safari-606-branch/Source/JavaScriptCore/runtime/JSGlobalObject.cpp</a></li>
<li><a href="#branchessafari606branchSourceJavaScriptCoreruntimeJSGlobalObjecth">branches/safari-606-branch/Source/JavaScriptCore/runtime/JSGlobalObject.h</a></li>
<li><a href="#branchessafari606branchSourceJavaScriptCoreruntimeJSObjecth">branches/safari-606-branch/Source/JavaScriptCore/runtime/JSObject.h</a></li>
<li><a href="#branchessafari606branchSourceJavaScriptCoreruntimeJSObjectInlinesh">branches/safari-606-branch/Source/JavaScriptCore/runtime/JSObjectInlines.h</a></li>
<li><a href="#branchessafari606branchSourceJavaScriptCoreruntimeStructureh">branches/safari-606-branch/Source/JavaScriptCore/runtime/Structure.h</a></li>
<li><a href="#branchessafari606branchSourceJavaScriptCoreruntimeStructureInlinesh">branches/safari-606-branch/Source/JavaScriptCore/runtime/StructureInlines.h</a></li>
<li><a href="#branchessafari606branchSourceJavaScriptCoretoolsJSDollarVMcpp">branches/safari-606-branch/Source/JavaScriptCore/tools/JSDollarVM.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#branchessafari606branchJSTestsstressregress189028js">branches/safari-606-branch/JSTests/stress/regress-189028.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchessafari606branchJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-606-branch/JSTests/ChangeLog (237476 => 237477)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-606-branch/JSTests/ChangeLog     2018-10-26 18:58:50 UTC (rev 237476)
+++ branches/safari-606-branch/JSTests/ChangeLog        2018-10-26 19:10:25 UTC (rev 237477)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2018-10-26  Mark Lam  <mark.lam@apple.com>
+
+        Cherry-pick r237469. rdar://problem/45363534
+
+    2018-10-26  Mark Lam  <mark.lam@apple.com>
+
+            Fix missing edge cases with JSGlobalObjects having a bad time.
+            https://bugs.webkit.org/show_bug.cgi?id=189028
+            <rdar://problem/45204939>
+
+            Reviewed by Saam Barati.
+
+            * stress/regress-189028.js: Added.
+
</ins><span class="cx"> 2018-10-23  Kocsen Chung  <kocsen_chung@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Cherry-pick r236589. rdar://problem/45285669
</span></span></pre></div>
<a id="branchessafari606branchJSTestsstressregress189028jsfromrev237469trunkJSTestsstressregress189028js"></a>
<div class="copfile"><h4>Copied: branches/safari-606-branch/JSTests/stress/regress-189028.js (from rev 237469, trunk/JSTests/stress/regress-189028.js) (0 => 237477)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-606-branch/JSTests/stress/regress-189028.js                              (rev 0)
+++ branches/safari-606-branch/JSTests/stress/regress-189028.js 2018-10-26 19:10:25 UTC (rev 237477)
</span><span class="lines">@@ -0,0 +1,242 @@
</span><ins>+function assert(x, y) {
+    if (x != y) {
+        $vm.print("actual: ", x);
+        $vm.print("expected: ", y);
+        throw "FAILED\n" + new Error().stack;
+    }
+}
+
+(function() {
+    let arr = [1.1, 2.2];
+    let arr2 = [1.1, 2.2];
+
+    assert($vm.isHavingABadTime(arr), false);
+    assert($vm.indexingMode(arr), "CopyOnWriteArrayWithDouble");
+    assert($vm.isHavingABadTime(arr2), false);
+    assert($vm.indexingMode(arr2), "CopyOnWriteArrayWithDouble");
+
+    let o = $vm.createGlobalObject();
+
+    $vm.haveABadTime(o);
+
+    let proto = new o.Object();
+    assert($vm.isHavingABadTime(o), true);
+    assert($vm.isHavingABadTime(proto), true);
+
+    arr2.__proto__ = proto;
+
+    assert($vm.isHavingABadTime(arr), false);
+    assert($vm.indexingMode(arr), "CopyOnWriteArrayWithDouble");
+    assert($vm.isHavingABadTime(arr2), false);
+    assert($vm.indexingMode(arr2), "ArrayWithSlowPutArrayStorage");
+})();
+
+gc();
+
+(function() {
+    let arr = [1.1, 2.2];
+    let arr2 = [1.1, 2.2];
+
+    assert($vm.isHavingABadTime(arr), false);
+    assert($vm.indexingMode(arr), "CopyOnWriteArrayWithDouble");
+    assert($vm.isHavingABadTime(arr2), false);
+    assert($vm.indexingMode(arr2), "CopyOnWriteArrayWithDouble");
+
+    let o = $vm.createGlobalObject();
+
+    let proto = new o.Object();
+    assert($vm.isHavingABadTime(o), false);
+    assert($vm.isHavingABadTime(proto), false);
+
+    arr2.__proto__ = proto;
+
+    assert($vm.isHavingABadTime(arr), false);
+    assert($vm.indexingMode(arr), "CopyOnWriteArrayWithDouble");
+    assert($vm.isHavingABadTime(arr2), false);
+    assert($vm.indexingMode(arr2), "ArrayWithDouble");
+
+    $vm.haveABadTime(o);
+
+    assert($vm.isHavingABadTime(o), true);
+    assert($vm.isHavingABadTime(proto), true);
+
+    assert($vm.isHavingABadTime(arr), false);
+    assert($vm.indexingMode(arr), "CopyOnWriteArrayWithDouble");
+    assert($vm.isHavingABadTime(arr2), false);
+    assert($vm.indexingMode(arr2), "ArrayWithSlowPutArrayStorage");
+})();
+
+gc();
+
+(function() {
+    let arr = [1.1, 2.2];
+    let arr2 = {};
+
+    assert($vm.isHavingABadTime(arr), false);
+    assert($vm.indexingMode(arr), "CopyOnWriteArrayWithDouble");
+    assert($vm.isHavingABadTime(arr2), false);
+    assert($vm.indexingMode(arr2), "NonArray");
+
+    let o = $vm.createGlobalObject();
+
+    $vm.haveABadTime(o);
+
+    let proto = new o.Object();
+    assert($vm.isHavingABadTime(o), true);
+    assert($vm.isHavingABadTime(proto), true);
+
+    arr2.__proto__ = proto;
+
+    assert($vm.isHavingABadTime(arr), false);
+    assert($vm.indexingMode(arr), "CopyOnWriteArrayWithDouble");
+    assert($vm.isHavingABadTime(arr2), false);
+    assert($vm.indexingMode(arr2), "NonArray");
+
+    arr2[0] = 1.1;
+
+    assert($vm.isHavingABadTime(arr), false);
+    assert($vm.indexingMode(arr), "CopyOnWriteArrayWithDouble");
+    assert($vm.isHavingABadTime(arr2), false);
+    assert($vm.indexingMode(arr2), "NonArrayWithSlowPutArrayStorage");
+})();
+
+gc();
+
+(function() {
+    let arr = [1.1, 2.2];
+    let arr2 = {};
+
+    assert($vm.isHavingABadTime(arr), false);
+    assert($vm.indexingMode(arr), "CopyOnWriteArrayWithDouble");
+    assert($vm.isHavingABadTime(arr2), false);
+    assert($vm.indexingMode(arr2), "NonArray");
+
+    let o = $vm.createGlobalObject();
+    let proto = new o.Object();
+
+    assert($vm.isHavingABadTime(o), false);
+    assert($vm.isHavingABadTime(proto), false);
+
+    arr2.__proto__ = proto;
+
+    assert($vm.isHavingABadTime(arr), false);
+    assert($vm.indexingMode(arr), "CopyOnWriteArrayWithDouble");
+    assert($vm.isHavingABadTime(arr2), false);
+    assert($vm.indexingMode(arr2), "NonArray");
+
+    arr2[0] = 1.1;
+
+    assert($vm.isHavingABadTime(arr), false);
+    assert($vm.indexingMode(arr), "CopyOnWriteArrayWithDouble");
+    assert($vm.isHavingABadTime(arr2), false);
+    assert($vm.indexingMode(arr2), "NonArrayWithDouble");
+
+    $vm.haveABadTime(o);
+
+    assert($vm.isHavingABadTime(o), true);
+    assert($vm.isHavingABadTime(proto), true);
+
+    assert($vm.isHavingABadTime(arr), false);
+    assert($vm.indexingMode(arr), "CopyOnWriteArrayWithDouble");
+    assert($vm.isHavingABadTime(arr2), false);
+    assert($vm.indexingMode(arr2), "NonArrayWithSlowPutArrayStorage");
+})();
+
+gc();
+
+(function() {
+    let g0 = $vm.createGlobalObject();
+    let o0 = new g0.Object(); 
+    assert($vm.isHavingABadTime(g0), false);
+    assert($vm.isHavingABadTime(o0), false);
+
+    let g1 = $vm.createGlobalObject();
+    let o1 = new g1.Object();
+    assert($vm.isHavingABadTime(g1), false);
+    assert($vm.isHavingABadTime(o1), false);
+
+    let g2 = $vm.createGlobalObject();
+    assert($vm.isHavingABadTime(g2), false);
+
+    $vm.haveABadTime(g1);
+    assert($vm.isHavingABadTime(g1), true);
+
+    o1.__proto__ = null;
+    g2.Array.prototype.__proto__ = o1;
+    o0.__proto__ = o1;
+
+    assert($vm.indexingMode(o0), "NonArray");
+    assert($vm.isHavingABadTime(g0), false);
+    assert($vm.isHavingABadTime(g2), true);
+})();
+
+gc();
+
+(function() {
+    let g0 = $vm.createGlobalObject();
+    let o0 = new g0.Object(); 
+    assert($vm.isHavingABadTime(g0), false);
+    assert($vm.isHavingABadTime(o0), false);
+
+    let g1 = $vm.createGlobalObject();
+    let o1 = new g1.Object();
+    assert($vm.isHavingABadTime(g1), false);
+    assert($vm.isHavingABadTime(o1), false);
+
+    let g2 = $vm.createGlobalObject();
+    assert($vm.isHavingABadTime(g2), false);
+
+    o1.__proto__ = null;
+    g2.Array.prototype.__proto__ = o1;
+    o0.__proto__ = o1;
+    assert($vm.isHavingABadTime(g0), false);
+    assert($vm.isHavingABadTime(g1), false);
+    assert($vm.isHavingABadTime(g2), false);
+
+    $vm.haveABadTime(g1);
+
+    assert($vm.indexingMode(o0), "NonArray");
+    assert($vm.isHavingABadTime(g0), false);
+    assert($vm.isHavingABadTime(g1), true);
+    assert($vm.isHavingABadTime(g2), true);
+})();
+
+gc();
+
+(function() {
+    let g0 = $vm.createGlobalObject();
+    let o0 = new g0.Object(); 
+    assert($vm.isHavingABadTime(g0), false);
+    assert($vm.isHavingABadTime(o0), false);
+
+    let g1 = $vm.createGlobalObject();
+    let o1 = new g1.Object();
+    assert($vm.isHavingABadTime(g1), false);
+    assert($vm.isHavingABadTime(o1), false);
+
+    let g2 = $vm.createGlobalObject();
+    let o2 = new g2.Object();
+    assert($vm.isHavingABadTime(g2), false);
+    assert($vm.isHavingABadTime(o2), false);
+
+    let g3 = $vm.createGlobalObject();
+    assert($vm.isHavingABadTime(g3), false);
+
+    o1.__proto__ = null;
+    g2.Array.prototype.__proto__ = o1;
+    o2.__proto__ = o1;
+    g3.Array.prototype.__proto__ = o2;
+    o0.__proto__ = o1;
+    assert($vm.isHavingABadTime(g0), false);
+    assert($vm.isHavingABadTime(g1), false);
+    assert($vm.isHavingABadTime(g2), false);
+    assert($vm.isHavingABadTime(g3), false);
+
+    $vm.haveABadTime(g1);
+
+    assert($vm.indexingMode(o0), "NonArray");
+    assert($vm.isHavingABadTime(g0), false);
+    assert($vm.isHavingABadTime(g1), true);
+    assert($vm.isHavingABadTime(g2), true);
+    assert($vm.isHavingABadTime(g2), true);
+})();
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="branchessafari606branchSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-606-branch/Source/JavaScriptCore/ChangeLog (237476 => 237477)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-606-branch/Source/JavaScriptCore/ChangeLog       2018-10-26 18:58:50 UTC (rev 237476)
+++ branches/safari-606-branch/Source/JavaScriptCore/ChangeLog  2018-10-26 19:10:25 UTC (rev 237477)
</span><span class="lines">@@ -1,3 +1,126 @@
</span><ins>+2018-10-26  Mark Lam  <mark.lam@apple.com>
+
+        Cherry-pick r237469. rdar://problem/45363534
+
+    2018-10-26  Mark Lam  <mark.lam@apple.com>
+
+            Fix missing edge cases with JSGlobalObjects having a bad time.
+            https://bugs.webkit.org/show_bug.cgi?id=189028
+            <rdar://problem/45204939>
+
+            Reviewed by Saam Barati.
+
+            Consider the following scenario:
+
+                let object O1 (of global G1) have an indexing type that is not SlowPut.
+                let global G2 have a bad time.
+                let object O2 (of global G2) be set as the prototype of O1.
+                let object O3 (of global G2) have indexed accessors.
+
+            In the existing code, if we set O3 as O2's prototype, we'll have a bug where
+            O1 will not be made aware that that there are indexed accessors in its prototype
+            chain.
+
+            In this patch, we solve this issue by introducing a new invariant:
+
+                A prototype chain is considered to possibly have indexed accessors if any
+                object in the chain belongs to a global object that is having a bad time.
+
+            We apply this invariant as follows:
+
+            1. Enhance JSGlobalObject::haveABadTime() to also check if other global objects are
+               affected by it having a bad time.  If so, it also ensures that those affected
+               global objects have a bad time.
+
+               The original code for JSGlobalObject::haveABadTime() uses a ObjectsWithBrokenIndexingFinder
+               to find all objects affected by the global object having a bad time.  We enhance
+               ObjectsWithBrokenIndexingFinder to also check for the possibility that any global
+               objects may be affected by other global objects having a bad time i.e.
+
+                    let g1 = global1
+                    let g2 = global2
+                    let o1 = an object in g1
+                    let o2 = an object in g2
+
+                    let g1 have a bad time
+                    g2 is affected if
+                        o1 is in the prototype chain of o2,
+                        and o2 may be a prototype.
+
+               If the ObjectsWithBrokenIndexingFinder does find the possibility of other global
+               objects being affected, it will abort its heap scan and let haveABadTime() take
+               a slow path to do a more complete multi global object scan.
+
+               The slow path works as follows:
+
+               1. Iterate the heap and record the graph of all global object dependencies.
+
+                  For each global object, record the list of other global objects that are
+                  affected by it.
+
+               2. Compute a list of global objects that need to have a bad time using the
+                  current global object dependency graph.
+
+               3. For each global object in the list of affected global objects, fire their
+                  HaveABadTime watchpoint and convert all their array structures to the
+                  SlowPut alternatives.
+
+               4. Re-run ObjectsWithBrokenIndexingFinder to find all objects that are affected
+                  by any of the globals in the list from (2).
+
+            2. Enhance Structure::mayInterceptIndexedAccesses() to also return true if the
+               structure's global object is having a bad time.
+
+            Note: there are 3 scenarios that we need to consider:
+
+                let g1 = global1
+                let g2 = global2
+                let o1 = an object in g1
+                let o2 = an object in g2
+
+                Scenario 1: o2 is a prototype, and
+                            g1 has a bad time after o1 is inserted into the o2's prototype chain.
+
+                Scenario 2: o2 is a prototype, and
+                            o1 is inserted into the o2's prototype chain after g1 has a bad time.
+
+                Scenario 3: o2 is NOT a prototype, and
+                            o1 is inserted into the o2's prototype chain after g1 has a bad time.
+
+                For scenario 1, when g1 has a bad time, we need to also make sure g2 has
+                a bad time.  This is handled by enhancement 1 above.
+
+                For scenario 2, when o1 is inserted into o2's prototype chain, we need to check
+                if o1's global object has a bad time.  If so, then we need to make sure o2's
+                global also has a bad time (because o2 is a prototype) and convert o2's
+                storage type to SlowPut.  This is handled by enhancement 2 above in conjunction
+                with JSObject::setPrototypeDirect().
+
+                For scenario 3, when o1 is inserted into o2's prototype chain, we need to check
+                if o1's global object has a bad time.  If so, then we only need to convert o2's
+                storage type to SlowPut (because o2 is NOT a prototype).  This is handled by
+                enhancement 2 above.
+
+            3. Also add $vm.isHavingABadTime(), $vm.createGlobalObject() to enable us to
+               write some tests for this issue.
+
+            * runtime/JSGlobalObject.cpp:
+            (JSC::JSGlobalObject::fireWatchpointAndMakeAllArrayStructuresSlowPut):
+            (JSC::JSGlobalObject::haveABadTime):
+            * runtime/JSGlobalObject.h:
+            * runtime/JSObject.h:
+            (JSC::JSObject::mayInterceptIndexedAccesses): Deleted.
+            * runtime/JSObjectInlines.h:
+            (JSC::JSObject::mayInterceptIndexedAccesses):
+            * runtime/Structure.h:
+            * runtime/StructureInlines.h:
+            (JSC::Structure::mayInterceptIndexedAccesses const):
+            * tools/JSDollarVM.cpp:
+            (JSC::functionHaveABadTime):
+            (JSC::functionIsHavingABadTime):
+            (JSC::functionCreateGlobalObject):
+            (JSC::JSDollarVM::finishCreation):
+
</ins><span class="cx"> 2018-10-23  Kocsen Chung  <kocsen_chung@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Cherry-pick r236606. rdar://problem/45285669
</span></span></pre></div>
<a id="branchessafari606branchSourceJavaScriptCoreruntimeJSGlobalObjectcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-606-branch/Source/JavaScriptCore/runtime/JSGlobalObject.cpp (237476 => 237477)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-606-branch/Source/JavaScriptCore/runtime/JSGlobalObject.cpp      2018-10-26 18:58:50 UTC (rev 237476)
+++ branches/safari-606-branch/Source/JavaScriptCore/runtime/JSGlobalObject.cpp 2018-10-26 19:10:25 UTC (rev 237477)
</span><span class="lines">@@ -1168,25 +1168,111 @@
</span><span class="cx"> // Private namespace for helpers for JSGlobalObject::haveABadTime()
</span><span class="cx"> namespace {
</span><span class="cx"> 
</span><ins>+class GlobalObjectDependencyFinder : public MarkedBlock::VoidFunctor {
+public:
+    GlobalObjectDependencyFinder(VM& vm)
+        : m_vm(vm)
+    { }
+
+    IterationStatus operator()(HeapCell*, HeapCell::Kind) const;
+
+    void addDependency(JSGlobalObject* key, JSGlobalObject* dependent);
+    HashSet<JSGlobalObject*>* dependentsFor(JSGlobalObject* key);
+
+private:
+    void visit(JSObject*);
+
+    VM& m_vm;
+    HashMap<JSGlobalObject*, HashSet<JSGlobalObject*>> m_dependencies;
+};
+
+inline void GlobalObjectDependencyFinder::addDependency(JSGlobalObject* key, JSGlobalObject* dependent)
+{
+    auto keyResult = m_dependencies.add(key, HashSet<JSGlobalObject*>());
+    keyResult.iterator->value.add(dependent);
+}
+
+inline HashSet<JSGlobalObject*>* GlobalObjectDependencyFinder::dependentsFor(JSGlobalObject* key)
+{
+    auto iterator = m_dependencies.find(key);
+    if (iterator == m_dependencies.end())
+        return nullptr;
+    return &iterator->value;
+}
+
+inline void GlobalObjectDependencyFinder::visit(JSObject* object)
+{
+    VM& vm = m_vm;
+
+    if (!object->mayBePrototype())
+        return;
+
+    JSObject* current = object;
+    JSGlobalObject* objectGlobalObject = object->globalObject(vm);
+    do {
+        JSValue prototypeValue = current->getPrototypeDirect(vm);
+        if (prototypeValue.isNull())
+            return;
+        current = asObject(prototypeValue);
+
+        JSGlobalObject* protoGlobalObject = current->globalObject(vm);
+        if (protoGlobalObject != objectGlobalObject)
+            addDependency(protoGlobalObject, objectGlobalObject);
+    } while (true);
+}
+
+IterationStatus GlobalObjectDependencyFinder::operator()(HeapCell* cell, HeapCell::Kind kind) const
+{
+    if (isJSCellKind(kind) && static_cast<JSCell*>(cell)->isObject()) {
+        // FIXME: This const_cast exists because this isn't a C++ lambda.
+        // https://bugs.webkit.org/show_bug.cgi?id=159644
+        const_cast<GlobalObjectDependencyFinder*>(this)->visit(jsCast<JSObject*>(static_cast<JSCell*>(cell)));
+    }
+    return IterationStatus::Continue;
+}
+
+enum class BadTimeFinderMode {
+    SingleGlobal,
+    MultipleGlobals
+};
+
+template<BadTimeFinderMode mode>
</ins><span class="cx"> class ObjectsWithBrokenIndexingFinder : public MarkedBlock::VoidFunctor {
</span><span class="cx"> public:
</span><del>-    ObjectsWithBrokenIndexingFinder(MarkedArgumentBuffer&, JSGlobalObject*);
</del><ins>+    ObjectsWithBrokenIndexingFinder(VM&, Vector<JSObject*>&, JSGlobalObject*);
+    ObjectsWithBrokenIndexingFinder(VM&, Vector<JSObject*>&, HashSet<JSGlobalObject*>&);
+
+    bool needsMultiGlobalsScan() const { return m_needsMultiGlobalsScan; }
</ins><span class="cx">     IterationStatus operator()(HeapCell*, HeapCell::Kind) const;
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    void visit(JSCell*);
</del><ins>+    IterationStatus visit(JSObject*);
</ins><span class="cx"> 
</span><del>-    MarkedArgumentBuffer& m_foundObjects;
-    JSGlobalObject* m_globalObject;
</del><ins>+    VM& m_vm;
+    Vector<JSObject*>& m_foundObjects;
+    JSGlobalObject* m_globalObject { nullptr }; // Only used for SingleBadTimeGlobal mode.
+    HashSet<JSGlobalObject*>* m_globalObjects { nullptr }; // Only used for BadTimeGlobalGraph mode;
+    bool m_needsMultiGlobalsScan { false };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><del>-ObjectsWithBrokenIndexingFinder::ObjectsWithBrokenIndexingFinder(
-    MarkedArgumentBuffer& foundObjects, JSGlobalObject* globalObject)
-    : m_foundObjects(foundObjects)
</del><ins>+template<>
+ObjectsWithBrokenIndexingFinder<BadTimeFinderMode::SingleGlobal>::ObjectsWithBrokenIndexingFinder(
+    VM& vm, Vector<JSObject*>& foundObjects, JSGlobalObject* globalObject)
+    : m_vm(vm)
+    , m_foundObjects(foundObjects)
</ins><span class="cx">     , m_globalObject(globalObject)
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template<>
+ObjectsWithBrokenIndexingFinder<BadTimeFinderMode::MultipleGlobals>::ObjectsWithBrokenIndexingFinder(
+    VM& vm, Vector<JSObject*>& foundObjects, HashSet<JSGlobalObject*>& globalObjects)
+    : m_vm(vm)
+    , m_foundObjects(foundObjects)
+    , m_globalObjects(&globalObjects)
+{
+}
+
</ins><span class="cx"> inline bool hasBrokenIndexing(IndexingType type)
</span><span class="cx"> {
</span><span class="cx">     return type && !hasSlowPutArrayStorage(type);
</span><span class="lines">@@ -1198,21 +1284,38 @@
</span><span class="cx">     return hasBrokenIndexing(type);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline void ObjectsWithBrokenIndexingFinder::visit(JSCell* cell)
</del><ins>+template<BadTimeFinderMode mode>
+inline IterationStatus ObjectsWithBrokenIndexingFinder<mode>::visit(JSObject* object)
</ins><span class="cx"> {
</span><del>-    if (!cell->isObject())
-        return;
-    
-    VM& vm = m_globalObject->vm();
</del><ins>+    VM& vm = m_vm;
</ins><span class="cx"> 
</span><span class="cx">     // We only want to have a bad time in the affected global object, not in the entire
</span><span class="cx">     // VM. But we have to be careful, since there may be objects that claim to belong to
</span><span class="cx">     // a different global object that have prototypes from our global object.
</span><del>-    auto isInEffectedGlobalObject = [&] (JSObject* object) {
</del><ins>+    auto isInAffectedGlobalObject = [&] (JSObject* object) {
+        JSGlobalObject* objectGlobalObject { nullptr };
+        bool objectMayBePrototype { false };
+
+        if (mode == BadTimeFinderMode::SingleGlobal) {
+            objectGlobalObject = object->globalObject(vm);
+            if (objectGlobalObject == m_globalObject)
+                return true;
+
+            objectMayBePrototype = object->mayBePrototype();
+        }
+
</ins><span class="cx">         for (JSObject* current = object; ;) {
</span><del>-            if (current->globalObject(vm) == m_globalObject)
-                return true;
-            
</del><ins>+            JSGlobalObject* currentGlobalObject = current->globalObject(vm);
+            if (mode == BadTimeFinderMode::SingleGlobal) {
+                if (objectMayBePrototype && currentGlobalObject != objectGlobalObject)
+                    m_needsMultiGlobalsScan = true;
+                if (currentGlobalObject == m_globalObject)
+                    return true;
+            } else {
+                if (m_globalObjects->contains(currentGlobalObject))
+                    return true;
+            }
+
</ins><span class="cx">             JSValue prototypeValue = current->getPrototypeDirect(vm);
</span><span class="cx">             if (prototypeValue.isNull())
</span><span class="cx">                 return false;
</span><span class="lines">@@ -1221,8 +1324,6 @@
</span><span class="cx">         RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-    JSObject* object = asObject(cell);
-
</del><span class="cx">     if (JSFunction* function = jsDynamicCast<JSFunction*>(vm, object)) {
</span><span class="cx">         if (FunctionRareData* rareData = function->rareData()) {
</span><span class="cx">             // We only use this to cache JSFinalObjects. They do not start off with a broken indexing type.
</span><span class="lines">@@ -1230,8 +1331,13 @@
</span><span class="cx"> 
</span><span class="cx">             if (Structure* structure = rareData->internalFunctionAllocationStructure()) {
</span><span class="cx">                 if (hasBrokenIndexing(structure->indexingType())) {
</span><del>-                    bool isRelevantGlobalObject = (structure->globalObject() == m_globalObject)
-                        || (structure->hasMonoProto() && !structure->storedPrototype().isNull() && isInEffectedGlobalObject(asObject(structure->storedPrototype())));
</del><ins>+                    bool isRelevantGlobalObject =
+                        (mode == BadTimeFinderMode::SingleGlobal
+                            ? m_globalObject == structure->globalObject()
+                            : m_globalObjects->contains(structure->globalObject()))
+                        || (structure->hasMonoProto() && !structure->storedPrototype().isNull() && isInAffectedGlobalObject(asObject(structure->storedPrototype())));
+                    if (mode == BadTimeFinderMode::SingleGlobal && m_needsMultiGlobalsScan)
+                        return IterationStatus::Done; // Bailing early and let the MultipleGlobals path handle everything.
</ins><span class="cx">                     if (isRelevantGlobalObject)
</span><span class="cx">                         rareData->clearInternalFunctionAllocationProfile();
</span><span class="cx">                 }
</span><span class="lines">@@ -1241,18 +1347,24 @@
</span><span class="cx"> 
</span><span class="cx">     // Run this filter first, since it's cheap, and ought to filter out a lot of objects.
</span><span class="cx">     if (!hasBrokenIndexing(object))
</span><del>-        return;
-    
-    if (isInEffectedGlobalObject(object))
</del><ins>+        return IterationStatus::Continue;
+
+    if (isInAffectedGlobalObject(object))
</ins><span class="cx">         m_foundObjects.append(object);
</span><ins>+
+    if (mode == BadTimeFinderMode::SingleGlobal && m_needsMultiGlobalsScan)
+        return IterationStatus::Done; // Bailing early and let the MultipleGlobals path handle everything.
+
+    return IterationStatus::Continue;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-IterationStatus ObjectsWithBrokenIndexingFinder::operator()(HeapCell* cell, HeapCell::Kind kind) const
</del><ins>+template<BadTimeFinderMode mode>
+IterationStatus ObjectsWithBrokenIndexingFinder<mode>::operator()(HeapCell* cell, HeapCell::Kind kind) const
</ins><span class="cx"> {
</span><del>-    if (isJSCellKind(kind)) {
</del><ins>+    if (isJSCellKind(kind) && static_cast<JSCell*>(cell)->isObject()) {
</ins><span class="cx">         // FIXME: This const_cast exists because this isn't a C++ lambda.
</span><span class="cx">         // https://bugs.webkit.org/show_bug.cgi?id=159644
</span><del>-        const_cast<ObjectsWithBrokenIndexingFinder*>(this)->visit(static_cast<JSCell*>(cell));
</del><ins>+        return const_cast<ObjectsWithBrokenIndexingFinder*>(this)->visit(jsCast<JSObject*>(static_cast<JSCell*>(cell)));
</ins><span class="cx">     }
</span><span class="cx">     return IterationStatus::Continue;
</span><span class="cx"> }
</span><span class="lines">@@ -1259,15 +1371,11 @@
</span><span class="cx"> 
</span><span class="cx"> } // end private namespace for helpers for JSGlobalObject::haveABadTime()
</span><span class="cx"> 
</span><del>-void JSGlobalObject::haveABadTime(VM& vm)
</del><ins>+void JSGlobalObject::fireWatchpointAndMakeAllArrayStructuresSlowPut(VM& vm)
</ins><span class="cx"> {
</span><del>-    ASSERT(&vm == &this->vm());
-    
</del><span class="cx">     if (isHavingABadTime())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    vm.structureCache.clear(); // We may be caching array structures in here.
-
</del><span class="cx">     // Make sure that all allocations or indexed storage transitions that are inlining
</span><span class="cx">     // the assumption that it's safe to transition to a non-SlowPut array storage don't
</span><span class="cx">     // do so anymore.
</span><span class="lines">@@ -1287,16 +1395,118 @@
</span><span class="cx">     m_regExpMatchesArrayWithGroupsStructure.set(vm, this, slowPutStructure);
</span><span class="cx">     slowPutStructure = ClonedArguments::createSlowPutStructure(vm, this, m_objectPrototype.get());
</span><span class="cx">     m_clonedArgumentsStructure.set(vm, this, slowPutStructure);
</span><ins>+};
</ins><span class="cx"> 
</span><del>-    // Make sure that all objects that have indexed storage switch to the slow kind of
-    // indexed storage.
-    MarkedArgumentBuffer foundObjects; // Use MarkedArgumentBuffer because switchToSlowPutArrayStorage() may GC.
-    ObjectsWithBrokenIndexingFinder finder(foundObjects, this);
</del><ins>+void JSGlobalObject::haveABadTime(VM& vm)
+{
+    ASSERT(&vm == &this->vm());
+    
+    if (isHavingABadTime())
+        return;
+
+    vm.structureCache.clear(); // We may be caching array structures in here.
+
+    DeferGC deferGC(vm.heap);
+
+    // Consider the following objects and prototype chains:
+    //    O (of global G1) -> A (of global G1)
+    //    B (of global G2) where G2 has a bad time
+    //
+    // If we set B as the prototype of A, G1 will need to have a bad time.
+    // See comments in Structure::mayInterceptIndexedAccesses() for why.
+    //
+    // Now, consider the following objects and prototype chains:
+    //    O1 (of global G1) -> A1 (of global G1) -> B1 (of global G2)
+    //    O2 (of global G2) -> A2 (of global G2)
+    //    B2 (of global G3) where G3 has a bad time.
+    //
+    // G1 and G2 does not have a bad time, but G3 already has a bad time.
+    // If we set B2 as the prototype of A2, then G2 needs to have a bad time.
+    // Note that by induction, G1 also now needs to have a bad time because of
+    // O1 -> A1 -> B1.
+    //
+    // We describe this as global G1 being affected by global G2, and G2 by G3.
+    // Similarly, we say that G1 is dependent on G2, and G2 on G3.
+    // Hence, when G3 has a bad time, we need to ensure that all globals that
+    // are transitively dependent on it also have a bad time (G2 and G1 in this
+    // example).
+    //
+    // Apart from clearing the VM structure cache above, there are 2 more things
+    // that we have to do when globals have a bad time:
+    // 1. For each affected global:
+    //    a. Fire its HaveABadTime watchpoint.
+    //    b. Convert all of its array structures to SlowPutArrayStorage.
+    // 2. Make sure that all affected objects  switch to the slow kind of
+    //    indexed storage. An object is considered to be affected if it has
+    //    indexed storage and has a prototype object which may have indexed
+    //    accessors. If the prototype object belongs to a global having a bad
+    //    time, then the prototype object is considered to possibly have indexed
+    //    accessors. See comments in Structure::mayInterceptIndexedAccesses()
+    //    for details.
+    //
+    // Note: step 1 must be completed before step 2 because step 2 relies on
+    // the HaveABadTime watchpoint having already been fired on all affected
+    // globals.
+    //
+    // In the common case, only this global will start having a bad time here,
+    // and no other globals are affected by it. So, we first proceed on this assumption
+    // with a simpler ObjectsWithBrokenIndexingFinder scan to find heap objects
+    // affected by this global that need to be converted to SlowPutArrayStorage.
+    // We'll also have the finder check for the presence of other global objects
+    // depending on this one.
+    //
+    // If we do discover other globals depending on this one, we'll abort this
+    // first ObjectsWithBrokenIndexingFinder scan because it will be insufficient
+    // to find all affected objects that need to be converted to SlowPutArrayStorage.
+    // It also does not make dependent globals have a bad time. Instead, we'll
+    // take a more comprehensive approach of first creating a dependency graph
+    // between globals, and then using that graph to determine all affected
+    // globals and objects. With that, we can make all affected globals have a
+    // bad time, and convert all affected objects to SlowPutArrayStorage.
+
+    fireWatchpointAndMakeAllArrayStructuresSlowPut(vm); // Step 1 above.
+    
+    Vector<JSObject*> foundObjects;
+    ObjectsWithBrokenIndexingFinder<BadTimeFinderMode::SingleGlobal> finder(vm, foundObjects, this);
</ins><span class="cx">     {
</span><span class="cx">         HeapIterationScope iterationScope(vm.heap);
</span><del>-        vm.heap.objectSpace().forEachLiveCell(iterationScope, finder);
</del><ins>+        vm.heap.objectSpace().forEachLiveCell(iterationScope, finder); // Attempt step 2 above.
</ins><span class="cx">     }
</span><del>-    RELEASE_ASSERT(!foundObjects.hasOverflowed());
</del><ins>+
+    if (finder.needsMultiGlobalsScan()) {
+        foundObjects.clear();
+
+        // Find all globals that will also have a bad time as a side effect of
+        // this global having a bad time.
+        GlobalObjectDependencyFinder dependencies(vm);
+        {
+            HeapIterationScope iterationScope(vm.heap);
+            vm.heap.objectSpace().forEachLiveCell(iterationScope, dependencies);
+        }
+
+        HashSet<JSGlobalObject*> globalsHavingABadTime;
+        Deque<JSGlobalObject*> globals;
+
+        globals.append(this);
+        while (!globals.isEmpty()) {
+            JSGlobalObject* global = globals.takeFirst();
+            global->fireWatchpointAndMakeAllArrayStructuresSlowPut(vm); // Step 1 above.
+            auto result = globalsHavingABadTime.add(global);
+            if (result.isNewEntry) {
+                if (HashSet<JSGlobalObject*>* dependents = dependencies.dependentsFor(global)) {
+                    for (JSGlobalObject* dependentGlobal : *dependents)
+                        globals.append(dependentGlobal);
+                }
+            }
+        }
+
+        ObjectsWithBrokenIndexingFinder<BadTimeFinderMode::MultipleGlobals> finder(vm, foundObjects, globalsHavingABadTime);
+        {
+            HeapIterationScope iterationScope(vm.heap);
+            vm.heap.objectSpace().forEachLiveCell(iterationScope, finder); // Step 2 above.
+        }
+    }
+
</ins><span class="cx">     while (!foundObjects.isEmpty()) {
</span><span class="cx">         JSObject* object = asObject(foundObjects.last());
</span><span class="cx">         foundObjects.removeLast();
</span></span></pre></div>
<a id="branchessafari606branchSourceJavaScriptCoreruntimeJSGlobalObjecth"></a>
<div class="modfile"><h4>Modified: branches/safari-606-branch/Source/JavaScriptCore/runtime/JSGlobalObject.h (237476 => 237477)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-606-branch/Source/JavaScriptCore/runtime/JSGlobalObject.h        2018-10-26 18:58:50 UTC (rev 237476)
+++ branches/safari-606-branch/Source/JavaScriptCore/runtime/JSGlobalObject.h   2018-10-26 19:10:25 UTC (rev 237477)
</span><span class="lines">@@ -962,6 +962,7 @@
</span><span class="cx"> private:
</span><span class="cx">     friend class LLIntOffsetsExtractor;
</span><span class="cx"> 
</span><ins>+    void fireWatchpointAndMakeAllArrayStructuresSlowPut(VM&);
</ins><span class="cx">     void setGlobalThis(VM&, JSObject* globalThis);
</span><span class="cx"> 
</span><span class="cx">     JS_EXPORT_PRIVATE void init(VM&);
</span></span></pre></div>
<a id="branchessafari606branchSourceJavaScriptCoreruntimeJSObjecth"></a>
<div class="modfile"><h4>Modified: branches/safari-606-branch/Source/JavaScriptCore/runtime/JSObject.h (237476 => 237477)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-606-branch/Source/JavaScriptCore/runtime/JSObject.h      2018-10-26 18:58:50 UTC (rev 237476)
+++ branches/safari-606-branch/Source/JavaScriptCore/runtime/JSObject.h 2018-10-26 19:10:25 UTC (rev 237477)
</span><span class="lines">@@ -159,11 +159,8 @@
</span><span class="cx">     bool setPrototype(VM&, ExecState*, JSValue prototype, bool shouldThrowIfCantSet = false);
</span><span class="cx">     JS_EXPORT_PRIVATE static bool setPrototype(JSObject*, ExecState*, JSValue prototype, bool shouldThrowIfCantSet);
</span><span class="cx">         
</span><del>-    bool mayInterceptIndexedAccesses(VM& vm)
-    {
-        return structure(vm)->mayInterceptIndexedAccesses();
-    }
-        
</del><ins>+    inline bool mayInterceptIndexedAccesses(VM&);
+
</ins><span class="cx">     JSValue get(ExecState*, PropertyName) const;
</span><span class="cx">     JSValue get(ExecState*, unsigned propertyName) const;
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchessafari606branchSourceJavaScriptCoreruntimeJSObjectInlinesh"></a>
<div class="modfile"><h4>Modified: branches/safari-606-branch/Source/JavaScriptCore/runtime/JSObjectInlines.h (237476 => 237477)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-606-branch/Source/JavaScriptCore/runtime/JSObjectInlines.h       2018-10-26 18:58:50 UTC (rev 237476)
+++ branches/safari-606-branch/Source/JavaScriptCore/runtime/JSObjectInlines.h  2018-10-26 19:10:25 UTC (rev 237477)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> #include "Error.h"
</span><span class="cx"> #include "JSObject.h"
</span><span class="cx"> #include "Lookup.h"
</span><ins>+#include "StructureInlines.h"
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -173,6 +174,11 @@
</span><span class="cx">     return JSObject::getOwnPropertySlot(this, exec, propertyName, slot);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline bool JSObject::mayInterceptIndexedAccesses(VM& vm)
+{
+    return structure(vm)->mayInterceptIndexedAccesses();
+}
+
</ins><span class="cx"> inline void JSObject::putDirectWithoutTransition(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!value.isGetterSetter() && !(attributes & PropertyAttribute::Accessor));
</span></span></pre></div>
<a id="branchessafari606branchSourceJavaScriptCoreruntimeStructureh"></a>
<div class="modfile"><h4>Modified: branches/safari-606-branch/Source/JavaScriptCore/runtime/Structure.h (237476 => 237477)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-606-branch/Source/JavaScriptCore/runtime/Structure.h     2018-10-26 18:58:50 UTC (rev 237476)
+++ branches/safari-606-branch/Source/JavaScriptCore/runtime/Structure.h        2018-10-26 19:10:25 UTC (rev 237477)
</span><span class="lines">@@ -263,11 +263,8 @@
</span><span class="cx">     IndexingType indexingMode() const  { return m_blob.indexingModeIncludingHistory() & AllArrayTypes; }
</span><span class="cx">     IndexingType indexingModeIncludingHistory() const { return m_blob.indexingModeIncludingHistory(); }
</span><span class="cx">         
</span><del>-    bool mayInterceptIndexedAccesses() const
-    {
-        return !!(indexingModeIncludingHistory() & MayHaveIndexedAccessors);
-    }
-        
</del><ins>+    inline bool mayInterceptIndexedAccesses() const;
+    
</ins><span class="cx">     bool holesMustForwardToPrototype(VM&, JSObject*) const;
</span><span class="cx">         
</span><span class="cx">     JSGlobalObject* globalObject() const { return m_globalObject.get(); }
</span></span></pre></div>
<a id="branchessafari606branchSourceJavaScriptCoreruntimeStructureInlinesh"></a>
<div class="modfile"><h4>Modified: branches/safari-606-branch/Source/JavaScriptCore/runtime/StructureInlines.h (237476 => 237477)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-606-branch/Source/JavaScriptCore/runtime/StructureInlines.h      2018-10-26 18:58:50 UTC (rev 237476)
+++ branches/safari-606-branch/Source/JavaScriptCore/runtime/StructureInlines.h 2018-10-26 19:10:25 UTC (rev 237477)
</span><span class="lines">@@ -59,6 +59,29 @@
</span><span class="cx">     return newStructure;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline bool Structure::mayInterceptIndexedAccesses() const
+{
+    if (indexingModeIncludingHistory() & MayHaveIndexedAccessors)
+        return true;
+
+    // Consider a scenario where object O (of global G1)'s prototype is set to A
+    // (of global G2), and G2 is already having a bad time. If an object B with
+    // indexed accessors is then set as the prototype of A:
+    //      O -> A -> B
+    // Then, O should be converted to SlowPutArrayStorage (because it now has an
+    // object with indexed accessors in its prototype chain). But it won't be
+    // converted because this conversion is done by JSGlobalObject::haveAbadTime(),
+    // but G2 is already having a bad time. We solve this by conservatively
+    // treating A as potentially having indexed accessors if its global is already
+    // having a bad time. Hence, when A is set as O's prototype, O will be
+    // converted to SlowPutArrayStorage.
+
+    JSGlobalObject* globalObject = this->globalObject();
+    if (!globalObject)
+        return false;
+    return globalObject->isHavingABadTime();
+}
+
</ins><span class="cx"> inline JSObject* Structure::storedPrototypeObject() const
</span><span class="cx"> {
</span><span class="cx">     ASSERT(hasMonoProto());
</span></span></pre></div>
<a id="branchessafari606branchSourceJavaScriptCoretoolsJSDollarVMcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-606-branch/Source/JavaScriptCore/tools/JSDollarVM.cpp (237476 => 237477)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-606-branch/Source/JavaScriptCore/tools/JSDollarVM.cpp    2018-10-26 18:58:50 UTC (rev 237476)
+++ branches/safari-606-branch/Source/JavaScriptCore/tools/JSDollarVM.cpp       2018-10-26 19:10:25 UTC (rev 237477)
</span><span class="lines">@@ -1530,6 +1530,57 @@
</span><span class="cx">     return JSValue::encode(jsNumber(getCurrentProcessID()));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// Make the globalObject have a bad time. Does nothing if the object is not a JSGlobalObject.
+// Usage: $vm.haveABadTime(globalObject)
+static EncodedJSValue JSC_HOST_CALL functionHaveABadTime(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    JSLockHolder lock(vm);
+    JSValue objValue = exec->argument(0);
+    if (!objValue.isObject())
+        return JSValue::encode(jsBoolean(false));
+
+    JSObject* obj = asObject(objValue.asCell());
+    JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(vm, obj);
+    if (!globalObject)
+        JSValue::encode(jsBoolean(false));
+
+    globalObject->haveABadTime(vm);
+    return JSValue::encode(jsBoolean(true));
+}
+
+// Checks if the object (or its global if the object is not a global) is having a bad time.
+// Usage: $vm.isHavingABadTime(obj)
+static EncodedJSValue JSC_HOST_CALL functionIsHavingABadTime(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    JSLockHolder lock(vm);
+    JSValue objValue = exec->argument(0);
+    if (!objValue.isObject())
+        return JSValue::encode(jsUndefined());
+
+    JSObject* obj = asObject(objValue.asCell());
+    JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(vm, obj);
+    if (globalObject)
+        JSValue::encode(jsBoolean(globalObject->isHavingABadTime()));
+
+    globalObject = obj->globalObject();
+    if (!globalObject)
+        return JSValue::encode(jsUndefined());
+
+    return JSValue::encode(jsBoolean(globalObject->isHavingABadTime()));
+}
+
+// Creates a new global object.
+// Usage: $vm.createGlobalObject()
+static EncodedJSValue JSC_HOST_CALL functionCreateGlobalObject(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    JSLockHolder lock(vm);
+    JSGlobalObject* globalObject = JSGlobalObject::create(vm, JSGlobalObject::createStructure(vm, jsNull()));
+    return JSValue::encode(globalObject);
+}
+
</ins><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx">     VM& vm = exec->vm();
</span><span class="lines">@@ -1994,6 +2045,10 @@
</span><span class="cx">     addFunction(vm, "value", functionValue, 1);
</span><span class="cx">     addFunction(vm, "getpid", functionGetPID, 0);
</span><span class="cx"> 
</span><ins>+    addFunction(vm, "haveABadTime", functionHaveABadTime, 1);
+    addFunction(vm, "isHavingABadTime", functionIsHavingABadTime, 1);
+
+    addFunction(vm, "createGlobalObject", functionCreateGlobalObject, 0);
</ins><span class="cx">     addFunction(vm, "createProxy", functionCreateProxy, 1);
</span><span class="cx">     addFunction(vm, "createRuntimeArray", functionCreateRuntimeArray, 0);
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>