| // Copyright 2017 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/builtins/builtins-utils-gen.h" |
| #include "src/builtins/builtins.h" |
| #include "src/codegen/code-stub-assembler.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| // ----------------------------------------------------------------------------- |
| // ES6 section 20.3 Date Objects |
| |
| class DateBuiltinsAssembler : public CodeStubAssembler { |
| public: |
| explicit DateBuiltinsAssembler(compiler::CodeAssemblerState* state) |
| : CodeStubAssembler(state) {} |
| |
| protected: |
| void Generate_DatePrototype_GetField(TNode<Context> context, |
| TNode<Object> receiver, int field_index); |
| }; |
| |
| void DateBuiltinsAssembler::Generate_DatePrototype_GetField( |
| TNode<Context> context, TNode<Object> receiver, int field_index) { |
| Label receiver_not_date(this, Label::kDeferred); |
| |
| GotoIf(TaggedIsSmi(receiver), &receiver_not_date); |
| TNode<Uint16T> receiver_instance_type = LoadInstanceType(CAST(receiver)); |
| GotoIfNot(InstanceTypeEqual(receiver_instance_type, JS_DATE_TYPE), |
| &receiver_not_date); |
| |
| TNode<JSDate> date_receiver = CAST(receiver); |
| // Load the specified date field, falling back to the runtime as necessary. |
| if (field_index == JSDate::kDateValue) { |
| Return(LoadObjectField(date_receiver, JSDate::kValueOffset)); |
| } else { |
| if (field_index < JSDate::kFirstUncachedField) { |
| Label stamp_mismatch(this, Label::kDeferred); |
| TNode<Object> date_cache_stamp = Load<Object>( |
| ExternalConstant(ExternalReference::date_cache_stamp(isolate()))); |
| |
| TNode<Object> cache_stamp = |
| LoadObjectField(date_receiver, JSDate::kCacheStampOffset); |
| GotoIf(TaggedNotEqual(date_cache_stamp, cache_stamp), &stamp_mismatch); |
| Return(LoadObjectField(date_receiver, |
| JSDate::kValueOffset + field_index * kTaggedSize)); |
| |
| BIND(&stamp_mismatch); |
| } |
| |
| TNode<ExternalReference> isolate_ptr = |
| ExternalConstant(ExternalReference::isolate_address(isolate())); |
| TNode<Smi> field_index_smi = SmiConstant(field_index); |
| TNode<ExternalReference> function = |
| ExternalConstant(ExternalReference::get_date_field_function()); |
| TNode<Object> result = CAST(CallCFunction( |
| function, MachineType::AnyTagged(), |
| std::make_pair(MachineType::Pointer(), isolate_ptr), |
| std::make_pair(MachineType::AnyTagged(), date_receiver), |
| std::make_pair(MachineType::AnyTagged(), field_index_smi))); |
| Return(result); |
| } |
| |
| // Raise a TypeError if the receiver is not a date. |
| BIND(&receiver_not_date); |
| { ThrowTypeError(context, MessageTemplate::kNotDateObject); } |
| } |
| |
| TF_BUILTIN(DatePrototypeGetDate, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kDay); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetDay, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kWeekday); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetFullYear, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kYear); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetHours, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kHour); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetMilliseconds, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kMillisecond); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetMinutes, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kMinute); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetMonth, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kMonth); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetSeconds, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kSecond); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetTime, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kDateValue); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetTimezoneOffset, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kTimezoneOffset); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetUTCDate, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kDayUTC); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetUTCDay, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kWeekdayUTC); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetUTCFullYear, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kYearUTC); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetUTCHours, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kHourUTC); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetUTCMilliseconds, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kMillisecondUTC); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetUTCMinutes, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kMinuteUTC); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetUTCMonth, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kMonthUTC); |
| } |
| |
| TF_BUILTIN(DatePrototypeGetUTCSeconds, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kSecondUTC); |
| } |
| |
| TF_BUILTIN(DatePrototypeValueOf, DateBuiltinsAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| Generate_DatePrototype_GetField(context, receiver, JSDate::kDateValue); |
| } |
| |
| TF_BUILTIN(DatePrototypeToPrimitive, CodeStubAssembler) { |
| auto context = Parameter<Context>(Descriptor::kContext); |
| auto receiver = Parameter<Object>(Descriptor::kReceiver); |
| auto hint = Parameter<Object>(Descriptor::kHint); |
| |
| // Check if the {receiver} is actually a JSReceiver. |
| Label receiver_is_invalid(this, Label::kDeferred); |
| GotoIf(TaggedIsSmi(receiver), &receiver_is_invalid); |
| GotoIfNot(IsJSReceiver(CAST(receiver)), &receiver_is_invalid); |
| |
| // Dispatch to the appropriate OrdinaryToPrimitive builtin. |
| Label hint_is_number(this), hint_is_string(this), |
| hint_is_invalid(this, Label::kDeferred); |
| |
| // Fast cases for internalized strings. |
| TNode<String> number_string = NumberStringConstant(); |
| GotoIf(TaggedEqual(hint, number_string), &hint_is_number); |
| TNode<String> default_string = DefaultStringConstant(); |
| GotoIf(TaggedEqual(hint, default_string), &hint_is_string); |
| TNode<String> string_string = StringStringConstant(); |
| GotoIf(TaggedEqual(hint, string_string), &hint_is_string); |
| |
| // Slow-case with actual string comparisons. |
| GotoIf(TaggedIsSmi(hint), &hint_is_invalid); |
| GotoIfNot(IsString(CAST(hint)), &hint_is_invalid); |
| GotoIf(TaggedEqual( |
| CallBuiltin(Builtins::kStringEqual, context, hint, number_string), |
| TrueConstant()), |
| &hint_is_number); |
| GotoIf(TaggedEqual( |
| CallBuiltin(Builtins::kStringEqual, context, hint, default_string), |
| TrueConstant()), |
| &hint_is_string); |
| GotoIf(TaggedEqual( |
| CallBuiltin(Builtins::kStringEqual, context, hint, string_string), |
| TrueConstant()), |
| &hint_is_string); |
| Goto(&hint_is_invalid); |
| |
| // Use the OrdinaryToPrimitive builtin to convert to a Number. |
| BIND(&hint_is_number); |
| { |
| Callable callable = CodeFactory::OrdinaryToPrimitive( |
| isolate(), OrdinaryToPrimitiveHint::kNumber); |
| TNode<Object> result = CallStub(callable, context, receiver); |
| Return(result); |
| } |
| |
| // Use the OrdinaryToPrimitive builtin to convert to a String. |
| BIND(&hint_is_string); |
| { |
| Callable callable = CodeFactory::OrdinaryToPrimitive( |
| isolate(), OrdinaryToPrimitiveHint::kString); |
| TNode<Object> result = CallStub(callable, context, receiver); |
| Return(result); |
| } |
| |
| // Raise a TypeError if the {hint} is invalid. |
| BIND(&hint_is_invalid); |
| { ThrowTypeError(context, MessageTemplate::kInvalidHint, hint); } |
| |
| // Raise a TypeError if the {receiver} is not a JSReceiver instance. |
| BIND(&receiver_is_invalid); |
| { |
| ThrowTypeError(context, MessageTemplate::kIncompatibleMethodReceiver, |
| StringConstant("Date.prototype [ @@toPrimitive ]"), |
| receiver); |
| } |
| } |
| |
| } // namespace internal |
| } // namespace v8 |