<!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>[178926] trunk</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/178926">178926</a></dd>
<dt>Author</dt> <dd>mark.lam@apple.com</dd>
<dt>Date</dt> <dd>2015-01-22 11:05:42 -0800 (Thu, 22 Jan 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>BytecodeGenerator::initializeCapturedVariable() sets a misleading value for the 5th operand of op_put_to_scope.
&lt;https://webkit.org/b/140743&gt;

Reviewed by Oliver Hunt.

Source/JavaScriptCore:

BytecodeGenerator::initializeCapturedVariable() was setting the 5th operand to
op_put_to_scope to an inappropriate value (i.e. 0).  As a result, the execution
of put_to_scope could store a wrong inferred value into the VariableWatchpointSet
for which ever captured variable is at local index 0.  In practice, this turns
out to be the local for the Arguments object.  In this reproduction case in the
bug, the wrong inferred value written there is the boolean true.

Subsequently, DFG compilation occurs and CreateArguments is emitted to first do
a check of the local for the Arguments object.  But because that local has a
wrong inferred value, the check always discovers a non-null value and we never
actually create the Arguments object.  Immediately after this, an OSR exit
occurs leaving the Arguments object local uninitialized.  Later on at arguments
tear off, we run into a boolean true where we had expected to find an Arguments
object, which in turn, leads to the crash.

The fix is to:
1. In the case where the resolveModeType is LocalClosureVar, change the
   5th operand of op_put_to_scope to be a boolean.  True means that the
   local var is watchable.  False means it is not watchable.  We no longer
   pass the local index (instead of true) and UINT_MAX (instead of false).

   This allows us to express more clearer in the code what that value means,
   as well as remove the redundant way of getting the local's identifier.
   The identifier is always the one passed in the 2nd operand.

2. Previously, though intuitively, we know that the watchable variable
   identifier should be the same as the one that is passed in operand 2, this
   relationship was not clear in the code.  By code analysis, I confirmed that
   the callers of BytecodeGenerator::emitPutToScope() always use the same
   identifier for operand 2 and for filling out the ResolveScopeInfo from
   which we get the watchable variable identifier later.  I've changed the
   code to make this clear now by always using the identifier passed in
   operand 2.

3. In the case where the resolveModeType is LocalClosureVar,
   initializeCapturedVariable() and emitPutToScope() will now query
   hasWatchableVariable() to determine if the local is watchable or not.
   Accordingly, we pass the boolean result of hasWatchableVariable() as
   operand 5 of op_put_to_scope.

Also added some assertions.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::initializeCapturedVariable):
(JSC::BytecodeGenerator::hasConstant):
(JSC::BytecodeGenerator::emitPutToScope):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::hasWatchableVariable):
(JSC::BytecodeGenerator::watchableVariableIdentifier):
(JSC::BytecodeGenerator::watchableVariable): Deleted.

LayoutTests:

