1 // Copyright 2014 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_COMPILER_COMMON_OPERATOR_H_ 6 #define V8_COMPILER_COMMON_OPERATOR_H_ 7 8 #include "src/base/compiler-specific.h" 9 #include "src/compiler/frame-states.h" 10 #include "src/deoptimize-reason.h" 11 #include "src/globals.h" 12 #include "src/machine-type.h" 13 #include "src/reloc-info.h" 14 #include "src/vector-slot-pair.h" 15 #include "src/zone/zone-containers.h" 16 #include "src/zone/zone-handle-set.h" 17 18 namespace v8 { 19 namespace internal { 20 namespace compiler { 21 22 // Forward declarations. 23 class CallDescriptor; 24 struct CommonOperatorGlobalCache; 25 class Operator; 26 class Type; 27 class Node; 28 29 // Prediction hint for branches. 30 enum class BranchHint : uint8_t { kNone, kTrue, kFalse }; 31 32 inline BranchHint NegateBranchHint(BranchHint hint) { 33 switch (hint) { 34 case BranchHint::kNone: 35 return hint; 36 case BranchHint::kTrue: 37 return BranchHint::kFalse; 38 case BranchHint::kFalse: 39 return BranchHint::kTrue; 40 } 41 UNREACHABLE(); 42 } 43 44 inline size_t hash_value(BranchHint hint) { return static_cast<size_t>(hint); } 45 46 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, BranchHint); 47 48 enum class IsSafetyCheck : uint8_t { 49 kCriticalSafetyCheck, 50 kSafetyCheck, 51 kNoSafetyCheck 52 }; 53 54 // Get the more critical safety check of the two arguments. 55 IsSafetyCheck CombineSafetyChecks(IsSafetyCheck, IsSafetyCheck); 56 57 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, IsSafetyCheck); 58 inline size_t hash_value(IsSafetyCheck is_safety_check) { 59 return static_cast<size_t>(is_safety_check); 60 } 61 62 enum class TrapId : uint32_t { 63 #define DEF_ENUM(Name, ...) k##Name, 64 FOREACH_WASM_TRAPREASON(DEF_ENUM) 65 #undef DEF_ENUM 66 kInvalid 67 }; 68 69 inline size_t hash_value(TrapId id) { return static_cast<uint32_t>(id); } 70 71 std::ostream& operator<<(std::ostream&, TrapId trap_id); 72 73 TrapId TrapIdOf(const Operator* const op); 74 75 struct BranchOperatorInfo { 76 BranchHint hint; 77 IsSafetyCheck is_safety_check; 78 }; 79 80 inline size_t hash_value(const BranchOperatorInfo& info) { 81 return base::hash_combine(info.hint, info.is_safety_check); 82 } 83 84 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, BranchOperatorInfo); 85 86 inline bool operator==(const BranchOperatorInfo& a, 87 const BranchOperatorInfo& b) { 88 return a.hint == b.hint && a.is_safety_check == b.is_safety_check; 89 } 90 91 V8_EXPORT_PRIVATE const BranchOperatorInfo& BranchOperatorInfoOf( 92 const Operator* const) V8_WARN_UNUSED_RESULT; 93 V8_EXPORT_PRIVATE BranchHint BranchHintOf(const Operator* const) 94 V8_WARN_UNUSED_RESULT; 95 96 // Helper function for return nodes, because returns have a hidden value input. 97 int ValueInputCountOfReturn(Operator const* const op); 98 99 // Parameters for the {Deoptimize} operator. 100 class DeoptimizeParameters final { 101 public: 102 DeoptimizeParameters(DeoptimizeKind kind, DeoptimizeReason reason, 103 VectorSlotPair const& feedback, 104 IsSafetyCheck is_safety_check) 105 : kind_(kind), 106 reason_(reason), 107 feedback_(feedback), 108 is_safety_check_(is_safety_check) {} 109 110 DeoptimizeKind kind() const { return kind_; } 111 DeoptimizeReason reason() const { return reason_; } 112 const VectorSlotPair& feedback() const { return feedback_; } 113 IsSafetyCheck is_safety_check() const { return is_safety_check_; } 114 115 private: 116 DeoptimizeKind const kind_; 117 DeoptimizeReason const reason_; 118 VectorSlotPair const feedback_; 119 IsSafetyCheck is_safety_check_; 120 }; 121 122 bool operator==(DeoptimizeParameters, DeoptimizeParameters); 123 bool operator!=(DeoptimizeParameters, DeoptimizeParameters); 124 125 size_t hast_value(DeoptimizeParameters p); 126 127 std::ostream& operator<<(std::ostream&, DeoptimizeParameters p); 128 129 DeoptimizeParameters const& DeoptimizeParametersOf(Operator const* const) 130 V8_WARN_UNUSED_RESULT; 131 132 IsSafetyCheck IsSafetyCheckOf(const Operator* op) V8_WARN_UNUSED_RESULT; 133 134 class SelectParameters final { 135 public: 136 explicit SelectParameters(MachineRepresentation representation, 137 BranchHint hint = BranchHint::kNone) 138 : representation_(representation), hint_(hint) {} 139 140 MachineRepresentation representation() const { return representation_; } 141 BranchHint hint() const { return hint_; } 142 143 private: 144 const MachineRepresentation representation_; 145 const BranchHint hint_; 146 }; 147 148 bool operator==(SelectParameters const&, SelectParameters const&); 149 bool operator!=(SelectParameters const&, SelectParameters const&); 150 151 size_t hash_value(SelectParameters const& p); 152 153 std::ostream& operator<<(std::ostream&, SelectParameters const& p); 154 155 V8_EXPORT_PRIVATE SelectParameters const& SelectParametersOf( 156 const Operator* const) V8_WARN_UNUSED_RESULT; 157 158 V8_EXPORT_PRIVATE CallDescriptor const* CallDescriptorOf(const Operator* const) 159 V8_WARN_UNUSED_RESULT; 160 161 V8_EXPORT_PRIVATE size_t ProjectionIndexOf(const Operator* const) 162 V8_WARN_UNUSED_RESULT; 163 164 V8_EXPORT_PRIVATE MachineRepresentation 165 PhiRepresentationOf(const Operator* const) V8_WARN_UNUSED_RESULT; 166 167 // The {IrOpcode::kParameter} opcode represents an incoming parameter to the 168 // function. This class bundles the index and a debug name for such operators. 169 class ParameterInfo final { 170 public: 171 ParameterInfo(int index, const char* debug_name) 172 : index_(index), debug_name_(debug_name) {} 173 174 int index() const { return index_; } 175 const char* debug_name() const { return debug_name_; } 176 177 private: 178 int index_; 179 const char* debug_name_; 180 }; 181 182 std::ostream& operator<<(std::ostream&, ParameterInfo const&); 183 184 V8_EXPORT_PRIVATE int ParameterIndexOf(const Operator* const) 185 V8_WARN_UNUSED_RESULT; 186 const ParameterInfo& ParameterInfoOf(const Operator* const) 187 V8_WARN_UNUSED_RESULT; 188 189 struct ObjectStateInfo final : std::pair<uint32_t, int> { 190 ObjectStateInfo(uint32_t object_id, int size) 191 : std::pair<uint32_t, int>(object_id, size) {} 192 uint32_t object_id() const { return first; } 193 int size() const { return second; } 194 }; 195 std::ostream& operator<<(std::ostream&, ObjectStateInfo const&); 196 size_t hash_value(ObjectStateInfo const& p); 197 198 struct TypedObjectStateInfo final 199 : std::pair<uint32_t, const ZoneVector<MachineType>*> { 200 TypedObjectStateInfo(uint32_t object_id, 201 const ZoneVector<MachineType>* machine_types) 202 : std::pair<uint32_t, const ZoneVector<MachineType>*>(object_id, 203 machine_types) {} 204 uint32_t object_id() const { return first; } 205 const ZoneVector<MachineType>* machine_types() const { return second; } 206 }; 207 std::ostream& operator<<(std::ostream&, TypedObjectStateInfo const&); 208 size_t hash_value(TypedObjectStateInfo const& p); 209 210 class RelocatablePtrConstantInfo final { 211 public: 212 enum Type { kInt32, kInt64 }; 213 214 RelocatablePtrConstantInfo(int32_t value, RelocInfo::Mode rmode) 215 : value_(value), rmode_(rmode), type_(kInt32) {} 216 RelocatablePtrConstantInfo(int64_t value, RelocInfo::Mode rmode) 217 : value_(value), rmode_(rmode), type_(kInt64) {} 218 219 intptr_t value() const { return value_; } 220 RelocInfo::Mode rmode() const { return rmode_; } 221 Type type() const { return type_; } 222 223 private: 224 intptr_t value_; 225 RelocInfo::Mode rmode_; 226 Type type_; 227 }; 228 229 bool operator==(RelocatablePtrConstantInfo const& lhs, 230 RelocatablePtrConstantInfo const& rhs); 231 bool operator!=(RelocatablePtrConstantInfo const& lhs, 232 RelocatablePtrConstantInfo const& rhs); 233 234 std::ostream& operator<<(std::ostream&, RelocatablePtrConstantInfo const&); 235 236 size_t hash_value(RelocatablePtrConstantInfo const& p); 237 238 // Used to define a sparse set of inputs. This can be used to efficiently encode 239 // nodes that can have a lot of inputs, but where many inputs can have the same 240 // value. 241 class SparseInputMask final { 242 public: 243 typedef uint32_t BitMaskType; 244 245 // The mask representing a dense input set. 246 static const BitMaskType kDenseBitMask = 0x0; 247 // The bits representing the end of a sparse input set. 248 static const BitMaskType kEndMarker = 0x1; 249 // The mask for accessing a sparse input entry in the bitmask. 250 static const BitMaskType kEntryMask = 0x1; 251 252 // The number of bits in the mask, minus one for the end marker. 253 static const int kMaxSparseInputs = (sizeof(BitMaskType) * kBitsPerByte - 1); 254 255 // An iterator over a node's sparse inputs. 256 class InputIterator final { 257 public: 258 InputIterator() {} 259 InputIterator(BitMaskType bit_mask, Node* parent); 260 261 Node* parent() const { return parent_; } 262 int real_index() const { return real_index_; } 263 264 // Advance the iterator to the next sparse input. Only valid if the iterator 265 // has not reached the end. 266 void Advance(); 267 268 // Get the current sparse input's real node value. Only valid if the 269 // current sparse input is real. 270 Node* GetReal() const; 271 272 // Get the current sparse input, returning either a real input node if 273 // the current sparse input is real, or the given {empty_value} if the 274 // current sparse input is empty. 275 Node* Get(Node* empty_value) const { 276 return IsReal() ? GetReal() : empty_value; 277 } 278 279 // True if the current sparse input is a real input node. 280 bool IsReal() const; 281 282 // True if the current sparse input is an empty value. 283 bool IsEmpty() const { return !IsReal(); } 284 285 // True if the iterator has reached the end of the sparse inputs. 286 bool IsEnd() const; 287 288 private: 289 BitMaskType bit_mask_; 290 Node* parent_; 291 int real_index_; 292 }; 293 294 explicit SparseInputMask(BitMaskType bit_mask) : bit_mask_(bit_mask) {} 295 296 // Provides a SparseInputMask representing a dense input set. 297 static SparseInputMask Dense() { return SparseInputMask(kDenseBitMask); } 298 299 BitMaskType mask() const { return bit_mask_; } 300 301 bool IsDense() const { return bit_mask_ == SparseInputMask::kDenseBitMask; } 302 303 // Counts how many real values are in the sparse array. Only valid for 304 // non-dense masks. 305 int CountReal() const; 306 307 // Returns an iterator over the sparse inputs of {node}. 308 InputIterator IterateOverInputs(Node* node); 309 310 private: 311 // 312 // The sparse input mask has a bitmask specifying if the node's inputs are 313 // represented sparsely. If the bitmask value is 0, then the inputs are dense; 314 // otherwise, they should be interpreted as follows: 315 // 316 // * The bitmask represents which values are real, with 1 for real values 317 // and 0 for empty values. 318 // * The inputs to the node are the real values, in the order of the 1s from 319 // least- to most-significant. 320 // * The top bit of the bitmask is a guard indicating the end of the values, 321 // whether real or empty (and is not representative of a real input 322 // itself). This is used so that we don't have to additionally store a 323 // value count. 324 // 325 // So, for N 1s in the bitmask, there are N - 1 inputs into the node. 326 BitMaskType bit_mask_; 327 }; 328 329 bool operator==(SparseInputMask const& lhs, SparseInputMask const& rhs); 330 bool operator!=(SparseInputMask const& lhs, SparseInputMask const& rhs); 331 332 class TypedStateValueInfo final { 333 public: 334 TypedStateValueInfo(ZoneVector<MachineType> const* machine_types, 335 SparseInputMask sparse_input_mask) 336 : machine_types_(machine_types), sparse_input_mask_(sparse_input_mask) {} 337 338 ZoneVector<MachineType> const* machine_types() const { 339 return machine_types_; 340 } 341 SparseInputMask sparse_input_mask() const { return sparse_input_mask_; } 342 343 private: 344 ZoneVector<MachineType> const* machine_types_; 345 SparseInputMask sparse_input_mask_; 346 }; 347 348 bool operator==(TypedStateValueInfo const& lhs, TypedStateValueInfo const& rhs); 349 bool operator!=(TypedStateValueInfo const& lhs, TypedStateValueInfo const& rhs); 350 351 std::ostream& operator<<(std::ostream&, TypedStateValueInfo const&); 352 353 size_t hash_value(TypedStateValueInfo const& p); 354 355 // Used to mark a region (as identified by BeginRegion/FinishRegion) as either 356 // JavaScript-observable or not (i.e. allocations are not JavaScript observable 357 // themselves, but transitioning stores are). 358 enum class RegionObservability : uint8_t { kObservable, kNotObservable }; 359 360 size_t hash_value(RegionObservability); 361 362 std::ostream& operator<<(std::ostream&, RegionObservability); 363 364 RegionObservability RegionObservabilityOf(Operator const*) 365 V8_WARN_UNUSED_RESULT; 366 367 std::ostream& operator<<(std::ostream& os, 368 const ZoneVector<MachineType>* types); 369 370 Type TypeGuardTypeOf(Operator const*) V8_WARN_UNUSED_RESULT; 371 372 int OsrValueIndexOf(Operator const*) V8_WARN_UNUSED_RESULT; 373 374 SparseInputMask SparseInputMaskOf(Operator const*) V8_WARN_UNUSED_RESULT; 375 376 ZoneVector<MachineType> const* MachineTypesOf(Operator const*) 377 V8_WARN_UNUSED_RESULT; 378 379 // The ArgumentsElementsState and ArgumentsLengthState can describe the layout 380 // for backing stores of arguments objects of various types: 381 // 382 // +------------------------------------+ 383 // - kUnmappedArguments: | arg0, ... argK-1, argK, ... argN-1 | {length:N} 384 // +------------------------------------+ 385 // +------------------------------------+ 386 // - kMappedArguments: | hole, ... hole, argK, ... argN-1 | {length:N} 387 // +------------------------------------+ 388 // +------------------+ 389 // - kRestParameter: | argK, ... argN-1 | {length:N-K} 390 // +------------------+ 391 // 392 // Here {K} represents the number for formal parameters of the active function, 393 // whereas {N} represents the actual number of arguments passed at runtime. 394 // Note that {N < K} can happen and causes {K} to be capped accordingly. 395 // 396 // Also note that it is possible for an arguments object of {kMappedArguments} 397 // type to carry a backing store of {kUnappedArguments} type when {K == 0}. 398 typedef CreateArgumentsType ArgumentsStateType; 399 400 ArgumentsStateType ArgumentsStateTypeOf(Operator const*) V8_WARN_UNUSED_RESULT; 401 402 uint32_t ObjectIdOf(Operator const*); 403 404 MachineRepresentation DeadValueRepresentationOf(Operator const*) 405 V8_WARN_UNUSED_RESULT; 406 407 class IfValueParameters final { 408 public: 409 IfValueParameters(int32_t value, int32_t comparison_order) 410 : value_(value), comparison_order_(comparison_order) {} 411 412 int32_t value() const { return value_; } 413 int32_t comparison_order() const { return comparison_order_; } 414 415 private: 416 int32_t value_; 417 int32_t comparison_order_; 418 }; 419 420 V8_EXPORT_PRIVATE bool operator==(IfValueParameters const&, 421 IfValueParameters const&); 422 423 size_t hash_value(IfValueParameters const&); 424 425 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, 426 IfValueParameters const&); 427 428 V8_EXPORT_PRIVATE IfValueParameters const& IfValueParametersOf( 429 const Operator* op) V8_WARN_UNUSED_RESULT; 430 431 const FrameStateInfo& FrameStateInfoOf(const Operator* op) 432 V8_WARN_UNUSED_RESULT; 433 434 Handle<HeapObject> HeapConstantOf(const Operator* op) V8_WARN_UNUSED_RESULT; 435 436 // Interface for building common operators that can be used at any level of IR, 437 // including JavaScript, mid-level, and low-level. 438 class V8_EXPORT_PRIVATE CommonOperatorBuilder final 439 : public NON_EXPORTED_BASE(ZoneObject) { 440 public: 441 explicit CommonOperatorBuilder(Zone* zone); 442 443 const Operator* Dead(); 444 const Operator* DeadValue(MachineRepresentation rep); 445 const Operator* Unreachable(); 446 const Operator* End(size_t control_input_count); 447 const Operator* Branch(BranchHint = BranchHint::kNone, 448 IsSafetyCheck = IsSafetyCheck::kSafetyCheck); 449 const Operator* IfTrue(); 450 const Operator* IfFalse(); 451 const Operator* IfSuccess(); 452 const Operator* IfException(); 453 const Operator* Switch(size_t control_output_count); 454 const Operator* IfValue(int32_t value, int32_t order = 0); 455 const Operator* IfDefault(); 456 const Operator* Throw(); 457 const Operator* Deoptimize(DeoptimizeKind kind, DeoptimizeReason reason, 458 VectorSlotPair const& feedback); 459 const Operator* DeoptimizeIf( 460 DeoptimizeKind kind, DeoptimizeReason reason, 461 VectorSlotPair const& feedback, 462 IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck); 463 const Operator* DeoptimizeUnless( 464 DeoptimizeKind kind, DeoptimizeReason reason, 465 VectorSlotPair const& feedback, 466 IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck); 467 const Operator* TrapIf(TrapId trap_id); 468 const Operator* TrapUnless(TrapId trap_id); 469 const Operator* Return(int value_input_count = 1); 470 const Operator* Terminate(); 471 472 const Operator* Start(int value_output_count); 473 const Operator* Loop(int control_input_count); 474 const Operator* Merge(int control_input_count); 475 const Operator* Parameter(int index, const char* debug_name = nullptr); 476 477 const Operator* OsrNormalEntry(); 478 const Operator* OsrLoopEntry(); 479 const Operator* OsrValue(int index); 480 481 const Operator* Int32Constant(int32_t); 482 const Operator* Int64Constant(int64_t); 483 const Operator* Float32Constant(volatile float); 484 const Operator* Float64Constant(volatile double); 485 const Operator* ExternalConstant(const ExternalReference&); 486 const Operator* NumberConstant(volatile double); 487 const Operator* PointerConstant(intptr_t); 488 const Operator* HeapConstant(const Handle<HeapObject>&); 489 const Operator* ObjectId(uint32_t); 490 491 const Operator* RelocatableInt32Constant(int32_t value, 492 RelocInfo::Mode rmode); 493 const Operator* RelocatableInt64Constant(int64_t value, 494 RelocInfo::Mode rmode); 495 496 const Operator* Select(MachineRepresentation, BranchHint = BranchHint::kNone); 497 const Operator* Phi(MachineRepresentation representation, 498 int value_input_count); 499 const Operator* EffectPhi(int effect_input_count); 500 const Operator* InductionVariablePhi(int value_input_count); 501 const Operator* LoopExit(); 502 const Operator* LoopExitValue(); 503 const Operator* LoopExitEffect(); 504 const Operator* Checkpoint(); 505 const Operator* BeginRegion(RegionObservability); 506 const Operator* FinishRegion(); 507 const Operator* StateValues(int arguments, SparseInputMask bitmask); 508 const Operator* TypedStateValues(const ZoneVector<MachineType>* types, 509 SparseInputMask bitmask); 510 const Operator* ArgumentsElementsState(ArgumentsStateType type); 511 const Operator* ArgumentsLengthState(ArgumentsStateType type); 512 const Operator* ObjectState(uint32_t object_id, int pointer_slots); 513 const Operator* TypedObjectState(uint32_t object_id, 514 const ZoneVector<MachineType>* types); 515 const Operator* FrameState(BailoutId bailout_id, 516 OutputFrameStateCombine state_combine, 517 const FrameStateFunctionInfo* function_info); 518 const Operator* Call(const CallDescriptor* call_descriptor); 519 const Operator* CallWithCallerSavedRegisters( 520 const CallDescriptor* call_descriptor); 521 const Operator* TailCall(const CallDescriptor* call_descriptor); 522 const Operator* Projection(size_t index); 523 const Operator* Retain(); 524 const Operator* TypeGuard(Type type); 525 526 // Constructs a new merge or phi operator with the same opcode as {op}, but 527 // with {size} inputs. 528 const Operator* ResizeMergeOrPhi(const Operator* op, int size); 529 530 // Constructs function info for frame state construction. 531 const FrameStateFunctionInfo* CreateFrameStateFunctionInfo( 532 FrameStateType type, int parameter_count, int local_count, 533 Handle<SharedFunctionInfo> shared_info); 534 535 const Operator* MarkAsSafetyCheck(const Operator* op, 536 IsSafetyCheck safety_check); 537 538 private: 539 Zone* zone() const { return zone_; } 540 541 const CommonOperatorGlobalCache& cache_; 542 Zone* const zone_; 543 544 DISALLOW_COPY_AND_ASSIGN(CommonOperatorBuilder); 545 }; 546 547 } // namespace compiler 548 } // namespace internal 549 } // namespace v8 550 551 #endif // V8_COMPILER_COMMON_OPERATOR_H_ 552