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:
DateBuiltinsAssembler(compiler::CodeAssemblerState * state)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
Generate_DatePrototype_GetField(Node * context,Node * receiver,int field_index)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
TF_BUILTIN(DatePrototypeGetDate,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetDay,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetFullYear,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetHours,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetMilliseconds,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetMinutes,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetMonth,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetSeconds,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetTime,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetTimezoneOffset,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetUTCDate,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetUTCDay,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetUTCFullYear,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetUTCHours,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetUTCMilliseconds,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetUTCMinutes,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetUTCMonth,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeGetUTCSeconds,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeValueOf,DateBuiltinsAssembler)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
TF_BUILTIN(DatePrototypeToPrimitive,CodeStubAssembler)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