Revision: 10981
Author:   [email protected]
Date:     Fri Mar  9 03:11:55 2012
Log:      New class for Date objects: caches individual date components.
First step, cache slots not used yet.

[email protected]
BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com/9117034
http://code.google.com/p/v8/source/detail?r=10981

Modified:
 /branches/bleeding_edge/include/v8.h
 /branches/bleeding_edge/src/api.cc
 /branches/bleeding_edge/src/arm/full-codegen-arm.cc
 /branches/bleeding_edge/src/arm/lithium-arm.cc
 /branches/bleeding_edge/src/arm/lithium-arm.h
 /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
 /branches/bleeding_edge/src/bootstrapper.cc
 /branches/bleeding_edge/src/date.js
 /branches/bleeding_edge/src/hydrogen-instructions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-ia32.cc
 /branches/bleeding_edge/src/ia32/lithium-ia32.h
 /branches/bleeding_edge/src/macros.py
 /branches/bleeding_edge/src/objects-debug.cc
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects-printer.cc
 /branches/bleeding_edge/src/objects-visiting.cc
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/runtime.h
 /branches/bleeding_edge/src/x64/full-codegen-x64.cc
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
 /branches/bleeding_edge/src/x64/lithium-x64.cc
 /branches/bleeding_edge/src/x64/lithium-x64.h
 /branches/bleeding_edge/test/mjsunit/fuzz-natives.js

=======================================
--- /branches/bleeding_edge/include/v8.h        Mon Feb 27 07:15:53 2012
+++ /branches/bleeding_edge/include/v8.h        Fri Mar  9 03:11:55 2012
@@ -3871,7 +3871,7 @@
   static const int kFullStringRepresentationMask = 0x07;
   static const int kExternalTwoByteRepresentationTag = 0x02;

-  static const int kJSObjectType = 0xa9;
+  static const int kJSObjectType = 0xaa;
   static const int kFirstNonstringType = 0x80;
   static const int kForeignType = 0x85;

=======================================
--- /branches/bleeding_edge/src/api.cc  Thu Mar  8 10:27:39 2012
+++ /branches/bleeding_edge/src/api.cc  Fri Mar  9 03:11:55 2012
@@ -4735,8 +4735,8 @@
   if (IsDeadCheck(isolate, "v8::Date::NumberValue()")) return 0;
   LOG_API(isolate, "Date::NumberValue");
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
-  i::Handle<i::JSValue> jsvalue = i::Handle<i::JSValue>::cast(obj);
-  return jsvalue->value()->Number();
+  i::Handle<i::JSDate> jsdate = i::Handle<i::JSDate>::cast(obj);
+  return jsdate->value()->Number();
 }


=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Wed Mar 7 05:24:44 2012 +++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Fri Mar 9 03:11:55 2012
@@ -2945,6 +2945,25 @@
   __ bind(&done);
   context()->Plug(r0);
 }
+
+
+void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  ASSERT(args->length() == 2);
+  ASSERT_NE(NULL, args->at(1)->AsLiteral());
+  int index = Smi::cast(*(args->at(1)->AsLiteral()->handle()))->value();
+
+  VisitForAccumulatorValue(args->at(0));  // Load the object.
+
+#ifdef DEBUG
+  __ AbortIfSmi(r0);
+  __ CompareObjectType(r0, r1, r1, JS_DATE_TYPE);
+  __ Assert(eq, "Trying to get date field from non-date.");
+#endif
+
+ __ ldr(r0, FieldMemOperand(r0, JSDate::kValueOffset + kPointerSize * index));
+  context()->Plug(r0);
+}


 void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
@@ -2989,6 +3008,37 @@
   __ bind(&done);
   context()->Plug(r0);
 }
+
+
+void FullCodeGenerator::EmitSetDateField(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  ASSERT(args->length() == 3);
+  ASSERT_NE(NULL, args->at(1)->AsLiteral());
+  int index = Smi::cast(*(args->at(1)->AsLiteral()->handle()))->value();
+
+  VisitForStackValue(args->at(0));  // Load the object.
+  VisitForAccumulatorValue(args->at(2));  // Load the value.
+  __ pop(r1);  // r0 = value. r1 = object.
+
+#ifdef DEBUG
+  __ AbortIfSmi(r1);
+  __ CompareObjectType(r1, r2, r2, JS_DATE_TYPE);
+  __ Assert(eq, "Trying to get date field from non-date.");
+#endif
+
+  // Store the value.
+ __ str(r0, FieldMemOperand(r1, JSDate::kValueOffset + kPointerSize * index)); + // Caches can only be smi or NaN, so we can skip the write barrier for them.
+  if (index < JSDate::kFirstBarrierFree) {
+    // Update the write barrier.  Save the value as it will be
+    // overwritten by the write barrier code and is needed afterward.
+    __ mov(r2, r0);
+    __ RecordWriteField(
+        r1, JSDate::kValueOffset + kPointerSize * index,
+        r2, r3, kLRHasBeenSaved, kDontSaveFPRegs);
+  }
+  context()->Plug(r0);
+}


 void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc      Mon Mar  5 00:17:16 2012
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc      Fri Mar  9 03:11:55 2012
@@ -1600,6 +1600,22 @@
   LValueOf* result = new(zone()) LValueOf(object, TempRegister());
   return DefineAsRegister(result);
 }
+
+
+LInstruction* LChunkBuilder::DoDateField(HDateField* instr) {
+  LOperand* object = UseRegister(instr->value());
+ LDateField* result = new LDateField(object, TempRegister(), instr->index());
+  return DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoSetDateField(HSetDateField* instr) {
+  LOperand* date = UseRegister(instr->OperandAt(1));
+  LOperand* value = UseRegister(instr->OperandAt(2));
+  LSetDateField* result =
+      new LSetDateField(date, value, TempRegister(), instr->index());
+  return DefineAsRegister(result);
+}


 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.h       Thu Mar  1 03:10:28 2012
+++ /branches/bleeding_edge/src/arm/lithium-arm.h       Fri Mar  9 03:11:55 2012
@@ -177,8 +177,9 @@
   V(ForInPrepareMap)                            \
   V(ForInCacheArray)                            \
   V(CheckMapValue)                              \
-  V(LoadFieldByIndex)
-
+  V(LoadFieldByIndex)                           \
+  V(DateField)                                  \
+  V(SetDateField)


 #define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)              \
@@ -990,6 +991,41 @@
 };


