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