Home | History | Annotate | Download | only in builtins
      1 // Copyright 2017 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/builtins/builtins-utils-gen.h"
      6 #include "src/builtins/builtins.h"
      7 #include "src/code-stub-assembler.h"
      8 
      9 namespace v8 {
     10 namespace internal {
     11 
     12 // -----------------------------------------------------------------------------
     13 // ES6 section 20.3 Date Objects
     14 
     15 class DateBuiltinsAssembler : public CodeStubAssembler {
     16  public:
     17   explicit DateBuiltinsAssembler(compiler::CodeAssemblerState* state)
     18       : CodeStubAssembler(state) {}
     19 
     20  protected:
     21   void Generate_DatePrototype_GetField(Node* context, Node* receiver,
     22                                        int field_index);
     23 };
     24 
     25 void DateBuiltinsAssembler::Generate_DatePrototype_GetField(Node* context,
     26                                                             Node* receiver,
     27                                                             int field_index) {
     28   Label receiver_not_date(this, Label::kDeferred);
     29 
     30   GotoIf(TaggedIsSmi(receiver), &receiver_not_date);
     31   Node* receiver_instance_type = LoadInstanceType(receiver);
     32   GotoIfNot(InstanceTypeEqual(receiver_instance_type, JS_DATE_TYPE),
     33             &receiver_not_date);
     34 
     35   // Load the specified date field, falling back to the runtime as necessary.
     36   if (field_index == JSDate::kDateValue) {
     37     Return(LoadObjectField(receiver, JSDate::kValueOffset));
     38   } else {
     39     if (field_index < JSDate::kFirstUncachedField) {
     40       Label stamp_mismatch(this, Label::kDeferred);
     41       Node* date_cache_stamp = Load(
     42           MachineType::AnyTagged(),
     43           ExternalConstant(ExternalReference::date_cache_stamp(isolate())));
     44 
     45       Node* cache_stamp = LoadObjectField(receiver, JSDate::kCacheStampOffset);
     46       GotoIf(WordNotEqual(date_cache_stamp, cache_stamp), &stamp_mismatch);
     47       Return(LoadObjectField(
     48           receiver, JSDate::kValueOffset + field_index * kPointerSize));
     49 
     50       BIND(&stamp_mismatch);
     51     }
     52 
     53     Node* field_index_smi = SmiConstant(field_index);
     54     Node* function =
     55         ExternalConstant(ExternalReference::get_date_field_function());
     56     Node* result = CallCFunction2(
     57         MachineType::AnyTagged(), MachineType::AnyTagged(),
     58         MachineType::AnyTagged(), function, receiver, field_index_smi);
     59     Return(result);
     60   }
     61 
     62   // Raise a TypeError if the receiver is not a date.
     63   BIND(&receiver_not_date);
     64   { ThrowTypeError(context, MessageTemplate::kNotDateObject); }
     65 }
     66 
     67 TF_BUILTIN(DatePrototypeGetDate, DateBuiltinsAssembler) {
     68   Node* context = Parameter(Descriptor::kContext);
     69   Node* receiver = Parameter(Descriptor::kReceiver);
     70   Generate_DatePrototype_GetField(context, receiver, JSDate::kDay);
     71 }
     72 
     73 TF_BUILTIN(DatePrototypeGetDay, DateBuiltinsAssembler) {
     74   Node* context = Parameter(Descriptor::kContext);
     75   Node* receiver = Parameter(Descriptor::kReceiver);
     76   Generate_DatePrototype_GetField(context, receiver, JSDate::kWeekday);
     77 }
     78 
     79 TF_BUILTIN(DatePrototypeGetFullYear, DateBuiltinsAssembler) {
     80   Node* context = Parameter(Descriptor::kContext);
     81   Node* receiver = Parameter(Descriptor::kReceiver);
     82   Generate_DatePrototype_GetField(context, receiver, JSDate::kYear);
     83 }
     84 
     85 TF_BUILTIN(DatePrototypeGetHours, DateBuiltinsAssembler) {
     86   Node* context = Parameter(Descriptor::kContext);
     87   Node* receiver = Parameter(Descriptor::kReceiver);
     88   Generate_DatePrototype_GetField(context, receiver, JSDate::kHour);
     89 }
     90 
     91 TF_BUILTIN(DatePrototypeGetMilliseconds, DateBuiltinsAssembler) {
     92   Node* context = Parameter(Descriptor::kContext);
     93   Node* receiver = Parameter(Descriptor::kReceiver);
     94   Generate_DatePrototype_GetField(context, receiver, JSDate::kMillisecond);
     95 }
     96 
     97 TF_BUILTIN(DatePrototypeGetMinutes, DateBuiltinsAssembler) {
     98   Node* context = Parameter(Descriptor::kContext);
     99   Node* receiver = Parameter(Descriptor::kReceiver);
    100   Generate_DatePrototype_GetField(context, receiver, JSDate::kMinute);
    101 }
    102 
    103 TF_BUILTIN(DatePrototypeGetMonth, DateBuiltinsAssembler) {
    104   Node* context = Parameter(Descriptor::kContext);
    105   Node* receiver = Parameter(Descriptor::kReceiver);
    106   Generate_DatePrototype_GetField(context, receiver, JSDate::kMonth);
    107 }
    108 
    109 TF_BUILTIN(DatePrototypeGetSeconds, DateBuiltinsAssembler) {
    110   Node* context = Parameter(Descriptor::kContext);
    111   Node* receiver = Parameter(Descriptor::kReceiver);
    112   Generate_DatePrototype_GetField(context, receiver, JSDate::kSecond);
    113 }
    114 
    115 TF_BUILTIN(DatePrototypeGetTime, DateBuiltinsAssembler) {
    116   Node* context = Parameter(Descriptor::kContext);
    117   Node* receiver = Parameter(Descriptor::kReceiver);
    118   Generate_DatePrototype_GetField(context, receiver, JSDate::kDateValue);
    119 }
    120 
    121 TF_BUILTIN(DatePrototypeGetTimezoneOffset, DateBuiltinsAssembler) {
    122   Node* context = Parameter(Descriptor::kContext);
    123   Node* receiver = Parameter(Descriptor::kReceiver);
    124   Generate_DatePrototype_GetField(context, receiver, JSDate::kTimezoneOffset);
    125 }
    126 
    127 TF_BUILTIN(DatePrototypeGetUTCDate, DateBuiltinsAssembler) {
    128   Node* context = Parameter(Descriptor::kContext);
    129   Node* receiver = Parameter(Descriptor::kReceiver);
    130   Generate_DatePrototype_GetField(context, receiver, JSDate::kDayUTC);
    131 }
    132 
    133 TF_BUILTIN(DatePrototypeGetUTCDay, DateBuiltinsAssembler) {
    134   Node* context = Parameter(Descriptor::kContext);
    135   Node* receiver = Parameter(Descriptor::kReceiver);
    136   Generate_DatePrototype_GetField(context, receiver, JSDate::kWeekdayUTC);
    137 }
    138 
    139 TF_BUILTIN(DatePrototypeGetUTCFullYear, DateBuiltinsAssembler) {
    140   Node* context = Parameter(Descriptor::kContext);
    141   Node* receiver = Parameter(Descriptor::kReceiver);
    142   Generate_DatePrototype_GetField(context, receiver, JSDate::kYearUTC);
    143 }
    144 
    145 TF_BUILTIN(DatePrototypeGetUTCHours, DateBuiltinsAssembler) {
    146   Node* context = Parameter(Descriptor::kContext);
    147   Node* receiver = Parameter(Descriptor::kReceiver);
    148   Generate_DatePrototype_GetField(context, receiver, JSDate::kHourUTC);
    149 }
    150 
    151 TF_BUILTIN(DatePrototypeGetUTCMilliseconds, DateBuiltinsAssembler) {
    152   Node* context = Parameter(Descriptor::kContext);
    153   Node* receiver = Parameter(Descriptor::kReceiver);
    154   Generate_DatePrototype_GetField(context, receiver, JSDate::kMillisecondUTC);
    155 }
    156 
    157 TF_BUILTIN(DatePrototypeGetUTCMinutes, DateBuiltinsAssembler) {
    158   Node* context = Parameter(Descriptor::kContext);
    159   Node* receiver = Parameter(Descriptor::kReceiver);
    160   Generate_DatePrototype_GetField(context, receiver, JSDate::kMinuteUTC);
    161 }
    162 
    163 TF_BUILTIN(DatePrototypeGetUTCMonth, DateBuiltinsAssembler) {
    164   Node* context = Parameter(Descriptor::kContext);
    165   Node* receiver = Parameter(Descriptor::kReceiver);
    166   Generate_DatePrototype_GetField(context, receiver, JSDate::kMonthUTC);
    167 }
    168 
    169 TF_BUILTIN(DatePrototypeGetUTCSeconds, DateBuiltinsAssembler) {
    170   Node* context = Parameter(Descriptor::kContext);
    171   Node* receiver = Parameter(Descriptor::kReceiver);
    172   Generate_DatePrototype_GetField(context, receiver, JSDate::kSecondUTC);
    173 }
    174 
    175 TF_BUILTIN(DatePrototypeValueOf, DateBuiltinsAssembler) {
    176   Node* context = Parameter(Descriptor::kContext);
    177   Node* receiver = Parameter(Descriptor::kReceiver);
    178   Generate_DatePrototype_GetField(context, receiver, JSDate::kDateValue);
    179 }
    180 
    181 TF_BUILTIN(DatePrototypeToPrimitive, CodeStubAssembler) {
    182   Node* context = Parameter(Descriptor::kContext);
    183   Node* receiver = Parameter(Descriptor::kReceiver);
    184   Node* hint = Parameter(Descriptor::kHint);
    185 
    186   // Check if the {receiver} is actually a JSReceiver.
    187   Label receiver_is_invalid(this, Label::kDeferred);
    188   GotoIf(TaggedIsSmi(receiver), &receiver_is_invalid);
    189   GotoIfNot(IsJSReceiver(receiver), &receiver_is_invalid);
    190 
    191   // Dispatch to the appropriate OrdinaryToPrimitive builtin.
    192   Label hint_is_number(this), hint_is_string(this),
    193       hint_is_invalid(this, Label::kDeferred);
    194 
    195   // Fast cases for internalized strings.
    196   Node* number_string = LoadRoot(Heap::knumber_stringRootIndex);
    197   GotoIf(WordEqual(hint, number_string), &hint_is_number);
    198   Node* default_string = LoadRoot(Heap::kdefault_stringRootIndex);
    199   GotoIf(WordEqual(hint, default_string), &hint_is_string);
    200   Node* string_string = LoadRoot(Heap::kstring_stringRootIndex);
    201   GotoIf(WordEqual(hint, string_string), &hint_is_string);
    202 
    203   // Slow-case with actual string comparisons.
    204   GotoIf(TaggedIsSmi(hint), &hint_is_invalid);
    205   GotoIfNot(IsString(hint), &hint_is_invalid);
    206   GotoIf(WordEqual(
    207              CallBuiltin(Builtins::kStringEqual, context, hint, number_string),
    208              TrueConstant()),
    209          &hint_is_number);
    210   GotoIf(WordEqual(
    211              CallBuiltin(Builtins::kStringEqual, context, hint, default_string),
    212              TrueConstant()),
    213          &hint_is_string);
    214   GotoIf(WordEqual(
    215              CallBuiltin(Builtins::kStringEqual, context, hint, string_string),
    216              TrueConstant()),
    217          &hint_is_string);
    218   Goto(&hint_is_invalid);
    219 
    220   // Use the OrdinaryToPrimitive builtin to convert to a Number.
    221   BIND(&hint_is_number);
    222   {
    223     Callable callable = CodeFactory::OrdinaryToPrimitive(
    224         isolate(), OrdinaryToPrimitiveHint::kNumber);
    225     Node* result = CallStub(callable, context, receiver);
    226     Return(result);
    227   }
    228 
    229   // Use the OrdinaryToPrimitive builtin to convert to a String.
    230   BIND(&hint_is_string);
    231   {
    232     Callable callable = CodeFactory::OrdinaryToPrimitive(
    233         isolate(), OrdinaryToPrimitiveHint::kString);
    234     Node* result = CallStub(callable, context, receiver);
    235     Return(result);
    236   }
    237 
    238   // Raise a TypeError if the {hint} is invalid.
    239   BIND(&hint_is_invalid);
    240   { ThrowTypeError(context, MessageTemplate::kInvalidHint, hint); }
    241 
    242   // Raise a TypeError if the {receiver} is not a JSReceiver instance.
    243   BIND(&receiver_is_invalid);
    244   {
    245     ThrowTypeError(context, MessageTemplate::kIncompatibleMethodReceiver,
    246                    StringConstant("Date.prototype [ @@toPrimitive ]"),
    247                    receiver);
    248   }
    249 }
    250 
    251 }  // namespace internal
    252 }  // namespace v8
    253