Add support to load/store byte fields.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 4 Oct 2013 07:13:43 +0000 (07:13 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 4 Oct 2013 07:13:43 +0000 (07:13 +0000)
This adds a new Byte representation and support for zero-extended
loads in HLoadNamedField and truncated stores in HStoreNamedField.

R=mvstanton@chromium.org

Committed: https://code.google.com/p/v8/source/detail?r=17079

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

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

src/arm/lithium-codegen-arm.cc
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/mips/lithium-codegen-mips.cc
src/property-details.h
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h

index 50ff06c..ea3fa00 100644 (file)
@@ -3042,7 +3042,12 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
 
   if (access.IsExternalMemory()) {
     Register result = ToRegister(instr->result());
-    __ ldr(result, MemOperand(object, offset));
+    MemOperand operand = MemOperand(object, offset);
+    if (access.representation().IsByte()) {
+      __ ldrb(result, operand);
+    } else {
+      __ ldr(result, operand);
+    }
     return;
   }
 
@@ -3053,11 +3058,15 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
   }
 
   Register result = ToRegister(instr->result());
-  if (access.IsInobject()) {
-    __ ldr(result, FieldMemOperand(object, offset));
-  } else {
+  if (!access.IsInobject()) {
     __ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
-    __ ldr(result, FieldMemOperand(result, offset));
+    object = result;
+  }
+  MemOperand operand = FieldMemOperand(object, offset);
+  if (access.representation().IsByte()) {
+    __ ldrb(result, operand);
+  } else {
+    __ ldr(result, operand);
   }
 }
 
@@ -4163,7 +4172,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
 
   if (access.IsExternalMemory()) {
     Register value = ToRegister(instr->value());
-    __ str(value, MemOperand(object, offset));
+    MemOperand operand = MemOperand(object, offset);
+    if (representation.IsByte()) {
+      __ strb(value, operand);
+    } else {
+      __ str(value, operand);
+    }
     return;
   }
 
