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(Builtins::kStringEqual, context, hint, number_string),
212              TrueConstant()),
213          &hint_is_number);
214   GotoIf(TaggedEqual(
215              CallBuiltin(Builtins::kStringEqual, context, hint, default_string),
216              TrueConstant()),
217          &hint_is_string);
218   GotoIf(TaggedEqual(
219              CallBuiltin(Builtins::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