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