Title: [161377] trunk/Source/_javascript_Core
Revision
161377
Author
[email protected]
Date
2014-01-06 15:04:25 -0800 (Mon, 06 Jan 2014)

Log Message

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:

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (161376 => 161377)


--- trunk/Source/_javascript_Core/ChangeLog	2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/_javascript_Core/ChangeLog	2014-01-06 23:04:25 UTC (rev 161377)
@@ -1,3 +1,26 @@
+2014-01-06  Mark Hahnenberg  <[email protected]>
+
+        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:
+
 2014-01-05  Sam Weinig  <[email protected]>
 
         [JS] Implement Promise.all()

Modified: trunk/Source/_javascript_Core/llint/LLIntOfflineAsmConfig.h (161376 => 161377)


--- trunk/Source/_javascript_Core/llint/LLIntOfflineAsmConfig.h	2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/_javascript_Core/llint/LLIntOfflineAsmConfig.h	2014-01-06 23:04:25 UTC (rev 161377)
@@ -148,4 +148,10 @@
 #define OFFLINE_ASM_ALWAYS_ALLOCATE_SLOW 0
 #endif
 
+#if ENABLE(GGC)
+#define OFFLINE_ASM_GGC 1
+#else
+#define OFFLINE_ASM_GGC 0
+#endif
+
 #endif // LLIntOfflineAsmConfig_h

Modified: trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp (161376 => 161377)


--- trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp	2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp	2014-01-06 23:04:25 UTC (rev 161377)
@@ -1388,6 +1388,11 @@
     LLINT_END();
 }
 
+extern "C" void llint_write_barrier_slow(ExecState*, JSCell* cell)
+{
+    Heap::writeBarrier(cell);
+}
+
 } } // namespace JSC::LLInt
 
 #endif // ENABLE(LLINT)

Modified: trunk/Source/_javascript_Core/llint/LLIntSlowPaths.h (161376 => 161377)


--- trunk/Source/_javascript_Core/llint/LLIntSlowPaths.h	2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/_javascript_Core/llint/LLIntSlowPaths.h	2014-01-06 23:04:25 UTC (rev 161377)
@@ -41,6 +41,7 @@
 
 extern "C" SlowPathReturnType llint_trace_operand(ExecState*, Instruction*, int fromWhere, int operand);
 extern "C" SlowPathReturnType llint_trace_value(ExecState*, Instruction*, int fromWhere, int operand);
+extern "C" void llint_write_barrier_slow(ExecState*, JSCell*);
 
 #define LLINT_SLOW_PATH_DECL(name) \
     extern "C" SlowPathReturnType llint_##name(ExecState* exec, Instruction* pc)

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm (161376 => 161377)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm	2014-01-06 23:04:25 UTC (rev 161377)
@@ -170,7 +170,11 @@
 
 const ResolveModeMask = 0xffff
 
-const MarkedBlockMask = ~0xffff
+const MarkedBlockSize = 64 * 1024
+const MarkedBlockMask = ~(MarkedBlockSize - 1)
+# Constants for checking mark bits.
+const AtomNumberShift = 3
+const BitMapWordShift = 4
 
 # Allocation constants
 if JSVALUE64
@@ -263,6 +267,18 @@
     loadb Structure::m_indexingType[structure], indexingType
 end
 
+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
+
 macro checkSwitchToJIT(increment, action)
     loadp CodeBlock[cfr], t0
     baddis increment, CodeBlock::m_llintExecuteCounter + ExecutionCounter::m_counter[t0], .continue

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm (161376 => 161377)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm	2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm	2014-01-06 23:04:25 UTC (rev 161377)
@@ -491,10 +491,58 @@
         payload)
 end
 
-macro writeBarrier(tag, payload)
-    # Nothing to do, since we don't have a generational or incremental collector.
+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
 end
 
+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
+
 macro valueProfile(tag, payload, operand, scratch)
     loadp operand[PC], scratch
     storei tag, ValueProfile::m_buckets + TagOffset[scratch]
@@ -575,6 +623,7 @@
     addi 1, t2
     btinz t2, .opEnterLoop
 .opEnterDone:
+    callSlowPath(_slow_path_enter)
     dispatch(1)
 
 
@@ -1255,10 +1304,10 @@
 
 _llint_op_init_global_const:
     traceExecution()
+    writeBarrierOnGlobalObject(2)
     loadi 8[PC], t1
     loadi 4[PC], t0
     loadConstantOrVariable(t1, t2, t3)
-    writeBarrier(t2, t3)
     storei t2, TagOffset[t0]
     storei t3, PayloadOffset[t0]
     dispatch(5)
