| // Copyright 2012 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/compiler/simplified-operator.h" |
| |
| #include "include/v8-fast-api-calls.h" |
| #include "src/base/lazy-instance.h" |
| #include "src/compiler/linkage.h" |
| #include "src/compiler/opcodes.h" |
| #include "src/compiler/operator.h" |
| #include "src/compiler/types.h" |
| #include "src/handles/handles-inl.h" |
| #include "src/objects/feedback-cell.h" |
| #include "src/objects/map.h" |
| #include "src/objects/name.h" |
| #include "src/objects/objects-inl.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace compiler { |
| |
| size_t hash_value(BaseTaggedness base_taggedness) { |
| return static_cast<uint8_t>(base_taggedness); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, BaseTaggedness base_taggedness) { |
| switch (base_taggedness) { |
| case kUntaggedBase: |
| return os << "untagged base"; |
| case kTaggedBase: |
| return os << "tagged base"; |
| } |
| UNREACHABLE(); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, |
| ConstFieldInfo const& const_field_info) { |
| if (const_field_info.IsConst()) { |
| return os << "const (field owner: " << const_field_info.owner_map.address() |
| << ")"; |
| } else { |
| return os << "mutable"; |
| } |
| UNREACHABLE(); |
| } |
| |
| bool operator==(ConstFieldInfo const& lhs, ConstFieldInfo const& rhs) { |
| return lhs.owner_map.address() == rhs.owner_map.address(); |
| } |
| |
| size_t hash_value(ConstFieldInfo const& const_field_info) { |
| return static_cast<size_t>(const_field_info.owner_map.address()); |
| } |
| |
| bool operator==(FieldAccess const& lhs, FieldAccess const& rhs) { |
| // On purpose we don't include the write barrier kind here, as this method is |
| // really only relevant for eliminating loads and they don't care about the |
| // write barrier mode. |
| return lhs.base_is_tagged == rhs.base_is_tagged && lhs.offset == rhs.offset && |
| lhs.map.address() == rhs.map.address() && |
| lhs.machine_type == rhs.machine_type && |
| lhs.const_field_info == rhs.const_field_info && |
| lhs.is_store_in_literal == rhs.is_store_in_literal; |
| } |
| |
| size_t hash_value(FieldAccess const& access) { |
| // On purpose we don't include the write barrier kind here, as this method is |
| // really only relevant for eliminating loads and they don't care about the |
| // write barrier mode. |
| return base::hash_combine(access.base_is_tagged, access.offset, |
| access.machine_type, access.const_field_info, |
| access.is_store_in_literal); |
| } |
| |
| size_t hash_value(LoadSensitivity load_sensitivity) { |
| return static_cast<size_t>(load_sensitivity); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, LoadSensitivity load_sensitivity) { |
| switch (load_sensitivity) { |
| case LoadSensitivity::kCritical: |
| return os << "Critical"; |
| case LoadSensitivity::kSafe: |
| return os << "Safe"; |
| case LoadSensitivity::kUnsafe: |
| return os << "Unsafe"; |
| } |
| UNREACHABLE(); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, FieldAccess const& access) { |
| os << "[" << access.base_is_tagged << ", " << access.offset << ", "; |
| #ifdef OBJECT_PRINT |
| Handle<Name> name; |
| if (access.name.ToHandle(&name)) { |
| name->NamePrint(os); |
| os << ", "; |
| } |
| Handle<Map> map; |
| if (access.map.ToHandle(&map)) { |
| os << Brief(*map) << ", "; |
| } |
| #endif |
| os << access.type << ", " << access.machine_type << ", " |
| << access.write_barrier_kind << ", " << access.const_field_info; |
| if (access.is_store_in_literal) { |
| os << " (store in literal)"; |
| } |
| if (FLAG_untrusted_code_mitigations) { |
| os << ", " << access.load_sensitivity; |
| } |
| os << "]"; |
| return os; |
| } |
| |
| template <> |
| void Operator1<FieldAccess>::PrintParameter(std::ostream& os, |
| PrintVerbosity verbose) const { |
| if (verbose == PrintVerbosity::kVerbose) { |
| os << parameter(); |
| } else { |
| os << "[+" << parameter().offset << "]"; |
| } |
| } |
| |
| bool operator==(ElementAccess const& lhs, ElementAccess const& rhs) { |
| // On purpose we don't include the write barrier kind here, as this method is |
| // really only relevant for eliminating loads and they don't care about the |
| // write barrier mode. |
| return lhs.base_is_tagged == rhs.base_is_tagged && |
| lhs.header_size == rhs.header_size && |
| lhs.machine_type == rhs.machine_type; |
| } |
| |
| size_t hash_value(ElementAccess const& access) { |
| // On purpose we don't include the write barrier kind here, as this method is |
| // really only relevant for eliminating loads and they don't care about the |
| // write barrier mode. |
| return base::hash_combine(access.base_is_tagged, access.header_size, |
| access.machine_type); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, ElementAccess const& access) { |
| os << access.base_is_tagged << ", " << access.header_size << ", " |
| << access.type << ", " << access.machine_type << ", " |
| << access.write_barrier_kind; |
| if (FLAG_untrusted_code_mitigations) { |
| os << ", " << access.load_sensitivity; |
| } |
| return os; |
| } |
| |
| bool operator==(ObjectAccess const& lhs, ObjectAccess const& rhs) { |
| return lhs.machine_type == rhs.machine_type && |
| lhs.write_barrier_kind == rhs.write_barrier_kind; |
| } |
| |
| size_t hash_value(ObjectAccess const& access) { |
| return base::hash_combine(access.machine_type, access.write_barrier_kind); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, ObjectAccess const& access) { |
| os << access.machine_type << ", " << access.write_barrier_kind; |
| return os; |
| } |
| |
| const FieldAccess& FieldAccessOf(const Operator* op) { |
| DCHECK_NOT_NULL(op); |
| DCHECK(op->opcode() == IrOpcode::kLoadField || |
| op->opcode() == IrOpcode::kStoreField); |
| return OpParameter<FieldAccess>(op); |
| } |
| |
| const ElementAccess& ElementAccessOf(const Operator* op) { |
| DCHECK_NOT_NULL(op); |
| DCHECK(op->opcode() == IrOpcode::kLoadElement || |
| op->opcode() == IrOpcode::kStoreElement); |
| return OpParameter<ElementAccess>(op); |
| } |
| |
| const ObjectAccess& ObjectAccessOf(const Operator* op) { |
| DCHECK_NOT_NULL(op); |
| DCHECK(op->opcode() == IrOpcode::kLoadFromObject || |
| op->opcode() == IrOpcode::kStoreToObject); |
| return OpParameter<ObjectAccess>(op); |
| } |
| |
| ExternalArrayType ExternalArrayTypeOf(const Operator* op) { |
| DCHECK(op->opcode() == IrOpcode::kLoadTypedElement || |
| op->opcode() == IrOpcode::kLoadDataViewElement || |
| op->opcode() == IrOpcode::kStoreTypedElement || |
| op->opcode() == IrOpcode::kStoreDataViewElement); |
| return OpParameter<ExternalArrayType>(op); |
| } |
| |
| ConvertReceiverMode ConvertReceiverModeOf(Operator const* op) { |
| DCHECK_EQ(IrOpcode::kConvertReceiver, op->opcode()); |
| return OpParameter<ConvertReceiverMode>(op); |
| } |
| |
| size_t hash_value(CheckFloat64HoleMode mode) { |
| return static_cast<size_t>(mode); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, CheckFloat64HoleMode mode) { |
| switch (mode) { |
| case CheckFloat64HoleMode::kAllowReturnHole: |
| return os << "allow-return-hole"; |
| case CheckFloat64HoleMode::kNeverReturnHole: |
| return os << "never-return-hole"; |
| } |
| UNREACHABLE(); |
| } |
| |
| CheckFloat64HoleParameters const& CheckFloat64HoleParametersOf( |
| Operator const* op) { |
| DCHECK_EQ(IrOpcode::kCheckFloat64Hole, op->opcode()); |
| return OpParameter<CheckFloat64HoleParameters>(op); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, |
| CheckFloat64HoleParameters const& params) { |
| return os << params.mode() << ", " << params.feedback(); |
| } |
| |
| size_t hash_value(const CheckFloat64HoleParameters& params) { |
| FeedbackSource::Hash feedback_hash; |
| return base::hash_combine(params.mode(), feedback_hash(params.feedback())); |
| } |
| |
| bool operator==(CheckFloat64HoleParameters const& lhs, |
| CheckFloat64HoleParameters const& rhs) { |
| return lhs.mode() == rhs.mode() && lhs.feedback() == rhs.feedback(); |
| } |
| |
| bool operator!=(CheckFloat64HoleParameters const& lhs, |
| CheckFloat64HoleParameters const& rhs) { |
| return !(lhs == rhs); |
| } |
| |
| CheckForMinusZeroMode CheckMinusZeroModeOf(const Operator* op) { |
| DCHECK(op->opcode() == IrOpcode::kChangeFloat64ToTagged || |
| op->opcode() == IrOpcode::kCheckedInt32Mul); |
| return OpParameter<CheckForMinusZeroMode>(op); |
| } |
| |
| size_t hash_value(CheckForMinusZeroMode mode) { |
| return static_cast<size_t>(mode); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, CheckForMinusZeroMode mode) { |
| switch (mode) { |
| case CheckForMinusZeroMode::kCheckForMinusZero: |
| return os << "check-for-minus-zero"; |
| case CheckForMinusZeroMode::kDontCheckForMinusZero: |
| return os << "dont-check-for-minus-zero"; |
| } |
| UNREACHABLE(); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, CheckMapsFlags flags) { |
| if (flags & CheckMapsFlag::kTryMigrateInstance) { |
| return os << "TryMigrateInstance"; |
| } else { |
| return os << "None"; |
| } |
| } |
| |
| bool operator==(CheckMapsParameters const& lhs, |
| CheckMapsParameters const& rhs) { |
| return lhs.flags() == rhs.flags() && lhs.maps() == rhs.maps() && |
| lhs.feedback() == rhs.feedback(); |
| } |
| |
| size_t hash_value(CheckMapsParameters const& p) { |
| FeedbackSource::Hash feedback_hash; |
| return base::hash_combine(p.flags(), p.maps(), feedback_hash(p.feedback())); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, CheckMapsParameters const& p) { |
| return os << p.flags() << ", " << p.maps() << ", " << p.feedback(); |
| } |
| |
| CheckMapsParameters const& CheckMapsParametersOf(Operator const* op) { |
| DCHECK_EQ(IrOpcode::kCheckMaps, op->opcode()); |
| return OpParameter<CheckMapsParameters>(op); |
| } |
| |
| bool operator==(DynamicCheckMapsParameters const& lhs, |
| DynamicCheckMapsParameters const& rhs) { |
| // FeedbackSource is sufficient as an equality check. FeedbackSource uniquely |
| // determines all other properties (handler, flags and the monomorphic map |
| DCHECK_IMPLIES(lhs.feedback() == rhs.feedback(), |
| lhs.flags() == rhs.flags() && lhs.state() == rhs.state() && |
| lhs.handler().address() == rhs.handler().address() && |
| lhs.maps() == rhs.maps()); |
| return lhs.feedback() == rhs.feedback(); |
| } |
| |
| size_t hash_value(DynamicCheckMapsParameters const& p) { |
| FeedbackSource::Hash feedback_hash; |
| // FeedbackSource is sufficient for hashing. FeedbackSource uniquely |
| // determines all other properties (handler, flags and the monomorphic map |
| return base::hash_combine(feedback_hash(p.feedback())); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, |
| DynamicCheckMapsParameters const& p) { |
| return os << p.handler() << ", " << p.feedback() << "," << p.state() << "," |
| << p.flags() << "," << p.maps(); |
| } |
| |
| DynamicCheckMapsParameters const& DynamicCheckMapsParametersOf( |
| Operator const* op) { |
| DCHECK_EQ(IrOpcode::kDynamicCheckMaps, op->opcode()); |
| return OpParameter<DynamicCheckMapsParameters>(op); |
| } |
| |
| ZoneHandleSet<Map> const& CompareMapsParametersOf(Operator const* op) { |
| DCHECK_EQ(IrOpcode::kCompareMaps, op->opcode()); |
| return OpParameter<ZoneHandleSet<Map>>(op); |
| } |
| |
| ZoneHandleSet<Map> const& MapGuardMapsOf(Operator const* op) { |
| DCHECK_EQ(IrOpcode::kMapGuard, op->opcode()); |
| return OpParameter<ZoneHandleSet<Map>>(op); |
| } |
| |
| size_t hash_value(CheckTaggedInputMode mode) { |
| return static_cast<size_t>(mode); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, CheckTaggedInputMode mode) { |
| switch (mode) { |
| case CheckTaggedInputMode::kNumber: |
| return os << "Number"; |
| case CheckTaggedInputMode::kNumberOrBoolean: |
| return os << "NumberOrBoolean"; |
| case CheckTaggedInputMode::kNumberOrOddball: |
| return os << "NumberOrOddball"; |
| } |
| UNREACHABLE(); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, GrowFastElementsMode mode) { |
| switch (mode) { |
| case GrowFastElementsMode::kDoubleElements: |
| return os << "DoubleElements"; |
| case GrowFastElementsMode::kSmiOrObjectElements: |
| return os << "SmiOrObjectElements"; |
| } |
| UNREACHABLE(); |
| } |
| |
| bool operator==(const GrowFastElementsParameters& lhs, |
| const GrowFastElementsParameters& rhs) { |
| return lhs.mode() == rhs.mode() && lhs.feedback() == rhs.feedback(); |
| } |
| |
| inline size_t hash_value(const GrowFastElementsParameters& params) { |
| FeedbackSource::Hash feedback_hash; |
| return base::hash_combine(params.mode(), feedback_hash(params.feedback())); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, |
| const GrowFastElementsParameters& params) { |
| return os << params.mode() << ", " << params.feedback(); |
| } |
| |
| const GrowFastElementsParameters& GrowFastElementsParametersOf( |
| const Operator* op) { |
| DCHECK_EQ(IrOpcode::kMaybeGrowFastElements, op->opcode()); |
| return OpParameter<GrowFastElementsParameters>(op); |
| } |
| |
| bool operator==(ElementsTransition const& lhs, ElementsTransition const& rhs) { |
| return lhs.mode() == rhs.mode() && |
| lhs.source().address() == rhs.source().address() && |
| lhs.target().address() == rhs.target().address(); |
| } |
| |
| size_t hash_value(ElementsTransition transition) { |
| return base::hash_combine(static_cast<uint8_t>(transition.mode()), |
| transition.source().address(), |
| transition.target().address()); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, ElementsTransition transition) { |
| switch (transition.mode()) { |
| case ElementsTransition::kFastTransition: |
| return os << "fast-transition from " << Brief(*transition.source()) |
| << " to " << Brief(*transition.target()); |
| case ElementsTransition::kSlowTransition: |
| return os << "slow-transition from " << Brief(*transition.source()) |
| << " to " << Brief(*transition.target()); |
| } |
| UNREACHABLE(); |
| } |
| |
| ElementsTransition const& ElementsTransitionOf(const Operator* op) { |
| DCHECK_EQ(IrOpcode::kTransitionElementsKind, op->opcode()); |
| return OpParameter<ElementsTransition>(op); |
| } |
| |
| namespace { |
| |
| // Parameters for the TransitionAndStoreElement opcode. |
| class TransitionAndStoreElementParameters final { |
| public: |
| TransitionAndStoreElementParameters(Handle<Map> double_map, |
| Handle<Map> fast_map); |
| |
| Handle<Map> double_map() const { return double_map_; } |
| Handle<Map> fast_map() const { return fast_map_; } |
| |
| private: |
| Handle<Map> const double_map_; |
| Handle<Map> const fast_map_; |
| }; |
| |
| TransitionAndStoreElementParameters::TransitionAndStoreElementParameters( |
| Handle<Map> double_map, Handle<Map> fast_map) |
| : double_map_(double_map), fast_map_(fast_map) {} |
| |
| bool operator==(TransitionAndStoreElementParameters const& lhs, |
| TransitionAndStoreElementParameters const& rhs) { |
| return lhs.fast_map().address() == rhs.fast_map().address() && |
| lhs.double_map().address() == rhs.double_map().address(); |
| } |
| |
| size_t hash_value(TransitionAndStoreElementParameters parameters) { |
| return base::hash_combine(parameters.fast_map().address(), |
| parameters.double_map().address()); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, |
| TransitionAndStoreElementParameters parameters) { |
| return os << "fast-map" << Brief(*parameters.fast_map()) << " double-map" |
| << Brief(*parameters.double_map()); |
| } |
| |
| } // namespace |
| |
| namespace { |
| |
| // Parameters for the TransitionAndStoreNonNumberElement opcode. |
| class TransitionAndStoreNonNumberElementParameters final { |
| public: |
| TransitionAndStoreNonNumberElementParameters(Handle<Map> fast_map, |
| Type value_type); |
| |
| Handle<Map> fast_map() const { return fast_map_; } |
| Type value_type() const { return value_type_; } |
| |
| private: |
| Handle<Map> const fast_map_; |
| Type value_type_; |
| }; |
| |
| TransitionAndStoreNonNumberElementParameters:: |
| TransitionAndStoreNonNumberElementParameters(Handle<Map> fast_map, |
| Type value_type) |
| : fast_map_(fast_map), value_type_(value_type) {} |
| |
| bool operator==(TransitionAndStoreNonNumberElementParameters const& lhs, |
| TransitionAndStoreNonNumberElementParameters const& rhs) { |
| return lhs.fast_map().address() == rhs.fast_map().address() && |
| lhs.value_type() == rhs.value_type(); |
| } |
| |
| size_t hash_value(TransitionAndStoreNonNumberElementParameters parameters) { |
| return base::hash_combine(parameters.fast_map().address(), |
| parameters.value_type()); |
| } |
| |
| std::ostream& operator<<( |
| std::ostream& os, TransitionAndStoreNonNumberElementParameters parameters) { |
| return os << parameters.value_type() << ", fast-map" |
| << Brief(*parameters.fast_map()); |
| } |
| |
| } // namespace |
| |
| namespace { |
| |
| // Parameters for the TransitionAndStoreNumberElement opcode. |
| class TransitionAndStoreNumberElementParameters final { |
| public: |
| explicit TransitionAndStoreNumberElementParameters(Handle<Map> double_map); |
| |
| Handle<Map> double_map() const { return double_map_; } |
| |
| private: |
| Handle<Map> const double_map_; |
| }; |
| |
| TransitionAndStoreNumberElementParameters:: |
| TransitionAndStoreNumberElementParameters(Handle<Map> double_map) |
| : double_map_(double_map) {} |
| |
| bool operator==(TransitionAndStoreNumberElementParameters const& lhs, |
| TransitionAndStoreNumberElementParameters const& rhs) { |
| return lhs.double_map().address() == rhs.double_map().address(); |
| } |
| |
| size_t hash_value(TransitionAndStoreNumberElementParameters parameters) { |
| return base::hash_combine(parameters.double_map().address()); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, |
| TransitionAndStoreNumberElementParameters parameters) { |
| return os << "double-map" << Brief(*parameters.double_map()); |
| } |
| |
| } // namespace |
| |
| Handle<Map> DoubleMapParameterOf(const Operator* op) { |
| if (op->opcode() == IrOpcode::kTransitionAndStoreElement) { |
| return OpParameter<TransitionAndStoreElementParameters>(op).double_map(); |
| } else if (op->opcode() == IrOpcode::kTransitionAndStoreNumberElement) { |
| return OpParameter<TransitionAndStoreNumberElementParameters>(op) |
| .double_map(); |
| } |
| UNREACHABLE(); |
| return Handle<Map>::null(); |
| } |
| |
| Type ValueTypeParameterOf(const Operator* op) { |
| DCHECK_EQ(IrOpcode::kTransitionAndStoreNonNumberElement, op->opcode()); |
| return OpParameter<TransitionAndStoreNonNumberElementParameters>(op) |
| .value_type(); |
| } |
| |
| Handle<Map> FastMapParameterOf(const Operator* op) { |
| if (op->opcode() == IrOpcode::kTransitionAndStoreElement) { |
| return OpParameter<TransitionAndStoreElementParameters>(op).fast_map(); |
| } else if (op->opcode() == IrOpcode::kTransitionAndStoreNonNumberElement) { |
| return OpParameter<TransitionAndStoreNonNumberElementParameters>(op) |
| .fast_map(); |
| } |
| UNREACHABLE(); |
| return Handle<Map>::null(); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, BigIntOperationHint hint) { |
| switch (hint) { |
| case BigIntOperationHint::kBigInt: |
| return os << "BigInt"; |
| } |
| UNREACHABLE(); |
| } |
| |
| size_t hash_value(BigIntOperationHint hint) { |
| return static_cast<uint8_t>(hint); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, NumberOperationHint hint) { |
| switch (hint) { |
| case NumberOperationHint::kSignedSmall: |
| return os << "SignedSmall"; |
| case NumberOperationHint::kSignedSmallInputs: |
| return os << "SignedSmallInputs"; |
| case NumberOperationHint::kSigned32: |
| return os << "Signed32"; |
| case NumberOperationHint::kNumber: |
| return os << "Number"; |
| case NumberOperationHint::kNumberOrBoolean: |
| return os << "NumberOrBoolean"; |
| case NumberOperationHint::kNumberOrOddball: |
| return os << "NumberOrOddball"; |
| } |
| UNREACHABLE(); |
| } |
| |
| size_t hash_value(NumberOperationHint hint) { |
| return static_cast<uint8_t>(hint); |
| } |
| |
| NumberOperationHint NumberOperationHintOf(const Operator* op) { |
| DCHECK(op->opcode() == IrOpcode::kSpeculativeNumberAdd || |
| op->opcode() == IrOpcode::kSpeculativeNumberSubtract || |
| op->opcode() == IrOpcode::kSpeculativeNumberMultiply || |
| op->opcode() == IrOpcode::kSpeculativeNumberDivide || |
| op->opcode() == IrOpcode::kSpeculativeNumberModulus || |
| op->opcode() == IrOpcode::kSpeculativeNumberShiftLeft || |
| op->opcode() == IrOpcode::kSpeculativeNumberShiftRight || |
| op->opcode() == IrOpcode::kSpeculativeNumberShiftRightLogical || |
| op->opcode() == IrOpcode::kSpeculativeNumberBitwiseAnd || |
| op->opcode() == IrOpcode::kSpeculativeNumberBitwiseOr || |
| op->opcode() == IrOpcode::kSpeculativeNumberBitwiseXor || |
| op->opcode() == IrOpcode::kSpeculativeNumberEqual || |
| op->opcode() == IrOpcode::kSpeculativeNumberLessThan || |
| op->opcode() == IrOpcode::kSpeculativeNumberLessThanOrEqual || |
| op->opcode() == IrOpcode::kSpeculativeSafeIntegerAdd || |
| op->opcode() == IrOpcode::kSpeculativeSafeIntegerSubtract); |
| return OpParameter<NumberOperationHint>(op); |
| } |
| |
| bool operator==(NumberOperationParameters const& lhs, |
| NumberOperationParameters const& rhs) { |
| return lhs.hint() == rhs.hint() && lhs.feedback() == rhs.feedback(); |
| } |
| |
| size_t hash_value(NumberOperationParameters const& p) { |
| FeedbackSource::Hash feedback_hash; |
| return base::hash_combine(p.hint(), feedback_hash(p.feedback())); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, NumberOperationParameters const& p) { |
| return os << p.hint() << ", " << p.feedback(); |
| } |
| |
| NumberOperationParameters const& NumberOperationParametersOf( |
| Operator const* op) { |
| DCHECK_EQ(IrOpcode::kSpeculativeToNumber, op->opcode()); |
| return OpParameter<NumberOperationParameters>(op); |
| } |
| |
| size_t hash_value(AllocateParameters info) { |
| return base::hash_combine(info.type(), |
| static_cast<int>(info.allocation_type())); |
| } |
| |
| V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, |
| AllocateParameters info) { |
| return os << info.type() << ", " << info.allocation_type(); |
| } |
| |
| bool operator==(AllocateParameters const& lhs, AllocateParameters const& rhs) { |
| return lhs.allocation_type() == rhs.allocation_type() && |
| lhs.type() == rhs.type(); |
| } |
| |
| const AllocateParameters& AllocateParametersOf(const Operator* op) { |
| DCHECK(op->opcode() == IrOpcode::kAllocate || |
| op->opcode() == IrOpcode::kAllocateRaw); |
| return OpParameter<AllocateParameters>(op); |
| } |
| |
| AllocationType AllocationTypeOf(const Operator* op) { |
| if (op->opcode() == IrOpcode::kNewDoubleElements || |
| op->opcode() == IrOpcode::kNewSmiOrObjectElements) { |
| return OpParameter<AllocationType>(op); |
| } |
| return AllocateParametersOf(op).allocation_type(); |
| } |
| |
| Type AllocateTypeOf(const Operator* op) { |
| DCHECK_EQ(IrOpcode::kAllocate, op->opcode()); |
| return AllocateParametersOf(op).type(); |
| } |
| |
| AbortReason AbortReasonOf(const Operator* op) { |
| DCHECK_EQ(IrOpcode::kRuntimeAbort, op->opcode()); |
| return static_cast<AbortReason>(OpParameter<int>(op)); |
| } |
| |
| const CheckTaggedInputParameters& CheckTaggedInputParametersOf( |
| const Operator* op) { |
| DCHECK(op->opcode() == IrOpcode::kCheckedTruncateTaggedToWord32 || |
| op->opcode() == IrOpcode::kCheckedTaggedToFloat64); |
| return OpParameter<CheckTaggedInputParameters>(op); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, |
| const CheckTaggedInputParameters& params) { |
| return os << params.mode() << ", " << params.feedback(); |
| } |
| |
| size_t hash_value(const CheckTaggedInputParameters& params) { |
| FeedbackSource::Hash feedback_hash; |
| return base::hash_combine(params.mode(), feedback_hash(params.feedback())); |
| } |
| |
| bool operator==(CheckTaggedInputParameters const& lhs, |
| CheckTaggedInputParameters const& rhs) { |
| return lhs.mode() == rhs.mode() && lhs.feedback() == rhs.feedback(); |
| } |
| |
| const CheckMinusZeroParameters& CheckMinusZeroParametersOf(const Operator* op) { |
| DCHECK(op->opcode() == IrOpcode::kCheckedTaggedToInt32 || |
| op->opcode() == IrOpcode::kCheckedTaggedToInt64 || |
| op->opcode() == IrOpcode::kCheckedFloat64ToInt32 || |
| op->opcode() == IrOpcode::kCheckedFloat64ToInt64); |
| return OpParameter<CheckMinusZeroParameters>(op); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, |
| const CheckMinusZeroParameters& params) { |
| return os << params.mode() << ", " << params.feedback(); |
| } |
| |
| size_t hash_value(const CheckMinusZeroParameters& params) { |
| FeedbackSource::Hash feedback_hash; |
| return base::hash_combine(params.mode(), feedback_hash(params.feedback())); |
| } |
| |
| bool operator==(CheckMinusZeroParameters const& lhs, |
| CheckMinusZeroParameters const& rhs) { |
| return lhs.mode() == rhs.mode() && lhs.feedback() == rhs.feedback(); |
| } |
| |
| #define PURE_OP_LIST(V) \ |
| V(BooleanNot, Operator::kNoProperties, 1, 0) \ |
| V(NumberEqual, Operator::kCommutative, 2, 0) \ |
| V(NumberLessThan, Operator::kNoProperties, 2, 0) \ |
| V(NumberLessThanOrEqual, Operator::kNoProperties, 2, 0) \ |
| V(NumberAdd, Operator::kCommutative, 2, 0) \ |
| V(NumberSubtract, Operator::kNoProperties, 2, 0) \ |
| V(NumberMultiply, Operator::kCommutative, 2, 0) \ |
| V(NumberDivide, Operator::kNoProperties, 2, 0) \ |
| V(NumberModulus, Operator::kNoProperties, 2, 0) \ |
| V(NumberBitwiseOr, Operator::kCommutative, 2, 0) \ |
| V(NumberBitwiseXor, Operator::kCommutative, 2, 0) \ |
| V(NumberBitwiseAnd, Operator::kCommutative, 2, 0) \ |
| V(NumberShiftLeft, Operator::kNoProperties, 2, 0) \ |
| V(NumberShiftRight, Operator::kNoProperties, 2, 0) \ |
| V(NumberShiftRightLogical, Operator::kNoProperties, 2, 0) \ |
| V(NumberImul, Operator::kCommutative, 2, 0) \ |
| V(NumberAbs, Operator::kNoProperties, 1, 0) \ |
| V(NumberClz32, Operator::kNoProperties, 1, 0) \ |
| V(NumberCeil, Operator::kNoProperties, 1, 0) \ |
| V(NumberFloor, Operator::kNoProperties, 1, 0) \ |
| V(NumberFround, Operator::kNoProperties, 1, 0) \ |
| V(NumberAcos, Operator::kNoProperties, 1, 0) \ |
| V(NumberAcosh, Operator::kNoProperties, 1, 0) \ |
| V(NumberAsin, Operator::kNoProperties, 1, 0) \ |
| V(NumberAsinh, Operator::kNoProperties, 1, 0) \ |
| V(NumberAtan, Operator::kNoProperties, 1, 0) \ |
| V(NumberAtan2, Operator::kNoProperties, 2, 0) \ |
| V(NumberAtanh, Operator::kNoProperties, 1, 0) \ |
| V(NumberCbrt, Operator::kNoProperties, 1, 0) \ |
| V(NumberCos, Operator::kNoProperties, 1, 0) \ |
| V(NumberCosh, Operator::kNoProperties, 1, 0) \ |
| V(NumberExp, Operator::kNoProperties, 1, 0) \ |
| V(NumberExpm1, Operator::kNoProperties, 1, 0) \ |
| V(NumberLog, Operator::kNoProperties, 1, 0) \ |
| V(NumberLog1p, Operator::kNoProperties, 1, 0) \ |
| V(NumberLog10, Operator::kNoProperties, 1, 0) \ |
| V(NumberLog2, Operator::kNoProperties, 1, 0) \ |
| V(NumberMax, Operator::kNoProperties, 2, 0) \ |
| V(NumberMin, Operator::kNoProperties, 2, 0) \ |
| V(NumberPow, Operator::kNoProperties, 2, 0) \ |
| V(NumberRound, Operator::kNoProperties, 1, 0) \ |
| V(NumberSign, Operator::kNoProperties, 1, 0) \ |
| V(NumberSin, Operator::kNoProperties, 1, 0) \ |
| V(NumberSinh, Operator::kNoProperties, 1, 0) \ |
| V(NumberSqrt, Operator::kNoProperties, 1, 0) \ |
| V(NumberTan, Operator::kNoProperties, 1, 0) \ |
| V(NumberTanh, Operator::kNoProperties, 1, 0) \ |
| V(NumberTrunc, Operator::kNoProperties, 1, 0) \ |
| V(NumberToBoolean, Operator::kNoProperties, 1, 0) \ |
| V(NumberToInt32, Operator::kNoProperties, 1, 0) \ |
| V(NumberToString, Operator::kNoProperties, 1, 0) \ |
| V(NumberToUint32, Operator::kNoProperties, 1, 0) \ |
| V(NumberToUint8Clamped, Operator::kNoProperties, 1, 0) \ |
| V(NumberSilenceNaN, Operator::kNoProperties, 1, 0) \ |
| V(BigIntNegate, Operator::kNoProperties, 1, 0) \ |
| V(StringConcat, Operator::kNoProperties, 3, 0) \ |
| V(StringToNumber, Operator::kNoProperties, 1, 0) \ |
| V(StringFromSingleCharCode, Operator::kNoProperties, 1, 0) \ |
| V(StringFromSingleCodePoint, Operator::kNoProperties, 1, 0) \ |
| V(StringIndexOf, Operator::kNoProperties, 3, 0) \ |
| V(StringLength, Operator::kNoProperties, 1, 0) \ |
| V(StringToLowerCaseIntl, Operator::kNoProperties, 1, 0) \ |
| V(StringToUpperCaseIntl, Operator::kNoProperties, 1, 0) \ |
| V(TypeOf, Operator::kNoProperties, 1, 1) \ |
| V(PlainPrimitiveToNumber, Operator::kNoProperties, 1, 0) \ |
| V(PlainPrimitiveToWord32, Operator::kNoProperties, 1, 0) \ |
| V(PlainPrimitiveToFloat64, Operator::kNoProperties, 1, 0) \ |
| V(ChangeTaggedSignedToInt32, Operator::kNoProperties, 1, 0) \ |
| V(ChangeTaggedSignedToInt64, Operator::kNoProperties, 1, 0) \ |
| V(ChangeTaggedToInt32, Operator::kNoProperties, 1, 0) \ |
| V(ChangeTaggedToInt64, Operator::kNoProperties, 1, 0) \ |
| V(ChangeTaggedToUint32, Operator::kNoProperties, 1, 0) \ |
| V(ChangeTaggedToFloat64, Operator::kNoProperties, 1, 0) \ |
| V(ChangeTaggedToTaggedSigned, Operator::kNoProperties, 1, 0) \ |
| V(ChangeFloat64ToTaggedPointer, Operator::kNoProperties, 1, 0) \ |
| V(ChangeInt31ToTaggedSigned, Operator::kNoProperties, 1, 0) \ |
| V(ChangeInt32ToTagged, Operator::kNoProperties, 1, 0) \ |
| V(ChangeInt64ToTagged, Operator::kNoProperties, 1, 0) \ |
| V(ChangeUint32ToTagged, Operator::kNoProperties, 1, 0) \ |
| V(ChangeUint64ToTagged, Operator::kNoProperties, 1, 0) \ |
| V(ChangeTaggedToBit, Operator::kNoProperties, 1, 0) \ |
| V(ChangeBitToTagged, Operator::kNoProperties, 1, 0) \ |
| V(TruncateBigIntToUint64, Operator::kNoProperties, 1, 0) \ |
| V(ChangeUint64ToBigInt, Operator::kNoProperties, 1, 0) \ |
| V(TruncateTaggedToBit, Operator::kNoProperties, 1, 0) \ |
| V(TruncateTaggedPointerToBit, Operator::kNoProperties, 1, 0) \ |
| V(TruncateTaggedToWord32, Operator::kNoProperties, 1, 0) \ |
| V(TruncateTaggedToFloat64, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsArrayBufferView, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsBigInt, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsCallable, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsConstructor, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsDetectableCallable, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsMinusZero, Operator::kNoProperties, 1, 0) \ |
| V(NumberIsMinusZero, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsNaN, Operator::kNoProperties, 1, 0) \ |
| V(NumberIsNaN, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsNonCallable, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsNumber, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsReceiver, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsSmi, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsString, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsSymbol, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsUndetectable, Operator::kNoProperties, 1, 0) \ |
| V(NumberIsFloat64Hole, Operator::kNoProperties, 1, 0) \ |
| V(NumberIsFinite, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsFiniteNumber, Operator::kNoProperties, 1, 0) \ |
| V(NumberIsInteger, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsSafeInteger, Operator::kNoProperties, 1, 0) \ |
| V(NumberIsSafeInteger, Operator::kNoProperties, 1, 0) \ |
| V(ObjectIsInteger, Operator::kNoProperties, 1, 0) \ |
| V(ConvertTaggedHoleToUndefined, Operator::kNoProperties, 1, 0) \ |
| V(SameValue, Operator::kCommutative, 2, 0) \ |
| V(SameValueNumbersOnly, Operator::kCommutative, 2, 0) \ |
| V(NumberSameValue, Operator::kCommutative, 2, 0) \ |
| V(ReferenceEqual, Operator::kCommutative, 2, 0) \ |
| V(StringEqual, Operator::kCommutative, 2, 0) \ |
| V(StringLessThan, Operator::kNoProperties, 2, 0) \ |
| V(StringLessThanOrEqual, Operator::kNoProperties, 2, 0) \ |
| V(ToBoolean, Operator::kNoProperties, 1, 0) \ |
| V(NewConsString, Operator::kNoProperties, 3, 0) \ |
| V(PoisonIndex, Operator::kNoProperties, 1, 0) |
| |
| #define EFFECT_DEPENDENT_OP_LIST(V) \ |
| V(BigIntAdd, Operator::kNoProperties, 2, 1) \ |
| V(BigIntSubtract, Operator::kNoProperties, 2, 1) \ |
| V(StringCharCodeAt, Operator::kNoProperties, 2, 1) \ |
| V(StringCodePointAt, Operator::kNoProperties, 2, 1) \ |
| V(StringFromCodePointAt, Operator::kNoProperties, 2, 1) \ |
| V(StringSubstring, Operator::kNoProperties, 3, 1) \ |
| V(DateNow, Operator::kNoProperties, 0, 1) |
| |
| #define SPECULATIVE_NUMBER_BINOP_LIST(V) \ |
| SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(V) \ |
| V(SpeculativeNumberEqual) \ |
| V(SpeculativeNumberLessThan) \ |
| V(SpeculativeNumberLessThanOrEqual) |
| |
| #define CHECKED_OP_LIST(V) \ |
| V(CheckEqualsInternalizedString, 2, 0) \ |
| V(CheckEqualsSymbol, 2, 0) \ |
| V(CheckHeapObject, 1, 1) \ |
| V(CheckInternalizedString, 1, 1) \ |
| V(CheckNotTaggedHole, 1, 1) \ |
| V(CheckReceiver, 1, 1) \ |
| V(CheckReceiverOrNullOrUndefined, 1, 1) \ |
| V(CheckSymbol, 1, 1) \ |
| V(CheckedInt32Add, 2, 1) \ |
| V(CheckedInt32Div, 2, 1) \ |
| V(CheckedInt32Mod, 2, 1) \ |
| V(CheckedInt32Sub, 2, 1) \ |
| V(CheckedUint32Div, 2, 1) \ |
| V(CheckedUint32Mod, 2, 1) |
| |
| #define CHECKED_WITH_FEEDBACK_OP_LIST(V) \ |
| V(CheckNumber, 1, 1) \ |
| V(CheckSmi, 1, 1) \ |
| V(CheckString, 1, 1) \ |
| V(CheckBigInt, 1, 1) \ |
| V(CheckedInt32ToTaggedSigned, 1, 1) \ |
| V(CheckedInt64ToInt32, 1, 1) \ |
| V(CheckedInt64ToTaggedSigned, 1, 1) \ |
| V(CheckedTaggedToArrayIndex, 1, 1) \ |
| V(CheckedTaggedSignedToInt32, 1, 1) \ |
| V(CheckedTaggedToTaggedPointer, 1, 1) \ |
| V(CheckedTaggedToTaggedSigned, 1, 1) \ |
| V(CheckedUint32ToInt32, 1, 1) \ |
| V(CheckedUint32ToTaggedSigned, 1, 1) \ |
| V(CheckedUint64ToInt32, 1, 1) \ |
| V(CheckedUint64ToTaggedSigned, 1, 1) |
| |
| #define CHECKED_BOUNDS_OP_LIST(V) \ |
| V(CheckedUint32Bounds) \ |
| V(CheckedUint64Bounds) |
| |
| struct SimplifiedOperatorGlobalCache final { |
| #define PURE(Name, properties, value_input_count, control_input_count) \ |
| struct Name##Operator final : public Operator { \ |
| Name##Operator() \ |
| : Operator(IrOpcode::k##Name, Operator::kPure | properties, #Name, \ |
| value_input_count, 0, control_input_count, 1, 0, 0) {} \ |
| }; \ |
| Name##Operator k##Name; |
| PURE_OP_LIST(PURE) |
| #undef PURE |
| |
| #define EFFECT_DEPENDENT(Name, properties, value_input_count, \ |
| control_input_count) \ |
| struct Name##Operator final : public Operator { \ |
| Name##Operator() \ |
| : Operator(IrOpcode::k##Name, Operator::kEliminatable | properties, \ |
| #Name, value_input_count, 1, control_input_count, 1, 1, \ |
| 0) {} \ |
| }; \ |
| Name##Operator k##Name; |
| EFFECT_DEPENDENT_OP_LIST(EFFECT_DEPENDENT) |
| #undef EFFECT_DEPENDENT |
| |
| #define CHECKED(Name, value_input_count, value_output_count) \ |
| struct Name##Operator final : public Operator { \ |
| Name##Operator() \ |
| : Operator(IrOpcode::k##Name, \ |
| Operator::kFoldable | Operator::kNoThrow, #Name, \ |
| value_input_count, 1, 1, value_output_count, 1, 0) {} \ |
| }; \ |
| Name##Operator k##Name; |
| CHECKED_OP_LIST(CHECKED) |
| #undef CHECKED |
| |
| #define CHECKED_WITH_FEEDBACK(Name, value_input_count, value_output_count) \ |
| struct Name##Operator final : public Operator1<CheckParameters> { \ |
| Name##Operator() \ |
| : Operator1<CheckParameters>( \ |
| IrOpcode::k##Name, Operator::kFoldable | Operator::kNoThrow, \ |
| #Name, value_input_count, 1, 1, value_output_count, 1, 0, \ |
| CheckParameters(FeedbackSource())) {} \ |
| }; \ |
| Name##Operator k##Name; |
| CHECKED_WITH_FEEDBACK_OP_LIST(CHECKED_WITH_FEEDBACK) |
| #undef CHECKED_WITH_FEEDBACK |
| |
| #define CHECKED_BOUNDS(Name) \ |
| struct Name##Operator final : public Operator1<CheckBoundsParameters> { \ |
| Name##Operator(FeedbackSource feedback, CheckBoundsFlags flags) \ |
| : Operator1<CheckBoundsParameters>( \ |
| IrOpcode::k##Name, Operator::kFoldable | Operator::kNoThrow, \ |
| #Name, 2, 1, 1, 1, 1, 0, \ |
| CheckBoundsParameters(feedback, flags)) {} \ |
| }; \ |
| Name##Operator k##Name = {FeedbackSource(), CheckBoundsFlags()}; \ |
| Name##Operator k##Name##Aborting = {FeedbackSource(), \ |
| CheckBoundsFlag::kAbortOnOutOfBounds}; |
| CHECKED_BOUNDS_OP_LIST(CHECKED_BOUNDS) |
| CHECKED_BOUNDS(CheckBounds) |
| // For IrOpcode::kCheckBounds, we allow additional flags: |
| CheckBoundsOperator kCheckBoundsConverting = { |
| FeedbackSource(), CheckBoundsFlag::kConvertStringAndMinusZero}; |
| CheckBoundsOperator kCheckBoundsAbortingAndConverting = { |
| FeedbackSource(), |
| CheckBoundsFlags(CheckBoundsFlag::kAbortOnOutOfBounds) | |
| CheckBoundsFlags(CheckBoundsFlag::kConvertStringAndMinusZero)}; |
| #undef CHECKED_BOUNDS |
| |
| template <DeoptimizeReason kDeoptimizeReason> |
| struct CheckIfOperator final : public Operator1<CheckIfParameters> { |
| CheckIfOperator() |
| : Operator1<CheckIfParameters>( |
| IrOpcode::kCheckIf, Operator::kFoldable | Operator::kNoThrow, |
| "CheckIf", 1, 1, 1, 0, 1, 0, |
| CheckIfParameters(kDeoptimizeReason, FeedbackSource())) {} |
| }; |
| #define CHECK_IF(Name, message) \ |
| CheckIfOperator<DeoptimizeReason::k##Name> kCheckIf##Name; |
| DEOPTIMIZE_REASON_LIST(CHECK_IF) |
| #undef CHECK_IF |
| |
| struct FindOrderedHashMapEntryOperator final : public Operator { |
| FindOrderedHashMapEntryOperator() |
| : Operator(IrOpcode::kFindOrderedHashMapEntry, Operator::kEliminatable, |
| "FindOrderedHashMapEntry", 2, 1, 1, 1, 1, 0) {} |
| }; |
| FindOrderedHashMapEntryOperator kFindOrderedHashMapEntry; |
| |
| struct FindOrderedHashMapEntryForInt32KeyOperator final : public Operator { |
| FindOrderedHashMapEntryForInt32KeyOperator() |
| : Operator(IrOpcode::kFindOrderedHashMapEntryForInt32Key, |
| Operator::kEliminatable, |
| "FindOrderedHashMapEntryForInt32Key", 2, 1, 1, 1, 1, 0) {} |
| }; |
| FindOrderedHashMapEntryForInt32KeyOperator |
| kFindOrderedHashMapEntryForInt32Key; |
| |
| struct ArgumentsFrameOperator final : public Operator { |
| ArgumentsFrameOperator() |
| : Operator(IrOpcode::kArgumentsFrame, Operator::kPure, "ArgumentsFrame", |
| 0, 0, 0, 1, 0, 0) {} |
| }; |
| ArgumentsFrameOperator kArgumentsFrame; |
| |
| template <CheckForMinusZeroMode kMode> |
| struct ChangeFloat64ToTaggedOperator final |
| : public Operator1<CheckForMinusZeroMode> { |
| ChangeFloat64ToTaggedOperator() |
| : Operator1<CheckForMinusZeroMode>( |
| IrOpcode::kChangeFloat64ToTagged, Operator::kPure, |
| "ChangeFloat64ToTagged", 1, 0, 0, 1, 0, 0, kMode) {} |
| }; |
| ChangeFloat64ToTaggedOperator<CheckForMinusZeroMode::kCheckForMinusZero> |
| kChangeFloat64ToTaggedCheckForMinusZeroOperator; |
| ChangeFloat64ToTaggedOperator<CheckForMinusZeroMode::kDontCheckForMinusZero> |
| kChangeFloat64ToTaggedDontCheckForMinusZeroOperator; |
| |
| template <CheckForMinusZeroMode kMode> |
| struct CheckedInt32MulOperator final |
| : public Operator1<CheckForMinusZeroMode> { |
| CheckedInt32MulOperator() |
| : Operator1<CheckForMinusZeroMode>( |
| IrOpcode::kCheckedInt32Mul, |
| Operator::kFoldable | Operator::kNoThrow, "CheckedInt32Mul", 2, 1, |
| 1, 1, 1, 0, kMode) {} |
| }; |
| CheckedInt32MulOperator<CheckForMinusZeroMode::kCheckForMinusZero> |
| kCheckedInt32MulCheckForMinusZeroOperator; |
| CheckedInt32MulOperator<CheckForMinusZeroMode::kDontCheckForMinusZero> |
| kCheckedInt32MulDontCheckForMinusZeroOperator; |
| |
| template <CheckForMinusZeroMode kMode> |
| struct CheckedFloat64ToInt32Operator final |
| : public Operator1<CheckMinusZeroParameters> { |
| CheckedFloat64ToInt32Operator() |
| : Operator1<CheckMinusZeroParameters>( |
| IrOpcode::kCheckedFloat64ToInt32, |
| Operator::kFoldable | Operator::kNoThrow, "CheckedFloat64ToInt32", |
| 1, 1, 1, 1, 1, 0, |
| CheckMinusZeroParameters(kMode, FeedbackSource())) {} |
| }; |
| CheckedFloat64ToInt32Operator<CheckForMinusZeroMode::kCheckForMinusZero> |
| kCheckedFloat64ToInt32CheckForMinusZeroOperator; |
| CheckedFloat64ToInt32Operator<CheckForMinusZeroMode::kDontCheckForMinusZero> |
| kCheckedFloat64ToInt32DontCheckForMinusZeroOperator; |
| |
| template <CheckForMinusZeroMode kMode> |
| struct CheckedFloat64ToInt64Operator final |
| : public Operator1<CheckMinusZeroParameters> { |
| CheckedFloat64ToInt64Operator() |
| : Operator1<CheckMinusZeroParameters>( |
| IrOpcode::kCheckedFloat64ToInt64, |
| Operator::kFoldable | Operator::kNoThrow, "CheckedFloat64ToInt64", |
| 1, 1, 1, 1, 1, 0, |
| CheckMinusZeroParameters(kMode, FeedbackSource())) {} |
| }; |
| CheckedFloat64ToInt64Operator<CheckForMinusZeroMode::kCheckForMinusZero> |
| kCheckedFloat64ToInt64CheckForMinusZeroOperator; |
| CheckedFloat64ToInt64Operator<CheckForMinusZeroMode::kDontCheckForMinusZero> |
| kCheckedFloat64ToInt64DontCheckForMinusZeroOperator; |
| |
| template <CheckForMinusZeroMode kMode> |
| struct CheckedTaggedToInt32Operator final |
| : public Operator1<CheckMinusZeroParameters> { |
| CheckedTaggedToInt32Operator() |
| : Operator1<CheckMinusZeroParameters>( |
| IrOpcode::kCheckedTaggedToInt32, |
| Operator::kFoldable | Operator::kNoThrow, "CheckedTaggedToInt32", |
| 1, 1, 1, 1, 1, 0, |
| CheckMinusZeroParameters(kMode, FeedbackSource())) {} |
| }; |
| CheckedTaggedToInt32Operator<CheckForMinusZeroMode::kCheckForMinusZero> |
| kCheckedTaggedToInt32CheckForMinusZeroOperator; |
| CheckedTaggedToInt32Operator<CheckForMinusZeroMode::kDontCheckForMinusZero> |
| kCheckedTaggedToInt32DontCheckForMinusZeroOperator; |
| |
| template <CheckForMinusZeroMode kMode> |
| struct CheckedTaggedToInt64Operator final |
| : public Operator1<CheckMinusZeroParameters> { |
| CheckedTaggedToInt64Operator() |
| : Operator1<CheckMinusZeroParameters>( |
| IrOpcode::kCheckedTaggedToInt64, |
| Operator::kFoldable | Operator::kNoThrow, "CheckedTaggedToInt64", |
| 1, 1, 1, 1, 1, 0, |
| CheckMinusZeroParameters(kMode, FeedbackSource())) {} |
| }; |
| CheckedTaggedToInt64Operator<CheckForMinusZeroMode::kCheckForMinusZero> |
| kCheckedTaggedToInt64CheckForMinusZeroOperator; |
| CheckedTaggedToInt64Operator<CheckForMinusZeroMode::kDontCheckForMinusZero> |
| kCheckedTaggedToInt64DontCheckForMinusZeroOperator; |
| |
| template <CheckTaggedInputMode kMode> |
| struct CheckedTaggedToFloat64Operator final |
| : public Operator1<CheckTaggedInputParameters> { |
| CheckedTaggedToFloat64Operator() |
| : Operator1<CheckTaggedInputParameters>( |
| IrOpcode::kCheckedTaggedToFloat64, |
| Operator::kFoldable | Operator::kNoThrow, |
| "CheckedTaggedToFloat64", 1, 1, 1, 1, 1, 0, |
| CheckTaggedInputParameters(kMode, FeedbackSource())) {} |
| }; |
| CheckedTaggedToFloat64Operator<CheckTaggedInputMode::kNumber> |
| kCheckedTaggedToFloat64NumberOperator; |
| CheckedTaggedToFloat64Operator<CheckTaggedInputMode::kNumberOrBoolean> |
| kCheckedTaggedToFloat64NumberOrBooleanOperator; |
| CheckedTaggedToFloat64Operator<CheckTaggedInputMode::kNumberOrOddball> |
| kCheckedTaggedToFloat64NumberOrOddballOperator; |
| |
| template <CheckTaggedInputMode kMode> |
| struct CheckedTruncateTaggedToWord32Operator final |
| : public Operator1<CheckTaggedInputParameters> { |
| CheckedTruncateTaggedToWord32Operator() |
| : Operator1<CheckTaggedInputParameters>( |
| IrOpcode::kCheckedTruncateTaggedToWord32, |
| Operator::kFoldable | Operator::kNoThrow, |
| "CheckedTruncateTaggedToWord32", 1, 1, 1, 1, 1, 0, |
| CheckTaggedInputParameters(kMode, FeedbackSource())) {} |
| }; |
| CheckedTruncateTaggedToWord32Operator<CheckTaggedInputMode::kNumber> |
| kCheckedTruncateTaggedToWord32NumberOperator; |
| CheckedTruncateTaggedToWord32Operator<CheckTaggedInputMode::kNumberOrOddball> |
| kCheckedTruncateTaggedToWord32NumberOrOddballOperator; |
| |
| template <ConvertReceiverMode kMode> |
| struct ConvertReceiverOperator final : public Operator1<ConvertReceiverMode> { |
| ConvertReceiverOperator() |
| : Operator1<ConvertReceiverMode>( // -- |
| IrOpcode::kConvertReceiver, // opcode |
| Operator::kEliminatable, // flags |
| "ConvertReceiver", // name |
| 2, 1, 1, 1, 1, 0, // counts |
| kMode) {} // param |
| }; |
| ConvertReceiverOperator<ConvertReceiverMode::kAny> |
| kConvertReceiverAnyOperator; |
| ConvertReceiverOperator<ConvertReceiverMode::kNullOrUndefined> |
| kConvertReceiverNullOrUndefinedOperator; |
| ConvertReceiverOperator<ConvertReceiverMode::kNotNullOrUndefined> |
| kConvertReceiverNotNullOrUndefinedOperator; |
| |
| template <CheckFloat64HoleMode kMode> |
| struct CheckFloat64HoleNaNOperator final |
| : public Operator1<CheckFloat64HoleParameters> { |
| CheckFloat64HoleNaNOperator() |
| : Operator1<CheckFloat64HoleParameters>( |
| IrOpcode::kCheckFloat64Hole, |
| Operator::kFoldable | Operator::kNoThrow, "CheckFloat64Hole", 1, |
| 1, 1, 1, 1, 0, |
| CheckFloat64HoleParameters(kMode, FeedbackSource())) {} |
| }; |
| CheckFloat64HoleNaNOperator<CheckFloat64HoleMode::kAllowReturnHole> |
| kCheckFloat64HoleAllowReturnHoleOperator; |
| CheckFloat64HoleNaNOperator<CheckFloat64HoleMode::kNeverReturnHole> |
| kCheckFloat64HoleNeverReturnHoleOperator; |
| |
| struct EnsureWritableFastElementsOperator final : public Operator { |
| EnsureWritableFastElementsOperator() |
| : Operator( // -- |
| IrOpcode::kEnsureWritableFastElements, // opcode |
| Operator::kNoDeopt | Operator::kNoThrow, // flags |
| "EnsureWritableFastElements", // name |
| 2, 1, 1, 1, 1, 0) {} // counts |
| }; |
| EnsureWritableFastElementsOperator kEnsureWritableFastElements; |
| |
| template <GrowFastElementsMode kMode> |
| struct GrowFastElementsOperator final |
| : public Operator1<GrowFastElementsParameters> { |
| GrowFastElementsOperator() |
| : Operator1(IrOpcode::kMaybeGrowFastElements, Operator::kNoThrow, |
| "MaybeGrowFastElements", 4, 1, 1, 1, 1, 0, |
| GrowFastElementsParameters(kMode, FeedbackSource())) {} |
| }; |
| |
| GrowFastElementsOperator<GrowFastElementsMode::kDoubleElements> |
| kGrowFastElementsOperatorDoubleElements; |
| GrowFastElementsOperator<GrowFastElementsMode::kSmiOrObjectElements> |
| kGrowFastElementsOperatorSmiOrObjectElements; |
| |
| struct LoadFieldByIndexOperator final : public Operator { |
| LoadFieldByIndexOperator() |
| : Operator( // -- |
| IrOpcode::kLoadFieldByIndex, // opcode |
| Operator::kEliminatable, // flags, |
| "LoadFieldByIndex", // name |
| 2, 1, 1, 1, 1, 0) {} // counts; |
| }; |
| LoadFieldByIndexOperator kLoadFieldByIndex; |
| |
| struct LoadStackArgumentOperator final : public Operator { |
| LoadStackArgumentOperator() |
| : Operator( // -- |
| IrOpcode::kLoadStackArgument, // opcode |
| Operator::kEliminatable, // flags |
| "LoadStackArgument", // name |
| 2, 1, 1, 1, 1, 0) {} // counts |
| }; |
| LoadStackArgumentOperator kLoadStackArgument; |
| |
| #define SPECULATIVE_NUMBER_BINOP(Name) \ |
| template <NumberOperationHint kHint> \ |
| struct Name##Operator final : public Operator1<NumberOperationHint> { \ |
| Name##Operator() \ |
| : Operator1<NumberOperationHint>( \ |
| IrOpcode::k##Name, Operator::kFoldable | Operator::kNoThrow, \ |
| #Name, 2, 1, 1, 1, 1, 0, kHint) {} \ |
| }; \ |
| Name##Operator<NumberOperationHint::kSignedSmall> \ |
| k##Name##SignedSmallOperator; \ |
| Name##Operator<NumberOperationHint::kSignedSmallInputs> \ |
| k##Name##SignedSmallInputsOperator; \ |
| Name##Operator<NumberOperationHint::kSigned32> k##Name##Signed32Operator; \ |
| Name##Operator<NumberOperationHint::kNumber> k##Name##NumberOperator; \ |
| Name##Operator<NumberOperationHint::kNumberOrOddball> \ |
| k##Name##NumberOrOddballOperator; |
| SPECULATIVE_NUMBER_BINOP_LIST(SPECULATIVE_NUMBER_BINOP) |
| #undef SPECULATIVE_NUMBER_BINOP |
| SpeculativeNumberEqualOperator<NumberOperationHint::kNumberOrBoolean> |
| kSpeculativeNumberEqualNumberOrBooleanOperator; |
| |
| template <NumberOperationHint kHint> |
| struct SpeculativeToNumberOperator final |
| : public Operator1<NumberOperationParameters> { |
| SpeculativeToNumberOperator() |
| : Operator1<NumberOperationParameters>( |
| IrOpcode::kSpeculativeToNumber, |
| Operator::kFoldable | Operator::kNoThrow, "SpeculativeToNumber", |
| 1, 1, 1, 1, 1, 0, |
| NumberOperationParameters(kHint, FeedbackSource())) {} |
| }; |
| SpeculativeToNumberOperator<NumberOperationHint::kSignedSmall> |
| kSpeculativeToNumberSignedSmallOperator; |
| SpeculativeToNumberOperator<NumberOperationHint::kSigned32> |
| kSpeculativeToNumberSigned32Operator; |
| SpeculativeToNumberOperator<NumberOperationHint::kNumber> |
| kSpeculativeToNumberNumberOperator; |
| SpeculativeToNumberOperator<NumberOperationHint::kNumberOrOddball> |
| kSpeculativeToNumberNumberOrOddballOperator; |
| }; |
| |
| namespace { |
| DEFINE_LAZY_LEAKY_OBJECT_GETTER(SimplifiedOperatorGlobalCache, |
| GetSimplifiedOperatorGlobalCache) |
| } // namespace |
| |
| SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone) |
| : cache_(*GetSimplifiedOperatorGlobalCache()), zone_(zone) {} |
| |
| #define GET_FROM_CACHE(Name, ...) \ |
| const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; } |
| PURE_OP_LIST(GET_FROM_CACHE) |
| EFFECT_DEPENDENT_OP_LIST(GET_FROM_CACHE) |
| CHECKED_OP_LIST(GET_FROM_CACHE) |
| GET_FROM_CACHE(ArgumentsFrame) |
| GET_FROM_CACHE(FindOrderedHashMapEntry) |
| GET_FROM_CACHE(FindOrderedHashMapEntryForInt32Key) |
| GET_FROM_CACHE(LoadFieldByIndex) |
| #undef GET_FROM_CACHE |
| |
| #define GET_FROM_CACHE_WITH_FEEDBACK(Name, value_input_count, \ |
| value_output_count) \ |
| const Operator* SimplifiedOperatorBuilder::Name( \ |
| const FeedbackSource& feedback) { \ |
| if (!feedback.IsValid()) { \ |
| return &cache_.k##Name; \ |
| } \ |
| return zone()->New<Operator1<CheckParameters>>( \ |
| IrOpcode::k##Name, Operator::kFoldable | Operator::kNoThrow, #Name, \ |
| value_input_count, 1, 1, value_output_count, 1, 0, \ |
| CheckParameters(feedback)); \ |
| } |
| CHECKED_WITH_FEEDBACK_OP_LIST(GET_FROM_CACHE_WITH_FEEDBACK) |
| #undef GET_FROM_CACHE_WITH_FEEDBACK |
| |
| #define GET_FROM_CACHE_WITH_FEEDBACK(Name) \ |
| const Operator* SimplifiedOperatorBuilder::Name( \ |
| const FeedbackSource& feedback, CheckBoundsFlags flags) { \ |
| DCHECK(!(flags & CheckBoundsFlag::kConvertStringAndMinusZero)); \ |
| if (!feedback.IsValid()) { \ |
| if (flags & CheckBoundsFlag::kAbortOnOutOfBounds) { \ |
| return &cache_.k##Name##Aborting; \ |
| } else { \ |
| return &cache_.k##Name; \ |
| } \ |
| } \ |
| return zone()->New<SimplifiedOperatorGlobalCache::Name##Operator>( \ |
| feedback, flags); \ |
| } |
| CHECKED_BOUNDS_OP_LIST(GET_FROM_CACHE_WITH_FEEDBACK) |
| #undef GET_FROM_CACHE_WITH_FEEDBACK |
| |
| // For IrOpcode::kCheckBounds, we allow additional flags: |
| const Operator* SimplifiedOperatorBuilder::CheckBounds( |
| const FeedbackSource& feedback, CheckBoundsFlags flags) { |
| if (!feedback.IsValid()) { |
| if (flags & CheckBoundsFlag::kAbortOnOutOfBounds) { |
| if (flags & CheckBoundsFlag::kConvertStringAndMinusZero) { |
| return &cache_.kCheckBoundsAbortingAndConverting; |
| } else { |
| return &cache_.kCheckBoundsAborting; |
| } |
| } else { |
| if (flags & CheckBoundsFlag::kConvertStringAndMinusZero) { |
| return &cache_.kCheckBoundsConverting; |
| } else { |
| return &cache_.kCheckBounds; |
| } |
| } |
| } |
| return zone()->New<SimplifiedOperatorGlobalCache::CheckBoundsOperator>( |
| feedback, flags); |
| } |
| |
| bool IsCheckedWithFeedback(const Operator* op) { |
| #define CASE(Name, ...) case IrOpcode::k##Name: |
| switch (op->opcode()) { |
| CHECKED_WITH_FEEDBACK_OP_LIST(CASE) return true; |
| default: |
| return false; |
| } |
| #undef CASE |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::RuntimeAbort(AbortReason reason) { |
| return zone()->New<Operator1<int>>( // -- |
| IrOpcode::kRuntimeAbort, // opcode |
| Operator::kNoThrow | Operator::kNoDeopt, // flags |
| "RuntimeAbort", // name |
| 0, 1, 1, 0, 1, 0, // counts |
| static_cast<int>(reason)); // parameter |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::BigIntAsUintN(int bits) { |
| CHECK(0 <= bits && bits <= 64); |
| |
| return zone()->New<Operator1<int>>(IrOpcode::kBigIntAsUintN, Operator::kPure, |
| "BigIntAsUintN", 1, 0, 0, 1, 0, 0, bits); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::UpdateInterruptBudget(int delta) { |
| return zone()->New<Operator1<int>>( |
| IrOpcode::kUpdateInterruptBudget, Operator::kNoThrow | Operator::kNoDeopt, |
| "UpdateInterruptBudget", 1, 1, 1, 0, 1, 0, delta); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::TierUpCheck() { |
| return zone()->New<Operator>(IrOpcode::kTierUpCheck, |
| Operator::kNoThrow | Operator::kNoDeopt, |
| "TierUpCheck", 5, 1, 1, 0, 1, 0); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::AssertType(Type type) { |
| DCHECK(type.IsRange()); |
| return zone()->New<Operator1<Type>>(IrOpcode::kAssertType, |
| Operator::kNoThrow | Operator::kNoDeopt, |
| "AssertType", 1, 0, 0, 1, 0, 0, type); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::CheckIf( |
| DeoptimizeReason reason, const FeedbackSource& feedback) { |
| if (!feedback.IsValid()) { |
| switch (reason) { |
| #define CHECK_IF(Name, message) \ |
| case DeoptimizeReason::k##Name: \ |
| return &cache_.kCheckIf##Name; |
| DEOPTIMIZE_REASON_LIST(CHECK_IF) |
| #undef CHECK_IF |
| } |
| } |
| return zone()->New<Operator1<CheckIfParameters>>( |
| IrOpcode::kCheckIf, Operator::kFoldable | Operator::kNoThrow, "CheckIf", |
| 1, 1, 1, 0, 1, 0, CheckIfParameters(reason, feedback)); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::ChangeFloat64ToTagged( |
| CheckForMinusZeroMode mode) { |
| switch (mode) { |
| case CheckForMinusZeroMode::kCheckForMinusZero: |
| return &cache_.kChangeFloat64ToTaggedCheckForMinusZeroOperator; |
| case CheckForMinusZeroMode::kDontCheckForMinusZero: |
| return &cache_.kChangeFloat64ToTaggedDontCheckForMinusZeroOperator; |
| } |
| UNREACHABLE(); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::CheckedInt32Mul( |
| CheckForMinusZeroMode mode) { |
| switch (mode) { |
| case CheckForMinusZeroMode::kCheckForMinusZero: |
| return &cache_.kCheckedInt32MulCheckForMinusZeroOperator; |
| case CheckForMinusZeroMode::kDontCheckForMinusZero: |
| return &cache_.kCheckedInt32MulDontCheckForMinusZeroOperator; |
| } |
| UNREACHABLE(); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::CheckedFloat64ToInt32( |
| CheckForMinusZeroMode mode, const FeedbackSource& feedback) { |
| if (!feedback.IsValid()) { |
| switch (mode) { |
| case CheckForMinusZeroMode::kCheckForMinusZero: |
| return &cache_.kCheckedFloat64ToInt32CheckForMinusZeroOperator; |
| case CheckForMinusZeroMode::kDontCheckForMinusZero: |
| return &cache_.kCheckedFloat64ToInt32DontCheckForMinusZeroOperator; |
| } |
| } |
| return zone()->New<Operator1<CheckMinusZeroParameters>>( |
| IrOpcode::kCheckedFloat64ToInt32, |
| Operator::kFoldable | Operator::kNoThrow, "CheckedFloat64ToInt32", 1, 1, |
| 1, 1, 1, 0, CheckMinusZeroParameters(mode, feedback)); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::CheckedFloat64ToInt64( |
| CheckForMinusZeroMode mode, const FeedbackSource& feedback) { |
| if (!feedback.IsValid()) { |
| switch (mode) { |
| case CheckForMinusZeroMode::kCheckForMinusZero: |
| return &cache_.kCheckedFloat64ToInt64CheckForMinusZeroOperator; |
| case CheckForMinusZeroMode::kDontCheckForMinusZero: |
| return &cache_.kCheckedFloat64ToInt64DontCheckForMinusZeroOperator; |
| } |
| } |
| return zone()->New<Operator1<CheckMinusZeroParameters>>( |
| IrOpcode::kCheckedFloat64ToInt64, |
| Operator::kFoldable | Operator::kNoThrow, "CheckedFloat64ToInt64", 1, 1, |
| 1, 1, 1, 0, CheckMinusZeroParameters(mode, feedback)); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::CheckedTaggedToInt32( |
| CheckForMinusZeroMode mode, const FeedbackSource& feedback) { |
| if (!feedback.IsValid()) { |
| switch (mode) { |
| case CheckForMinusZeroMode::kCheckForMinusZero: |
| return &cache_.kCheckedTaggedToInt32CheckForMinusZeroOperator; |
| case CheckForMinusZeroMode::kDontCheckForMinusZero: |
| return &cache_.kCheckedTaggedToInt32DontCheckForMinusZeroOperator; |
| } |
| } |
| return zone()->New<Operator1<CheckMinusZeroParameters>>( |
| IrOpcode::kCheckedTaggedToInt32, Operator::kFoldable | Operator::kNoThrow, |
| "CheckedTaggedToInt32", 1, 1, 1, 1, 1, 0, |
| CheckMinusZeroParameters(mode, feedback)); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::CheckedTaggedToInt64( |
| CheckForMinusZeroMode mode, const FeedbackSource& feedback) { |
| if (!feedback.IsValid()) { |
| switch (mode) { |
| case CheckForMinusZeroMode::kCheckForMinusZero: |
| return &cache_.kCheckedTaggedToInt64CheckForMinusZeroOperator; |
| case CheckForMinusZeroMode::kDontCheckForMinusZero: |
| return &cache_.kCheckedTaggedToInt64DontCheckForMinusZeroOperator; |
| } |
| } |
| return zone()->New<Operator1<CheckMinusZeroParameters>>( |
| IrOpcode::kCheckedTaggedToInt64, Operator::kFoldable | Operator::kNoThrow, |
| "CheckedTaggedToInt64", 1, 1, 1, 1, 1, 0, |
| CheckMinusZeroParameters(mode, feedback)); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::CheckedTaggedToFloat64( |
| CheckTaggedInputMode mode, const FeedbackSource& feedback) { |
| if (!feedback.IsValid()) { |
| switch (mode) { |
| case CheckTaggedInputMode::kNumber: |
| return &cache_.kCheckedTaggedToFloat64NumberOperator; |
| case CheckTaggedInputMode::kNumberOrBoolean: |
| return &cache_.kCheckedTaggedToFloat64NumberOrBooleanOperator; |
| case CheckTaggedInputMode::kNumberOrOddball: |
| return &cache_.kCheckedTaggedToFloat64NumberOrOddballOperator; |
| } |
| } |
| return zone()->New<Operator1<CheckTaggedInputParameters>>( |
| IrOpcode::kCheckedTaggedToFloat64, |
| Operator::kFoldable | Operator::kNoThrow, "CheckedTaggedToFloat64", 1, 1, |
| 1, 1, 1, 0, CheckTaggedInputParameters(mode, feedback)); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::CheckedTruncateTaggedToWord32( |
| CheckTaggedInputMode mode, const FeedbackSource& feedback) { |
| if (!feedback.IsValid()) { |
| switch (mode) { |
| case CheckTaggedInputMode::kNumber: |
| return &cache_.kCheckedTruncateTaggedToWord32NumberOperator; |
| case CheckTaggedInputMode::kNumberOrBoolean: |
| // Not used currently. |
| UNREACHABLE(); |
| case CheckTaggedInputMode::kNumberOrOddball: |
| return &cache_.kCheckedTruncateTaggedToWord32NumberOrOddballOperator; |
| } |
| } |
| return zone()->New<Operator1<CheckTaggedInputParameters>>( |
| IrOpcode::kCheckedTruncateTaggedToWord32, |
| Operator::kFoldable | Operator::kNoThrow, "CheckedTruncateTaggedToWord32", |
| 1, 1, 1, 1, 1, 0, CheckTaggedInputParameters(mode, feedback)); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::CheckMaps( |
| CheckMapsFlags flags, ZoneHandleSet<Map> maps, |
| const FeedbackSource& feedback) { |
| CheckMapsParameters const parameters(flags, maps, feedback); |
| return zone()->New<Operator1<CheckMapsParameters>>( // -- |
| IrOpcode::kCheckMaps, // opcode |
| Operator::kNoThrow | Operator::kNoWrite, // flags |
| "CheckMaps", // name |
| 1, 1, 1, 0, 1, 0, // counts |
| parameters); // parameter |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::DynamicCheckMaps( |
| CheckMapsFlags flags, Handle<Object> handler, |
| ZoneHandleSet<Map> const& maps, const FeedbackSource& feedback) { |
| DynamicCheckMapsParameters const parameters(flags, handler, maps, feedback); |
| return zone()->New<Operator1<DynamicCheckMapsParameters>>( // -- |
| IrOpcode::kDynamicCheckMaps, // opcode |
| Operator::kNoThrow | Operator::kNoWrite, // flags |
| "DynamicCheckMaps", // name |
| 1, 1, 1, 0, 1, 0, // counts |
| parameters); // parameter |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::MapGuard(ZoneHandleSet<Map> maps) { |
| DCHECK_LT(0, maps.size()); |
| return zone()->New<Operator1<ZoneHandleSet<Map>>>( // -- |
| IrOpcode::kMapGuard, Operator::kEliminatable, // opcode |
| "MapGuard", // name |
| 1, 1, 1, 0, 1, 0, // counts |
| maps); // parameter |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::CompareMaps( |
| ZoneHandleSet<Map> maps) { |
| DCHECK_LT(0, maps.size()); |
| return zone()->New<Operator1<ZoneHandleSet<Map>>>( // -- |
| IrOpcode::kCompareMaps, // opcode |
| Operator::kNoThrow | Operator::kNoWrite, // flags |
| "CompareMaps", // name |
| 1, 1, 1, 1, 1, 0, // counts |
| maps); // parameter |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::ConvertReceiver( |
| ConvertReceiverMode mode) { |
| switch (mode) { |
| case ConvertReceiverMode::kAny: |
| return &cache_.kConvertReceiverAnyOperator; |
| case ConvertReceiverMode::kNullOrUndefined: |
| return &cache_.kConvertReceiverNullOrUndefinedOperator; |
| case ConvertReceiverMode::kNotNullOrUndefined: |
| return &cache_.kConvertReceiverNotNullOrUndefinedOperator; |
| } |
| UNREACHABLE(); |
| return nullptr; |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::CheckFloat64Hole( |
| CheckFloat64HoleMode mode, FeedbackSource const& feedback) { |
| if (!feedback.IsValid()) { |
| switch (mode) { |
| case CheckFloat64HoleMode::kAllowReturnHole: |
| return &cache_.kCheckFloat64HoleAllowReturnHoleOperator; |
| case CheckFloat64HoleMode::kNeverReturnHole: |
| return &cache_.kCheckFloat64HoleNeverReturnHoleOperator; |
| } |
| UNREACHABLE(); |
| } |
| return zone()->New<Operator1<CheckFloat64HoleParameters>>( |
| IrOpcode::kCheckFloat64Hole, Operator::kFoldable | Operator::kNoThrow, |
| "CheckFloat64Hole", 1, 1, 1, 1, 1, 0, |
| CheckFloat64HoleParameters(mode, feedback)); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::SpeculativeBigIntAdd( |
| BigIntOperationHint hint) { |
| return zone()->New<Operator1<BigIntOperationHint>>( |
| IrOpcode::kSpeculativeBigIntAdd, Operator::kFoldable | Operator::kNoThrow, |
| "SpeculativeBigIntAdd", 2, 1, 1, 1, 1, 0, hint); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::SpeculativeBigIntSubtract( |
| BigIntOperationHint hint) { |
| return zone()->New<Operator1<BigIntOperationHint>>( |
| IrOpcode::kSpeculativeBigIntSubtract, |
| Operator::kFoldable | Operator::kNoThrow, "SpeculativeBigIntSubtract", 2, |
| 1, 1, 1, 1, 0, hint); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::SpeculativeBigIntNegate( |
| BigIntOperationHint hint) { |
| return zone()->New<Operator1<BigIntOperationHint>>( |
| IrOpcode::kSpeculativeBigIntNegate, |
| Operator::kFoldable | Operator::kNoThrow, "SpeculativeBigIntNegate", 1, 1, |
| 1, 1, 1, 0, hint); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::CheckClosure( |
| const Handle<FeedbackCell>& feedback_cell) { |
| return zone()->New<Operator1<Handle<FeedbackCell>>>( // -- |
| IrOpcode::kCheckClosure, // opcode |
| Operator::kNoThrow | Operator::kNoWrite, // flags |
| "CheckClosure", // name |
| 1, 1, 1, 1, 1, 0, // counts |
| feedback_cell); // parameter |
| } |
| |
| Handle<FeedbackCell> FeedbackCellOf(const Operator* op) { |
| DCHECK(IrOpcode::kCheckClosure == op->opcode()); |
| return OpParameter<Handle<FeedbackCell>>(op); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::SpeculativeToNumber( |
| NumberOperationHint hint, const FeedbackSource& feedback) { |
| if (!feedback.IsValid()) { |
| switch (hint) { |
| case NumberOperationHint::kSignedSmall: |
| return &cache_.kSpeculativeToNumberSignedSmallOperator; |
| case NumberOperationHint::kSignedSmallInputs: |
| break; |
| case NumberOperationHint::kSigned32: |
| return &cache_.kSpeculativeToNumberSigned32Operator; |
| case NumberOperationHint::kNumber: |
| return &cache_.kSpeculativeToNumberNumberOperator; |
| case NumberOperationHint::kNumberOrBoolean: |
| // Not used currently. |
| UNREACHABLE(); |
| case NumberOperationHint::kNumberOrOddball: |
| return &cache_.kSpeculativeToNumberNumberOrOddballOperator; |
| } |
| } |
| return zone()->New<Operator1<NumberOperationParameters>>( |
| IrOpcode::kSpeculativeToNumber, Operator::kFoldable | Operator::kNoThrow, |
| "SpeculativeToNumber", 1, 1, 1, 1, 1, 0, |
| NumberOperationParameters(hint, feedback)); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::EnsureWritableFastElements() { |
| return &cache_.kEnsureWritableFastElements; |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::MaybeGrowFastElements( |
| GrowFastElementsMode mode, const FeedbackSource& feedback) { |
| if (!feedback.IsValid()) { |
| switch (mode) { |
| case GrowFastElementsMode::kDoubleElements: |
| return &cache_.kGrowFastElementsOperatorDoubleElements; |
| case GrowFastElementsMode::kSmiOrObjectElements: |
| return &cache_.kGrowFastElementsOperatorSmiOrObjectElements; |
| } |
| } |
| return zone()->New<Operator1<GrowFastElementsParameters>>( // -- |
| IrOpcode::kMaybeGrowFastElements, // opcode |
| Operator::kNoThrow, // flags |
| "MaybeGrowFastElements", // name |
| 4, 1, 1, 1, 1, 0, // counts |
| GrowFastElementsParameters(mode, feedback)); // parameter |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::TransitionElementsKind( |
| ElementsTransition transition) { |
| return zone()->New<Operator1<ElementsTransition>>( // -- |
| IrOpcode::kTransitionElementsKind, // opcode |
| Operator::kNoThrow, // flags |
| "TransitionElementsKind", // name |
| 1, 1, 1, 0, 1, 0, // counts |
| transition); // parameter |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::ArgumentsLength( |
| int formal_parameter_count) { |
| return zone()->New<Operator1<int>>( // -- |
| IrOpcode::kArgumentsLength, // opcode |
| Operator::kPure, // flags |
| "ArgumentsLength", // name |
| 1, 0, 0, 1, 0, 0, // counts |
| formal_parameter_count); // parameter |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::RestLength( |
| int formal_parameter_count) { |
| return zone()->New<Operator1<int>>( // -- |
| IrOpcode::kRestLength, // opcode |
| Operator::kPure, // flags |
| "RestLength", // name |
| 1, 0, 0, 1, 0, 0, // counts |
| formal_parameter_count); // parameter |
| } |
| |
| int FormalParameterCountOf(const Operator* op) { |
| DCHECK(op->opcode() == IrOpcode::kArgumentsLength || |
| op->opcode() == IrOpcode::kRestLength); |
| return OpParameter<int>(op); |
| } |
| |
| bool operator==(CheckParameters const& lhs, CheckParameters const& rhs) { |
| return lhs.feedback() == rhs.feedback(); |
| } |
| |
| size_t hash_value(CheckParameters const& p) { |
| FeedbackSource::Hash feedback_hash; |
| return feedback_hash(p.feedback()); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, CheckParameters const& p) { |
| return os << p.feedback(); |
| } |
| |
| CheckParameters const& CheckParametersOf(Operator const* op) { |
| if (op->opcode() == IrOpcode::kCheckBounds || |
| op->opcode() == IrOpcode::kCheckedUint32Bounds || |
| op->opcode() == IrOpcode::kCheckedUint64Bounds) { |
| return OpParameter<CheckBoundsParameters>(op).check_parameters(); |
| } |
| #define MAKE_OR(name, arg2, arg3) op->opcode() == IrOpcode::k##name || |
| CHECK((CHECKED_WITH_FEEDBACK_OP_LIST(MAKE_OR) false)); |
| #undef MAKE_OR |
| return OpParameter<CheckParameters>(op); |
| } |
| |
| bool operator==(CheckBoundsParameters const& lhs, |
| CheckBoundsParameters const& rhs) { |
| return lhs.check_parameters() == rhs.check_parameters() && |
| lhs.flags() == rhs.flags(); |
| } |
| |
| size_t hash_value(CheckBoundsParameters const& p) { |
| return base::hash_combine(hash_value(p.check_parameters()), p.flags()); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, CheckBoundsParameters const& p) { |
| os << p.check_parameters() << ", " << p.flags(); |
| return os; |
| } |
| |
| CheckBoundsParameters const& CheckBoundsParametersOf(Operator const* op) { |
| DCHECK(op->opcode() == IrOpcode::kCheckBounds || |
| op->opcode() == IrOpcode::kCheckedUint32Bounds || |
| op->opcode() == IrOpcode::kCheckedUint64Bounds); |
| return OpParameter<CheckBoundsParameters>(op); |
| } |
| |
| bool operator==(CheckIfParameters const& lhs, CheckIfParameters const& rhs) { |
| return lhs.reason() == rhs.reason() && lhs.feedback() == rhs.feedback(); |
| } |
| |
| size_t hash_value(CheckIfParameters const& p) { |
| FeedbackSource::Hash feedback_hash; |
| return base::hash_combine(p.reason(), feedback_hash(p.feedback())); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, CheckIfParameters const& p) { |
| return os << p.reason() << ", " << p.feedback(); |
| } |
| |
| CheckIfParameters const& CheckIfParametersOf(Operator const* op) { |
| CHECK(op->opcode() == IrOpcode::kCheckIf); |
| return OpParameter<CheckIfParameters>(op); |
| } |
| |
| FastApiCallParameters const& FastApiCallParametersOf(const Operator* op) { |
| DCHECK_EQ(IrOpcode::kFastApiCall, op->opcode()); |
| return OpParameter<FastApiCallParameters>(op); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, FastApiCallParameters const& p) { |
| return os << p.signature() << ", " << p.feedback() << ", " << p.descriptor(); |
| } |
| |
| size_t hash_value(FastApiCallParameters const& p) { |
| return base::hash_combine(p.signature(), FeedbackSource::Hash()(p.feedback()), |
| p.descriptor()); |
| } |
| |
| bool operator==(FastApiCallParameters const& lhs, |
| FastApiCallParameters const& rhs) { |
| return lhs.signature() == rhs.signature() && |
| lhs.feedback() == rhs.feedback() && |
| lhs.descriptor() == rhs.descriptor(); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::NewDoubleElements( |
| AllocationType allocation) { |
| return zone()->New<Operator1<AllocationType>>( // -- |
| IrOpcode::kNewDoubleElements, // opcode |
| Operator::kEliminatable, // flags |
| "NewDoubleElements", // name |
| 1, 1, 1, 1, 1, 0, // counts |
| allocation); // parameter |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::NewSmiOrObjectElements( |
| AllocationType allocation) { |
| return zone()->New<Operator1<AllocationType>>( // -- |
| IrOpcode::kNewSmiOrObjectElements, // opcode |
| Operator::kEliminatable, // flags |
| "NewSmiOrObjectElements", // name |
| 1, 1, 1, 1, 1, 0, // counts |
| allocation); // parameter |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::NewArgumentsElements( |
| CreateArgumentsType type, int formal_parameter_count) { |
| return zone()->New<Operator1<NewArgumentsElementsParameters>>( // -- |
| IrOpcode::kNewArgumentsElements, // opcode |
| Operator::kEliminatable, // flags |
| "NewArgumentsElements", // name |
| 2, 1, 0, 1, 1, 0, // counts |
| NewArgumentsElementsParameters(type, |
| formal_parameter_count)); // parameter |
| } |
| |
| bool operator==(const NewArgumentsElementsParameters& lhs, |
| const NewArgumentsElementsParameters& rhs) { |
| return lhs.arguments_type() == rhs.arguments_type() && |
| lhs.formal_parameter_count() == rhs.formal_parameter_count(); |
| } |
| |
| inline size_t hash_value(const NewArgumentsElementsParameters& params) { |
| return base::hash_combine(params.arguments_type(), |
| params.formal_parameter_count()); |
| } |
| |
| std::ostream& operator<<(std::ostream& os, |
| const NewArgumentsElementsParameters& params) { |
| return os << params.arguments_type() |
| << ", parameter_count = " << params.formal_parameter_count(); |
| } |
| |
| const NewArgumentsElementsParameters& NewArgumentsElementsParametersOf( |
| const Operator* op) { |
| DCHECK_EQ(IrOpcode::kNewArgumentsElements, op->opcode()); |
| return OpParameter<NewArgumentsElementsParameters>(op); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::Allocate(Type type, |
| AllocationType allocation) { |
| return zone()->New<Operator1<AllocateParameters>>( |
| IrOpcode::kAllocate, Operator::kEliminatable, "Allocate", 1, 1, 1, 1, 1, |
| 0, AllocateParameters(type, allocation)); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::AllocateRaw( |
| Type type, AllocationType allocation, |
| AllowLargeObjects allow_large_objects) { |
| // We forbid optimized allocations to allocate in a different generation than |
| // requested. |
| DCHECK(!(allow_large_objects == AllowLargeObjects::kTrue && |
| allocation == AllocationType::kYoung && |
| !FLAG_young_generation_large_objects)); |
| return zone()->New<Operator1<AllocateParameters>>( |
| IrOpcode::kAllocateRaw, Operator::kEliminatable, "AllocateRaw", 1, 1, 1, |
| 1, 1, 1, AllocateParameters(type, allocation, allow_large_objects)); |
| } |
| |
| #define SPECULATIVE_NUMBER_BINOP(Name) \ |
| const Operator* SimplifiedOperatorBuilder::Name(NumberOperationHint hint) { \ |
| switch (hint) { \ |
| case NumberOperationHint::kSignedSmall: \ |
| return &cache_.k##Name##SignedSmallOperator; \ |
| case NumberOperationHint::kSignedSmallInputs: \ |
| return &cache_.k##Name##SignedSmallInputsOperator; \ |
| case NumberOperationHint::kSigned32: \ |
| return &cache_.k##Name##Signed32Operator; \ |
| case NumberOperationHint::kNumber: \ |
| return &cache_.k##Name##NumberOperator; \ |
| case NumberOperationHint::kNumberOrBoolean: \ |
| /* Not used currenly. */ \ |
| UNREACHABLE(); \ |
| case NumberOperationHint::kNumberOrOddball: \ |
| return &cache_.k##Name##NumberOrOddballOperator; \ |
| } \ |
| UNREACHABLE(); \ |
| return nullptr; \ |
| } |
| SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(SPECULATIVE_NUMBER_BINOP) |
| SPECULATIVE_NUMBER_BINOP(SpeculativeNumberLessThan) |
| SPECULATIVE_NUMBER_BINOP(SpeculativeNumberLessThanOrEqual) |
| #undef SPECULATIVE_NUMBER_BINOP |
| const Operator* SimplifiedOperatorBuilder::SpeculativeNumberEqual( |
| NumberOperationHint hint) { |
| switch (hint) { |
| case NumberOperationHint::kSignedSmall: |
| return &cache_.kSpeculativeNumberEqualSignedSmallOperator; |
| case NumberOperationHint::kSignedSmallInputs: |
| return &cache_.kSpeculativeNumberEqualSignedSmallInputsOperator; |
| case NumberOperationHint::kSigned32: |
| return &cache_.kSpeculativeNumberEqualSigned32Operator; |
| case NumberOperationHint::kNumber: |
| return &cache_.kSpeculativeNumberEqualNumberOperator; |
| case NumberOperationHint::kNumberOrBoolean: |
| return &cache_.kSpeculativeNumberEqualNumberOrBooleanOperator; |
| case NumberOperationHint::kNumberOrOddball: |
| return &cache_.kSpeculativeNumberEqualNumberOrOddballOperator; |
| } |
| UNREACHABLE(); |
| return nullptr; |
| } |
| |
| #define ACCESS_OP_LIST(V) \ |
| V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1, 1) \ |
| V(StoreField, FieldAccess, Operator::kNoRead, 2, 1, 0) \ |
| V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1, 1) \ |
| V(StoreElement, ElementAccess, Operator::kNoRead, 3, 1, 0) \ |
| V(LoadTypedElement, ExternalArrayType, Operator::kNoWrite, 4, 1, 1) \ |
| V(LoadFromObject, ObjectAccess, Operator::kNoWrite, 2, 1, 1) \ |
| V(StoreTypedElement, ExternalArrayType, Operator::kNoRead, 5, 1, 0) \ |
| V(StoreToObject, ObjectAccess, Operator::kNoRead, 3, 1, 0) \ |
| V(LoadDataViewElement, ExternalArrayType, Operator::kNoWrite, 4, 1, 1) \ |
| V(StoreDataViewElement, ExternalArrayType, Operator::kNoRead, 5, 1, 0) |
| |
| #define ACCESS(Name, Type, properties, value_input_count, control_input_count, \ |
| output_count) \ |
| const Operator* SimplifiedOperatorBuilder::Name(const Type& access) { \ |
| return zone()->New<Operator1<Type>>( \ |
| IrOpcode::k##Name, \ |
| Operator::kNoDeopt | Operator::kNoThrow | properties, #Name, \ |
| value_input_count, 1, control_input_count, output_count, 1, 0, \ |
| access); \ |
| } |
| ACCESS_OP_LIST(ACCESS) |
| #undef ACCESS |
| |
| const Operator* SimplifiedOperatorBuilder::LoadMessage() { |
| return zone()->New<Operator>(IrOpcode::kLoadMessage, Operator::kEliminatable, |
| "LoadMessage", 1, 1, 1, 1, 1, 0); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::StoreMessage() { |
| return zone()->New<Operator>( |
| IrOpcode::kStoreMessage, |
| Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoRead, |
| "StoreMessage", 2, 1, 1, 0, 1, 0); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::LoadStackArgument() { |
| return &cache_.kLoadStackArgument; |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::TransitionAndStoreElement( |
| Handle<Map> double_map, Handle<Map> fast_map) { |
| TransitionAndStoreElementParameters parameters(double_map, fast_map); |
| return zone()->New<Operator1<TransitionAndStoreElementParameters>>( |
| IrOpcode::kTransitionAndStoreElement, |
| Operator::kNoDeopt | Operator::kNoThrow, "TransitionAndStoreElement", 3, |
| 1, 1, 0, 1, 0, parameters); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::StoreSignedSmallElement() { |
| return zone()->New<Operator>(IrOpcode::kStoreSignedSmallElement, |
| Operator::kNoDeopt | Operator::kNoThrow, |
| "StoreSignedSmallElement", 3, 1, 1, 0, 1, 0); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::TransitionAndStoreNumberElement( |
| Handle<Map> double_map) { |
| TransitionAndStoreNumberElementParameters parameters(double_map); |
| return zone()->New<Operator1<TransitionAndStoreNumberElementParameters>>( |
| IrOpcode::kTransitionAndStoreNumberElement, |
| Operator::kNoDeopt | Operator::kNoThrow, |
| "TransitionAndStoreNumberElement", 3, 1, 1, 0, 1, 0, parameters); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::TransitionAndStoreNonNumberElement( |
| Handle<Map> fast_map, Type value_type) { |
| TransitionAndStoreNonNumberElementParameters parameters(fast_map, value_type); |
| return zone()->New<Operator1<TransitionAndStoreNonNumberElementParameters>>( |
| IrOpcode::kTransitionAndStoreNonNumberElement, |
| Operator::kNoDeopt | Operator::kNoThrow, |
| "TransitionAndStoreNonNumberElement", 3, 1, 1, 0, 1, 0, parameters); |
| } |
| |
| const Operator* SimplifiedOperatorBuilder::FastApiCall( |
| const CFunctionInfo* signature, FeedbackSource const& feedback, |
| CallDescriptor* descriptor) { |
| int value_input_count = |
| (signature->ArgumentCount() + |
| FastApiCallNode::kFastTargetInputCount) + // fast call |
| static_cast<int>(descriptor->ParameterCount()) + // slow call |
| FastApiCallNode::kEffectAndControlInputCount; |
| return zone()->New<Operator1<FastApiCallParameters>>( |
| IrOpcode::kFastApiCall, Operator::kNoThrow, "FastApiCall", |
| value_input_count, 1, 1, 1, 1, 0, |
| FastApiCallParameters(signature, feedback, descriptor)); |
| } |
| |
| int FastApiCallNode::FastCallArgumentCount() const { |
| FastApiCallParameters p = FastApiCallParametersOf(node()->op()); |
| const CFunctionInfo* signature = p.signature(); |
| CHECK_NOT_NULL(signature); |
| return signature->ArgumentCount(); |
| } |
| |
| int FastApiCallNode::SlowCallArgumentCount() const { |
| FastApiCallParameters p = FastApiCallParametersOf(node()->op()); |
| CallDescriptor* descriptor = p.descriptor(); |
| CHECK_NOT_NULL(descriptor); |
| return static_cast<int>(descriptor->ParameterCount()) + |
| kContextAndFrameStateInputCount; |
| } |
| |
| #undef PURE_OP_LIST |
| #undef EFFECT_DEPENDENT_OP_LIST |
| #undef SPECULATIVE_NUMBER_BINOP_LIST |
| #undef CHECKED_WITH_FEEDBACK_OP_LIST |
| #undef CHECKED_BOUNDS_OP_LIST |
| #undef CHECKED_OP_LIST |
| #undef ACCESS_OP_LIST |
| |
| } // namespace compiler |
| } // namespace internal |
| } // namespace v8 |