<!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>[161377] 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/161377">161377</a></dd>
<dt>Author</dt> <dd>mhahnenberg@apple.com</dd>
<dt>Date</dt> <dd>2014-01-06 15:04:25 -0800 (Mon, 06 Jan 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add write barriers to the LLInt
https://bugs.webkit.org/show_bug.cgi?id=126527

Reviewed by Filip Pizlo.

This patch takes a similar approach to how write barriers work in the baseline JIT.
We execute the write barrier at the beginning of the opcode so we don't have to
worry about saving and restoring live registers across write barrier slow path calls
to C code.

* llint/LLIntOfflineAsmConfig.h:
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::llint_write_barrier_slow):
* llint/LLIntSlowPaths.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* offlineasm/arm64.rb:
* offlineasm/instructions.rb:
* offlineasm/x86.rb:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLLIntOfflineAsmConfigh">trunk/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h</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="#trunkSourceJavaScriptCorellintLowLevelInterpreterasm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm</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>
<li><a href="#trunkSourceJavaScriptCoreofflineasmarmrb">trunk/Source/JavaScriptCore/offlineasm/arm.rb</a></li>
<li><a href="#trunkSourceJavaScriptCoreofflineasmarm64rb">trunk/Source/JavaScriptCore/offlineasm/arm64.rb</a></li>
<li><a href="#trunkSourceJavaScriptCoreofflineasmmipsrb">trunk/Source/JavaScriptCore/offlineasm/mips.rb</a></li>
<li><a href="#trunkSourceJavaScriptCoreofflineasmx86rb">trunk/Source/JavaScriptCore/offlineasm/x86.rb</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (161376 => 161377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-01-06 23:04:25 UTC (rev 161377)
</span><span class="lines">@@ -1,3 +1,26 @@
</span><ins>+2014-01-06  Mark Hahnenberg  &lt;mhahnenberg@apple.com&gt;
+
+        Add write barriers to the LLInt
+        https://bugs.webkit.org/show_bug.cgi?id=126527
+
+        Reviewed by Filip Pizlo.
+
+        This patch takes a similar approach to how write barriers work in the baseline JIT.
+        We execute the write barrier at the beginning of the opcode so we don't have to 
+        worry about saving and restoring live registers across write barrier slow path calls 
+        to C code.
+
+        * llint/LLIntOfflineAsmConfig.h:
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::llint_write_barrier_slow):
+        * llint/LLIntSlowPaths.h:
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * offlineasm/arm64.rb:
+        * offlineasm/instructions.rb:
+        * offlineasm/x86.rb:
+
</ins><span class="cx"> 2014-01-05  Sam Weinig  &lt;sam@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         [JS] Implement Promise.all()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLLIntOfflineAsmConfigh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h (161376 => 161377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h        2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h        2014-01-06 23:04:25 UTC (rev 161377)
</span><span class="lines">@@ -148,4 +148,10 @@
</span><span class="cx"> #define OFFLINE_ASM_ALWAYS_ALLOCATE_SLOW 0
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+#if ENABLE(GGC)
+#define OFFLINE_ASM_GGC 1
+#else
+#define OFFLINE_ASM_GGC 0
+#endif
+
</ins><span class="cx"> #endif // LLIntOfflineAsmConfig_h
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLLIntSlowPathscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp (161376 => 161377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp        2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp        2014-01-06 23:04:25 UTC (rev 161377)
</span><span class="lines">@@ -1388,6 +1388,11 @@
</span><span class="cx">     LLINT_END();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+extern &quot;C&quot; void llint_write_barrier_slow(ExecState*, JSCell* cell)
+{
+    Heap::writeBarrier(cell);
+}
+
</ins><span class="cx"> } } // namespace JSC::LLInt
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(LLINT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLLIntSlowPathsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.h (161376 => 161377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.h        2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.h        2014-01-06 23:04:25 UTC (rev 161377)
</span><span class="lines">@@ -41,6 +41,7 @@
</span><span class="cx"> 
</span><span class="cx"> extern &quot;C&quot; SlowPathReturnType llint_trace_operand(ExecState*, Instruction*, int fromWhere, int operand);
</span><span class="cx"> extern &quot;C&quot; SlowPathReturnType llint_trace_value(ExecState*, Instruction*, int fromWhere, int operand);
</span><ins>+extern &quot;C&quot; void llint_write_barrier_slow(ExecState*, JSCell*);
</ins><span class="cx"> 
</span><span class="cx"> #define LLINT_SLOW_PATH_DECL(name) \
</span><span class="cx">     extern &quot;C&quot; SlowPathReturnType llint_##name(ExecState* exec, Instruction* pc)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreterasm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm (161376 => 161377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm        2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm        2014-01-06 23:04:25 UTC (rev 161377)
</span><span class="lines">@@ -170,7 +170,11 @@
</span><span class="cx"> 
</span><span class="cx"> const ResolveModeMask = 0xffff
</span><span class="cx"> 
</span><del>-const MarkedBlockMask = ~0xffff
</del><ins>+const MarkedBlockSize = 64 * 1024
+const MarkedBlockMask = ~(MarkedBlockSize - 1)
+# Constants for checking mark bits.
+const AtomNumberShift = 3
+const BitMapWordShift = 4
</ins><span class="cx"> 
</span><span class="cx"> # Allocation constants
</span><span class="cx"> if JSVALUE64
</span><span class="lines">@@ -263,6 +267,18 @@
</span><span class="cx">     loadb Structure::m_indexingType[structure], indexingType
</span><span class="cx"> end
</span><span class="cx"> 
</span><ins>+macro checkMarkByte(cell, scratch1, scratch2, continuation)
+    move cell, scratch1
+    move cell, scratch2
+
+    andp MarkedBlockMask, scratch1
+    andp ~MarkedBlockMask, scratch2
+
+    rshiftp AtomNumberShift + BitMapWordShift, scratch2
+    loadb MarkedBlock::m_marks[scratch1, scratch2, 1], scratch1
+    continuation(scratch1)
+end
+
</ins><span class="cx"> macro checkSwitchToJIT(increment, action)
</span><span class="cx">     loadp CodeBlock[cfr], t0
</span><span class="cx">     baddis increment, CodeBlock::m_llintExecuteCounter + ExecutionCounter::m_counter[t0], .continue
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter32_64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm (161376 => 161377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm        2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm        2014-01-06 23:04:25 UTC (rev 161377)
</span><span class="lines">@@ -491,10 +491,58 @@
</span><span class="cx">         payload)
</span><span class="cx"> end
</span><span class="cx"> 
</span><del>-macro writeBarrier(tag, payload)
-    # Nothing to do, since we don't have a generational or incremental collector.
</del><ins>+macro writeBarrierOnOperand(cellOperand)
+    if GGC
+        loadisFromInstruction(cellOperand, t1)
+        loadConstantOrVariablePayload(t1, CellTag, t0, .writeBarrierDone)
+        checkMarkByte(t0, t1, t2, 
+            macro(marked)
+                btbz marked, .writeBarrierDone
+                push cfr, PC
+                # We make two extra slots because cCall2 will poke.
+                subp 8, sp
+                cCall2(_llint_write_barrier_slow, cfr, t0)
+                addp 8, sp
+                pop PC, cfr
+            end
+        )
+    .writeBarrierDone:
+    end
</ins><span class="cx"> end
</span><span class="cx"> 
</span><ins>+macro writeBarrierOnOperands(cellOperand, valueOperand)
+    if GGC
+        loadisFromInstruction(valueOperand, t1)
+        loadConstantOrVariableTag(t1, t0)
+        bineq t0, CellTag, .writeBarrierDone
+    
+        writeBarrierOnOperand(cellOperand)
+    .writeBarrierDone:
+    end
+end
+
+macro writeBarrierOnGlobalObject(valueOperand)
+    if GGC
+        loadisFromInstruction(valueOperand, t1)
+        bineq t0, CellTag, .writeBarrierDone
+    
+        loadp CodeBlock[cfr], t0
+        loadp CodeBlock::m_globalObject[t0], t0
+        checkMarkByte(t0, t1, t2,
+            macro(marked)
+                btbz marked, .writeBarrierDone
+                push cfr, PC
+                # We make two extra slots because cCall2 will poke.
+                subp 8, sp
+                cCall2(_llint_write_barrier_slow, cfr, t0)
+                addp 8, sp
+                pop PC, cfr
+            end
+        )
+    .writeBarrierDone:
+    end
+end
+
</ins><span class="cx"> macro valueProfile(tag, payload, operand, scratch)
</span><span class="cx">     loadp operand[PC], scratch
</span><span class="cx">     storei tag, ValueProfile::m_buckets + TagOffset[scratch]
</span><span class="lines">@@ -575,6 +623,7 @@
</span><span class="cx">     addi 1, t2
</span><span class="cx">     btinz t2, .opEnterLoop
</span><span class="cx"> .opEnterDone:
</span><ins>+    callSlowPath(_slow_path_enter)
</ins><span class="cx">     dispatch(1)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -1255,10 +1304,10 @@
</span><span class="cx"> 
</span><span class="cx"> _llint_op_init_global_const:
</span><span class="cx">     traceExecution()
</span><ins>+    writeBarrierOnGlobalObject(2)
</ins><span class="cx">     loadi 8[PC], t1
</span><span class="cx">     loadi 4[PC], t0
</span><span class="cx">     loadConstantOrVariable(t1, t2, t3)
</span><del>-    writeBarrier(t2, t3)
</del><span class="cx">     storei t2, TagOffset[t0]
</span><span class="cx">     storei t3, PayloadOffset[t0]
</span><span class="cx">     dispatch(5)
</span><span class="lines">@@ -1344,6 +1393,7 @@
</span><span class="cx"> 
</span><span class="cx"> macro putById(getPropertyStorage)
</span><span class="cx">     traceExecution()
</span><ins>+    writeBarrierOnOperands(1, 3)
</ins><span class="cx">     loadi 4[PC], t3
</span><span class="cx">     loadi 16[PC], t1
</span><span class="cx">     loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
</span><span class="lines">@@ -1355,7 +1405,6 @@
</span><span class="cx">             bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
</span><span class="cx">             loadi 20[PC], t1
</span><span class="cx">             loadConstantOrVariable2Reg(t2, scratch, t2)
</span><del>-            writeBarrier(scratch, t2)
</del><span class="cx">             storei scratch, TagOffset[propertyStorage, t1]
</span><span class="cx">             storei t2, PayloadOffset[propertyStorage, t1]
</span><span class="cx">             dispatch(9)
</span><span class="lines">@@ -1376,6 +1425,7 @@
</span><span class="cx"> 
</span><span class="cx"> macro putByIdTransition(additionalChecks, getPropertyStorage)
</span><span class="cx">     traceExecution()
</span><ins>+    writeBarrierOnOperand(1)
</ins><span class="cx">     loadi 4[PC], t3
</span><span class="cx">     loadi 16[PC], t1
</span><span class="cx">     loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
</span><span class="lines">@@ -1389,7 +1439,6 @@
</span><span class="cx">         macro (propertyStorage, scratch)
</span><span class="cx">             addp t1, propertyStorage, t3
</span><span class="cx">             loadConstantOrVariable2Reg(t2, t1, t2)
</span><del>-            writeBarrier(t1, t2)
</del><span class="cx">             storei t1, TagOffset[t3]
</span><span class="cx">             loadi 24[PC], t1
</span><span class="cx">             storei t2, PayloadOffset[t3]
</span><span class="lines">@@ -1561,6 +1610,7 @@
</span><span class="cx"> 
</span><span class="cx"> macro putByVal(holeCheck, slowPath)
</span><span class="cx">     traceExecution()
</span><ins>+    writeBarrierOnOperands(1, 3)
</ins><span class="cx">     loadi 4[PC], t0
</span><span class="cx">     loadConstantOrVariablePayload(t0, CellTag, t1, .opPutByValSlow)
</span><span class="cx">     loadp JSCell::m_structure[t1], t2
</span><span class="lines">@@ -1602,7 +1652,6 @@
</span><span class="cx">             const tag = scratch
</span><span class="cx">             const payload = operand
</span><span class="cx">             loadConstantOrVariable2Reg(operand, tag, payload)
</span><del>-            writeBarrier(tag, payload)
</del><span class="cx">             storei tag, TagOffset[base, index, 8]
</span><span class="cx">             storei payload, PayloadOffset[base, index, 8]
</span><span class="cx">         end)
</span><span class="lines">@@ -1614,7 +1663,6 @@
</span><span class="cx"> .opPutByValArrayStorageStoreResult:
</span><span class="cx">     loadi 12[PC], t2
</span><span class="cx">     loadConstantOrVariable2Reg(t2, t1, t2)
</span><del>-    writeBarrier(t1, t2)
</del><span class="cx">     storei t1, ArrayStorage::m_vector + TagOffset[t0, t3, 8]
</span><span class="cx">     storei t2, ArrayStorage::m_vector + PayloadOffset[t0, t3, 8]
</span><span class="cx">     dispatch(5)
</span><span class="lines">@@ -2339,35 +2387,41 @@
</span><span class="cx"> 
</span><span class="cx"> #pGlobalProperty:
</span><span class="cx">     bineq t0, GlobalProperty, .pGlobalVar
</span><ins>+    writeBarrierOnOperands(1, 3)
</ins><span class="cx">     loadWithStructureCheck(1, .pDynamic)
</span><span class="cx">     putProperty()
</span><span class="cx">     dispatch(7)
</span><span class="cx"> 
</span><span class="cx"> .pGlobalVar:
</span><span class="cx">     bineq t0, GlobalVar, .pClosureVar
</span><ins>+    writeBarrierOnGlobalObject(3)
</ins><span class="cx">     putGlobalVar()
</span><span class="cx">     dispatch(7)
</span><span class="cx"> 
</span><span class="cx"> .pClosureVar:
</span><span class="cx">     bineq t0, ClosureVar, .pGlobalPropertyWithVarInjectionChecks
</span><ins>+    writeBarrierOnOperands(1, 3)
</ins><span class="cx">     loadVariable(1, t2, t1, t0)
</span><span class="cx">     putClosureVar()
</span><span class="cx">     dispatch(7)
</span><span class="cx"> 
</span><span class="cx"> .pGlobalPropertyWithVarInjectionChecks:
</span><span class="cx">     bineq t0, GlobalPropertyWithVarInjectionChecks, .pGlobalVarWithVarInjectionChecks
</span><ins>+    writeBarrierOnOperands(1, 3)
</ins><span class="cx">     loadWithStructureCheck(1, .pDynamic)
</span><span class="cx">     putProperty()
</span><span class="cx">     dispatch(7)
</span><span class="cx"> 
</span><span class="cx"> .pGlobalVarWithVarInjectionChecks:
</span><span class="cx">     bineq t0, GlobalVarWithVarInjectionChecks, .pClosureVarWithVarInjectionChecks
</span><ins>+    writeBarrierOnGlobalObject(3)
</ins><span class="cx">     varInjectionCheck(.pDynamic)
</span><span class="cx">     putGlobalVar()
</span><span class="cx">     dispatch(7)
</span><span class="cx"> 
</span><span class="cx"> .pClosureVarWithVarInjectionChecks:
</span><span class="cx">     bineq t0, ClosureVarWithVarInjectionChecks, .pDynamic
</span><ins>+    writeBarrierOnOperands(1, 3)
</ins><span class="cx">     varInjectionCheck(.pDynamic)
</span><span class="cx">     loadVariable(1, t2, t1, t0)
</span><span class="cx">     putClosureVar()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (161376 => 161377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2014-01-06 23:04:25 UTC (rev 161377)
</span><span class="lines">@@ -331,10 +331,53 @@
</span><span class="cx">     btqnz value, tagMask, slow
</span><span class="cx"> end
</span><span class="cx"> 
</span><del>-macro writeBarrier(value)
-    # Nothing to do, since we don't have a generational or incremental collector.
</del><ins>+macro writeBarrierOnOperand(cellOperand)
+    if GGC
+        loadisFromInstruction(cellOperand, t1)
+        loadConstantOrVariableCell(t1, t0, .writeBarrierDone)
+        checkMarkByte(t0, t1, t2, 
+            macro(marked)
+                btbz marked, .writeBarrierDone
+                push PB, PC
+                cCall2(_llint_write_barrier_slow, cfr, t0)
+                push PC, PB
+            end
+        )
+    .writeBarrierDone:
+    end
</ins><span class="cx"> end
</span><span class="cx"> 
</span><ins>+macro writeBarrierOnOperands(cellOperand, valueOperand)
+    if GGC
+        loadisFromInstruction(valueOperand, t1)
+        loadConstantOrVariable(t1, t0)
+        btpz t0, .writeBarrierDone
+    
+        writeBarrierOnOperand(cellOperand)
+    .writeBarrierDone:
+    end
+end
+
+macro writeBarrierOnGlobalObject(valueOperand)
+    if GGC
+        loadisFromInstruction(valueOperand, t1)
+        loadConstantOrVariable(t1, t0)
+        btpz t0, .writeBarrierDone
+    
+        loadp CodeBlock[cfr], t0
+        loadp CodeBlock::m_globalObject[t0], t0
+        checkMarkByte(t0, t1, t2,
+            macro(marked)
+                btbz marked, .writeBarrierDone
+                push PB, PC
+                cCall2(_llint_write_barrier_slow, cfr, t0)
+                pop PC, PB
+            end
+        )
+    .writeBarrierDone:
+    end
+end
+
</ins><span class="cx"> macro valueProfile(value, operand, scratch)
</span><span class="cx">     loadpFromInstruction(operand, scratch)
</span><span class="cx">     storeq value, ValueProfile::m_buckets[scratch]
</span><span class="lines">@@ -412,6 +455,7 @@
</span><span class="cx">     addq 1, t2
</span><span class="cx">     btqnz t2, .opEnterLoop
</span><span class="cx"> .opEnterDone:
</span><ins>+    callSlowPath(_slow_path_enter)
</ins><span class="cx">     dispatch(1)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -1064,10 +1108,10 @@
</span><span class="cx"> 
</span><span class="cx"> _llint_op_init_global_const:
</span><span class="cx">     traceExecution()
</span><ins>+    writeBarrierOnGlobalObject(2)
</ins><span class="cx">     loadisFromInstruction(2, t1)
</span><span class="cx">     loadpFromInstruction(1, t0)
</span><span class="cx">     loadConstantOrVariable(t1, t2)
</span><del>-    writeBarrier(t2)
</del><span class="cx">     storeq t2, [t0]
</span><span class="cx">     dispatch(5)
</span><span class="cx"> 
</span><span class="lines">@@ -1149,6 +1193,7 @@
</span><span class="cx"> 
</span><span class="cx"> macro putById(getPropertyStorage)
</span><span class="cx">     traceExecution()
</span><ins>+    writeBarrierOnOperands(1, 3)
</ins><span class="cx">     loadisFromInstruction(1, t3)
</span><span class="cx">     loadpFromInstruction(4, t1)
</span><span class="cx">     loadConstantOrVariableCell(t3, t0, .opPutByIdSlow)
</span><span class="lines">@@ -1160,7 +1205,6 @@
</span><span class="cx">             bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
</span><span class="cx">             loadisFromInstruction(5, t1)
</span><span class="cx">             loadConstantOrVariable(t2, scratch)
</span><del>-            writeBarrier(t0)
</del><span class="cx">             storeq scratch, [propertyStorage, t1]
</span><span class="cx">             dispatch(9)
</span><span class="cx">         end)
</span><span class="lines">@@ -1180,6 +1224,7 @@
</span><span class="cx"> 
</span><span class="cx"> macro putByIdTransition(additionalChecks, getPropertyStorage)
</span><span class="cx">     traceExecution()
</span><ins>+    writeBarrierOnOperand(1)
</ins><span class="cx">     loadisFromInstruction(1, t3)
</span><span class="cx">     loadpFromInstruction(4, t1)
</span><span class="cx">     loadConstantOrVariableCell(t3, t0, .opPutByIdSlow)
</span><span class="lines">@@ -1193,7 +1238,6 @@
</span><span class="cx">         macro (propertyStorage, scratch)
</span><span class="cx">             addp t1, propertyStorage, t3
</span><span class="cx">             loadConstantOrVariable(t2, t1)
</span><del>-            writeBarrier(t1)
</del><span class="cx">             storeq t1, [t3]
</span><span class="cx">             loadpFromInstruction(6, t1)
</span><span class="cx">             storep t1, JSCell::m_structure[t0]
</span><span class="lines">@@ -1362,6 +1406,7 @@
</span><span class="cx"> 
</span><span class="cx"> macro putByVal(holeCheck, slowPath)
</span><span class="cx">     traceExecution()
</span><ins>+    writeBarrierOnOperands(1, 3)
</ins><span class="cx">     loadisFromInstruction(1, t0)
</span><span class="cx">     loadConstantOrVariableCell(t0, t1, .opPutByValSlow)
</span><span class="cx">     loadp JSCell::m_structure[t1], t2
</span><span class="lines">@@ -1401,7 +1446,6 @@
</span><span class="cx">     contiguousPutByVal(
</span><span class="cx">         macro (operand, scratch, address)
</span><span class="cx">             loadConstantOrVariable(operand, scratch)
</span><del>-            writeBarrier(scratch)
</del><span class="cx">             storep scratch, address
</span><span class="cx">         end)
</span><span class="cx"> 
</span><span class="lines">@@ -1412,7 +1456,6 @@
</span><span class="cx"> .opPutByValArrayStorageStoreResult:
</span><span class="cx">     loadisFromInstruction(3, t2)
</span><span class="cx">     loadConstantOrVariable(t2, t1)
</span><del>-    writeBarrier(t1)
</del><span class="cx">     storeq t1, ArrayStorage::m_vector[t0, t3, 8]
</span><span class="cx">     dispatch(5)
</span><span class="cx"> 
</span><span class="lines">@@ -2107,35 +2150,41 @@
</span><span class="cx"> 
</span><span class="cx"> #pGlobalProperty:
</span><span class="cx">     bineq t0, GlobalProperty, .pGlobalVar
</span><ins>+    writeBarrierOnOperands(1, 3)
</ins><span class="cx">     loadWithStructureCheck(1, .pDynamic)
</span><span class="cx">     putProperty()
</span><span class="cx">     dispatch(7)
</span><span class="cx"> 
</span><span class="cx"> .pGlobalVar:
</span><span class="cx">     bineq t0, GlobalVar, .pClosureVar
</span><ins>+    writeBarrierOnGlobalObject(3)
</ins><span class="cx">     putGlobalVar()
</span><span class="cx">     dispatch(7)
</span><span class="cx"> 
</span><span class="cx"> .pClosureVar:
</span><span class="cx">     bineq t0, ClosureVar, .pGlobalPropertyWithVarInjectionChecks
</span><ins>+    writeBarrierOnOperands(1, 3)
</ins><span class="cx">     loadVariable(1, t0)
</span><span class="cx">     putClosureVar()
</span><span class="cx">     dispatch(7)
</span><span class="cx"> 
</span><span class="cx"> .pGlobalPropertyWithVarInjectionChecks:
</span><span class="cx">     bineq t0, GlobalPropertyWithVarInjectionChecks, .pGlobalVarWithVarInjectionChecks
</span><ins>+    writeBarrierOnOperands(1, 3)
</ins><span class="cx">     loadWithStructureCheck(1, .pDynamic)
</span><span class="cx">     putProperty()
</span><span class="cx">     dispatch(7)
</span><span class="cx"> 
</span><span class="cx"> .pGlobalVarWithVarInjectionChecks:
</span><span class="cx">     bineq t0, GlobalVarWithVarInjectionChecks, .pClosureVarWithVarInjectionChecks
</span><ins>+    writeBarrierOnGlobalObject(3)
</ins><span class="cx">     varInjectionCheck(.pDynamic)
</span><span class="cx">     putGlobalVar()
</span><span class="cx">     dispatch(7)
</span><span class="cx"> 
</span><span class="cx"> .pClosureVarWithVarInjectionChecks:
</span><span class="cx">     bineq t0, ClosureVarWithVarInjectionChecks, .pDynamic
</span><ins>+    writeBarrierOnOperands(1, 3)
</ins><span class="cx">     varInjectionCheck(.pDynamic)
</span><span class="cx">     loadVariable(1, t0)
</span><span class="cx">     putClosureVar()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreofflineasmarmrb"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/offlineasm/arm.rb (161376 => 161377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/offlineasm/arm.rb        2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/JavaScriptCore/offlineasm/arm.rb        2014-01-06 23:04:25 UTC (rev 161377)
</span><span class="lines">@@ -457,9 +457,15 @@
</span><span class="cx">             # FIXME: either support this or remove it.
</span><span class="cx">             raise &quot;ARM does not support this opcode yet, #{codeOrigin}&quot;
</span><span class="cx">         when &quot;pop&quot;
</span><del>-            $asm.puts &quot;pop { #{operands[0].armOperand} }&quot;
</del><ins>+            operands.each {
+                | op |
+                $asm.puts &quot;pop { #{op.armOperand} }&quot;
+            }
</ins><span class="cx">         when &quot;push&quot;
</span><del>-            $asm.puts &quot;push { #{operands[0].armOperand} }&quot;
</del><ins>+            operands.each {
+                | op |
+                $asm.puts &quot;push { #{op.armOperand} }&quot;
+            }
</ins><span class="cx">         when &quot;popCalleeSaves&quot;
</span><span class="cx">             if isARMv7
</span><span class="cx">                 $asm.puts &quot;pop {r4-r6, r8-r11}&quot;                
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreofflineasmarm64rb"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/offlineasm/arm64.rb (161376 => 161377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/offlineasm/arm64.rb        2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/JavaScriptCore/offlineasm/arm64.rb        2014-01-06 23:04:25 UTC (rev 161377)
</span><span class="lines">@@ -566,11 +566,24 @@
</span><span class="cx">             # FIXME: Remove it or support it.
</span><span class="cx">             raise &quot;ARM64 does not support this opcode yet, #{codeOriginString}&quot;
</span><span class="cx">         when &quot;pop&quot;
</span><del>-            # FIXME: Remove it or support it.
-            raise &quot;ARM64 does not support this opcode yet, #{codeOriginString}&quot;
</del><ins>+            operands.each_slice(2) {
+                | ops |
+                # Note that the operands are in the reverse order of the case for push.
+                # This is due to the fact that order matters for pushing and popping, and 
+                # on platforms that only push/pop one slot at a time they pop their 
+                # arguments in the reverse order that they were pushed. In order to remain 
+                # compatible with those platforms we assume here that that's what has been done.
+
+                # So for example, if we did push(A, B, C, D), we would then pop(D, C, B, A).
+                # But since the ordering of arguments doesn't change on arm64 between the stp and ldp 
+                # instructions we need to flip flop the argument positions that were passed to us.
+                $asm.puts &quot;ldp #{ops[1].arm64Operand(:ptr)}, #{ops[0].arm64Operand(:ptr)}, [sp], #16&quot;
+            }
</ins><span class="cx">         when &quot;push&quot;
</span><del>-            # FIXME: Remove it or support it.
-            raise &quot;ARM64 does not support this opcode yet, #{codeOriginString}&quot;
</del><ins>+            operands.each_slice(2) {
+                | ops |
+                $asm.puts &quot;stp #{ops[0].arm64Operand(:ptr)}, #{ops[1].arm64Operand(:ptr)}, [sp, #-16]!&quot;
+            }
</ins><span class="cx">         when &quot;popLRAndFP&quot;
</span><span class="cx">             $asm.puts &quot;ldp fp, lr, [sp], #16&quot;
</span><span class="cx">         when &quot;pushLRAndFP&quot;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreofflineasmmipsrb"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/offlineasm/mips.rb (161376 => 161377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/offlineasm/mips.rb        2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/JavaScriptCore/offlineasm/mips.rb        2014-01-06 23:04:25 UTC (rev 161377)
</span><span class="lines">@@ -839,11 +839,17 @@
</span><span class="cx">             # FIXME: either support this or remove it.
</span><span class="cx">             raise &quot;MIPS does not support this opcode yet, #{codeOrigin}&quot;
</span><span class="cx">         when &quot;pop&quot;
</span><del>-            $asm.puts &quot;lw #{operands[0].mipsOperand}, 0($sp)&quot;
-            $asm.puts &quot;addiu $sp, $sp, 4&quot;
</del><ins>+            operands.each {
+                | op |
+                $asm.puts &quot;lw #{op.mipsOperand}, 0($sp)&quot;
+                $asm.puts &quot;addiu $sp, $sp, 4&quot;
+            }
</ins><span class="cx">         when &quot;push&quot;
</span><del>-            $asm.puts &quot;addiu $sp, $sp, -4&quot;
-            $asm.puts &quot;sw #{operands[0].mipsOperand}, 0($sp)&quot;
</del><ins>+            operands.each {
+                | op |
+                $asm.puts &quot;addiu $sp, $sp, -4&quot;
+                $asm.puts &quot;sw #{op.mipsOperand}, 0($sp)&quot;
+            }
</ins><span class="cx">         when &quot;popCalleeSaves&quot;
</span><span class="cx">             $asm.puts &quot;lw $16, 0($sp)&quot;
</span><span class="cx">             $asm.puts &quot;lw $17, 4($sp)&quot;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreofflineasmx86rb"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/offlineasm/x86.rb (161376 => 161377)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/offlineasm/x86.rb        2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/JavaScriptCore/offlineasm/x86.rb        2014-01-06 23:04:25 UTC (rev 161377)
</span><span class="lines">@@ -100,7 +100,7 @@
</span><span class="cx">             when :quad
</span><span class="cx">                 isX64 ? &quot;%rax&quot; : raise
</span><span class="cx">             else
</span><del>-                raise
</del><ins>+                raise &quot;Invalid kind #{kind} for name #{name}&quot;
</ins><span class="cx">             end
</span><span class="cx">         when &quot;t1&quot;, &quot;a1&quot;, &quot;r1&quot;
</span><span class="cx">             case kind
</span><span class="lines">@@ -978,9 +978,15 @@
</span><span class="cx">                 $asm.puts &quot;xorpd #{operands[0].x86Operand(:double)}, #{operands[0].x86Operand(:double)}&quot;
</span><span class="cx">             end
</span><span class="cx">         when &quot;pop&quot;
</span><del>-            $asm.puts &quot;pop #{operands[0].x86Operand(:ptr)}&quot;
</del><ins>+            operands.each {
+                | op |
+                $asm.puts &quot;pop #{op.x86Operand(:ptr)}&quot;
+            }
</ins><span class="cx">         when &quot;push&quot;
</span><del>-            $asm.puts &quot;push #{operands[0].x86Operand(:ptr)}&quot;
</del><ins>+            operands.each {
+                | op |
+                $asm.puts &quot;push #{op.x86Operand(:ptr)}&quot;
+            }
</ins><span class="cx">         when &quot;popCalleeSaves&quot;
</span><span class="cx">             if isX64
</span><span class="cx">                 $asm.puts &quot;pop %rbx&quot;
</span></span></pre>
</div>
</div>

</body>
</html>