@@ -1344,6 +1393,7 @@
 
 macro putById(getPropertyStorage)
     traceExecution()
+    writeBarrierOnOperands(1, 3)
     loadi 4[PC], t3
     loadi 16[PC], t1
     loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
@@ -1355,7 +1405,6 @@
             bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
             loadi 20[PC], t1
             loadConstantOrVariable2Reg(t2, scratch, t2)
-            writeBarrier(scratch, t2)
             storei scratch, TagOffset[propertyStorage, t1]
             storei t2, PayloadOffset[propertyStorage, t1]
             dispatch(9)
@@ -1376,6 +1425,7 @@
 
 macro putByIdTransition(additionalChecks, getPropertyStorage)
     traceExecution()
+    writeBarrierOnOperand(1)
     loadi 4[PC], t3
     loadi 16[PC], t1
     loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
@@ -1389,7 +1439,6 @@
         macro (propertyStorage, scratch)
             addp t1, propertyStorage, t3
             loadConstantOrVariable2Reg(t2, t1, t2)
-            writeBarrier(t1, t2)
             storei t1, TagOffset[t3]
             loadi 24[PC], t1
             storei t2, PayloadOffset[t3]
@@ -1561,6 +1610,7 @@
 
 macro putByVal(holeCheck, slowPath)
     traceExecution()
+    writeBarrierOnOperands(1, 3)
     loadi 4[PC], t0
     loadConstantOrVariablePayload(t0, CellTag, t1, .opPutByValSlow)
     loadp JSCell::m_structure[t1], t2
@@ -1602,7 +1652,6 @@
             const tag = scratch
             const payload = operand
             loadConstantOrVariable2Reg(operand, tag, payload)
-            writeBarrier(tag, payload)
             storei tag, TagOffset[base, index, 8]
             storei payload, PayloadOffset[base, index, 8]
         end)
@@ -1614,7 +1663,6 @@
 .opPutByValArrayStorageStoreResult:
     loadi 12[PC], t2
     loadConstantOrVariable2Reg(t2, t1, t2)
-    writeBarrier(t1, t2)
     storei t1, ArrayStorage::m_vector + TagOffset[t0, t3, 8]
     storei t2, ArrayStorage::m_vector + PayloadOffset[t0, t3, 8]
     dispatch(5)
@@ -2339,35 +2387,41 @@
 
 #pGlobalProperty:
     bineq t0, GlobalProperty, .pGlobalVar
+    writeBarrierOnOperands(1, 3)
     loadWithStructureCheck(1, .pDynamic)
     putProperty()
     dispatch(7)
 
 .pGlobalVar:
     bineq t0, GlobalVar, .pClosureVar
+    writeBarrierOnGlobalObject(3)
     putGlobalVar()
     dispatch(7)
 
 .pClosureVar:
     bineq t0, ClosureVar, .pGlobalPropertyWithVarInjectionChecks
+    writeBarrierOnOperands(1, 3)
     loadVariable(1, t2, t1, t0)
     putClosureVar()
     dispatch(7)
 
 .pGlobalPropertyWithVarInjectionChecks:
     bineq t0, GlobalPropertyWithVarInjectionChecks, .pGlobalVarWithVarInjectionChecks
+    writeBarrierOnOperands(1, 3)
     loadWithStructureCheck(1, .pDynamic)
     putProperty()
     dispatch(7)
 
 .pGlobalVarWithVarInjectionChecks:
     bineq t0, GlobalVarWithVarInjectionChecks, .pClosureVarWithVarInjectionChecks
+    writeBarrierOnGlobalObject(3)
     varInjectionCheck(.pDynamic)
     putGlobalVar()
     dispatch(7)
 
 .pClosureVarWithVarInjectionChecks:
     bineq t0, ClosureVarWithVarInjectionChecks, .pDynamic
+    writeBarrierOnOperands(1, 3)
     varInjectionCheck(.pDynamic)
     loadVariable(1, t2, t1, t0)
     putClosureVar()

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (161376 => 161377)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2014-01-06 23:04:25 UTC (rev 161377)
@@ -331,10 +331,53 @@
     btqnz value, tagMask, slow
 end
 
-macro writeBarrier(value)
-    # Nothing to do, since we don't have a generational or incremental collector.
+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
 end
 
+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
+
 macro valueProfile(value, operand, scratch)
     loadpFromInstruction(operand, scratch)
     storeq value, ValueProfile::m_buckets[scratch]