+class LDateField: public LTemplateInstruction<1, 1, 1> {
+ public:
+  LDateField(LOperand* date, LOperand* temp, int index) : index_(index) {
+    inputs_[0] = date;
+    temps_[0] = temp;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(ValueOf, "date-field")
+  DECLARE_HYDROGEN_ACCESSOR(ValueOf)
+  int index() const { return index_; }
+
+ private:
+  int index_;
+};
+
+
+class LSetDateField: public LTemplateInstruction<1, 2, 1> {
+ public:
+  LSetDateField(LOperand* date, LOperand* value, LOperand* temp, int index)
+      : index_(index) {
+    inputs_[0] = date;
+    inputs_[1] = value;
+    temps_[0] = temp;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(DateField, "date-set-field")
+  DECLARE_HYDROGEN_ACCESSOR(DateField)
+
+  int index() const { return index_; }
+
+ private:
+  int index_;
+};
+
+
 class LThrow: public LTemplateInstruction<0, 1, 0> {
  public:
   explicit LThrow(LOperand* value) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue Mar 6 08:12:11 2012 +++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Fri Mar 9 03:11:55 2012
@@ -1436,6 +1436,49 @@

   __ bind(&done);
 }
+
+
+void LCodeGen::DoDateField(LDateField* instr) {
+  Register input = ToRegister(instr->InputAt(0));
+  Register result = ToRegister(instr->result());
+  Register map = ToRegister(instr->TempAt(0));
+
+#ifdef DEBUG
+  __ AbortIfSmi(input);
+  __ CompareObjectType(input, map, map, JS_DATE_TYPE);
+  __ Assert(eq, "Trying to get date field from non-date.");
+#endif
+
+  __ ldr(result, FieldMemOperand(input,
+ JSDate::kValueOffset + kPointerSize * instr->index()));
+}
+
+
+void LCodeGen::DoSetDateField(LSetDateField* instr) {
+  Register date = ToRegister(instr->InputAt(0));
+  Register value = ToRegister(instr->InputAt(1));
+  Register result = ToRegister(instr->result());
+  Register temp = ToRegister(instr->TempAt(0));
+  int index = instr->index();
+
+#ifdef DEBUG
+  __ AbortIfSmi(date);
+  __ CompareObjectType(date, temp, temp, JS_DATE_TYPE);
+  __ Assert(eq, "Trying to get date field from non-date.");
+#endif
+
+  __ str(value,
+ FieldMemOperand(date, JSDate::kValueOffset + kPointerSize * index)); + // Caches can only be smi or NaN, so we can skip the write barrier for them.
+  if (index < JSDate::kFirstBarrierFree) {
+    // Update the write barrier.  Save the value as it will be
+    // overwritten by the write barrier code and is needed afterward.
+    __ mov(result, value);
+    __ RecordWriteField(
+        date, JSDate::kValueOffset + kPointerSize * index,
+        value, temp, kLRHasBeenSaved, kDontSaveFPRegs);
+  }
+}


 void LCodeGen::DoBitNotI(LBitNotI* instr) {
=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Thu Feb 23 01:12:57 2012
+++ /branches/bleeding_edge/src/bootstrapper.cc Fri Mar  9 03:11:55 2012
@@ -927,7 +927,7 @@
   {  // --- D a t e ---
     // Builtin functions for Date.prototype.
     Handle<JSFunction> date_fun =
-        InstallFunction(global, "Date", JS_VALUE_TYPE, JSValue::kSize,
+        InstallFunction(global, "Date", JS_DATE_TYPE, JSDate::kSize,
                         isolate->initial_object_prototype(),
                         Builtins::kIllegal, true);

=======================================
--- /branches/bleeding_edge/src/date.js Mon Feb 20 05:48:24 2012
+++ /branches/bleeding_edge/src/date.js Fri Mar  9 03:11:55 2012
@@ -451,7 +451,7 @@
     var time = MakeTime(hours, minutes, seconds, ms);
     value = TimeClip(UTC(MakeDate(day, time)));
   }
-  %_SetValueOf(this, value);
+  SET_DATE_VALUE(this, value);
 });


@@ -564,7 +564,7 @@
           TO_INTEGER(year) <= 99) ? 1900 + TO_INTEGER(year) : year;
   var day = MakeDay(year, month, date);
   var time = MakeTime(hours, minutes, seconds, ms);
-  return %_SetValueOf(this, TimeClip(MakeDate(day, time)));
+  return TimeClip(MakeDate(day, time));
 }


@@ -773,7 +773,7 @@
 // ECMA 262 - 15.9.5.27
 function DateSetTime(ms) {
   if (!IS_DATE(this)) ThrowDateTypeError();
-  return %_SetValueOf(this, TimeClip(ToNumber(ms)));
+  return SET_DATE_VALUE(this, TimeClip(ToNumber(ms)));
 }


@@ -785,7 +785,7 @@
                       MIN_FROM_TIME(t),
                       SEC_FROM_TIME(t),
                       ms);
-  return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
+  return SET_DATE_VALUE(this, TimeClip(UTC(MakeDate(DAY(t), time))));
 }


@@ -797,7 +797,7 @@
                       MIN_FROM_TIME(t),
                       SEC_FROM_TIME(t),
                       ms);
-  return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
+  return SET_DATE_VALUE(this, TimeClip(MakeDate(DAY(t), time)));
 }


@@ -807,7 +807,7 @@
   sec = ToNumber(sec);
   ms = %_ArgumentsLength() < 2 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
   var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), sec, ms);
-  return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
+  return SET_DATE_VALUE(this, TimeClip(UTC(MakeDate(DAY(t), time))));
 }


@@ -817,7 +817,7 @@
   sec = ToNumber(sec);
   ms = %_ArgumentsLength() < 2 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
   var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), sec, ms);
