<!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>[201456] trunk/Source/JavaScriptCore</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/201456">201456</a></dd>
<dt>Author</dt> <dd>keith_miller@apple.com</dd>
<dt>Date</dt> <dd>2016-05-27 11:36:30 -0700 (Fri, 27 May 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>get_by_id should support caching unset properties in the LLInt
https://bugs.webkit.org/show_bug.cgi?id=158136

Reviewed by Benjamin Poulain.

Recently, we started supporting prototype load caching for get_by_id
in the LLInt. This patch extends that to caching unset properties.
While it is uncommon in general for a program to see a single structure
without a given property, the Array.prototype.concat function needs to
lookup the Symbol.isConcatSpreadable property. For any existing code
That property will never be set as it did not exist prior to ES6.

Similarly to the get_by_id_proto_load bytecode, this patch adds a new
bytecode, get_by_id_unset that checks the structureID of the base and
assigns undefined to the result.

There are no new tests here since we already have many tests that
incidentally cover this change.

* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::printGetByIdOp):
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::finalizeLLIntInlineCaches):
* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::computeFromLLInt):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::setupGetByIdPrototypeCache):
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LLIntSlowPaths.h:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeBytecodeListjson">trunk/Source/JavaScriptCore/bytecode/BytecodeList.json</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeBytecodeUseDefh">trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockcpp">trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeGetByIdStatuscpp">trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCapabilitiescpp">trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITcpp">trunk/Source/JavaScriptCore/jit/JIT.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLLIntSlowPathscpp">trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLLIntSlowPathsh">trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.h</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreter32_64asm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreter64asm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (201455 => 201456)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-05-27 18:35:49 UTC (rev 201455)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-05-27 18:36:30 UTC (rev 201456)
</span><span class="lines">@@ -1,3 +1,48 @@
</span><ins>+2016-05-27  Keith Miller  &lt;keith_miller@apple.com&gt;
+
+        get_by_id should support caching unset properties in the LLInt
+        https://bugs.webkit.org/show_bug.cgi?id=158136
+
+        Reviewed by Benjamin Poulain.
+
+        Recently, we started supporting prototype load caching for get_by_id
+        in the LLInt. This patch extends that to caching unset properties.
+        While it is uncommon in general for a program to see a single structure
+        without a given property, the Array.prototype.concat function needs to
+        lookup the Symbol.isConcatSpreadable property. For any existing code
+        That property will never be set as it did not exist prior to ES6.
+
+        Similarly to the get_by_id_proto_load bytecode, this patch adds a new
+        bytecode, get_by_id_unset that checks the structureID of the base and
+        assigns undefined to the result.
+
+        There are no new tests here since we already have many tests that
+        incidentally cover this change.
+
+        * bytecode/BytecodeList.json:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::printGetByIdOp):
+        (JSC::CodeBlock::dumpBytecode):
+        (JSC::CodeBlock::finalizeLLIntInlineCaches):
+        * bytecode/GetByIdStatus.cpp:
+        (JSC::GetByIdStatus::computeFromLLInt):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        (JSC::JIT::privateCompileSlowCases):
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::setupGetByIdPrototypeCache):
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * llint/LLIntSlowPaths.h:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+
</ins><span class="cx"> 2016-05-26  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Bogus uses of regexp matching should realize that they will OOM before they start swapping
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeBytecodeListjson"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/BytecodeList.json (201455 => 201456)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/BytecodeList.json        2016-05-27 18:35:49 UTC (rev 201455)
+++ trunk/Source/JavaScriptCore/bytecode/BytecodeList.json        2016-05-27 18:36:30 UTC (rev 201456)
</span><span class="lines">@@ -61,6 +61,7 @@
</span><span class="cx">             { &quot;name&quot; : &quot;op_get_array_length&quot;, &quot;length&quot; : 9 },
</span><span class="cx">             { &quot;name&quot; : &quot;op_get_by_id&quot;, &quot;length&quot; : 9  },
</span><span class="cx">             { &quot;name&quot; : &quot;op_get_by_id_proto_load&quot;, &quot;length&quot; : 9 },
</span><ins>+            { &quot;name&quot; : &quot;op_get_by_id_unset&quot;, &quot;length&quot; : 9 },
</ins><span class="cx">             { &quot;name&quot; : &quot;op_get_by_id_with_this&quot;, &quot;length&quot; : 5 },
</span><span class="cx">             { &quot;name&quot; : &quot;op_get_by_val_with_this&quot;, &quot;length&quot; : 5 },
</span><span class="cx">             { &quot;name&quot; : &quot;op_try_get_by_id&quot;, &quot;length&quot; : 4 },
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeBytecodeUseDefh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h (201455 => 201456)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h        2016-05-27 18:35:49 UTC (rev 201455)
+++ trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h        2016-05-27 18:36:30 UTC (rev 201456)
</span><span class="lines">@@ -159,6 +159,7 @@
</span><span class="cx">     case op_try_get_by_id:
</span><span class="cx">     case op_get_by_id:
</span><span class="cx">     case op_get_by_id_proto_load:
</span><ins>+    case op_get_by_id_unset:
</ins><span class="cx">     case op_get_array_length:
</span><span class="cx">     case op_typeof:
</span><span class="cx">     case op_is_empty:
</span><span class="lines">@@ -394,6 +395,7 @@
</span><span class="cx">     case op_try_get_by_id:
</span><span class="cx">     case op_get_by_id:
</span><span class="cx">     case op_get_by_id_proto_load:
</span><ins>+    case op_get_by_id_unset:
</ins><span class="cx">     case op_get_by_id_with_this:
</span><span class="cx">     case op_get_by_val_with_this:
</span><span class="cx">     case op_get_array_length:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp (201455 => 201456)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2016-05-27 18:35:49 UTC (rev 201455)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2016-05-27 18:36:30 UTC (rev 201456)
</span><span class="lines">@@ -349,6 +349,9 @@
</span><span class="cx">     case op_get_by_id_proto_load:
</span><span class="cx">         op = &quot;get_by_id_proto_load&quot;;
</span><span class="cx">         break;
</span><ins>+    case op_get_by_id_unset:
+        op = &quot;get_by_id_unset&quot;;
+        break;
</ins><span class="cx">     case op_get_array_length:
</span><span class="cx">         op = &quot;array_length&quot;;
</span><span class="cx">         break;
</span><span class="lines">@@ -1119,6 +1122,7 @@
</span><span class="cx">         }
</span><span class="cx">         case op_get_by_id:
</span><span class="cx">         case op_get_by_id_proto_load:
</span><ins>+        case op_get_by_id_unset:
</ins><span class="cx">         case op_get_array_length: {
</span><span class="cx">             printGetByIdOp(out, exec, location, it);
</span><span class="cx">             printGetByIdCacheStatus(out, exec, location, stubInfos);
</span><span class="lines">@@ -2806,7 +2810,8 @@
</span><span class="cx">         Instruction* curInstruction = &amp;instructions()[propertyAccessInstructions[i]];
</span><span class="cx">         switch (interpreter-&gt;getOpcodeID(curInstruction[0].u.opcode)) {
</span><span class="cx">         case op_get_by_id:
</span><del>-        case op_get_by_id_proto_load: {
</del><ins>+        case op_get_by_id_proto_load:
+        case op_get_by_id_unset: {
</ins><span class="cx">             StructureID oldStructureID = curInstruction[4].u.structureID;
</span><span class="cx">             if (!oldStructureID || Heap::isMarked(m_vm-&gt;heap.structureIDTable().get(oldStructureID)))
</span><span class="cx">                 break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeGetByIdStatuscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp (201455 => 201456)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp        2016-05-27 18:35:49 UTC (rev 201455)
+++ trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp        2016-05-27 18:36:30 UTC (rev 201456)
</span><span class="lines">@@ -78,9 +78,11 @@
</span><span class="cx"> 
</span><span class="cx">     Opcode opcode = instruction[0].u.opcode;
</span><span class="cx"> 
</span><ins>+    ASSERT(opcode == LLInt::getOpcode(op_get_array_length) || opcode == LLInt::getOpcode(op_try_get_by_id) || opcode == LLInt::getOpcode(op_get_by_id_proto_load) || opcode == LLInt::getOpcode(op_get_by_id) || opcode == LLInt::getOpcode(op_get_by_id_unset));
+
</ins><span class="cx">     // FIXME: We should not just bail if we see a try_get_by_id or a get_by_id_proto_load.
</span><span class="cx">     // https://bugs.webkit.org/show_bug.cgi?id=158039
</span><del>-    if (opcode == LLInt::getOpcode(op_get_array_length) || opcode == LLInt::getOpcode(op_try_get_by_id) || opcode == LLInt::getOpcode(op_get_by_id_proto_load))
</del><ins>+    if (opcode != LLInt::getOpcode(op_get_by_id))
</ins><span class="cx">         return GetByIdStatus(NoInformation, false);
</span><span class="cx"> 
</span><span class="cx">     StructureID structureID = instruction[4].u.structureID;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (201455 => 201456)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2016-05-27 18:35:49 UTC (rev 201455)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2016-05-27 18:36:30 UTC (rev 201456)
</span><span class="lines">@@ -4082,6 +4082,7 @@
</span><span class="cx"> 
</span><span class="cx">         case op_get_by_id:
</span><span class="cx">         case op_get_by_id_proto_load:
</span><ins>+        case op_get_by_id_unset:
</ins><span class="cx">         case op_get_array_length: {
</span><span class="cx">             SpeculatedType prediction = getPrediction();
</span><span class="cx">             
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp (201455 => 201456)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp        2016-05-27 18:35:49 UTC (rev 201455)
+++ trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp        2016-05-27 18:36:30 UTC (rev 201456)
</span><span class="lines">@@ -155,6 +155,7 @@
</span><span class="cx">     case op_try_get_by_id:
</span><span class="cx">     case op_get_by_id:
</span><span class="cx">     case op_get_by_id_proto_load:
</span><ins>+    case op_get_by_id_unset:
</ins><span class="cx">     case op_get_by_id_with_this:
</span><span class="cx">     case op_get_by_val_with_this:
</span><span class="cx">     case op_get_array_length:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JIT.cpp (201455 => 201456)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JIT.cpp        2016-05-27 18:35:49 UTC (rev 201455)
+++ trunk/Source/JavaScriptCore/jit/JIT.cpp        2016-05-27 18:36:30 UTC (rev 201456)
</span><span class="lines">@@ -241,6 +241,7 @@
</span><span class="cx">         DEFINE_OP(op_try_get_by_id)
</span><span class="cx">         case op_get_array_length:
</span><span class="cx">         case op_get_by_id_proto_load:
</span><ins>+        case op_get_by_id_unset:
</ins><span class="cx">         DEFINE_OP(op_get_by_id)
</span><span class="cx">         DEFINE_OP(op_get_by_id_with_this)
</span><span class="cx">         DEFINE_OP(op_get_by_val)
</span><span class="lines">@@ -424,6 +425,7 @@
</span><span class="cx">         DEFINE_SLOWCASE_OP(op_try_get_by_id)
</span><span class="cx">         case op_get_array_length:
</span><span class="cx">         case op_get_by_id_proto_load:
</span><ins>+        case op_get_by_id_unset:
</ins><span class="cx">         DEFINE_SLOWCASE_OP(op_get_by_id)
</span><span class="cx">         DEFINE_SLOWCASE_OP(op_get_by_val)
</span><span class="cx">         DEFINE_SLOWCASE_OP(op_instanceof)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLLIntSlowPathscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp (201455 => 201456)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp        2016-05-27 18:35:49 UTC (rev 201455)
+++ trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp        2016-05-27 18:36:30 UTC (rev 201456)
</span><span class="lines">@@ -589,7 +589,11 @@
</span><span class="cx">     if (structure-&gt;typeInfo().prohibitsPropertyCaching() || structure-&gt;isDictionary())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    ObjectPropertyConditionSet conditions = generateConditionsForPrototypePropertyHit(vm, codeBlock, exec, structure, slot.slotBase(), ident.impl());
</del><ins>+    ObjectPropertyConditionSet conditions;
+    if (slot.isUnset())
+        conditions = generateConditionsForPropertyMiss(vm, codeBlock, exec, structure, ident.impl());
+    else
+        conditions = generateConditionsForPrototypePropertyHit(vm, codeBlock, exec, structure, slot.slotBase(), ident.impl());
</ins><span class="cx"> 
</span><span class="cx">     if (!conditions.isValid())
</span><span class="cx">         return;
</span><span class="lines">@@ -604,16 +608,22 @@
</span><span class="cx">             offset = condition.condition().offset();
</span><span class="cx">         result.iterator-&gt;value.add(condition, pc)-&gt;install();
</span><span class="cx">     }
</span><del>-    ASSERT(offset != invalidOffset);
</del><ins>+    ASSERT((offset == invalidOffset) == slot.isUnset());
</ins><span class="cx"> 
</span><span class="cx">     ConcurrentJITLocker locker(codeBlock-&gt;m_lock);
</span><span class="cx"> 
</span><ins>+    if (slot.isUnset()) {
+        pc[0].u.opcode = LLInt::getOpcode(op_get_by_id_unset);
+        pc[4].u.structureID = structure-&gt;id();
+        return;
+    }
+    ASSERT(slot.isValue());
+
</ins><span class="cx">     pc[0].u.opcode = LLInt::getOpcode(op_get_by_id_proto_load);
</span><span class="cx">     pc[4].u.structureID = structure-&gt;id();
</span><span class="cx">     pc[5].u.operand = offset;
</span><del>-    // We know that this pointer will remain valid because it is the prototype of some structure, s,
-    // watchpointed above. If any object with structure s were to change prototypes then the conditions
-    // for this cache would fail and this value will never be used again.
</del><ins>+    // We know that this pointer will remain valid because it will be cleared by either a watchpoint fire or
+    // during GC when we clear the LLInt caches.
</ins><span class="cx">     pc[6].u.pointer = slot.slotBase();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -632,11 +642,11 @@
</span><span class="cx">     
</span><span class="cx">     if (!LLINT_ALWAYS_ACCESS_SLOW
</span><span class="cx">         &amp;&amp; baseValue.isCell()
</span><del>-        &amp;&amp; slot.isCacheableValue()) {
</del><ins>+        &amp;&amp; slot.isCacheable()) {
</ins><span class="cx"> 
</span><span class="cx">         JSCell* baseCell = baseValue.asCell();
</span><span class="cx">         Structure* structure = baseCell-&gt;structure();
</span><del>-        if (slot.slotBase() == baseValue) {
</del><ins>+        if (slot.isValue() &amp;&amp; slot.slotBase() == baseValue) {
</ins><span class="cx">             // Start out by clearing out the old cache.
</span><span class="cx">             pc[0].u.opcode = LLInt::getOpcode(op_get_by_id);
</span><span class="cx">             pc[4].u.pointer = nullptr; // old structure
</span><span class="lines">@@ -653,7 +663,7 @@
</span><span class="cx">                 pc[4].u.structureID = structure-&gt;id();
</span><span class="cx">                 pc[5].u.operand = slot.cachedOffset();
</span><span class="cx">             }
</span><del>-        } else if (UNLIKELY(pc[7].u.operand)) {
</del><ins>+        } else if (UNLIKELY(pc[7].u.operand &amp;&amp; (slot.isValue() || slot.isUnset()))) {
</ins><span class="cx">             ASSERT(slot.slotBase() != baseValue);
</span><span class="cx"> 
</span><span class="cx">             if (!(--pc[7].u.operand))
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLLIntSlowPathsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.h (201455 => 201456)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.h        2016-05-27 18:35:49 UTC (rev 201455)
+++ trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.h        2016-05-27 18:36:30 UTC (rev 201456)
</span><span class="lines">@@ -71,7 +71,6 @@
</span><span class="cx"> LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_instanceof_custom);
</span><span class="cx"> LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_try_get_by_id);
</span><span class="cx"> LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id);
</span><del>-LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id_proto_load);
</del><span class="cx"> LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_arguments_length);
</span><span class="cx"> LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_by_id);
</span><span class="cx"> LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_del_by_id);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter32_64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm (201455 => 201456)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm        2016-05-27 18:35:49 UTC (rev 201455)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm        2016-05-27 18:36:30 UTC (rev 201456)
</span><span class="lines">@@ -1337,8 +1337,9 @@
</span><span class="cx"> # opcode for own properties. We also allow for the cache to change anytime it fails,
</span><span class="cx"> # since ping-ponging is free. At best we get lucky and the get_by_id will continue
</span><span class="cx"> # to take fast path on the new cache. At worst we take slow path, which is what
</span><del>-# we would have been doing anyway. For prototype properties, we will attempt to
-# convert opcode into a get_by_id_proto_load after a execution counter hits zero.
</del><ins>+# we would have been doing anyway. For prototype/unset properties, we will attempt to
+# convert opcode into a get_by_id_proto_load/get_by_id_unset, respectively, after an
+# execution counter hits zero.
</ins><span class="cx"> 
</span><span class="cx"> _llint_op_get_by_id:
</span><span class="cx">     traceExecution()
</span><span class="lines">@@ -1359,7 +1360,6 @@
</span><span class="cx">     dispatch(9)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> _llint_op_get_by_id_proto_load:
</span><span class="cx">     traceExecution()
</span><span class="cx">     loadi 8[PC], t0
</span><span class="lines">@@ -1380,6 +1380,23 @@
</span><span class="cx">     dispatch(9)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+_llint_op_get_by_id_unset:
+    traceExecution()
+    loadi 8[PC], t0
+    loadi 16[PC], t1
+    loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdUnsetSlow)
+    bineq JSCell::m_structureID[t3], t1, .opGetByIdUnsetSlow
+    loadi 4[PC], t2
+    storei UndefinedTag, TagOffset[cfr, t2, 8]
+    storei 0, PayloadOffset[cfr, t2, 8]
+    valueProfile(UndefinedTag, 0, 32, t2)
+    dispatch(9)
+
+.opGetByIdUnsetSlow:
+    callSlowPath(_llint_slow_path_get_by_id)
+    dispatch(9)
+
+
</ins><span class="cx"> _llint_op_get_array_length:
</span><span class="cx">     traceExecution()
</span><span class="cx">     loadi 8[PC], t0
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (201455 => 201456)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2016-05-27 18:35:49 UTC (rev 201455)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2016-05-27 18:36:30 UTC (rev 201456)
</span><span class="lines">@@ -1252,6 +1252,23 @@
</span><span class="cx">     dispatch(9)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+_llint_op_get_by_id_unset:
+    traceExecution()
+    loadisFromInstruction(2, t0)
+    loadConstantOrVariableCell(t0, t3, .opGetByIdUnsetSlow)
+    loadi JSCell::m_structureID[t3], t1
+    loadisFromInstruction(4, t2)
+    bineq t2, t1, .opGetByIdUnsetSlow
+    loadisFromInstruction(1, t2)
+    storeq ValueUndefined, [cfr, t2, 8]
+    valueProfile(ValueUndefined, 8, t1)
+    dispatch(9)
+
+.opGetByIdUnsetSlow:
+    callSlowPath(_llint_slow_path_get_by_id)
+    dispatch(9)
+
+
</ins><span class="cx"> _llint_op_get_array_length:
</span><span class="cx">     traceExecution()
</span><span class="cx">     loadisFromInstruction(2, t0)
</span></span></pre>
</div>
</div>

</body>
</html>