@@ -412,6 +455,7 @@
     addq 1, t2
     btqnz t2, .opEnterLoop
 .opEnterDone:
+    callSlowPath(_slow_path_enter)
     dispatch(1)
 
 
@@ -1064,10 +1108,10 @@
 
 _llint_op_init_global_const:
     traceExecution()
+    writeBarrierOnGlobalObject(2)
     loadisFromInstruction(2, t1)
     loadpFromInstruction(1, t0)
     loadConstantOrVariable(t1, t2)
-    writeBarrier(t2)
     storeq t2, [t0]
     dispatch(5)
 
@@ -1149,6 +1193,7 @@
 
 macro putById(getPropertyStorage)
     traceExecution()
+    writeBarrierOnOperands(1, 3)
     loadisFromInstruction(1, t3)
     loadpFromInstruction(4, t1)
     loadConstantOrVariableCell(t3, t0, .opPutByIdSlow)
@@ -1160,7 +1205,6 @@
             bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
             loadisFromInstruction(5, t1)
             loadConstantOrVariable(t2, scratch)
-            writeBarrier(t0)
             storeq scratch, [propertyStorage, t1]
             dispatch(9)
         end)
@@ -1180,6 +1224,7 @@
 
 macro putByIdTransition(additionalChecks, getPropertyStorage)
     traceExecution()
+    writeBarrierOnOperand(1)
     loadisFromInstruction(1, t3)
     loadpFromInstruction(4, t1)
     loadConstantOrVariableCell(t3, t0, .opPutByIdSlow)
@@ -1193,7 +1238,6 @@
         macro (propertyStorage, scratch)
             addp t1, propertyStorage, t3
             loadConstantOrVariable(t2, t1)
-            writeBarrier(t1)
             storeq t1, [t3]
             loadpFromInstruction(6, t1)
             storep t1, JSCell::m_structure[t0]
@@ -1362,6 +1406,7 @@
 
 macro putByVal(holeCheck, slowPath)
     traceExecution()
+    writeBarrierOnOperands(1, 3)
     loadisFromInstruction(1, t0)
     loadConstantOrVariableCell(t0, t1, .opPutByValSlow)
     loadp JSCell::m_structure[t1], t2
@@ -1401,7 +1446,6 @@
     contiguousPutByVal(
         macro (operand, scratch, address)
             loadConstantOrVariable(operand, scratch)
-            writeBarrier(scratch)
             storep scratch, address
         end)
 
@@ -1412,7 +1456,6 @@
 .opPutByValArrayStorageStoreResult:
     loadisFromInstruction(3, t2)
     loadConstantOrVariable(t2, t1)
-    writeBarrier(t1)
     storeq t1, ArrayStorage::m_vector[t0, t3, 8]
     dispatch(5)
 
@@ -2107,35 +2150,41 @@
 
 #pGlobalProperty:
     bineq t0, GlobalProperty, .pGlobalVar
+    writeBarrierOnOperands(1, 3)
     loadWithStructureCheck(1, .pDynamic)
     putProperty()
     dispatch(7)
 
 .pGlobalVar:
     bineq t0, GlobalVar, .pClosureVar
+    writeBarrierOnGlobalObject(3)
     putGlobalVar()
     dispatch(7)
 
 .pClosureVar:
     bineq t0, ClosureVar, .pGlobalPropertyWithVarInjectionChecks
+    writeBarrierOnOperands(1, 3)
     loadVariable(1, t0)
     putClosureVar()
     dispatch(7)
 
 .pGlobalPropertyWithVarInjectionChecks:
     bineq t0, GlobalPropertyWithVarInjectionChecks, .pGlobalVarWithVarInjectionChecks
+    writeBarrierOnOperands(1, 3)
     loadWithStructureCheck(1, .pDynamic)
     putProperty()
     dispatch(7)
 
 .pGlobalVarWithVarInjectionChecks:
     bineq t0, GlobalVarWithVarInjectionChecks, .pClosureVarWithVarInjectionChecks
+    writeBarrierOnGlobalObject(3)
     varInjectionCheck(.pDynamic)
     putGlobalVar()
     dispatch(7)
 
 .pClosureVarWithVarInjectionChecks:
     bineq t0, ClosureVarWithVarInjectionChecks, .pDynamic
+    writeBarrierOnOperands(1, 3)
     varInjectionCheck(.pDynamic)
     loadVariable(1, t0)
     putClosureVar()

Modified: trunk/Source/_javascript_Core/offlineasm/arm.rb (161376 => 161377)