-  return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
+  return SET_DATE_VALUE(this, TimeClip(MakeDate(DAY(t), time)));
 }


@@ -829,7 +829,7 @@
   sec = argc < 2 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
   ms = argc < 3 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
   var time = MakeTime(HOUR_FROM_TIME(t), min, sec, ms);
-  return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
+  return SET_DATE_VALUE(this, TimeClip(UTC(MakeDate(DAY(t), time))));
 }


@@ -841,7 +841,7 @@
   sec = argc < 2 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
   ms = argc < 3 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
   var time = MakeTime(HOUR_FROM_TIME(t), min, sec, ms);
-  return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
+  return SET_DATE_VALUE(this, TimeClip(MakeDate(DAY(t), time)));
 }


@@ -854,7 +854,7 @@
   sec = argc < 3 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
   ms = argc < 4 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
   var time = MakeTime(hour, min, sec, ms);
-  return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
+  return SET_DATE_VALUE(this, TimeClip(UTC(MakeDate(DAY(t), time))));
 }


@@ -867,7 +867,7 @@
   sec = argc < 3 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
   ms = argc < 4 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
   var time = MakeTime(hour, min, sec, ms);
-  return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
+  return SET_DATE_VALUE(this, TimeClip(MakeDate(DAY(t), time)));
 }


@@ -876,7 +876,7 @@
   var t = LocalTime(DATE_VALUE(this));
   date = ToNumber(date);
   var day = MakeDay(YearFromTime(t), MonthFromTime(t), date);
- return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t))))); + return SET_DATE_VALUE(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
 }


@@ -885,7 +885,7 @@
   var t = DATE_VALUE(this);
   date = ToNumber(date);
   var day = MakeDay(YearFromTime(t), MonthFromTime(t), date);
-  return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
+  return SET_DATE_VALUE(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
 }


@@ -895,7 +895,7 @@
   month = ToNumber(month);
date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
   var day = MakeDay(YearFromTime(t), month, date);
- return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t))))); + return SET_DATE_VALUE(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
 }


@@ -905,7 +905,7 @@
   month = ToNumber(month);
date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
   var day = MakeDay(YearFromTime(t), month, date);
-  return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
+  return SET_DATE_VALUE(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
 }


@@ -918,7 +918,7 @@
   month = argc < 2 ? MonthFromTime(t) : ToNumber(month);
   date = argc < 3 ? DateFromTime(t) : ToNumber(date);
   var day = MakeDay(year, month, date);
- return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t))))); + return SET_DATE_VALUE(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
 }


@@ -931,7 +931,7 @@
   month = argc < 2 ? MonthFromTime(t) : ToNumber(month);
   date = argc < 3 ? DateFromTime(t) : ToNumber(date);
   var day = MakeDay(year, month, date);
-  return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
+  return SET_DATE_VALUE(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
 }


@@ -961,11 +961,11 @@
   var t = LocalTime(DATE_VALUE(this));
   if (NUMBER_IS_NAN(t)) t = 0;
   year = ToNumber(year);
-  if (NUMBER_IS_NAN(year)) return %_SetValueOf(this, $NaN);
+  if (NUMBER_IS_NAN(year)) return SET_DATE_VALUE(this, $NaN);
   year = (0 <= TO_INTEGER(year) && TO_INTEGER(year) <= 99)
       ? 1900 + TO_INTEGER(year) : year;
   var day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
- return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t))))); + return SET_DATE_VALUE(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
 }


=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Mon Mar 5 00:17:16 2012 +++ /branches/bleeding_edge/src/hydrogen-instructions.h Fri Mar 9 03:11:55 2012
@@ -184,7 +184,9 @@
   V(ForInPrepareMap)                           \
   V(ForInCacheArray)                           \
   V(CheckMapValue)                             \
-  V(LoadFieldByIndex)
+  V(LoadFieldByIndex)                          \
+  V(DateField)                                 \
+  V(SetDateField)

 #define GVN_FLAG_LIST(V)                       \
   V(Calls)                                     \
@@ -4602,6 +4604,45 @@
 };


+class HDateField: public HUnaryOperation {
+ public:
+ HDateField(HValue* date, int index) : HUnaryOperation(date), index_(index) {
+    set_representation(Representation::Tagged());
+  }
+
+  int index() const { return index_; }
+
+  virtual Representation RequiredInputRepresentation(int index) {
+    return Representation::Tagged();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(DateField)
+
+ private:
+  int index_;
+};
+
+
+class HSetDateField: public HBinaryOperation {
+ public:
+  HSetDateField(HValue* context, HValue* date, HValue* value, int index)
+    : HBinaryOperation(context, date, value), index_(index) {
+    set_representation(Representation::Tagged());
+  }
+
+  int index() const { return index_; }
+
+  virtual Representation RequiredInputRepresentation(int index) {
+    return Representation::Tagged();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(SetDateField)
+
+ private:
+  int index_;
+};
+
+
 class HDeleteProperty: public HBinaryOperation {
  public:
   HDeleteProperty(HValue* context, HValue* obj, HValue* key)
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Fri Mar  9 01:04:39 2012
+++ /branches/bleeding_edge/src/hydrogen.cc     Fri Mar  9 03:11:55 2012
@@ -7120,6 +7120,18 @@
   HValueOf* result = new(zone()) HValueOf(value);
   return ast_context()->ReturnInstruction(result, call->id());
 }
+
+
+void HGraphBuilder::GenerateDateField(CallRuntime* call) {
+  ASSERT(call->arguments()->length() == 2);
+  ASSERT_NE(NULL, call->arguments()->at(1)->AsLiteral());
+  int index =
+ Smi::cast(*(call->arguments()->at(1)->AsLiteral()->handle()))->value();
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  HValue* date = Pop();
+  HDateField* result = new(zone()) HDateField(date, index);
+  return ast_context()->ReturnInstruction(result, call->id());
+}


 void HGraphBuilder::GenerateSetValueOf(CallRuntime* call) {
@@ -7162,6 +7174,22 @@
   set_current_block(join);
   return ast_context()->ReturnValue(value);
 }
+
+
+void HGraphBuilder::GenerateSetDateField(CallRuntime* call) {
+  ASSERT(call->arguments()->length() == 3);
+  ASSERT_NE(NULL, call->arguments()->at(1)->AsLiteral());
+  int index =
+ Smi::cast(*(call->arguments()->at(1)->AsLiteral()->handle()))->value();
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+  CHECK_ALIVE(VisitForValue(call->arguments()->at(2)));
+  HValue* value = Pop();
+  HValue* date = Pop();
+  HValue* context = environment()->LookupContext();
+  HSetDateField* result =
+      new(zone()) HSetDateField(context, date, value, index);
+  return ast_context()->ReturnInstruction(result, call->id());
+}


 // Fast support for charCodeAt(n).
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Wed Mar 7 05:24:44 2012 +++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Fri Mar 9 03:11:55 2012
@@ -2959,6 +2959,25 @@
   __ bind(&done);
   context()->Plug(eax);
 }
+
+
+void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  ASSERT(args->length() == 2);
+  ASSERT_NE(NULL, args->at(1)->AsLiteral());
+  int index = Smi::cast(*(args->at(1)->AsLiteral()->handle()))->value();
+
+  VisitForAccumulatorValue(args->at(0));  // Load the object.
+
+#ifdef DEBUG
+  __ AbortIfSmi(eax);
+  __ CmpObjectType(eax, JS_DATE_TYPE, ebx);
+  __ Assert(equal, "Trying to get date field from non-date.");
+#endif
+
+ __ mov(eax, FieldOperand(eax, JSDate::kValueOffset + kPointerSize * index));
+  context()->Plug(eax);
+}


 void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
