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 : CodeStubAssembler(state) {} 19 20 protected: 21 void Generate_DatePrototype_GetField(Node* context, Node* receiver, 22 int field_index); 23 }; 24 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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