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 9namespace v8 { 10namespace internal { 11 12// ----------------------------------------------------------------------------- 13// ES6 section 20.3 Date Objects 14 15class DateBuiltinsAssembler : public CodeStubAssembler { 16 public: 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 25void 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 71TF_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 77TF_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 83TF_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 89TF_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 95TF_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 101TF_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 107TF_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 113TF_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 119TF_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 125TF_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 131TF_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 137TF_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 143TF_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 149TF_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 155TF_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 161TF_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 167TF_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 173TF_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 179TF_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 185TF_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