// 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 "src/base/lazy-instance.h" #include "src/compiler/opcodes.h" #include "src/compiler/operator.h" #include "src/compiler/types.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(); return os; } MachineType BufferAccess::machine_type() const { switch (external_array_type_) { case kExternalUint8Array: case kExternalUint8ClampedArray: return MachineType::Uint8(); case kExternalInt8Array: return MachineType::Int8(); case kExternalUint16Array: return MachineType::Uint16(); case kExternalInt16Array: return MachineType::Int16(); case kExternalUint32Array: return MachineType::Uint32(); case kExternalInt32Array: return MachineType::Int32(); case kExternalFloat32Array: return MachineType::Float32(); case kExternalFloat64Array: return MachineType::Float64(); } UNREACHABLE(); return MachineType::None(); } bool operator==(BufferAccess lhs, BufferAccess rhs) { return lhs.external_array_type() == rhs.external_array_type(); } bool operator!=(BufferAccess lhs, BufferAccess rhs) { return !(lhs == rhs); } size_t hash_value(BufferAccess access) { return base::hash<ExternalArrayType>()(access.external_array_type()); } std::ostream& operator<<(std::ostream& os, BufferAccess access) { switch (access.external_array_type()) { #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ case kExternal##Type##Array: \ return os << #Type; TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE } UNREACHABLE(); return os; } BufferAccess const BufferAccessOf(const Operator* op) { DCHECK(op->opcode() == IrOpcode::kLoadBuffer || op->opcode() == IrOpcode::kStoreBuffer); return OpParameter<BufferAccess>(op); } 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; } bool operator!=(FieldAccess const& lhs, FieldAccess const& rhs) { return !(lhs == rhs); } 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); } 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->Print(os); os << ", "; } Handle<Map> map; if (access.map.ToHandle(&map)) { os << Brief(*map) << ", "; } #endif access.type->PrintTo(os); os << ", " << access.machine_type << ", " << access.write_barrier_kind << "]"; 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; } bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs) { return !(lhs == rhs); } 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->PrintTo(os); 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); } ExternalArrayType ExternalArrayTypeOf(const Operator* op) { DCHECK(op->opcode() == IrOpcode::kLoadTypedElement || op->opcode() == IrOpcode::kStoreTypedElement); return OpParameter<ExternalArrayType>(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(); return os; } CheckFloat64HoleMode CheckFloat64HoleModeOf(const Operator* op) { DCHECK_EQ(IrOpcode::kCheckFloat64Hole, op->opcode()); return OpParameter<CheckFloat64HoleMode>(op); } CheckForMinusZeroMode CheckMinusZeroModeOf(const Operator* op) { DCHECK(op->opcode() == IrOpcode::kCheckedInt32Mul || op->opcode() == IrOpcode::kCheckedFloat64ToInt32 || op->opcode() == IrOpcode::kCheckedTaggedToInt32); 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(); return os; } std::ostream& operator<<(std::ostream& os, CheckMapsFlags flags) { bool empty = true; if (flags & CheckMapsFlag::kTryMigrateInstance) { os << "TryMigrateInstance"; empty = false; } if (empty) os << "None"; return os; } bool operator==(CheckMapsParameters const& lhs, CheckMapsParameters const& rhs) { return lhs.flags() == rhs.flags() && lhs.maps() == rhs.maps(); } bool operator!=(CheckMapsParameters const& lhs, CheckMapsParameters const& rhs) { return !(lhs == rhs); } size_t hash_value(CheckMapsParameters const& p) { return base::hash_combine(p.flags(), p.maps()); } std::ostream& operator<<(std::ostream& os, CheckMapsParameters const& p) { ZoneHandleSet<Map> const& maps = p.maps(); os << p.flags(); for (size_t i = 0; i < maps.size(); ++i) { os << ", " << Brief(*maps[i]); } return os; } CheckMapsParameters const& CheckMapsParametersOf(Operator const* op) { DCHECK_EQ(IrOpcode::kCheckMaps, op->opcode()); return OpParameter<CheckMapsParameters>(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::kNumberOrOddball: return os << "NumberOrOddball"; } UNREACHABLE(); return os; } CheckTaggedInputMode CheckTaggedInputModeOf(const Operator* op) { DCHECK_EQ(IrOpcode::kCheckedTaggedToFloat64, op->opcode()); return OpParameter<CheckTaggedInputMode>(op); } std::ostream& operator<<(std::ostream& os, GrowFastElementsFlags flags) { bool empty = true; if (flags & GrowFastElementsFlag::kArrayObject) { os << "ArrayObject"; empty = false; } if (flags & GrowFastElementsFlag::kDoubleElements) { if (!empty) os << "|"; os << "DoubleElements"; empty = false; } if (flags & GrowFastElementsFlag::kHoleyElements) { if (!empty) os << "|"; os << "HoleyElements"; empty = false; } if (empty) os << "None"; return os; } GrowFastElementsFlags GrowFastElementsFlagsOf(const Operator* op) { DCHECK_EQ(IrOpcode::kMaybeGrowFastElements, op->opcode()); return OpParameter<GrowFastElementsFlags>(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(); } bool operator!=(ElementsTransition const& lhs, ElementsTransition const& rhs) { return !(lhs == rhs); } 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(); return os; } ElementsTransition const& ElementsTransitionOf(const Operator* op) { DCHECK_EQ(IrOpcode::kTransitionElementsKind, op->opcode()); return OpParameter<ElementsTransition>(op); } std::ostream& operator<<(std::ostream& os, NumberOperationHint hint) { switch (hint) { case NumberOperationHint::kSignedSmall: return os << "SignedSmall"; case NumberOperationHint::kSigned32: return os << "Signed32"; case NumberOperationHint::kNumber: return os << "Number"; case NumberOperationHint::kNumberOrOddball: return os << "NumberOrOddball"; } UNREACHABLE(); return os; } 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); return OpParameter<NumberOperationHint>(op); } int ParameterCountOf(const Operator* op) { DCHECK(op->opcode() == IrOpcode::kNewUnmappedArgumentsElements || op->opcode() == IrOpcode::kNewRestParameterElements); return OpParameter<int>(op); } PretenureFlag PretenureFlagOf(const Operator* op) { DCHECK_EQ(IrOpcode::kAllocate, op->opcode()); return OpParameter<PretenureFlag>(op); } UnicodeEncoding UnicodeEncodingOf(const Operator* op) { DCHECK(op->opcode() == IrOpcode::kStringFromCodePoint); return OpParameter<UnicodeEncoding>(op); } #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(NumberToUint32, Operator::kNoProperties, 1, 0) \ V(NumberToUint8Clamped, Operator::kNoProperties, 1, 0) \ V(NumberSilenceNaN, Operator::kNoProperties, 1, 0) \ V(StringCharAt, Operator::kNoProperties, 2, 1) \ V(StringCharCodeAt, Operator::kNoProperties, 2, 1) \ V(StringFromCharCode, Operator::kNoProperties, 1, 0) \ V(StringIndexOf, Operator::kNoProperties, 3, 0) \ 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(ChangeTaggedToInt32, Operator::kNoProperties, 1, 0) \ V(ChangeTaggedToUint32, Operator::kNoProperties, 1, 0) \ V(ChangeTaggedToFloat64, Operator::kNoProperties, 1, 0) \ V(ChangeTaggedToTaggedSigned, Operator::kNoProperties, 1, 0) \ V(ChangeFloat64ToTagged, Operator::kNoProperties, 1, 0) \ V(ChangeFloat64ToTaggedPointer, Operator::kNoProperties, 1, 0) \ V(ChangeInt31ToTaggedSigned, Operator::kNoProperties, 1, 0) \ V(ChangeInt32ToTagged, Operator::kNoProperties, 1, 0) \ V(ChangeUint32ToTagged, Operator::kNoProperties, 1, 0) \ V(ChangeTaggedToBit, Operator::kNoProperties, 1, 0) \ V(ChangeBitToTagged, Operator::kNoProperties, 1, 0) \ V(TruncateTaggedToBit, Operator::kNoProperties, 1, 0) \ V(TruncateTaggedToWord32, Operator::kNoProperties, 1, 0) \ V(TruncateTaggedToFloat64, Operator::kNoProperties, 1, 0) \ V(ObjectIsDetectableCallable, 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(ObjectIsUndetectable, Operator::kNoProperties, 1, 0) \ V(ConvertTaggedHoleToUndefined, Operator::kNoProperties, 1, 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) #define SPECULATIVE_NUMBER_BINOP_LIST(V) \ SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(V) \ V(SpeculativeNumberEqual) \ V(SpeculativeNumberLessThan) \ V(SpeculativeNumberLessThanOrEqual) #define CHECKED_OP_LIST(V) \ V(CheckBounds, 2, 1) \ V(CheckHeapObject, 1, 1) \ V(CheckIf, 1, 0) \ V(CheckInternalizedString, 1, 1) \ V(CheckNumber, 1, 1) \ V(CheckReceiver, 1, 1) \ V(CheckSmi, 1, 1) \ V(CheckString, 1, 1) \ V(CheckTaggedHole, 1, 1) \ V(CheckedInt32Add, 2, 1) \ V(CheckedInt32Sub, 2, 1) \ V(CheckedInt32Div, 2, 1) \ V(CheckedInt32Mod, 2, 1) \ V(CheckedUint32Div, 2, 1) \ V(CheckedUint32Mod, 2, 1) \ V(CheckedUint32ToInt32, 1, 1) \ V(CheckedUint32ToTaggedSigned, 1, 1) \ V(CheckedInt32ToTaggedSigned, 1, 1) \ V(CheckedTaggedSignedToInt32, 1, 1) \ V(CheckedTaggedToTaggedSigned, 1, 1) \ V(CheckedTaggedToTaggedPointer, 1, 1) \ V(CheckedTruncateTaggedToWord32, 1, 1) 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 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 template <UnicodeEncoding kEncoding> struct StringFromCodePointOperator final : public Operator1<UnicodeEncoding> { StringFromCodePointOperator() : Operator1<UnicodeEncoding>(IrOpcode::kStringFromCodePoint, Operator::kPure, "StringFromCodePoint", 1, 0, 0, 1, 0, 0, kEncoding) {} }; StringFromCodePointOperator<UnicodeEncoding::UTF16> kStringFromCodePointOperatorUTF16; StringFromCodePointOperator<UnicodeEncoding::UTF32> kStringFromCodePointOperatorUTF32; struct ArrayBufferWasNeuteredOperator final : public Operator { ArrayBufferWasNeuteredOperator() : Operator(IrOpcode::kArrayBufferWasNeutered, Operator::kEliminatable, "ArrayBufferWasNeutered", 1, 1, 1, 1, 1, 0) {} }; ArrayBufferWasNeuteredOperator kArrayBufferWasNeutered; 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<CheckForMinusZeroMode> { CheckedFloat64ToInt32Operator() : Operator1<CheckForMinusZeroMode>( IrOpcode::kCheckedFloat64ToInt32, Operator::kFoldable | Operator::kNoThrow, "CheckedFloat64ToInt32", 1, 1, 1, 1, 1, 0, kMode) {} }; CheckedFloat64ToInt32Operator<CheckForMinusZeroMode::kCheckForMinusZero> kCheckedFloat64ToInt32CheckForMinusZeroOperator; CheckedFloat64ToInt32Operator<CheckForMinusZeroMode::kDontCheckForMinusZero> kCheckedFloat64ToInt32DontCheckForMinusZeroOperator; template <CheckForMinusZeroMode kMode> struct CheckedTaggedToInt32Operator final : public Operator1<CheckForMinusZeroMode> { CheckedTaggedToInt32Operator() : Operator1<CheckForMinusZeroMode>( IrOpcode::kCheckedTaggedToInt32, Operator::kFoldable | Operator::kNoThrow, "CheckedTaggedToInt32", 1, 1, 1, 1, 1, 0, kMode) {} }; CheckedTaggedToInt32Operator<CheckForMinusZeroMode::kCheckForMinusZero> kCheckedTaggedToInt32CheckForMinusZeroOperator; CheckedTaggedToInt32Operator<CheckForMinusZeroMode::kDontCheckForMinusZero> kCheckedTaggedToInt32DontCheckForMinusZeroOperator; template <CheckTaggedInputMode kMode> struct CheckedTaggedToFloat64Operator final : public Operator1<CheckTaggedInputMode> { CheckedTaggedToFloat64Operator() : Operator1<CheckTaggedInputMode>( IrOpcode::kCheckedTaggedToFloat64, Operator::kFoldable | Operator::kNoThrow, "CheckedTaggedToFloat64", 1, 1, 1, 1, 1, 0, kMode) {} }; CheckedTaggedToFloat64Operator<CheckTaggedInputMode::kNumber> kCheckedTaggedToFloat64NumberOperator; CheckedTaggedToFloat64Operator<CheckTaggedInputMode::kNumberOrOddball> kCheckedTaggedToFloat64NumberOrOddballOperator; template <CheckFloat64HoleMode kMode> struct CheckFloat64HoleNaNOperator final : public Operator1<CheckFloat64HoleMode> { CheckFloat64HoleNaNOperator() : Operator1<CheckFloat64HoleMode>( IrOpcode::kCheckFloat64Hole, Operator::kFoldable | Operator::kNoThrow, "CheckFloat64Hole", 1, 1, 1, 1, 1, 0, kMode) {} }; CheckFloat64HoleNaNOperator<CheckFloat64HoleMode::kAllowReturnHole> kCheckFloat64HoleAllowReturnHoleOperator; CheckFloat64HoleNaNOperator<CheckFloat64HoleMode::kNeverReturnHole> kCheckFloat64HoleNeverReturnHoleOperator; template <PretenureFlag kPretenure> struct AllocateOperator final : public Operator1<PretenureFlag> { AllocateOperator() : Operator1<PretenureFlag>( IrOpcode::kAllocate, Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite, "Allocate", 1, 1, 1, 1, 1, 0, kPretenure) {} }; AllocateOperator<NOT_TENURED> kAllocateNotTenuredOperator; AllocateOperator<TENURED> kAllocateTenuredOperator; 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; #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::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 #define BUFFER_ACCESS(Type, type, TYPE, ctype, size) \ struct LoadBuffer##Type##Operator final : public Operator1<BufferAccess> { \ LoadBuffer##Type##Operator() \ : Operator1<BufferAccess>( \ IrOpcode::kLoadBuffer, \ Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite, \ "LoadBuffer", 3, 1, 1, 1, 1, 0, \ BufferAccess(kExternal##Type##Array)) {} \ }; \ struct StoreBuffer##Type##Operator final : public Operator1<BufferAccess> { \ StoreBuffer##Type##Operator() \ : Operator1<BufferAccess>( \ IrOpcode::kStoreBuffer, \ Operator::kNoDeopt | Operator::kNoRead | Operator::kNoThrow, \ "StoreBuffer", 4, 1, 1, 0, 1, 0, \ BufferAccess(kExternal##Type##Array)) {} \ }; \ LoadBuffer##Type##Operator kLoadBuffer##Type; \ StoreBuffer##Type##Operator kStoreBuffer##Type; TYPED_ARRAYS(BUFFER_ACCESS) #undef BUFFER_ACCESS }; static base::LazyInstance<SimplifiedOperatorGlobalCache>::type kCache = LAZY_INSTANCE_INITIALIZER; SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone) : cache_(kCache.Get()), zone_(zone) {} #define GET_FROM_CACHE(Name, ...) \ const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; } PURE_OP_LIST(GET_FROM_CACHE) CHECKED_OP_LIST(GET_FROM_CACHE) GET_FROM_CACHE(ArrayBufferWasNeutered) #undef GET_FROM_CACHE const Operator* SimplifiedOperatorBuilder::CheckedInt32Mul( CheckForMinusZeroMode mode) { switch (mode) { case CheckForMinusZeroMode::kCheckForMinusZero: return &cache_.kCheckedInt32MulCheckForMinusZeroOperator; case CheckForMinusZeroMode::kDontCheckForMinusZero: return &cache_.kCheckedInt32MulDontCheckForMinusZeroOperator; } UNREACHABLE(); return nullptr; } const Operator* SimplifiedOperatorBuilder::CheckedFloat64ToInt32( CheckForMinusZeroMode mode) { switch (mode) { case CheckForMinusZeroMode::kCheckForMinusZero: return &cache_.kCheckedFloat64ToInt32CheckForMinusZeroOperator; case CheckForMinusZeroMode::kDontCheckForMinusZero: return &cache_.kCheckedFloat64ToInt32DontCheckForMinusZeroOperator; } UNREACHABLE(); return nullptr; } const Operator* SimplifiedOperatorBuilder::CheckedTaggedToInt32( CheckForMinusZeroMode mode) { switch (mode) { case CheckForMinusZeroMode::kCheckForMinusZero: return &cache_.kCheckedTaggedToInt32CheckForMinusZeroOperator; case CheckForMinusZeroMode::kDontCheckForMinusZero: return &cache_.kCheckedTaggedToInt32DontCheckForMinusZeroOperator; } UNREACHABLE(); return nullptr; } const Operator* SimplifiedOperatorBuilder::CheckedTaggedToFloat64( CheckTaggedInputMode mode) { switch (mode) { case CheckTaggedInputMode::kNumber: return &cache_.kCheckedTaggedToFloat64NumberOperator; case CheckTaggedInputMode::kNumberOrOddball: return &cache_.kCheckedTaggedToFloat64NumberOrOddballOperator; } UNREACHABLE(); return nullptr; } const Operator* SimplifiedOperatorBuilder::CheckMaps(CheckMapsFlags flags, ZoneHandleSet<Map> maps) { CheckMapsParameters const parameters(flags, maps); return new (zone()) Operator1<CheckMapsParameters>( // -- IrOpcode::kCheckMaps, // opcode Operator::kNoThrow | Operator::kNoWrite, // flags "CheckMaps", // name 1, 1, 1, 0, 1, 0, // counts parameters); // parameter } const Operator* SimplifiedOperatorBuilder::CheckFloat64Hole( CheckFloat64HoleMode mode) { switch (mode) { case CheckFloat64HoleMode::kAllowReturnHole: return &cache_.kCheckFloat64HoleAllowReturnHoleOperator; case CheckFloat64HoleMode::kNeverReturnHole: return &cache_.kCheckFloat64HoleNeverReturnHoleOperator; } UNREACHABLE(); return nullptr; } const Operator* SimplifiedOperatorBuilder::EnsureWritableFastElements() { return &cache_.kEnsureWritableFastElements; } const Operator* SimplifiedOperatorBuilder::MaybeGrowFastElements( GrowFastElementsFlags flags) { return new (zone()) Operator1<GrowFastElementsFlags>( // -- IrOpcode::kMaybeGrowFastElements, // opcode Operator::kNoThrow, // flags "MaybeGrowFastElements", // name 4, 1, 1, 1, 1, 0, // counts flags); // parameter } const Operator* SimplifiedOperatorBuilder::TransitionElementsKind( ElementsTransition transition) { return new (zone()) Operator1<ElementsTransition>( // -- IrOpcode::kTransitionElementsKind, // opcode Operator::kNoDeopt | Operator::kNoThrow, // flags "TransitionElementsKind", // name 1, 1, 1, 0, 1, 0, // counts transition); // parameter } const Operator* SimplifiedOperatorBuilder::NewUnmappedArgumentsElements( int parameter_count) { return new (zone()) Operator1<int>( // -- IrOpcode::kNewUnmappedArgumentsElements, // opcode Operator::kEliminatable, // flags "NewUnmappedArgumentsElements", // name 0, 1, 0, 1, 1, 0, // counts parameter_count); // parameter } const Operator* SimplifiedOperatorBuilder::NewRestParameterElements( int parameter_count) { return new (zone()) Operator1<int>( // -- IrOpcode::kNewRestParameterElements, // opcode Operator::kEliminatable, // flags "NewRestParameterElements", // name 0, 1, 0, 1, 1, 0, // counts parameter_count); // parameter } const Operator* SimplifiedOperatorBuilder::Allocate(PretenureFlag pretenure) { switch (pretenure) { case NOT_TENURED: return &cache_.kAllocateNotTenuredOperator; case TENURED: return &cache_.kAllocateTenuredOperator; } UNREACHABLE(); return nullptr; } const Operator* SimplifiedOperatorBuilder::LoadBuffer(BufferAccess access) { switch (access.external_array_type()) { #define LOAD_BUFFER(Type, type, TYPE, ctype, size) \ case kExternal##Type##Array: \ return &cache_.kLoadBuffer##Type; TYPED_ARRAYS(LOAD_BUFFER) #undef LOAD_BUFFER } UNREACHABLE(); return nullptr; } const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) { switch (access.external_array_type()) { #define STORE_BUFFER(Type, type, TYPE, ctype, size) \ case kExternal##Type##Array: \ return &cache_.kStoreBuffer##Type; TYPED_ARRAYS(STORE_BUFFER) #undef STORE_BUFFER } UNREACHABLE(); return nullptr; } const Operator* SimplifiedOperatorBuilder::StringFromCodePoint( UnicodeEncoding encoding) { switch (encoding) { case UnicodeEncoding::UTF16: return &cache_.kStringFromCodePointOperatorUTF16; case UnicodeEncoding::UTF32: return &cache_.kStringFromCodePointOperatorUTF32; } UNREACHABLE(); return nullptr; } #define SPECULATIVE_NUMBER_BINOP(Name) \ const Operator* SimplifiedOperatorBuilder::Name(NumberOperationHint hint) { \ switch (hint) { \ case NumberOperationHint::kSignedSmall: \ return &cache_.k##Name##SignedSmallOperator; \ case NumberOperationHint::kSigned32: \ return &cache_.k##Name##Signed32Operator; \ case NumberOperationHint::kNumber: \ return &cache_.k##Name##NumberOperator; \ case NumberOperationHint::kNumberOrOddball: \ return &cache_.k##Name##NumberOrOddballOperator; \ } \ UNREACHABLE(); \ return nullptr; \ } SPECULATIVE_NUMBER_BINOP_LIST(SPECULATIVE_NUMBER_BINOP) #undef SPECULATIVE_NUMBER_BINOP #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(StoreTypedElement, 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 new (zone()) \ 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 } // namespace compiler } // namespace internal } // namespace v8