builtins-date-gen.cc 9.56 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"

namespace v8 {
namespace internal {

// -----------------------------------------------------------------------------
// ES6 section 20.3 Date Objects

class DateBuiltinsAssembler : public CodeStubAssembler {
 public:
  explicit DateBuiltinsAssembler(compiler::CodeAssemblerState* state)
      : CodeStubAssembler(state) {}

 protected:
21 22
  void Generate_DatePrototype_GetField(Node* context, Node* receiver,
                                       int field_index);
23 24
};

25 26 27
void DateBuiltinsAssembler::Generate_DatePrototype_GetField(Node* context,
                                                            Node* receiver,
                                                            int field_index) {
28 29 30 31
  Label receiver_not_date(this, Label::kDeferred);

  GotoIf(TaggedIsSmi(receiver), &receiver_not_date);
  Node* receiver_instance_type = LoadInstanceType(receiver);
32 33
  GotoIfNot(InstanceTypeEqual(receiver_instance_type, JS_DATE_TYPE),
            &receiver_not_date);
34 35 36 37 38 39 40 41 42 43 44 45 46

  // Load the specified date field, falling back to the runtime as necessary.
  if (field_index == JSDate::kDateValue) {
    Return(LoadObjectField(receiver, JSDate::kValueOffset));
  } else {
    if (field_index < JSDate::kFirstUncachedField) {
      Label stamp_mismatch(this, Label::kDeferred);
      Node* date_cache_stamp = Load(
          MachineType::AnyTagged(),
          ExternalConstant(ExternalReference::date_cache_stamp(isolate())));

      Node* cache_stamp = LoadObjectField(receiver, JSDate::kCacheStampOffset);
      GotoIf(WordNotEqual(date_cache_stamp, cache_stamp), &stamp_mismatch);
47 48
      Return(LoadObjectField(receiver,
                             JSDate::kValueOffset + field_index * kTaggedSize));
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 57 58 59 60 61 62
    Node* result = CallCFunction2(
        MachineType::AnyTagged(), MachineType::AnyTagged(),
        MachineType::AnyTagged(), function, receiver, field_index_smi);
    Return(result);
  }

  // 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 69 70
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kDay);
71 72 73
}

TF_BUILTIN(DatePrototypeGetDay, DateBuiltinsAssembler) {
74 75 76
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kWeekday);
77 78 79
}

TF_BUILTIN(DatePrototypeGetFullYear, DateBuiltinsAssembler) {
80 81 82
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kYear);
83 84 85
}

TF_BUILTIN(DatePrototypeGetHours, DateBuiltinsAssembler) {
86 87 88
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kHour);
89 90 91
}

TF_BUILTIN(DatePrototypeGetMilliseconds, DateBuiltinsAssembler) {
92 93 94
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kMillisecond);
95 96 97
}

TF_BUILTIN(DatePrototypeGetMinutes, DateBuiltinsAssembler) {
98 99 100
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kMinute);
101 102 103
}

TF_BUILTIN(DatePrototypeGetMonth, DateBuiltinsAssembler) {
104 105 106
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kMonth);
107 108 109
}

TF_BUILTIN(DatePrototypeGetSeconds, DateBuiltinsAssembler) {
110 111 112
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kSecond);
113 114 115
}

TF_BUILTIN(DatePrototypeGetTime, DateBuiltinsAssembler) {
116 117 118
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kDateValue);
119 120 121
}

TF_BUILTIN(DatePrototypeGetTimezoneOffset, DateBuiltinsAssembler) {
122 123 124
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kTimezoneOffset);
125 126 127
}

TF_BUILTIN(DatePrototypeGetUTCDate, DateBuiltinsAssembler) {
128 129 130
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kDayUTC);
131 132 133
}

TF_BUILTIN(DatePrototypeGetUTCDay, DateBuiltinsAssembler) {
134 135 136
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kWeekdayUTC);
137 138 139
}

TF_BUILTIN(DatePrototypeGetUTCFullYear, DateBuiltinsAssembler) {
140 141 142
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kYearUTC);
143 144 145
}