@@ -3005,6 +3024,36 @@
   __ bind(&done);
   context()->Plug(eax);
 }
+
+
+void FullCodeGenerator::EmitSetDateField(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  ASSERT(args->length() == 3);
+  ASSERT_NE(NULL, args->at(1)->AsLiteral());
+  int index = Smi::cast(*(args->at(1)->AsLiteral()->handle()))->value();
+
+  VisitForStackValue(args->at(0));  // Load the object.
+  VisitForAccumulatorValue(args->at(2));  // Load the value.
+  __ pop(ebx);  // eax = value. ebx = object.
+
+#ifdef DEBUG
+  __ AbortIfSmi(ebx);
+  __ CmpObjectType(ebx, JS_DATE_TYPE, ecx);
+  __ Assert(equal, "Trying to set date field on non-date.");
+#endif
+
+  // Store the value.
+ __ mov(FieldOperand(ebx, JSDate::kValueOffset + kPointerSize * index), eax); + // Caches can only be smi or NaN, so we can skip the write barrier for them.
+  if (index < JSDate::kFirstBarrierFree) {
+    // Update the write barrier.  Save the value as it will be
+    // overwritten by the write barrier code and is needed afterward.
+    __ mov(edx, eax);
+    __ RecordWriteField(ebx, JSDate::kValueOffset + kPointerSize * index,
+                        edx, ecx, kDontSaveFPRegs);
+  }
+  context()->Plug(eax);
+}


 void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Tue Mar 6 08:12:11 2012 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Fri Mar 9 03:11:55 2012
@@ -1273,6 +1273,7 @@
   Register result = ToRegister(instr->result());
   Register map = ToRegister(instr->TempAt(0));
   ASSERT(input.is(result));
+
   Label done;
   // If the object is a smi return the object.
   __ JumpIfSmi(input, &done, Label::kNear);
@@ -1284,6 +1285,49 @@

   __ bind(&done);
 }
+
+
+void LCodeGen::DoDateField(LDateField* instr) {
+  Register input = ToRegister(instr->InputAt(0));
+  Register result = ToRegister(instr->result());
+  Register map = ToRegister(instr->TempAt(0));
+  ASSERT(input.is(result));
+
+#ifdef DEBUG
+  __ AbortIfSmi(input);
+  __ CmpObjectType(input, JS_DATE_TYPE, map);
+  __ Assert(equal, "Trying to get date field from non-date.");
+#endif
+
+  __ mov(result, FieldOperand(input,
+ JSDate::kValueOffset + kPointerSize * instr->index()));
+}
+
+
+void LCodeGen::DoSetDateField(LSetDateField* instr) {
+  Register date = ToRegister(instr->InputAt(0));
+  Register value = ToRegister(instr->InputAt(1));
+  Register result = ToRegister(instr->result());
+  Register temp = ToRegister(instr->TempAt(0));
+  int index = instr->index();
+
+#ifdef DEBUG
+  __ AbortIfSmi(date);
+  __ CmpObjectType(date, JS_DATE_TYPE, temp);
+  __ Assert(equal, "Trying to get date field from non-date.");
+#endif
+
+  __ mov(FieldOperand(date, JSDate::kValueOffset + kPointerSize * index),
+         value);
+ // Caches can only be smi or NaN, so we can skip the write barrier for them.
+  if (index < JSDate::kFirstBarrierFree) {
+    // Update the write barrier.  Save the value as it will be
+    // overwritten by the write barrier code and is needed afterward.
+    __ mov(result, value);
+    __ RecordWriteField(date, JSDate::kValueOffset + kPointerSize * index,
+                        value, temp, kDontSaveFPRegs);
+  }
+}


 void LCodeGen::DoBitNotI(LBitNotI* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Mon Mar 5 00:17:16 2012 +++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Fri Mar 9 03:11:55 2012
@@ -1645,6 +1645,23 @@
   LValueOf* result = new(zone()) LValueOf(object, TempRegister());
   return DefineSameAsFirst(result);
 }