* js/dfg-osr-exit-between-create-and-tearoff-arguments-expected.txt: Added.
* js/dfg-osr-exit-between-create-and-tearoff-arguments.html: Added.
* js/script-tests/dfg-osr-exit-between-create-and-tearoff-arguments.js: Added.
(foo):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockcpp">trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsdfgosrexitbetweencreateandtearoffargumentsexpectedtxt">trunk/LayoutTests/js/dfg-osr-exit-between-create-and-tearoff-arguments-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsdfgosrexitbetweencreateandtearoffargumentshtml">trunk/LayoutTests/js/dfg-osr-exit-between-create-and-tearoff-arguments.html</a></li>
<li><a href="#trunkLayoutTestsjsscripttestsdfgosrexitbetweencreateandtearoffargumentsjs">trunk/LayoutTests/js/script-tests/dfg-osr-exit-between-create-and-tearoff-arguments.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (178925 => 178926)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-01-22 18:51:56 UTC (rev 178925)
+++ trunk/LayoutTests/ChangeLog        2015-01-22 19:05:42 UTC (rev 178926)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2015-01-22  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        BytecodeGenerator::initializeCapturedVariable() sets a misleading value for the 5th operand of op_put_to_scope.
+        &lt;https://webkit.org/b/140743&gt;
+
+        Reviewed by Oliver Hunt.
+
+        * js/dfg-osr-exit-between-create-and-tearoff-arguments-expected.txt: Added.
+        * js/dfg-osr-exit-between-create-and-tearoff-arguments.html: Added.
+        * js/script-tests/dfg-osr-exit-between-create-and-tearoff-arguments.js: Added.
+        (foo):
+
</ins><span class="cx"> 2015-01-22  Brent Fulgham  &lt;bfulgham@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [Win] More unskips and rebaselines. 
</span></span></pre></div>
<a id="trunkLayoutTestsjsdfgosrexitbetweencreateandtearoffargumentsexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/dfg-osr-exit-between-create-and-tearoff-arguments-expected.txt (0 => 178926)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/dfg-osr-exit-between-create-and-tearoff-arguments-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/dfg-osr-exit-between-create-and-tearoff-arguments-expected.txt        2015-01-22 19:05:42 UTC (rev 178926)
</span><span class="lines">@@ -0,0 +1,9 @@
</span><ins>+Tests that an OSR exit between CreateArguments and TearOffArguments does not cause a crash.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsdfgosrexitbetweencreateandtearoffargumentshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/dfg-osr-exit-between-create-and-tearoff-arguments.html (0 => 178926)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/dfg-osr-exit-between-create-and-tearoff-arguments.html                                (rev 0)
+++ trunk/LayoutTests/js/dfg-osr-exit-between-create-and-tearoff-arguments.html        2015-01-22 19:05:42 UTC (rev 178926)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;script-tests/dfg-osr-exit-between-create-and-tearoff-arguments.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjsscripttestsdfgosrexitbetweencreateandtearoffargumentsjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/script-tests/dfg-osr-exit-between-create-and-tearoff-arguments.js (0 => 178926)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/dfg-osr-exit-between-create-and-tearoff-arguments.js                                (rev 0)
+++ trunk/LayoutTests/js/script-tests/dfg-osr-exit-between-create-and-tearoff-arguments.js        2015-01-22 19:05:42 UTC (rev 178926)
</span><span class="lines">@@ -0,0 +1,22 @@
</span><ins>+description(
+&quot;Tests that an OSR exit between CreateArguments and TearOffArguments does not cause a crash.&quot;
+);
+
+var foo = function(x) {
+    function goo(reenter) {
+        var captured = x;
+        return x + 5;
+    }
+
+    // Loop here to get this function to DFG compile.  Because we have captured vars,
+    // there will be a forced OSR exit on entry should we call this function again.
+    // We need this OSR exit to occur between the DFG generated code for
+    // CreateArguments and TearOffArguments in order for the bug to trigger a crash.
+    // See https://webkit.org/b/140743.
+    while (!dfgCompiled({f: foo}))
+        goo();
+    return arguments;
+}
+
+foo(1); // First call to get the DFG to compile foo() due to its big loop.
+foo(1); // Second call to trigger the OSR exit and verify that we don't crash.
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (178925 => 178926)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-01-22 18:51:56 UTC (rev 178925)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-01-22 19:05:42 UTC (rev 178926)
</span><span class="lines">@@ -1,3 +1,63 @@
</span><ins>+2015-01-22  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        BytecodeGenerator::initializeCapturedVariable() sets a misleading value for the 5th operand of op_put_to_scope.
+        &lt;https://webkit.org/b/140743&gt;
+
+        Reviewed by Oliver Hunt.
+
+        BytecodeGenerator::initializeCapturedVariable() was setting the 5th operand to
+        op_put_to_scope to an inappropriate value (i.e. 0).  As a result, the execution
+        of put_to_scope could store a wrong inferred value into the VariableWatchpointSet
+        for which ever captured variable is at local index 0.  In practice, this turns
+        out to be the local for the Arguments object.  In this reproduction case in the
+        bug, the wrong inferred value written there is the boolean true.
+
+        Subsequently, DFG compilation occurs and CreateArguments is emitted to first do
+        a check of the local for the Arguments object.  But because that local has a
+        wrong inferred value, the check always discovers a non-null value and we never
+        actually create the Arguments object.  Immediately after this, an OSR exit
+        occurs leaving the Arguments object local uninitialized.  Later on at arguments
+        tear off, we run into a boolean true where we had expected to find an Arguments
+        object, which in turn, leads to the crash.
+
+        The fix is to:
+        1. In the case where the resolveModeType is LocalClosureVar, change the
+           5th operand of op_put_to_scope to be a boolean.  True means that the
+           local var is watchable.  False means it is not watchable.  We no longer
+           pass the local index (instead of true) and UINT_MAX (instead of false).
+
+           This allows us to express more clearer in the code what that value means,
+           as well as remove the redundant way of getting the local's identifier.
+           The identifier is always the one passed in the 2nd operand. 
+
+        2. Previously, though intuitively, we know that the watchable variable
+           identifier should be the same as the one that is passed in operand 2, this
+           relationship was not clear in the code.  By code analysis, I confirmed that 
+           the callers of BytecodeGenerator::emitPutToScope() always use the same
+           identifier for operand 2 and for filling out the ResolveScopeInfo from
+           which we get the watchable variable identifier later.  I've changed the
+           code to make this clear now by always using the identifier passed in
+           operand 2.
+
+        3. In the case where the resolveModeType is LocalClosureVar,
+           initializeCapturedVariable() and emitPutToScope() will now query
+           hasWatchableVariable() to determine if the local is watchable or not.
+           Accordingly, we pass the boolean result of hasWatchableVariable() as
+           operand 5 of op_put_to_scope.
+
+        Also added some assertions.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::CodeBlock):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::initializeCapturedVariable):
+        (JSC::BytecodeGenerator::hasConstant):
+        (JSC::BytecodeGenerator::emitPutToScope):
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::hasWatchableVariable):
+        (JSC::BytecodeGenerator::watchableVariableIdentifier):
+        (JSC::BytecodeGenerator::watchableVariable): Deleted.
+
</ins><span class="cx"> 2015-01-22  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         PropertyListNode::emitNode duplicates the code to put a constant property
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp (178925 => 178926)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2015-01-22 18:51:56 UTC (rev 178925)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2015-01-22 19:05:42 UTC (rev 178926)
</span><span class="lines">@@ -1998,11 +1998,12 @@
</span><span class="cx"> 
</span><span class="cx">             ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand);
</span><span class="cx">             if (modeAndType.type() == LocalClosureVar) {
</span><del>-                if (pc[5].u.index == UINT_MAX) {
-                    instructions[i + 5].u.watchpointSet = 0;
</del><ins>+                bool isWatchableVariable = pc[5].u.operand;
+                if (!isWatchableVariable) {
+                    instructions[i + 5].u.watchpointSet = nullptr;
</ins><span class="cx">                     break;
</span><span class="cx">                 }
</span><del>-                StringImpl* uid = identifier(pc[5].u.index).impl();
</del><ins>+                StringImpl* uid = ident.impl();
</ins><span class="cx">                 RELEASE_ASSERT(didCloneSymbolTable);
</span><span class="cx">                 if (ident != m_vm-&gt;propertyNames-&gt;arguments) {
</span><span class="cx">                     ConcurrentJITLocker locker(m_symbolTable-&gt;m_lock);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (178925 => 178926)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2015-01-22 18:51:56 UTC (rev 178925)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2015-01-22 19:05:42 UTC (rev 178926)
</span><span class="lines">@@ -517,7 +517,10 @@
</span><span class="cx">     instructions().append(addConstant(propertyName));
</span><span class="cx">     instructions().append(value-&gt;index());
</span><span class="cx">     instructions().append(ResolveModeAndType(ThrowIfNotFound, LocalClosureVar).operand());
</span><del>-    instructions().append(0);
</del><ins>+    int operand = registerFor(dst-&gt;index()).index();
+    bool isWatchableVariable = hasWatchableVariable(operand);
+    ASSERT(!isWatchableVariable || watchableVariableIdentifier(operand) == propertyName);
+    instructions().append(isWatchableVariable);
</ins><span class="cx">     instructions().append(dst-&gt;index());
</span><span class="cx">     return dst;
</span><span class="cx"> }
</span><span class="lines">@@ -998,6 +1001,12 @@
</span><span class="cx">     return target;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool BytecodeGenerator::hasConstant(const Identifier&amp; ident) const
+{
+    StringImpl* rep = ident.impl();
+    return m_identifierMap.contains(rep);
+}
+    
</ins><span class="cx"> unsigned BytecodeGenerator::addConstant(const Identifier&amp; ident)
</span><span class="cx"> {
</span><span class="cx">     StringImpl* rep = ident.impl();
</span><span class="lines">@@ -1396,10 +1405,14 @@
</span><span class="cx">     instructions().append(value-&gt;index());
</span><span class="cx">     if (info.isLocal()) {
</span><span class="cx">         instructions().append(ResolveModeAndType(resolveMode, LocalClosureVar).operand());
</span><del>-        instructions().append(watchableVariable(registerFor(info.localIndex()).index()));
</del><ins>+        int operand = registerFor(info.localIndex()).index();
+        bool isWatchableVariable = hasWatchableVariable(operand);
+        ASSERT(!isWatchableVariable || watchableVariableIdentifier(operand) == identifier);
+        instructions().append(isWatchableVariable);
</ins><span class="cx">     } else {
</span><ins>+        ASSERT(resolveType() != LocalClosureVar);
</ins><span class="cx">         instructions().append(ResolveModeAndType(resolveMode, resolveType()).operand());
</span><del>-        instructions().append(0);
</del><ins>+        instructions().append(false);
</ins><span class="cx">     }
</span><span class="cx">     instructions().append(info.localIndex());
</span><span class="cx">     return value;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h (178925 => 178926)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2015-01-22 18:51:56 UTC (rev 178925)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2015-01-22 19:05:42 UTC (rev 178926)
</span><span class="lines">@@ -652,6 +652,7 @@
</span><span class="cx">             return m_parameters[VirtualRegister(index).toArgument()];
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        bool hasConstant(const Identifier&amp;) const;
</ins><span class="cx">         unsigned addConstant(const Identifier&amp;);
</span><span class="cx">         RegisterID* addConstantValue(JSValue);
</span><span class="cx">         RegisterID* addConstantEmptyValue();
</span><span class="lines">@@ -726,22 +727,25 @@
</span><span class="cx">         void createArgumentsIfNecessary();
</span><span class="cx">         RegisterID* createLazyRegisterIfNecessary(RegisterID*);
</span><span class="cx">         
</span><del>-        unsigned watchableVariable(int operand)
</del><ins>+        bool hasWatchableVariable(int operand) const
</ins><span class="cx">         {
</span><span class="cx">             VirtualRegister reg(operand);
</span><span class="cx">             if (!reg.isLocal())
</span><del>-                return UINT_MAX;
</del><ins>+                return false;
</ins><span class="cx">             if (static_cast&lt;size_t&gt;(reg.toLocal()) &gt;= m_watchableVariables.size())
</span><del>-                return UINT_MAX;
-            Identifier&amp; ident = m_watchableVariables[reg.toLocal()];
</del><ins>+                return false;
+            const Identifier&amp; ident = m_watchableVariables[reg.toLocal()];
</ins><span class="cx">             if (ident.isNull())
</span><del>-                return UINT_MAX;
-            return addConstant(ident);
</del><ins>+                return false;
+            ASSERT(hasConstant(ident)); // Should have already been added.
+            return true;
</ins><span class="cx">         }
</span><span class="cx">         
</span><del>-        bool hasWatchableVariable(int operand)
</del><ins>+        const Identifier&amp; watchableVariableIdentifier(int operand) const
</ins><span class="cx">         {
</span><del>-            return watchableVariable(operand) != UINT_MAX;
</del><ins>+            ASSERT(hasWatchableVariable(operand));
+            VirtualRegister reg(operand);
+            return m_watchableVariables[reg.toLocal()];
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">     private:
</span></span></pre>
</div>
</div>

</body>
</html>