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
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(TNode<Context> context,
22 TNode<Object> receiver, int field_index);
23 };
24
Generate_DatePrototype_GetField(TNode<Context> context,TNode<Object> receiver,int field_index)25 void 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
TF_BUILTIN(DatePrototypeGetDate,DateBuiltinsAssembler)71 TF_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
TF_BUILTIN(DatePrototypeGetDay,DateBuiltinsAssembler)77 TF_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
TF_BUILTIN(DatePrototypeGetFullYear,DateBuiltinsAssembler)83 TF_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
TF_BUILTIN(DatePrototypeGetHours,DateBuiltinsAssembler)89 TF_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
TF_BUILTIN(DatePrototypeGetMilliseconds,DateBuiltinsAssembler)95 TF_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
TF_BUILTIN(DatePrototypeGetMinutes,DateBuiltinsAssembler)101 TF_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
TF_BUILTIN(DatePrototypeGetMonth,DateBuiltinsAssembler)107 TF_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
TF_BUILTIN(DatePrototypeGetSeconds,DateBuiltinsAssembler)113 TF_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
TF_BUILTIN(DatePrototypeGetTime,DateBuiltinsAssembler)119 TF_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
TF_BUILTIN(DatePrototypeGetTimezoneOffset,DateBuiltinsAssembler)125 TF_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
TF_BUILTIN(DatePrototypeGetUTCDate,DateBuiltinsAssembler)131 TF_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
TF_BUILTIN(DatePrototypeGetUTCDay,DateBuiltinsAssembler)137 TF_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
TF_BUILTIN(DatePrototypeGetUTCFullYear,DateBuiltinsAssembler)143 TF_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
TF_BUILTIN(DatePrototypeGetUTCHours,DateBuiltinsAssembler)149 TF_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
TF_BUILTIN(DatePrototypeGetUTCMilliseconds,DateBuiltinsAssembler)155 TF_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
TF_BUILTIN(DatePrototypeGetUTCMinutes,DateBuiltinsAssembler)161 TF_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
TF_BUILTIN(DatePrototypeGetUTCMonth,DateBuiltinsAssembler)167 TF_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
TF_BUILTIN(DatePrototypeGetUTCSeconds,DateBuiltinsAssembler)173 TF_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
TF_BUILTIN(DatePrototypeValueOf,DateBuiltinsAssembler)179 TF_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
TF_BUILTIN(DatePrototypeToPrimitive,CodeStubAssembler)185 TF_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