+
+
+LInstruction* LChunkBuilder::DoDateField(HDateField* instr) {
+  LOperand* date = UseRegister(instr->value());
+  LDateField* result =
+      new(zone()) LDateField(date, TempRegister(), instr->index());
+  return DefineSameAsFirst(result);
+}
+
+
+LInstruction* LChunkBuilder::DoSetDateField(HSetDateField* instr) {
+  LOperand* date = UseRegister(instr->OperandAt(1));
+  LOperand* value = UseRegister(instr->OperandAt(2));
+  LSetDateField* result =
+ new(zone()) LSetDateField(date, value, TempRegister(), instr->index());
+  return DefineAsRegister(result);
+}


 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.h     Thu Mar  1 03:10:28 2012
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.h     Fri Mar  9 03:11:55 2012
@@ -172,7 +172,9 @@
   V(ForInPrepareMap)                            \
   V(ForInCacheArray)                            \
   V(CheckMapValue)                              \
-  V(LoadFieldByIndex)
+  V(LoadFieldByIndex)                           \
+  V(DateField)                                  \
+  V(SetDateField)


 #define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)              \
@@ -1002,6 +1004,42 @@
 };


+class LDateField: public LTemplateInstruction<1, 1, 1> {
+ public:
+  LDateField(LOperand* date, LOperand* temp, int index) : index_(index) {
+    inputs_[0] = date;
+    temps_[0] = temp;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(DateField, "date-field")
+  DECLARE_HYDROGEN_ACCESSOR(DateField)
+
+  int index() const { return index_; }
+
+ private:
+  int index_;
+};
+
+
+class LSetDateField: public LTemplateInstruction<1, 2, 1> {
+ public:
+  LSetDateField(LOperand* date, LOperand* value, LOperand* temp, int index)
+      : index_(index) {
+    inputs_[0] = date;
+    inputs_[1] = value;
+    temps_[0] = temp;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(DateField, "date-set-field")
+  DECLARE_HYDROGEN_ACCESSOR(DateField)
+
+  int index() const { return index_; }
+
+ private:
+  int index_;
+};
+
+
 class LThrow: public LTemplateInstruction<0, 2, 0> {
  public:
   LThrow(LOperand* context, LOperand* value) {
=======================================
--- /branches/bleeding_edge/src/macros.py       Mon Jan 16 04:38:59 2012
+++ /branches/bleeding_edge/src/macros.py       Fri Mar  9 03:11:55 2012
@@ -164,7 +164,22 @@

 # Gets the value of a Date object. If arg is not a Date object
 # a type error is thrown.
-macro DATE_VALUE(arg) = (%_ClassOf(arg) === 'Date' ? %_ValueOf(arg) : ThrowDateTypeError()); +macro DATE_VALUE(arg) = (%_ClassOf(arg) === 'Date' ? %_DateField(arg, 0) : ThrowDateTypeError()); +macro DATE_YEAR(arg) = (%_ClassOf(arg) === 'Date' ? %_DateField(arg, 1) : ThrowDateTypeError()); +macro DATE_MONTH(arg) = (%_ClassOf(arg) === 'Date' ? %_DateField(arg, 2) : ThrowDateTypeError()); +macro DATE_DAY(arg) = (%_ClassOf(arg) === 'Date' ? %_DateField(arg, 3) : ThrowDateTypeError()); +macro DATE_HOUR(arg) = (%_ClassOf(arg) === 'Date' ? %_DateField(arg, 4) : ThrowDateTypeError()); +macro DATE_MIN(arg) = (%_ClassOf(arg) === 'Date' ? %_DateField(arg, 5) : ThrowDateTypeError()); +macro DATE_SEC(arg) = (%_ClassOf(arg) === 'Date' ? %_DateField(arg, 6) : ThrowDateTypeError()); +macro DATE_MS(arg) = (%_ClassOf(arg) === 'Date' ? %_DateField(arg, 7) : ThrowDateTypeError());
+macro SET_DATE_VALUE(arg, value) = (%_SetDateField(arg, 0, value));
+macro SET_DATE_YEAR(arg, value) = (%_SetDateField(arg, 1, value));
+macro SET_DATE_MONTH(arg, value) = (%_SetDateField(arg, 2, value));
+macro SET_DATE_DAY(arg, value) = (%_SetDateField(arg, 3, value));
+macro SET_DATE_HOUR(arg, value) = (%_SetDateField(arg, 4, value));
+macro SET_DATE_MIN(arg, value) = (%_SetDateField(arg, 5, value));
+macro SET_DATE_SEC(arg, value) = (%_SetDateField(arg, 6, value));
+macro SET_DATE_MS(arg, value) = (%_SetDateField(arg, 7, value));
 macro DAY(time) = ($floor(time / 86400000));
macro NAN_OR_DATE_FROM_TIME(time) = (NUMBER_IS_NAN(time) ? time : DateFromTime(time));
 macro HOUR_FROM_TIME(time) = (Modulo($floor(time / 3600000), 24));
=======================================
--- /branches/bleeding_edge/src/objects-debug.cc        Fri Feb 24 06:34:01 2012
+++ /branches/bleeding_edge/src/objects-debug.cc        Fri Mar  9 03:11:55 2012
@@ -138,6 +138,9 @@
     case JS_VALUE_TYPE:
       JSValue::cast(this)->JSValueVerify();
       break;
+    case JS_DATE_TYPE:
+      JSDate::cast(this)->JSDateVerify();
+      break;
     case JS_FUNCTION_TYPE:
       JSFunction::cast(this)->JSFunctionVerify();
       break;
@@ -369,6 +372,45 @@
     VerifyHeapPointer(v);
   }
 }
+
+
+void JSDate::JSDateVerify() {
+  if (value()->IsHeapObject()) {
+    VerifyHeapPointer(value());
+  }
+ CHECK(value()->IsUndefined() || value()->IsSmi() || value()->IsHeapNumber());
+/* Don't check yet, will still be undefined...
+ if (value()->IsHeapNumber() && isnan(HeapNumber::cast(value())->value())) { + CHECK(year()->IsHeapNumber() && isnan(HeapNumber::cast(year())->value())); + CHECK(month()->IsHeapNumber() && isnan(HeapNumber::cast(month())->value())); + CHECK(day()->IsHeapNumber() && isnan(HeapNumber::cast(day())->value())); + CHECK(hour()->IsHeapNumber() && isnan(HeapNumber::cast(hour())->value())); + CHECK(min()->IsHeapNumber() && isnan(HeapNumber::cast(min())->value())); + CHECK(sec()->IsHeapNumber() && isnan(HeapNumber::cast(sec())->value()));
+    CHECK(ms()->IsHeapNumber() && isnan(HeapNumber::cast(ms())->value()));
+    return;
+  }
+  CHECK(year()->IsSmi());
+  CHECK(month()->IsSmi());
+  CHECK(day()->IsSmi());
+  CHECK(hour()->IsSmi());
+  CHECK(min()->IsSmi());
+  CHECK(sec()->IsSmi());
+  CHECK(ms()->IsSmi());
+  int month = Smi::cast(this->month())->value();
+  int day = Smi::cast(this->day())->value();
+  int hour = Smi::cast(this->hour())->value();
+  int min = Smi::cast(this->min())->value();
+  int sec = Smi::cast(this->sec())->value();
+  int ms = Smi::cast(this->ms())->value();
+  CHECK(1 <= month && month <= 12);
+  CHECK(1 <= day && day <= 31);
+  CHECK(0 <= hour && hour <= 23);
+  CHECK(0 <= min && min <= 59);
+  CHECK(0 <= sec && sec <= 59);
+  CHECK(0 <= ms && ms <= 999);
+*/
+}


 void JSMessageObject::JSMessageObjectVerify() {
=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Fri Mar  2 06:03:59 2012
+++ /branches/bleeding_edge/src/objects-inl.h   Fri Mar  9 03:11:55 2012
@@ -605,6 +605,7 @@
 TYPE_CHECKER(JSGlobalPropertyCell, JS_GLOBAL_PROPERTY_CELL_TYPE)
 TYPE_CHECKER(SharedFunctionInfo, SHARED_FUNCTION_INFO_TYPE)
 TYPE_CHECKER(JSValue, JS_VALUE_TYPE)
+TYPE_CHECKER(JSDate, JS_DATE_TYPE)
 TYPE_CHECKER(JSMessageObject, JS_MESSAGE_OBJECT_TYPE)


@@ -1425,6 +1426,8 @@
       return JSFunction::kSize;
     case JS_VALUE_TYPE:
       return JSValue::kSize;
+    case JS_DATE_TYPE:
+      return JSDate::kSize;
     case JS_ARRAY_TYPE:
       return JSArray::kSize;
     case JS_WEAK_MAP_TYPE:
@@ -4117,6 +4120,23 @@
   ASSERT(HeapObject::cast(obj)->Size() == JSValue::kSize);
   return reinterpret_cast<JSValue*>(obj);
 }
+
+
+ACCESSORS(JSDate, value, Object, kValueOffset)
+ACCESSORS(JSDate, year, Object, kYearOffset)
+ACCESSORS(JSDate, month, Object, kMonthOffset)
+ACCESSORS(JSDate, day, Object, kDayOffset)
+ACCESSORS(JSDate, hour, Object, kHourOffset)
+ACCESSORS(JSDate, min, Object, kMinOffset)
+ACCESSORS(JSDate, sec, Object, kSecOffset)
+ACCESSORS(JSDate, ms, Object, kMsOffset)
+
+
+JSDate* JSDate::cast(Object* obj) {
+  ASSERT(obj->IsJSDate());
+  ASSERT(HeapObject::cast(obj)->Size() == JSDate::kSize);
+  return reinterpret_cast<JSDate*>(obj);
+}


 ACCESSORS(JSMessageObject, type, String, kTypeOffset)
=======================================
--- /branches/bleeding_edge/src/objects-printer.cc      Fri Feb 24 06:34:01 2012
+++ /branches/bleeding_edge/src/objects-printer.cc      Fri Mar  9 03:11:55 2012
@@ -151,6 +151,9 @@
       PrintF(out, "Value wrapper around:");
       JSValue::cast(this)->value()->Print(out);
       break;
+    case JS_DATE_TYPE:
+      JSDate::cast(this)->value()->Print(out);
+      break;
     case CODE_TYPE:
       Code::cast(this)->CodePrint(out);
       break;
@@ -658,6 +661,26 @@
   buffer[length()] = 0;
   return buffer;
 }
+
+
+void JSDate::JSDatePrint(FILE* out) {
+  HeapObject::PrintHeader(out, "JSDate");
+  PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+  PrintF(out, " - value = ");
+  value()->Print(out);
+  if (!year()->IsSmi()) {
+    PrintF(out, " - time = NaN\n");
+  } else {
+    PrintF(out, " - time = %04d/%02d/%02d %02d:%02d:%02d.%03d\n",
+           Smi::cast(year())->value(),
+           Smi::cast(month())->value(),
+           Smi::cast(day())->value(),
+           Smi::cast(hour())->value(),
+           Smi::cast(min())->value(),
+           Smi::cast(sec())->value(),
+           Smi::cast(ms())->value());
+  }
+}


 void JSProxy::JSProxyPrint(FILE* out) {
=======================================
--- /branches/bleeding_edge/src/objects-visiting.cc     Wed Nov 23 05:08:28 2011
+++ /branches/bleeding_edge/src/objects-visiting.cc     Fri Mar  9 03:11:55 2012
@@ -134,6 +134,7 @@
     case JS_OBJECT_TYPE:
     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
     case JS_VALUE_TYPE:
+    case JS_DATE_TYPE:
     case JS_ARRAY_TYPE:
     case JS_GLOBAL_PROXY_TYPE:
     case JS_GLOBAL_OBJECT_TYPE:
=======================================
--- /branches/bleeding_edge/src/objects.cc      Wed Mar  7 02:03:32 2012
+++ /branches/bleeding_edge/src/objects.cc      Fri Mar  9 03:11:55 2012
@@ -1067,7 +1067,7 @@
   switch (map()->instance_type()) {
     case JS_ARRAY_TYPE: {
       double length = JSArray::cast(this)->length()->Number();
-      accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
+      accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
       break;
     }
     case JS_WEAK_MAP_TYPE: {
@@ -1338,6 +1338,7 @@
     case JS_OBJECT_TYPE:
     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
     case JS_VALUE_TYPE:
+    case JS_DATE_TYPE:
     case JS_ARRAY_TYPE:
     case JS_SET_TYPE:
     case JS_MAP_TYPE:
=======================================
--- /branches/bleeding_edge/src/objects.h       Wed Mar  7 05:24:44 2012
+++ /branches/bleeding_edge/src/objects.h       Fri Mar  9 03:11:55 2012
@@ -64,6 +64,7 @@
 //             - JSBuiltinsObject
 //           - JSGlobalProxy
 //           - JSValue
+//             - JSDate
 //           - JSMessageObject
 //         - JSProxy
 //           - JSFunctionProxy
@@ -300,6 +301,7 @@
V(JS_MESSAGE_OBJECT_TYPE) \ \ V(JS_VALUE_TYPE) \ + V(JS_DATE_TYPE) \ V(JS_OBJECT_TYPE) \ V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \ V(JS_GLOBAL_OBJECT_TYPE) \
@@ -619,6 +621,7 @@
   JS_PROXY_TYPE,  // LAST_JS_PROXY_TYPE

   JS_VALUE_TYPE,  // FIRST_JS_OBJECT_TYPE
+  JS_DATE_TYPE,
   JS_OBJECT_TYPE,
   JS_CONTEXT_EXTENSION_OBJECT_TYPE,
   JS_GLOBAL_OBJECT_TYPE,
@@ -813,6 +816,7 @@
   V(Oddball)                                   \
   V(SharedFunctionInfo)                        \
   V(JSValue)                                   \
+  V(JSDate)                                    \
   V(JSMessageObject)                           \
   V(StringWrapper)                             \
   V(Foreign)                                   \
@@ -5994,7 +5998,7 @@
 };


-// Representation for JS Wrapper objects, String, Number, Boolean, Date, etc.
+// Representation for JS Wrapper objects, String, Number, Boolean, etc.
 class JSValue: public JSObject {
  public:
   // [value]: the object being wrapped.
@@ -6023,6 +6027,60 @@
 };


+// Representation for JS date objects.
+class JSDate: public JSObject {
+ public:
+  // If one component is NaN, all of them are, indicating a NaN time value.
+  // [value]: the time value.
+  DECL_ACCESSORS(value, Object)
+  // [year]: caches year. Either undefined, smi, or NaN.
+  DECL_ACCESSORS(year, Object)
+  // [month]: caches month. Either undefined, smi, or NaN.
+  DECL_ACCESSORS(month, Object)
+  // [day]: caches day. Either undefined, smi, or NaN.
+  DECL_ACCESSORS(day, Object)
+  // [hour]: caches hours. Either undefined, smi, or NaN.
+  DECL_ACCESSORS(hour, Object)
+  // [min]: caches minutes. Either undefined, smi, or NaN.
+  DECL_ACCESSORS(min, Object)
+  // [sec]: caches seconds. Either undefined, smi, or NaN.
+  DECL_ACCESSORS(sec, Object)
+  // [ms]: caches milliseconds. Either undefined, smi, or NaN.
+  DECL_ACCESSORS(ms, Object)
+
+  // Casting.
+  static inline JSDate* cast(Object* obj);
+
+  // Dispatched behavior.
+#ifdef OBJECT_PRINT
+  inline void JSDatePrint() {
+    JSDatePrint(stdout);
+  }
+  void JSDatePrint(FILE* out);
+#endif
+#ifdef DEBUG
+  void JSDateVerify();
+#endif
+
+  // Layout description.
+  static const int kValueOffset = JSObject::kHeaderSize;
+  static const int kYearOffset = kValueOffset + kPointerSize;
+  static const int kMonthOffset = kYearOffset + kPointerSize;
+  static const int kDayOffset = kMonthOffset + kPointerSize;
+  static const int kHourOffset = kDayOffset + kPointerSize;
+  static const int kMinOffset = kHourOffset + kPointerSize;
+  static const int kSecOffset = kMinOffset + kPointerSize;
+  static const int kMsOffset = kSecOffset + kPointerSize;
+  static const int kSize = kMsOffset + kPointerSize;
+
+  // Index of first field not requiring a write barrier.
+  static const int kFirstBarrierFree = 1;  // year
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(JSDate);
+};
+
+
 // Representation of message objects used for error reporting through
 // the API. The messages are formatted in JavaScript so this object is
 // a real JavaScript object. The information used for formatting the
=======================================
--- /branches/bleeding_edge/src/runtime.h       Wed Mar  7 02:57:36 2012
+++ /branches/bleeding_edge/src/runtime.h       Fri Mar  9 03:11:55 2012
@@ -491,6 +491,8 @@
F(Arguments, 1, 1) \ F(ValueOf, 1, 1) \ F(SetValueOf, 2, 1) \ + F(DateField, 2, 1) \ + F(SetDateField, 3, 1) \ F(StringCharFromCode, 1, 1) \ F(StringCharAt, 2, 1) \ F(ObjectEquals, 2, 1) \
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Wed Mar 7 05:24:44 2012 +++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Fri Mar 9 03:11:55 2012
@@ -2832,6 +2832,25 @@
   __ bind(&done);
   context()->Plug(rax);
 }
+
+
+void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  ASSERT(args->length() == 2);
+  ASSERT_NE(NULL, args->at(1)->AsLiteral());
+  int index = Smi::cast(*(args->at(1)->AsLiteral()->handle()))->value();
+
+  VisitForAccumulatorValue(args->at(0));  // Load the object.
+
+#ifdef DEBUG
+  __ AbortIfSmi(rax);
+  __ CmpObjectType(rax, JS_DATE_TYPE, rbx);
+  __ Assert(equal, "Trying to get date field from non-date.");
+#endif
+
+ __ movq(rax, FieldOperand(rax, JSDate::kValueOffset + kPointerSize * index));
+  context()->Plug(rax);
+}


 void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
@@ -2872,6 +2891,36 @@
   __ bind(&done);
   context()->Plug(rax);
 }
