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