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