+
+
+void FullCodeGenerator::EmitSetDateField(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  ASSERT(args->length() == 3);
+  ASSERT_NE(NULL, args->at(1)->AsLiteral());
+  int index = Smi::cast(*(args->at(1)->AsLiteral()->handle()))->value();
+
+  VisitForStackValue(args->at(0));  // Load the object.
+  VisitForAccumulatorValue(args->at(2));  // Load the value.
+  __ pop(rbx);  // rax = value. rbx = object.
+
+#ifdef DEBUG
+  __ AbortIfSmi(rbx);
+  __ CmpObjectType(rbx, JS_DATE_TYPE, rcx);
+  __ Assert(equal, "Trying to set date field on non-date.");
+#endif
+
+  // Store the value.
+ __ movq(FieldOperand(rbx, JSDate::kValueOffset + kPointerSize * index), rax); + // Caches can only be smi or NaN, so we can skip the write barrier for them.
+  if (index < JSDate::kFirstBarrierFree) {
+    // Update the write barrier.  Save the value as it will be
+    // overwritten by the write barrier code and is needed afterward.
+    __ movq(rdx, rax);
+    __ RecordWriteField(rbx, JSDate::kValueOffset + kPointerSize * index,
+                        rdx, rcx, kDontSaveFPRegs);
+  }
+  context()->Plug(rax);
+}


 void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Mar 6 08:12:11 2012 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Fri Mar 9 03:11:55 2012