TF_BUILTIN(DatePrototypeGetUTCHours, DateBuiltinsAssembler) {
146 147 148
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kHourUTC);
149 150 151
}

TF_BUILTIN(DatePrototypeGetUTCMilliseconds, DateBuiltinsAssembler) {
152 153 154
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kMillisecondUTC);
155 156 157
}

TF_BUILTIN(DatePrototypeGetUTCMinutes, DateBuiltinsAssembler) {
158 159 160
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kMinuteUTC);
161 162 163
}

TF_BUILTIN(DatePrototypeGetUTCMonth, DateBuiltinsAssembler) {
164 165 166
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kMonthUTC);
167 168 169
}

TF_BUILTIN(DatePrototypeGetUTCSeconds, DateBuiltinsAssembler) {
170 171 172
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kSecondUTC);
173 174 175
}

TF_BUILTIN(DatePrototypeValueOf, DateBuiltinsAssembler) {
176 177 178
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Generate_DatePrototype_GetField(context, receiver, JSDate::kDateValue);
179 180 181
}

TF_BUILTIN(DatePrototypeToPrimitive, CodeStubAssembler) {
182 183 184
  Node* context = Parameter(Descriptor::kContext);
  Node* receiver = Parameter(Descriptor::kReceiver);
  Node* hint = Parameter(Descriptor::kHint);
185 186 187 188 189 190 191 192 193 194 195

  // Check if the {receiver} is actually a JSReceiver.
  Label receiver_is_invalid(this, Label::kDeferred);
  GotoIf(TaggedIsSmi(receiver), &receiver_is_invalid);
  GotoIfNot(IsJSReceiver(receiver), &receiver_is_invalid);

  // Dispatch to the appropriate OrdinaryToPrimitive builtin.
  Label hint_is_number(this), hint_is_string(this),
      hint_is_invalid(this, Label::kDeferred);

  // Fast cases for internalized strings.
196
  Node* number_string = LoadRoot(RootIndex::knumber_string);
197
  GotoIf(WordEqual(hint, number_string), &hint_is_number);
198
  Node* default_string = LoadRoot(RootIndex::kdefault_string);
199
  GotoIf(WordEqual(hint, default_string), &hint_is_string);
200
  Node* string_string = LoadRoot(RootIndex::kstring_string);
201 202 203 204 205
  GotoIf(WordEqual(hint, string_string), &hint_is_string);

  // Slow-case with actual string comparisons.
  GotoIf(TaggedIsSmi(hint), &hint_is_invalid);
  GotoIfNot(IsString(hint), &hint_is_invalid);
206 207 208
  GotoIf(WordEqual(
             CallBuiltin(Builtins::kStringEqual, context, hint, number_string),
             TrueConstant()),
209
         &hint_is_number);
210 211 212
  GotoIf(WordEqual(
             CallBuiltin(Builtins::kStringEqual, context, hint, default_string),
             TrueConstant()),
213
         &hint_is_string);
214 215 216
  GotoIf(WordEqual(
             CallBuiltin(Builtins::kStringEqual, context, hint, string_string),
             TrueConstant()),
217 218 219 220
         &hint_is_string);
  Goto(&hint_is_invalid);

  // Use the OrdinaryToPrimitive builtin to convert to a Number.
221
  BIND(&hint_is_number);
222 223 224 225 226 227 228 229
  {
    Callable callable = CodeFactory::OrdinaryToPrimitive(
        isolate(), OrdinaryToPrimitiveHint::kNumber);
    Node* result = CallStub(callable, context, receiver);
    Return(result);
  }

  // Use the OrdinaryToPrimitive builtin to convert to a String.
230
  BIND(&hint_is_string);
231 232 233 234 235 236 237 238
  {
    Callable callable = CodeFactory::OrdinaryToPrimitive(
        isolate(), OrdinaryToPrimitiveHint::kString);
    Node* result = CallStub(callable, context, receiver);
    Return(result);
  }

  // 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 246 247
    ThrowTypeError(context, MessageTemplate::kIncompatibleMethodReceiver,
                   StringConstant("Date.prototype [ @@toPrimitive ]"),
                   receiver);
248 249 250 251 252
  }
}

}  // namespace internal
}  // namespace v8