--- trunk/Source/_javascript_Core/offlineasm/arm.rb	2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/_javascript_Core/offlineasm/arm.rb	2014-01-06 23:04:25 UTC (rev 161377)
@@ -457,9 +457,15 @@
             # FIXME: either support this or remove it.
             raise "ARM does not support this opcode yet, #{codeOrigin}"
         when "pop"
-            $asm.puts "pop { #{operands[0].armOperand} }"
+            operands.each {
+                | op |
+                $asm.puts "pop { #{op.armOperand} }"
+            }
         when "push"
-            $asm.puts "push { #{operands[0].armOperand} }"
+            operands.each {
+                | op |
+                $asm.puts "push { #{op.armOperand} }"
+            }
         when "popCalleeSaves"
             if isARMv7
                 $asm.puts "pop {r4-r6, r8-r11}"                

Modified: trunk/Source/_javascript_Core/offlineasm/arm64.rb (161376 => 161377)


--- trunk/Source/_javascript_Core/offlineasm/arm64.rb	2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/_javascript_Core/offlineasm/arm64.rb	2014-01-06 23:04:25 UTC (rev 161377)
@@ -566,11 +566,24 @@
             # FIXME: Remove it or support it.
             raise "ARM64 does not support this opcode yet, #{codeOriginString}"
         when "pop"
-            # FIXME: Remove it or support it.
-            raise "ARM64 does not support this opcode yet, #{codeOriginString}"
+            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 "ldp #{ops[1].arm64Operand(:ptr)}, #{ops[0].arm64Operand(:ptr)}, [sp], #16"
+            }
         when "push"
-            # FIXME: Remove it or support it.
-            raise "ARM64 does not support this opcode yet, #{codeOriginString}"
+            operands.each_slice(2) {
+                | ops |
+                $asm.puts "stp #{ops[0].arm64Operand(:ptr)}, #{ops[1].arm64Operand(:ptr)}, [sp, #-16]!"
+            }
         when "popLRAndFP"
             $asm.puts "ldp fp, lr, [sp], #16"
         when "pushLRAndFP"

Modified: trunk/Source/_javascript_Core/offlineasm/mips.rb (161376 => 161377)


--- trunk/Source/_javascript_Core/offlineasm/mips.rb	2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/_javascript_Core/offlineasm/mips.rb	2014-01-06 23:04:25 UTC (rev 161377)
@@ -839,11 +839,17 @@
             # FIXME: either support this or remove it.
             raise "MIPS does not support this opcode yet, #{codeOrigin}"
         when "pop"
-            $asm.puts "lw #{operands[0].mipsOperand}, 0($sp)"
-            $asm.puts "addiu $sp, $sp, 4"
+            operands.each {
+                | op |
+                $asm.puts "lw #{op.mipsOperand}, 0($sp)"
+                $asm.puts "addiu $sp, $sp, 4"
+            }
         when "push"
-            $asm.puts "addiu $sp, $sp, -4"
-            $asm.puts "sw #{operands[0].mipsOperand}, 0($sp)"
+            operands.each {
+                | op |
+                $asm.puts "addiu $sp, $sp, -4"
+                $asm.puts "sw #{op.mipsOperand}, 0($sp)"
+            }
         when "popCalleeSaves"
             $asm.puts "lw $16, 0($sp)"
             $asm.puts "lw $17, 4($sp)"

Modified: trunk/Source/_javascript_Core/offlineasm/x86.rb (161376 => 161377)


--- trunk/Source/_javascript_Core/offlineasm/x86.rb	2014-01-06 22:46:29 UTC (rev 161376)
+++ trunk/Source/_javascript_Core/offlineasm/x86.rb	2014-01-06 23:04:25 UTC (rev 161377)
@@ -100,7 +100,7 @@
             when :quad
                 isX64 ? "%rax" : raise
             else
-                raise
+                raise "Invalid kind #{kind} for name #{name}"
             end
         when "t1", "a1", "r1"
             case kind
@@ -978,9 +978,15 @@
                 $asm.puts "xorpd #{operands[0].x86Operand(:double)}, #{operands[0].x86Operand(:double)}"
             end
         when "pop"
-            $asm.puts "pop #{operands[0].x86Operand(:ptr)}"
+            operands.each {
+                | op |
+                $asm.puts "pop #{op.x86Operand(:ptr)}"
+            }
         when "push"
-            $asm.puts "push #{operands[0].x86Operand(:ptr)}"
+            operands.each {
+                | op |
+                $asm.puts "push #{op.x86Operand(:ptr)}"
+            }
         when "popCalleeSaves"
             if isX64
                 $asm.puts "pop %rbx"
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to