@@ -1222,6 +1222,47 @@

   __ bind(&done);
 }
+
+
+void LCodeGen::DoDateField(LDateField* instr) {
+  Register input = ToRegister(instr->InputAt(0));
+  Register result = ToRegister(instr->result());
+  ASSERT(input.is(result));
+
+#ifdef DEBUG
+  __ AbortIfSmi(input);
+  __ CmpObjectType(input, JS_DATE_TYPE, kScratchRegister);
+  __ Assert(equal, "Trying to get date field from non-date.");
+#endif
+
+  __ movq(result, FieldOperand(input,
+ JSDate::kValueOffset + kPointerSize * instr->index()));
+}
+
+
+void LCodeGen::DoSetDateField(LSetDateField* instr) {
+  Register date = ToRegister(instr->InputAt(0));
+  Register value = ToRegister(instr->InputAt(1));
+  Register result = ToRegister(instr->result());
+  int index = instr->index();
+
+#ifdef DEBUG
+  __ AbortIfSmi(date);
+  __ CmpObjectType(date, JS_DATE_TYPE, kScratchRegister);
+  __ Assert(equal, "Trying to get date field from non-date.");
+#endif
+
+  __ movq(FieldOperand(date, JSDate::kValueOffset + kPointerSize * index),
+          value);
+ // Caches can only be smi or NaN, so we can skip the write barrier for them.
+  if (index < JSDate::kFirstBarrierFree) {
+    // Update the write barrier.  Save the value as it will be
+    // overwritten by the write barrier code and is needed afterward.
+    __ movq(result, value);
+    __ RecordWriteField(date, JSDate::kValueOffset + kPointerSize * index,
+                        value, kScratchRegister, kDontSaveFPRegs);
+  }
+}


 void LCodeGen::DoBitNotI(LBitNotI* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc      Mon Mar  5 00:17:16 2012
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc      Fri Mar  9 03:11:55 2012
@@ -1599,6 +1599,21 @@
   LValueOf* result = new(zone()) LValueOf(object);
   return DefineSameAsFirst(result);
 }