@@ -4208,7 +4222,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
       instr->hydrogen()->value()->IsHeapObject()
           ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
   if (access.IsInobject()) {
-    __ str(value, FieldMemOperand(object, offset));
+    MemOperand operand = FieldMemOperand(object, offset);
+    if (representation.IsByte()) {
+      __ strb(value, operand);
+    } else {
+      __ str(value, operand);
+    }
     if (instr->hydrogen()->NeedsWriteBarrier()) {
       // Update the write barrier for the object for in-object properties.
       __ RecordWriteField(object,
@@ -4222,7 +4241,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
     }
   } else {
     __ ldr(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset));
-    __ str(value, FieldMemOperand(scratch, offset));
+    MemOperand operand = FieldMemOperand(scratch, offset);
+    if (representation.IsByte()) {
+      __ strb(value, operand);
+    } else {
+      __ str(value, operand);
+    }
     if (instr->hydrogen()->NeedsWriteBarrier()) {
       // Update the write barrier for the properties array.
       // object is used as a scratch register.
index 61da776..e16bb22 100644 (file)
@@ -2829,6 +2829,9 @@ Range* HShl::InferRange(Zone* zone) {
 
 
 Range* HLoadNamedField::InferRange(Zone* zone) {
+  if (access().representation().IsByte()) {
+    return new(zone) Range(0, 255);
+  }
   if (access().IsStringLength()) {
     return new(zone) Range(0, String::kMaxLength);
   }
index c1aaec0..c564872 100644 (file)
@@ -5954,7 +5954,9 @@ class HLoadNamedField V8_FINAL : public HTemplateInstruction<1> {
     SetOperandAt(0, object);
 
     Representation representation = access.representation();
-    if (representation.IsSmi()) {
+    if (representation.IsByte()) {
+      set_representation(Representation::Integer32());
+    } else if (representation.IsSmi()) {
       set_type(HType::Smi());
       set_representation(representation);
     } else if (representation.IsDouble() ||
@@ -6252,11 +6254,14 @@ class HStoreNamedField V8_FINAL : public HTemplateInstruction<3> {
     if (index == 0 && access().IsExternalMemory()) {
       // object must be external in case of external memory access
       return Representation::External();
-    } else if (index == 1 &&
-        (field_representation().IsDouble() ||
-         field_representation().IsSmi() ||
-         field_representation().IsInteger32())) {
-      return field_representation();
+    } else if (index == 1) {
+      if (field_representation().IsByte() ||
+          field_representation().IsInteger32()) {
+        return Representation::Integer32();
+      } else if (field_representation().IsDouble() ||
+                 field_representation().IsSmi()) {
+        return field_representation();
+      }
     }
     return Representation::Tagged();
   }
index 14d16c0..a4f95db 100644 (file)
@@ -3225,12 +3225,15 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
 
   if (access.IsExternalMemory()) {
     Register result = ToRegister(instr->result());
-    if (instr->object()->IsConstantOperand()) {
-      ExternalReference external_reference = ToExternalReference(
-          LConstantOperand::cast(instr->object()));
-      __ mov(result, MemOperand::StaticVariable(external_reference));
+    MemOperand operand = instr->object()->IsConstantOperand()
+        ? MemOperand::StaticVariable(ToExternalReference(
+                LConstantOperand::cast(instr->object())))
+        : MemOperand(ToRegister(instr->object()), offset);
+    if (access.representation().IsByte()) {
+      ASSERT(instr->hydrogen()->representation().IsInteger32());
+      __ movzx_b(result, operand);
     } else {
-      __ mov(result, MemOperand(ToRegister(instr->object()), offset));
+      __ mov(result, operand);
     }
     return;
   }
@@ -3249,11 +3252,15 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
   }
 
   Register result = ToRegister(instr->result());
-  if (access.IsInobject()) {
-    __ mov(result, FieldOperand(object, offset));
-  } else {
+  if (!access.IsInobject()) {
     __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
-    __ mov(result, FieldOperand(result, offset));
+    object = result;
+  }
+  if (access.representation().IsByte()) {
+    ASSERT(instr->hydrogen()->representation().IsInteger32());
+    __ movzx_b(result, FieldOperand(object, offset));
+  } else {
+    __ mov(result, FieldOperand(object, offset));
   }
 }
 
@@ -4428,11 +4435,16 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
             ToExternalReference(LConstantOperand::cast(instr->object())))
         : MemOperand(ToRegister(instr->object()), offset);
     if (instr->value()->IsConstantOperand()) {
+      ASSERT(!representation.IsByte());
       LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
       __ mov(operand, Immediate(ToInteger32(operand_value)));
     } else {
       Register value = ToRegister(instr->value());
-      __ mov(operand, value);
+      if (representation.IsByte()) {
+        __ mov_b(operand, value);
+      } else {
+        __ mov(operand, value);
+      }
     }
     return;
   }
@@ -4505,17 +4517,28 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
     __ mov(write_register, FieldOperand(object, JSObject::kPropertiesOffset));
   }
 
+  MemOperand operand = FieldOperand(write_register, offset);
   if (instr->value()->IsConstantOperand()) {
     LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
     if (operand_value->IsRegister()) {
-      __ mov(FieldOperand(write_register, offset), ToRegister(operand_value));
+      Register value = ToRegister(operand_value);
+      if (representation.IsByte()) {
+        __ mov_b(operand, value);
+      } else {
+        __ mov(operand, value);
+      }
     } else {
       Handle<Object> handle_value = ToHandle(operand_value);
       ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
-      __ mov(FieldOperand(write_register, offset), handle_value);
+      __ mov(operand, handle_value);
     }
   } else {
-    __ mov(FieldOperand(write_register, offset), ToRegister(instr->value()));
+    Register value = ToRegister(instr->value());
+    if (representation.IsByte()) {
+      __ mov_b(operand, value);
+    } else {
+      __ mov(operand, value);
+    }
   }
 
   if (instr->hydrogen()->NeedsWriteBarrier()) {
index 83b4138..a4d2e18 100644 (file)
@@ -2422,7 +2422,11 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
       !(FLAG_track_double_fields && instr->field_representation().IsDouble());
 
   LOperand* val;
-  if (needs_write_barrier) {
+  if (instr->field_representation().IsByte()) {
+    // mov_b requires a byte register (i.e. any of eax, ebx, ecx, edx).
+    // Just force the value to be in eax and we're safe here.
+    val = UseFixed(instr->value(), eax);
+  } else if (needs_write_barrier) {
     val = UseTempRegister(instr->value());
   } else if (can_be_constant) {
     val = UseRegisterOrConstant(instr->value());
index 5e6b7ce..bbcf204 100644 (file)
@@ -2896,7 +2896,12 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
 
   if (access.IsExternalMemory()) {
     Register result = ToRegister(instr->result());
-    __ lw(result, MemOperand(object, offset));
+    MemOperand operand = MemOperand(object, offset);
+    if (access.representation().IsByte()) {
+      __ lb(result, operand);
+    } else {
+      __ lw(result, operand);
+    }
     return;
   }
 
@@ -2907,11 +2912,15 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
   }
 
   Register result = ToRegister(instr->result());
-  if (access.IsInobject()) {
-    __ lw(result, FieldMemOperand(object, offset));
-  } else {
+  if (!access.IsInobject()) {
     __ lw(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
-    __ lw(result, FieldMemOperand(result, offset));
+    object = result;
+  }
+  MemOperand operand = FieldMemOperand(object, offset);
+  if (access.representation().IsByte()) {
+    __ lb(result, operand);
+  } else {
+    __ lw(result, operand);
   }
 }
 
@@ -4075,7 +4084,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
 
   if (access.IsExternalMemory()) {
     Register value = ToRegister(instr->value());
-    __ sw(value, MemOperand(object, offset));
+    MemOperand operand = MemOperand(object, offset);
+    if (representation.IsByte()) {
+      __ sb(value, operand);
+    } else {
+      __ sw(value, operand);
+    }
     return;
   }
 
@@ -4120,7 +4134,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
       instr->hydrogen()->value()->IsHeapObject()
           ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
   if (access.IsInobject()) {
-    __ sw(value, FieldMemOperand(object, offset));
+    MemOperand operand = FieldMemOperand(object, offset);
+    if (representation.IsByte()) {
+      __ sb(value, operand);
+    } else {
+      __ sw(value, operand);
+    }
     if (instr->hydrogen()->NeedsWriteBarrier()) {
       // Update the write barrier for the object for in-object properties.
       __ RecordWriteField(object,
@@ -4134,7 +4153,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
     }
   } else {
     __ lw(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset));
-    __ sw(value, FieldMemOperand(scratch, offset));
+    MemOperand operand = FieldMemOperand(scratch, offset);
+    if (representation.IsByte()) {
+      __ sb(value, operand);
+    } else {
+      __ sw(value, operand);
+    }
     if (instr->hydrogen()->NeedsWriteBarrier()) {
       // Update the write barrier for the properties array.
       // object is used as a scratch register.
index 7f44b79..659fbd1 100644 (file)
@@ -82,6 +82,7 @@ class Representation {
  public:
   enum Kind {
     kNone,
+    kByte,
     kSmi,
     kInteger32,
     kDouble,
@@ -95,6 +96,7 @@ class Representation {
 
   static Representation None() { return Representation(kNone); }
   static Representation Tagged() { return Representation(kTagged); }
+  static Representation Byte() { return Representation(kByte); }
   static Representation Smi() { return Representation(kSmi); }
   static Representation Integer32() { return Representation(kInteger32); }
   static Representation Double() { return Representation(kDouble); }
@@ -139,6 +141,7 @@ class Representation {
 
   Kind kind() const { return static_cast<Kind>(kind_); }
   bool IsNone() const { return kind_ == kNone; }
+  bool IsByte() const { return kind_ == kByte; }
   bool IsTagged() const { return kind_ == kTagged; }
   bool IsSmi() const { return kind_ == kSmi; }
   bool IsSmiOrTagged() const { return IsSmi() || IsTagged(); }
@@ -148,7 +151,7 @@ class Representation {
   bool IsHeapObject() const { return kind_ == kHeapObject; }
   bool IsExternal() const { return kind_ == kExternal; }
   bool IsSpecialization() const {
-    return kind_ == kInteger32 || kind_ == kDouble || kind_ == kSmi;
+    return IsByte() || IsSmi() || IsInteger32() || IsDouble();
   }
   const char* Mnemonic() const;
 
index 4524059..0e98746 100644 (file)
@@ -2725,14 +2725,13 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
   int offset = access.offset();
 
   if (access.IsExternalMemory()) {
-    ASSERT(!access.representation().IsInteger32());
     Register result = ToRegister(instr->result());
     if (instr->object()->IsConstantOperand()) {
       ASSERT(result.is(rax));
       __ load_rax(ToExternalReference(LConstantOperand::cast(instr->object())));
     } else {
       Register object = ToRegister(instr->object());
-      __ movq(result, MemOperand(object, offset));
+      __ Load(result, MemOperand(object, offset), access.representation());
     }
     return;
   }
@@ -2746,20 +2745,11 @@ void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
   }
 
   Register result = ToRegister(instr->result());
-  if (access.IsInobject()) {
-    if (access.representation().IsInteger32()) {
-      __ movl(result, FieldOperand(object, offset));
-    } else {
-      __ movq(result, FieldOperand(object, offset));
-    }
-  } else {
+  if (!access.IsInobject()) {
     __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset));
-    if (access.representation().IsInteger32()) {
-      __ movl(result, FieldOperand(result, offset));
-    } else {
-      __ movq(result, FieldOperand(result, offset));
-    }
+    object = result;
   }
+  __ Load(result, FieldOperand(object, offset), access.representation());
 }
 
 
@@ -3881,16 +3871,16 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
   int offset = access.offset();
 
   if (access.IsExternalMemory()) {
-    ASSERT(!access.representation().IsInteger32());
     ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
     Register value = ToRegister(instr->value());
     if (instr->object()->IsConstantOperand()) {
       ASSERT(value.is(rax));
+      ASSERT(!access.representation().IsSpecialization());
       LConstantOperand* object = LConstantOperand::cast(instr->object());
       __ store_rax(ToExternalReference(object));
     } else {
       Register object = ToRegister(instr->object());
-      __ movq(MemOperand(object, offset), value);
+      __ Store(MemOperand(object, offset), value, representation);
     }
     return;
   }
@@ -3959,24 +3949,16 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
   if (instr->value()->IsConstantOperand()) {
     LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
     if (operand_value->IsRegister()) {
-      if (access.representation().IsInteger32()) {
-        __ movl(FieldOperand(write_register, offset),
-                ToRegister(operand_value));
-      } else {
-        __ movq(FieldOperand(write_register, offset),
-                ToRegister(operand_value));
-      }
+      Register value = ToRegister(operand_value);
+      __ Store(FieldOperand(write_register, offset), value, representation);
     } else {
       Handle<Object> handle_value = ToHandle(operand_value);
       ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
       __ Move(FieldOperand(write_register, offset), handle_value);
     }
   } else {
-    if (access.representation().IsInteger32()) {
-      __ movl(FieldOperand(write_register, offset), ToRegister(instr->value()));
-    } else {
-      __ movq(FieldOperand(write_register, offset), ToRegister(instr->value()));
-    }
+    Register value = ToRegister(instr->value());
+    __ Store(FieldOperand(write_register, offset), value, representation);
   }
 
   if (instr->hydrogen()->NeedsWriteBarrier()) {
index c01d1de..9b9ac04 100644 (file)
@@ -2060,7 +2060,14 @@ LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
 
 
 LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
-  if (instr->access().IsExternalMemory() && instr->access().offset() == 0) {
+  // Use the special mov rax, moffs64 encoding for external
+  // memory accesses with 64-bit word-sized values.
+  if (instr->access().IsExternalMemory() &&
+      instr->access().offset() == 0 &&
+      (instr->access().representation().IsSmi() ||
+       instr->access().representation().IsTagged() ||
+       instr->access().representation().IsHeapObject() ||
+       instr->access().representation().IsExternal())) {
     LOperand* obj = UseRegisterOrConstantAtStart(instr->object());
     return DefineFixed(new(zone()) LLoadNamedField(obj), rax);
   }
index 11150d9..27900c1 100644 (file)
@@ -947,6 +947,28 @@ void MacroAssembler::Cvtlsi2sd(XMMRegister dst, const Operand& src) {
 }
 
 
+void MacroAssembler::Load(Register dst, const Operand& src, Representation r) {
+  if (r.IsByte()) {
+    movzxbl(dst, src);
+  } else if (r.IsInteger32()) {
+    movl(dst, src);
+  } else {
+    movq(dst, src);
+  }
+}
+
+
+void MacroAssembler::Store(const Operand& dst, Register src, Representation r) {
+  if (r.IsByte()) {
+    movb(dst, src);
+  } else if (r.IsInteger32()) {
+    movl(dst, src);
+  } else {
+    movq(dst, src);
+  }
+}
+
+
 void MacroAssembler::Set(Register dst, int64_t x) {
   if (x == 0) {
     xorl(dst, dst);
index 0a12df8..3d5a456 100644 (file)
@@ -781,6 +781,10 @@ class MacroAssembler: public Assembler {
   // ---------------------------------------------------------------------------
   // Macro instructions.
 
+  // Load/store with specific representation.
+  void Load(Register dst, const Operand& src, Representation r);
+  void Store(const Operand& dst, Register src, Representation r);
+
   // Load a register with a long value as efficiently as possible.
   void Set(Register dst, int64_t x);
   void Set(const Operand& dst, int64_t x);