ARM: Fix register misuse bug in Allocate().
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 19 Aug 2013 13:37:57 +0000 (13:37 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 19 Aug 2013 13:37:57 +0000 (13:37 +0000)
The bug is triggered if flags contains DOUBLE_ALIGNMENT and the
object_size is not an ARM immediate value. In this case, the code
for DOUBLE_ALIGNMENT uses the scratch2 register, which is aliased
to obj_size_reg containing the object_size.

Instead of pre-loading the object_size, which is difficult since
we are out of registers here, we simply generate a non-empty
sequence of add instructions for the addition of the constant
object_size (carefully handling possible overflow in each step).

Also turn static ASSERT into STATIC_ASSERT in Allocate().

BUG=v8:2851
R=svenpanne@chromium.org

Review URL: https://codereview.chromium.org/23323002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16221 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/arm/macro-assembler-arm.cc

index a56744b..4e28021 100644 (file)
@@ -1702,15 +1702,9 @@ void MacroAssembler::Allocate(int object_size,
   ASSERT((limit - top) == kPointerSize);
   ASSERT(result.code() < ip.code());
 
-  // Set up allocation top address and object size registers.
+  // Set up allocation top address register.
   Register topaddr = scratch1;
-  Register obj_size_reg = scratch2;
   mov(topaddr, Operand(allocation_top));
-  Operand obj_size_operand = Operand(object_size);
-  if (!obj_size_operand.is_single_instruction(this)) {
-    // We are about to steal IP, so we need to load this value first
-    mov(obj_size_reg, obj_size_operand);
-  }
 
   // This code stores a temporary value in ip. This is OK, as the code below
   // does not need ip for implicit literal generation.
@@ -1734,7 +1728,7 @@ void MacroAssembler::Allocate(int object_size,
     // Align the next allocation. Storing the filler map without checking top is
     // always safe because the limit of the heap is always aligned.
     ASSERT((flags & PRETENURE_OLD_POINTER_SPACE) == 0);
-    ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
+    STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
     and_(scratch2, result, Operand(kDoubleAlignmentMask), SetCC);
     Label aligned;
     b(eq, &aligned);
@@ -1744,13 +1738,25 @@ void MacroAssembler::Allocate(int object_size,
   }
 
   // Calculate new top and bail out if new space is exhausted. Use result
-  // to calculate the new top.
-  if (obj_size_operand.is_single_instruction(this)) {
-    // We can add the size as an immediate
-    add(scratch2, result, obj_size_operand, SetCC);
-  } else {
-    // Doesn't fit in an immediate, we have to use the register
-    add(scratch2, result, obj_size_reg, SetCC);
+  // to calculate the new top. We must preserve the ip register at this
+  // point, so we cannot just use add().
+  ASSERT(object_size > 0);
+  Register source = result;
+  Condition cond = al;
+  int shift = 0;
+  while (object_size != 0) {
+    if (((object_size >> shift) & 0x03) == 0) {
+      shift += 2;
+    } else {
+      int bits = object_size & (0xff << shift);
+      object_size -= bits;
+      shift += 8;
+      Operand bits_operand(bits);
+      ASSERT(bits_operand.is_single_instruction(this));
+      add(scratch2, source, bits_operand, SetCC, cond);
+      source = scratch2;
+      cond = cc;
+    }
   }
   b(cs, gc_required);
   cmp(scratch2, Operand(ip));