+
+
+LInstruction* LChunkBuilder::DoDateField(HDateField* instr) {
+  LOperand* date = UseRegister(instr->value());
+  LDateField* result = new LDateField(date, instr->index());
+  return DefineSameAsFirst(result);
+}
+
+
+LInstruction* LChunkBuilder::DoSetDateField(HSetDateField* instr) {
+  LOperand* date = UseRegister(instr->OperandAt(1));
+  LOperand* value = UseRegister(instr->OperandAt(2));
+  LSetDateField* result = new LSetDateField(date, value, instr->index());
+  return DefineAsRegister(result);
+}


 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.h       Thu Mar  1 03:10:28 2012
+++ /branches/bleeding_edge/src/x64/lithium-x64.h       Fri Mar  9 03:11:55 2012
@@ -177,7 +177,9 @@
   V(ForInPrepareMap)                            \
   V(ForInCacheArray)                            \
   V(CheckMapValue)                              \
-  V(LoadFieldByIndex)
+  V(LoadFieldByIndex)                           \
+  V(DateField)                                  \
+  V(SetDateField)


 #define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)              \
@@ -987,6 +989,39 @@
 };


+class LDateField: public LTemplateInstruction<1, 1, 0> {
+ public:
+  LDateField(LOperand* date, int index) : index_(index) {
+    inputs_[0] = date;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(ValueOf, "date-field")
+  DECLARE_HYDROGEN_ACCESSOR(ValueOf)
+
+  int index() const { return index_; }
+
+ private:
+  int index_;
+};
+
+
+class LSetDateField: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LSetDateField(LOperand* date, LOperand* value, int index) : index_(index) {
+    inputs_[0] = date;
+    inputs_[1] = value;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(DateField, "date-set-field")
+  DECLARE_HYDROGEN_ACCESSOR(DateField)
+
+  int index() const { return index_; }
+
+ private:
+  int index_;
+};
+
+
 class LThrow: public LTemplateInstruction<0, 1, 0> {
  public:
   explicit LThrow(LOperand* value) {
=======================================
--- /branches/bleeding_edge/test/mjsunit/fuzz-natives.js Tue Nov 8 06:39:37 2011 +++ /branches/bleeding_edge/test/mjsunit/fuzz-natives.js Fri Mar 9 03:11:55 2012
@@ -184,8 +184,10 @@
   "RegExpConstructResult": true,
   "_RegExpConstructResult": true,

-  // This function performs some checks compile time (it requires its first
-  // argument to be a compile time smi).
+ // This functions perform some checks compile time (they require one of their
+  // arguments to be a compile time smi).
+  "_DateField": true,
+  "_SetDateField": true,
   "_GetFromCache": true,

   // This function expects its first argument to be a non-smi.

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to