1 // Copyright 2015 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_CODE_ASSEMBLER_H_ 6 #define V8_COMPILER_CODE_ASSEMBLER_H_ 7 8 #include <map> 9 #include <memory> 10 11 // Clients of this interface shouldn't depend on lots of compiler internals. 12 // Do not include anything from src/compiler here! 13 #include "src/allocation.h" 14 #include "src/base/macros.h" 15 #include "src/builtins/builtins.h" 16 #include "src/code-factory.h" 17 #include "src/globals.h" 18 #include "src/heap/heap.h" 19 #include "src/machine-type.h" 20 #include "src/objects.h" 21 #include "src/objects/data-handler.h" 22 #include "src/objects/map.h" 23 #include "src/objects/maybe-object.h" 24 #include "src/runtime/runtime.h" 25 #include "src/zone/zone-containers.h" 26 27 namespace v8 { 28 namespace internal { 29 30 class Callable; 31 class CallInterfaceDescriptor; 32 class Isolate; 33 class JSCollection; 34 class JSRegExpStringIterator; 35 class JSWeakCollection; 36 class JSWeakMap; 37 class JSWeakSet; 38 class MaybeObject; 39 class PromiseCapability; 40 class PromiseFulfillReactionJobTask; 41 class PromiseReaction; 42 class PromiseReactionJobTask; 43 class PromiseRejectReactionJobTask; 44 class InterpreterData; 45 class Factory; 46 class Zone; 47 48 template <typename T> 49 class Signature; 50 51 struct UntaggedT {}; 52 53 struct IntegralT : UntaggedT {}; 54 55 struct WordT : IntegralT { 56 static const MachineRepresentation kMachineRepresentation = 57 (kPointerSize == 4) ? MachineRepresentation::kWord32 58 : MachineRepresentation::kWord64; 59 }; 60 61 struct RawPtrT : WordT { 62 static constexpr MachineType kMachineType = MachineType::Pointer(); 63 }; 64 65 template <class To> 66 struct RawPtr : RawPtrT {}; 67 68 struct Word32T : IntegralT { 69 static const MachineRepresentation kMachineRepresentation = 70 MachineRepresentation::kWord32; 71 }; 72 struct Int32T : Word32T { 73 static constexpr MachineType kMachineType = MachineType::Int32(); 74 }; 75 struct Uint32T : Word32T { 76 static constexpr MachineType kMachineType = MachineType::Uint32(); 77 }; 78 79 struct Word64T : IntegralT { 80 static const MachineRepresentation kMachineRepresentation = 81 MachineRepresentation::kWord64; 82 }; 83 struct Int64T : Word64T { 84 static constexpr MachineType kMachineType = MachineType::Int64(); 85 }; 86 struct Uint64T : Word64T { 87 static constexpr MachineType kMachineType = MachineType::Uint64(); 88 }; 89 90 struct IntPtrT : WordT { 91 static constexpr MachineType kMachineType = MachineType::IntPtr(); 92 }; 93 struct UintPtrT : WordT { 94 static constexpr MachineType kMachineType = MachineType::UintPtr(); 95 }; 96 97 struct Float32T : UntaggedT { 98 static const MachineRepresentation kMachineRepresentation = 99 MachineRepresentation::kFloat32; 100 static constexpr MachineType kMachineType = MachineType::Float32(); 101 }; 102 103 struct Float64T : UntaggedT { 104 static const MachineRepresentation kMachineRepresentation = 105 MachineRepresentation::kFloat64; 106 static constexpr MachineType kMachineType = MachineType::Float64(); 107 }; 108 109 // Result of a comparison operation. 110 struct BoolT : Word32T {}; 111 112 // Value type of a Turbofan node with two results. 113 template <class T1, class T2> 114 struct PairT {}; 115 116 inline constexpr MachineType CommonMachineType(MachineType type1, 117 MachineType type2) { 118 return (type1 == type2) ? type1 119 : ((type1.IsTagged() && type2.IsTagged()) 120 ? MachineType::AnyTagged() 121 : MachineType::None()); 122 } 123 124 template <class Type, class Enable = void> 125 struct MachineTypeOf { 126 static constexpr MachineType value = Type::kMachineType; 127 }; 128 129 template <class Type, class Enable> 130 constexpr MachineType MachineTypeOf<Type, Enable>::value; 131 132 template <> 133 struct MachineTypeOf<Object> { 134 static constexpr MachineType value = MachineType::AnyTagged(); 135 }; 136 template <> 137 struct MachineTypeOf<MaybeObject> { 138 static constexpr MachineType value = MachineType::AnyTagged(); 139 }; 140 template <> 141 struct MachineTypeOf<Smi> { 142 static constexpr MachineType value = MachineType::TaggedSigned(); 143 }; 144 template <class HeapObjectSubtype> 145 struct MachineTypeOf<HeapObjectSubtype, 146 typename std::enable_if<std::is_base_of< 147 HeapObject, HeapObjectSubtype>::value>::type> { 148 static constexpr MachineType value = MachineType::TaggedPointer(); 149 }; 150 151 template <class HeapObjectSubtype> 152 constexpr MachineType MachineTypeOf< 153 HeapObjectSubtype, typename std::enable_if<std::is_base_of< 154 HeapObject, HeapObjectSubtype>::value>::type>::value; 155 156 template <class Type, class Enable = void> 157 struct MachineRepresentationOf { 158 static const MachineRepresentation value = Type::kMachineRepresentation; 159 }; 160 template <class T> 161 struct MachineRepresentationOf< 162 T, typename std::enable_if<std::is_base_of<Object, T>::value>::type> { 163 static const MachineRepresentation value = 164 MachineTypeOf<T>::value.representation(); 165 }; 166 template <class T> 167 struct MachineRepresentationOf< 168 T, typename std::enable_if<std::is_base_of<MaybeObject, T>::value>::type> { 169 static const MachineRepresentation value = 170 MachineTypeOf<T>::value.representation(); 171 }; 172 173 template <class T> 174 struct is_valid_type_tag { 175 static const bool value = std::is_base_of<Object, T>::value || 176 std::is_base_of<UntaggedT, T>::value || 177 std::is_base_of<MaybeObject, T>::value || 178 std::is_same<ExternalReference, T>::value; 179 static const bool is_tagged = std::is_base_of<Object, T>::value || 180 std::is_base_of<MaybeObject, T>::value; 181 }; 182 183 template <class T1, class T2> 184 struct is_valid_type_tag<PairT<T1, T2>> { 185 static const bool value = 186 is_valid_type_tag<T1>::value && is_valid_type_tag<T2>::value; 187 static const bool is_tagged = false; 188 }; 189 190 template <class T1, class T2> 191 struct UnionT; 192 193 template <class T1, class T2> 194 struct is_valid_type_tag<UnionT<T1, T2>> { 195 static const bool is_tagged = 196 is_valid_type_tag<T1>::is_tagged && is_valid_type_tag<T2>::is_tagged; 197 static const bool value = is_tagged; 198 }; 199 200 template <class T1, class T2> 201 struct UnionT { 202 static constexpr MachineType kMachineType = 203 CommonMachineType(MachineTypeOf<T1>::value, MachineTypeOf<T2>::value); 204 static const MachineRepresentation kMachineRepresentation = 205 kMachineType.representation(); 206 static_assert(kMachineRepresentation != MachineRepresentation::kNone, 207 "no common representation"); 208 static_assert(is_valid_type_tag<T1>::is_tagged && 209 is_valid_type_tag<T2>::is_tagged, 210 "union types are only possible for tagged values"); 211 }; 212 213 using Number = UnionT<Smi, HeapNumber>; 214 using Numeric = UnionT<Number, BigInt>; 215 216 #define ENUM_ELEMENT(Name) k##Name, 217 #define ENUM_STRUCT_ELEMENT(NAME, Name, name) k##Name, 218 enum class ObjectType { 219 kObject, 220 OBJECT_TYPE_LIST(ENUM_ELEMENT) HEAP_OBJECT_TYPE_LIST(ENUM_ELEMENT) 221 STRUCT_LIST(ENUM_STRUCT_ELEMENT) 222 }; 223 #undef ENUM_ELEMENT 224 #undef ENUM_STRUCT_ELEMENT 225 226 class AccessCheckNeeded; 227 class BigIntWrapper; 228 class ClassBoilerplate; 229 class BooleanWrapper; 230 class CompilationCacheTable; 231 class Constructor; 232 class Filler; 233 class InternalizedString; 234 class JSArgumentsObject; 235 class JSContextExtensionObject; 236 class JSError; 237 class JSSloppyArgumentsObject; 238 class MapCache; 239 class MutableHeapNumber; 240 class NativeContext; 241 class NumberWrapper; 242 class ScriptWrapper; 243 class SloppyArgumentsElements; 244 class StringWrapper; 245 class SymbolWrapper; 246 class Undetectable; 247 class UniqueName; 248 class WasmExportedFunctionData; 249 class WasmGlobalObject; 250 class WasmMemoryObject; 251 class WasmModuleObject; 252 class WasmTableObject; 253 254 template <class T> 255 struct ObjectTypeOf {}; 256 257 #define OBJECT_TYPE_CASE(Name) \ 258 template <> \ 259 struct ObjectTypeOf<Name> { \ 260 static const ObjectType value = ObjectType::k##Name; \ 261 }; 262 #define OBJECT_TYPE_STRUCT_CASE(NAME, Name, name) \ 263 template <> \ 264 struct ObjectTypeOf<Name> { \ 265 static const ObjectType value = ObjectType::k##Name; \ 266 }; 267 #define OBJECT_TYPE_TEMPLATE_CASE(Name) \ 268 template <class... Args> \ 269 struct ObjectTypeOf<Name<Args...>> { \ 270 static const ObjectType value = ObjectType::k##Name; \ 271 }; 272 OBJECT_TYPE_CASE(Object) 273 OBJECT_TYPE_LIST(OBJECT_TYPE_CASE) 274 HEAP_OBJECT_ORDINARY_TYPE_LIST(OBJECT_TYPE_CASE) 275 STRUCT_LIST(OBJECT_TYPE_STRUCT_CASE) 276 HEAP_OBJECT_TEMPLATE_TYPE_LIST(OBJECT_TYPE_TEMPLATE_CASE) 277 #undef OBJECT_TYPE_CASE 278 #undef OBJECT_TYPE_STRUCT_CASE 279 #undef OBJECT_TYPE_TEMPLATE_CASE 280 281 Smi* CheckObjectType(Object* value, Smi* type, String* location); 282 283 namespace compiler { 284 285 class CallDescriptor; 286 class CodeAssemblerLabel; 287 class CodeAssemblerVariable; 288 template <class T> 289 class TypedCodeAssemblerVariable; 290 class CodeAssemblerState; 291 class Node; 292 class RawMachineAssembler; 293 class RawMachineLabel; 294 295 typedef ZoneVector<CodeAssemblerVariable*> CodeAssemblerVariableList; 296 297 typedef std::function<void()> CodeAssemblerCallback; 298 299 template <class T, class U> 300 struct is_subtype { 301 static const bool value = std::is_base_of<U, T>::value; 302 }; 303 template <class T1, class T2, class U> 304 struct is_subtype<UnionT<T1, T2>, U> { 305 static const bool value = 306 is_subtype<T1, U>::value && is_subtype<T2, U>::value; 307 }; 308 template <class T, class U1, class U2> 309 struct is_subtype<T, UnionT<U1, U2>> { 310 static const bool value = 311 is_subtype<T, U1>::value || is_subtype<T, U2>::value; 312 }; 313 template <class T1, class T2, class U1, class U2> 314 struct is_subtype<UnionT<T1, T2>, UnionT<U1, U2>> { 315 static const bool value = 316 (is_subtype<T1, U1>::value || is_subtype<T1, U2>::value) && 317 (is_subtype<T2, U1>::value || is_subtype<T2, U2>::value); 318 }; 319 320 template <class T, class U> 321 struct types_have_common_values { 322 static const bool value = is_subtype<T, U>::value || is_subtype<U, T>::value; 323 }; 324 template <class U> 325 struct types_have_common_values<Uint32T, U> { 326 static const bool value = types_have_common_values<Word32T, U>::value; 327 }; 328 template <class U> 329 struct types_have_common_values<Int32T, U> { 330 static const bool value = types_have_common_values<Word32T, U>::value; 331 }; 332 template <class U> 333 struct types_have_common_values<Uint64T, U> { 334 static const bool value = types_have_common_values<Word64T, U>::value; 335 }; 336 template <class U> 337 struct types_have_common_values<Int64T, U> { 338 static const bool value = types_have_common_values<Word64T, U>::value; 339 }; 340 template <class U> 341 struct types_have_common_values<IntPtrT, U> { 342 static const bool value = types_have_common_values<WordT, U>::value; 343 }; 344 template <class U> 345 struct types_have_common_values<UintPtrT, U> { 346 static const bool value = types_have_common_values<WordT, U>::value; 347 }; 348 template <class T1, class T2, class U> 349 struct types_have_common_values<UnionT<T1, T2>, U> { 350 static const bool value = types_have_common_values<T1, U>::value || 351 types_have_common_values<T2, U>::value; 352 }; 353 354 template <class T, class U1, class U2> 355 struct types_have_common_values<T, UnionT<U1, U2>> { 356 static const bool value = types_have_common_values<T, U1>::value || 357 types_have_common_values<T, U2>::value; 358 }; 359 template <class T1, class T2, class U1, class U2> 360 struct types_have_common_values<UnionT<T1, T2>, UnionT<U1, U2>> { 361 static const bool value = types_have_common_values<T1, U1>::value || 362 types_have_common_values<T1, U2>::value || 363 types_have_common_values<T2, U1>::value || 364 types_have_common_values<T2, U2>::value; 365 }; 366 367 template <class T> 368 struct types_have_common_values<T, MaybeObject> { 369 static const bool value = types_have_common_values<T, Object>::value; 370 }; 371 372 template <class T> 373 struct types_have_common_values<MaybeObject, T> { 374 static const bool value = types_have_common_values<Object, T>::value; 375 }; 376 377 // TNode<T> is an SSA value with the static type tag T, which is one of the 378 // following: 379 // - a subclass of internal::Object represents a tagged type 380 // - a subclass of internal::UntaggedT represents an untagged type 381 // - ExternalReference 382 // - PairT<T1, T2> for an operation returning two values, with types T1 383 // and T2 384 // - UnionT<T1, T2> represents either a value of type T1 or of type T2. 385 template <class T> 386 class TNode { 387 public: 388 static_assert(is_valid_type_tag<T>::value, "invalid type tag"); 389 390 template <class U, 391 typename std::enable_if<is_subtype<U, T>::value, int>::type = 0> 392 TNode(const TNode<U>& other) : node_(other) {} 393 TNode() : node_(nullptr) {} 394 395 TNode operator=(TNode other) { 396 DCHECK_NOT_NULL(other.node_); 397 node_ = other.node_; 398 return *this; 399 } 400 401 operator compiler::Node*() const { return node_; } 402 403 static TNode UncheckedCast(compiler::Node* node) { return TNode(node); } 404 405 protected: 406 explicit TNode(compiler::Node* node) : node_(node) {} 407 408 private: 409 compiler::Node* node_; 410 }; 411 412 // SloppyTNode<T> is a variant of TNode<T> and allows implicit casts from 413 // Node*. It is intended for function arguments as long as some call sites 414 // still use untyped Node* arguments. 415 // TODO(tebbi): Delete this class once transition is finished. 416 template <class T> 417 class SloppyTNode : public TNode<T> { 418 public: 419 SloppyTNode(compiler::Node* node) // NOLINT(runtime/explicit) 420 : TNode<T>(node) {} 421 template <class U, typename std::enable_if<is_subtype<U, T>::value, 422 int>::type = 0> 423 SloppyTNode(const TNode<U>& other) // NOLINT(runtime/explicit) 424 : TNode<T>(other) {} 425 }; 426 427 // This macro alias allows to use PairT<T1, T2> as a macro argument. 428 #define PAIR_TYPE(T1, T2) PairT<T1, T2> 429 430 #define CODE_ASSEMBLER_COMPARE_BINARY_OP_LIST(V) \ 431 V(Float32Equal, BoolT, Float32T, Float32T) \ 432 V(Float32LessThan, BoolT, Float32T, Float32T) \ 433 V(Float32LessThanOrEqual, BoolT, Float32T, Float32T) \ 434 V(Float32GreaterThan, BoolT, Float32T, Float32T) \ 435 V(Float32GreaterThanOrEqual, BoolT, Float32T, Float32T) \ 436 V(Float64Equal, BoolT, Float64T, Float64T) \ 437 V(Float64NotEqual, BoolT, Float64T, Float64T) \ 438 V(Float64LessThan, BoolT, Float64T, Float64T) \ 439 V(Float64LessThanOrEqual, BoolT, Float64T, Float64T) \ 440 V(Float64GreaterThan, BoolT, Float64T, Float64T) \ 441 V(Float64GreaterThanOrEqual, BoolT, Float64T, Float64T) \ 442 /* Use Word32Equal if you need Int32Equal */ \ 443 V(Int32GreaterThan, BoolT, Word32T, Word32T) \ 444 V(Int32GreaterThanOrEqual, BoolT, Word32T, Word32T) \ 445 V(Int32LessThan, BoolT, Word32T, Word32T) \ 446 V(Int32LessThanOrEqual, BoolT, Word32T, Word32T) \ 447 /* Use WordEqual if you need IntPtrEqual */ \ 448 V(IntPtrLessThan, BoolT, WordT, WordT) \ 449 V(IntPtrLessThanOrEqual, BoolT, WordT, WordT) \ 450 V(IntPtrGreaterThan, BoolT, WordT, WordT) \ 451 V(IntPtrGreaterThanOrEqual, BoolT, WordT, WordT) \ 452 /* Use Word32Equal if you need Uint32Equal */ \ 453 V(Uint32LessThan, BoolT, Word32T, Word32T) \ 454 V(Uint32LessThanOrEqual, BoolT, Word32T, Word32T) \ 455 V(Uint32GreaterThan, BoolT, Word32T, Word32T) \ 456 V(Uint32GreaterThanOrEqual, BoolT, Word32T, Word32T) \ 457 /* Use WordEqual if you need UintPtrEqual */ \ 458 V(UintPtrLessThan, BoolT, WordT, WordT) \ 459 V(UintPtrLessThanOrEqual, BoolT, WordT, WordT) \ 460 V(UintPtrGreaterThan, BoolT, WordT, WordT) \ 461 V(UintPtrGreaterThanOrEqual, BoolT, WordT, WordT) 462 463 #define CODE_ASSEMBLER_BINARY_OP_LIST(V) \ 464 CODE_ASSEMBLER_COMPARE_BINARY_OP_LIST(V) \ 465 V(Float64Add, Float64T, Float64T, Float64T) \ 466 V(Float64Sub, Float64T, Float64T, Float64T) \ 467 V(Float64Mul, Float64T, Float64T, Float64T) \ 468 V(Float64Div, Float64T, Float64T, Float64T) \ 469 V(Float64Mod, Float64T, Float64T, Float64T) \ 470 V(Float64Atan2, Float64T, Float64T, Float64T) \ 471 V(Float64Pow, Float64T, Float64T, Float64T) \ 472 V(Float64Max, Float64T, Float64T, Float64T) \ 473 V(Float64Min, Float64T, Float64T, Float64T) \ 474 V(Float64InsertLowWord32, Float64T, Float64T, Word32T) \ 475 V(Float64InsertHighWord32, Float64T, Float64T, Word32T) \ 476 V(IntPtrAddWithOverflow, PAIR_TYPE(IntPtrT, BoolT), IntPtrT, IntPtrT) \ 477 V(IntPtrSubWithOverflow, PAIR_TYPE(IntPtrT, BoolT), IntPtrT, IntPtrT) \ 478 V(Int32Add, Word32T, Word32T, Word32T) \ 479 V(Int32AddWithOverflow, PAIR_TYPE(Int32T, BoolT), Int32T, Int32T) \ 480 V(Int32Sub, Word32T, Word32T, Word32T) \ 481 V(Int32SubWithOverflow, PAIR_TYPE(Int32T, BoolT), Int32T, Int32T) \ 482 V(Int32Mul, Word32T, Word32T, Word32T) \ 483 V(Int32MulWithOverflow, PAIR_TYPE(Int32T, BoolT), Int32T, Int32T) \ 484 V(Int32Div, Int32T, Int32T, Int32T) \ 485 V(Int32Mod, Int32T, Int32T, Int32T) \ 486 V(WordRor, WordT, WordT, IntegralT) \ 487 V(Word32Ror, Word32T, Word32T, Word32T) \ 488 V(Word64Ror, Word64T, Word64T, Word64T) 489 490 TNode<Float64T> Float64Add(TNode<Float64T> a, TNode<Float64T> b); 491 492 #define CODE_ASSEMBLER_UNARY_OP_LIST(V) \ 493 V(Float64Abs, Float64T, Float64T) \ 494 V(Float64Acos, Float64T, Float64T) \ 495 V(Float64Acosh, Float64T, Float64T) \ 496 V(Float64Asin, Float64T, Float64T) \ 497 V(Float64Asinh, Float64T, Float64T) \ 498 V(Float64Atan, Float64T, Float64T) \ 499 V(Float64Atanh, Float64T, Float64T) \ 500 V(Float64Cos, Float64T, Float64T) \ 501 V(Float64Cosh, Float64T, Float64T) \ 502 V(Float64Exp, Float64T, Float64T) \ 503 V(Float64Expm1, Float64T, Float64T) \ 504 V(Float64Log, Float64T, Float64T) \ 505 V(Float64Log1p, Float64T, Float64T) \ 506 V(Float64Log2, Float64T, Float64T) \ 507 V(Float64Log10, Float64T, Float64T) \ 508 V(Float64Cbrt, Float64T, Float64T) \ 509 V(Float64Neg, Float64T, Float64T) \ 510 V(Float64Sin, Float64T, Float64T) \ 511 V(Float64Sinh, Float64T, Float64T) \ 512 V(Float64Sqrt, Float64T, Float64T) \ 513 V(Float64Tan, Float64T, Float64T) \ 514 V(Float64Tanh, Float64T, Float64T) \ 515 V(Float64ExtractLowWord32, Word32T, Float64T) \ 516 V(Float64ExtractHighWord32, Word32T, Float64T) \ 517 V(BitcastTaggedToWord, IntPtrT, Object) \ 518 V(BitcastMaybeObjectToWord, IntPtrT, MaybeObject) \ 519 V(BitcastWordToTagged, Object, WordT) \ 520 V(BitcastWordToTaggedSigned, Smi, WordT) \ 521 V(TruncateFloat64ToFloat32, Float32T, Float64T) \ 522 V(TruncateFloat64ToWord32, Word32T, Float64T) \ 523 V(TruncateInt64ToInt32, Int32T, Int64T) \ 524 V(ChangeFloat32ToFloat64, Float64T, Float32T) \ 525 V(ChangeFloat64ToUint32, Uint32T, Float64T) \ 526 V(ChangeFloat64ToUint64, Uint64T, Float64T) \ 527 V(ChangeInt32ToFloat64, Float64T, Int32T) \ 528 V(ChangeInt32ToInt64, Int64T, Int32T) \ 529 V(ChangeUint32ToFloat64, Float64T, Word32T) \ 530 V(ChangeUint32ToUint64, Uint64T, Word32T) \ 531 V(BitcastInt32ToFloat32, Float32T, Word32T) \ 532 V(BitcastFloat32ToInt32, Word32T, Float32T) \ 533 V(RoundFloat64ToInt32, Int32T, Float64T) \ 534 V(RoundInt32ToFloat32, Int32T, Float32T) \ 535 V(Float64SilenceNaN, Float64T, Float64T) \ 536 V(Float64RoundDown, Float64T, Float64T) \ 537 V(Float64RoundUp, Float64T, Float64T) \ 538 V(Float64RoundTiesEven, Float64T, Float64T) \ 539 V(Float64RoundTruncate, Float64T, Float64T) \ 540 V(Word32Clz, Int32T, Word32T) \ 541 V(Word32BitwiseNot, Word32T, Word32T) \ 542 V(WordNot, WordT, WordT) \ 543 V(Int32AbsWithOverflow, PAIR_TYPE(Int32T, BoolT), Int32T) \ 544 V(Int64AbsWithOverflow, PAIR_TYPE(Int64T, BoolT), Int64T) \ 545 V(IntPtrAbsWithOverflow, PAIR_TYPE(IntPtrT, BoolT), IntPtrT) \ 546 V(Word32BinaryNot, BoolT, Word32T) 547 548 // A "public" interface used by components outside of compiler directory to 549 // create code objects with TurboFan's backend. This class is mostly a thin 550 // shim around the RawMachineAssembler, and its primary job is to ensure that 551 // the innards of the RawMachineAssembler and other compiler implementation 552 // details don't leak outside of the the compiler directory.. 553 // 554 // V8 components that need to generate low-level code using this interface 555 // should include this header--and this header only--from the compiler 556 // directory (this is actually enforced). Since all interesting data 557 // structures are forward declared, it's not possible for clients to peek 558 // inside the compiler internals. 559 // 560 // In addition to providing isolation between TurboFan and code generation 561 // clients, CodeAssembler also provides an abstraction for creating variables 562 // and enhanced Label functionality to merge variable values along paths where 563 // they have differing values, including loops. 564 // 565 // The CodeAssembler itself is stateless (and instances are expected to be 566 // temporary-scoped and short-lived); all its state is encapsulated into 567 // a CodeAssemblerState instance. 568 class V8_EXPORT_PRIVATE CodeAssembler { 569 public: 570 explicit CodeAssembler(CodeAssemblerState* state) : state_(state) {} 571 ~CodeAssembler(); 572 573 static Handle<Code> GenerateCode(CodeAssemblerState* state, 574 const AssemblerOptions& options); 575 576 bool Is64() const; 577 bool IsFloat64RoundUpSupported() const; 578 bool IsFloat64RoundDownSupported() const; 579 bool IsFloat64RoundTiesEvenSupported() const; 580 bool IsFloat64RoundTruncateSupported() const; 581 bool IsInt32AbsWithOverflowSupported() const; 582 bool IsInt64AbsWithOverflowSupported() const; 583 bool IsIntPtrAbsWithOverflowSupported() const; 584 585 // Shortened aliases for use in CodeAssembler subclasses. 586 using Label = CodeAssemblerLabel; 587 using Variable = CodeAssemblerVariable; 588 template <class T> 589 using TVariable = TypedCodeAssemblerVariable<T>; 590 using VariableList = CodeAssemblerVariableList; 591 592 // =========================================================================== 593 // Base Assembler 594 // =========================================================================== 595 596 template <class PreviousType, bool FromTyped> 597 class CheckedNode { 598 public: 599 #ifdef DEBUG 600 CheckedNode(Node* node, CodeAssembler* code_assembler, const char* location) 601 : node_(node), code_assembler_(code_assembler), location_(location) {} 602 #else 603 CheckedNode(compiler::Node* node, CodeAssembler*, const char*) 604 : node_(node) {} 605 #endif 606 607 template <class A> 608 operator TNode<A>() { 609 static_assert( 610 !std::is_same<A, MaybeObject>::value, 611 "Can't cast to MaybeObject, use explicit conversion functions. "); 612 613 static_assert(types_have_common_values<A, PreviousType>::value, 614 "Incompatible types: this cast can never succeed."); 615 static_assert(std::is_convertible<TNode<A>, TNode<Object>>::value, 616 "Coercion to untagged values cannot be " 617 "checked."); 618 static_assert( 619 !FromTyped || 620 !std::is_convertible<TNode<PreviousType>, TNode<A>>::value, 621 "Unnecessary CAST: types are convertible."); 622 #ifdef DEBUG 623 if (FLAG_debug_code) { 624 if (std::is_same<PreviousType, MaybeObject>::value) { 625 code_assembler_->GenerateCheckMaybeObjectIsObject(node_, location_); 626 } 627 Node* function = code_assembler_->ExternalConstant( 628 ExternalReference::check_object_type()); 629 code_assembler_->CallCFunction3( 630 MachineType::AnyTagged(), MachineType::AnyTagged(), 631 MachineType::TaggedSigned(), MachineType::AnyTagged(), function, 632 node_, 633 code_assembler_->SmiConstant( 634 static_cast<int>(ObjectTypeOf<A>::value)), 635 code_assembler_->StringConstant(location_)); 636 } 637 #endif 638 return TNode<A>::UncheckedCast(node_); 639 } 640 641 template <class A> 642 operator SloppyTNode<A>() { 643 return implicit_cast<TNode<A>>(*this); 644 } 645 646 Node* node() const { return node_; } 647 648 private: 649 Node* node_; 650 #ifdef DEBUG 651 CodeAssembler* code_assembler_; 652 const char* location_; 653 #endif 654 }; 655 656 template <class T> 657 TNode<T> UncheckedCast(Node* value) { 658 return TNode<T>::UncheckedCast(value); 659 } 660 template <class T, class U> 661 TNode<T> UncheckedCast(TNode<U> value) { 662 static_assert(types_have_common_values<T, U>::value, 663 "Incompatible types: this cast can never succeed."); 664 return TNode<T>::UncheckedCast(value); 665 } 666 667 // ReinterpretCast<T>(v) has the power to cast even when the type of v is 668 // unrelated to T. Use with care. 669 template <class T> 670 TNode<T> ReinterpretCast(Node* value) { 671 return TNode<T>::UncheckedCast(value); 672 } 673 674 CheckedNode<Object, false> Cast(Node* value, const char* location = "") { 675 return {value, this, location}; 676 } 677 678 template <class T> 679 CheckedNode<T, true> Cast(TNode<T> value, const char* location = "") { 680 return {value, this, location}; 681 } 682 683 #ifdef DEBUG 684 #define STRINGIFY(x) #x 685 #define TO_STRING_LITERAL(x) STRINGIFY(x) 686 #define CAST(x) \ 687 Cast(x, "CAST(" #x ") at " __FILE__ ":" TO_STRING_LITERAL(__LINE__)) 688 #else 689 #define CAST(x) Cast(x) 690 #endif 691 692 #ifdef DEBUG 693 void GenerateCheckMaybeObjectIsObject(Node* node, const char* location); 694 #endif 695 696 // Constants. 697 TNode<Int32T> Int32Constant(int32_t value); 698 TNode<Int64T> Int64Constant(int64_t value); 699 TNode<IntPtrT> IntPtrConstant(intptr_t value); 700 TNode<Number> NumberConstant(double value); 701 TNode<Smi> SmiConstant(Smi* value); 702 TNode<Smi> SmiConstant(int value); 703 template <typename E, 704 typename = typename std::enable_if<std::is_enum<E>::value>::type> 705 TNode<Smi> SmiConstant(E value) { 706 STATIC_ASSERT(sizeof(E) <= sizeof(int)); 707 return SmiConstant(static_cast<int>(value)); 708 } 709 TNode<HeapObject> UntypedHeapConstant(Handle<HeapObject> object); 710 template <class Type> 711 TNode<Type> HeapConstant(Handle<Type> object) { 712 return UncheckedCast<Type>(UntypedHeapConstant(object)); 713 } 714 TNode<String> StringConstant(const char* str); 715 TNode<Oddball> BooleanConstant(bool value); 716 TNode<ExternalReference> ExternalConstant(ExternalReference address); 717 TNode<Float64T> Float64Constant(double value); 718 TNode<HeapNumber> NaNConstant(); 719 TNode<BoolT> Int32TrueConstant() { 720 return ReinterpretCast<BoolT>(Int32Constant(1)); 721 } 722 TNode<BoolT> Int32FalseConstant() { 723 return ReinterpretCast<BoolT>(Int32Constant(0)); 724 } 725 TNode<BoolT> BoolConstant(bool value) { 726 return value ? Int32TrueConstant() : Int32FalseConstant(); 727 } 728 729 bool ToInt32Constant(Node* node, int32_t& out_value); 730 bool ToInt64Constant(Node* node, int64_t& out_value); 731 bool ToSmiConstant(Node* node, Smi*& out_value); 732 bool ToIntPtrConstant(Node* node, intptr_t& out_value); 733 734 bool IsUndefinedConstant(TNode<Object> node); 735 bool IsNullConstant(TNode<Object> node); 736 737 TNode<Int32T> Signed(TNode<Word32T> x) { return UncheckedCast<Int32T>(x); } 738 TNode<IntPtrT> Signed(TNode<WordT> x) { return UncheckedCast<IntPtrT>(x); } 739 TNode<Uint32T> Unsigned(TNode<Word32T> x) { 740 return UncheckedCast<Uint32T>(x); 741 } 742 TNode<UintPtrT> Unsigned(TNode<WordT> x) { 743 return UncheckedCast<UintPtrT>(x); 744 } 745 746 static constexpr int kTargetParameterIndex = -1; 747 748 Node* Parameter(int value); 749 750 TNode<Context> GetJSContextParameter(); 751 void Return(SloppyTNode<Object> value); 752 void Return(SloppyTNode<Object> value1, SloppyTNode<Object> value2); 753 void Return(SloppyTNode<Object> value1, SloppyTNode<Object> value2, 754 SloppyTNode<Object> value3); 755 void PopAndReturn(Node* pop, Node* value); 756 757 void ReturnIf(Node* condition, Node* value); 758 759 void ReturnRaw(Node* value); 760 761 void DebugAbort(Node* message); 762 void DebugBreak(); 763 void Unreachable(); 764 void Comment(const char* format, ...); 765 766 void Bind(Label* label); 767 #if DEBUG 768 void Bind(Label* label, AssemblerDebugInfo debug_info); 769 #endif // DEBUG 770 void Goto(Label* label); 771 void GotoIf(SloppyTNode<IntegralT> condition, Label* true_label); 772 void GotoIfNot(SloppyTNode<IntegralT> condition, Label* false_label); 773 void Branch(SloppyTNode<IntegralT> condition, Label* true_label, 774 Label* false_label); 775 776 void Branch(TNode<BoolT> condition, std::function<void()> true_body, 777 std::function<void()> false_body); 778 void Branch(TNode<BoolT> condition, Label* true_label, 779 std::function<void()> false_body); 780 void Branch(TNode<BoolT> condition, std::function<void()> true_body, 781 Label* false_label); 782 783 void Switch(Node* index, Label* default_label, const int32_t* case_values, 784 Label** case_labels, size_t case_count); 785 786 // Access to the frame pointer 787 Node* LoadFramePointer(); 788 Node* LoadParentFramePointer(); 789 790 // Access to the stack pointer 791 Node* LoadStackPointer(); 792 793 // Poison |value| on speculative paths. 794 TNode<Object> TaggedPoisonOnSpeculation(SloppyTNode<Object> value); 795 TNode<WordT> WordPoisonOnSpeculation(SloppyTNode<WordT> value); 796 797 // Load raw memory location. 798 Node* Load(MachineType rep, Node* base, 799 LoadSensitivity needs_poisoning = LoadSensitivity::kSafe); 800 template <class Type> 801 TNode<Type> Load(MachineType rep, TNode<RawPtr<Type>> base) { 802 DCHECK( 803 IsSubtype(rep.representation(), MachineRepresentationOf<Type>::value)); 804 return UncheckedCast<Type>(Load(rep, static_cast<Node*>(base))); 805 } 806 Node* Load(MachineType rep, Node* base, Node* offset, 807 LoadSensitivity needs_poisoning = LoadSensitivity::kSafe); 808 Node* AtomicLoad(MachineType rep, Node* base, Node* offset); 809 810 // Load a value from the root array. 811 TNode<Object> LoadRoot(Heap::RootListIndex root_index); 812 813 // Store value to raw memory location. 814 Node* Store(Node* base, Node* value); 815 Node* Store(Node* base, Node* offset, Node* value); 816 Node* StoreWithMapWriteBarrier(Node* base, Node* offset, Node* value); 817 Node* StoreNoWriteBarrier(MachineRepresentation rep, Node* base, Node* value); 818 Node* StoreNoWriteBarrier(MachineRepresentation rep, Node* base, Node* offset, 819 Node* value); 820 Node* AtomicStore(MachineRepresentation rep, Node* base, Node* offset, 821 Node* value); 822 823 // Exchange value at raw memory location 824 Node* AtomicExchange(MachineType type, Node* base, Node* offset, Node* value); 825 826 // Compare and Exchange value at raw memory location 827 Node* AtomicCompareExchange(MachineType type, Node* base, Node* offset, 828 Node* old_value, Node* new_value); 829 830 Node* AtomicAdd(MachineType type, Node* base, Node* offset, Node* value); 831 832 Node* AtomicSub(MachineType type, Node* base, Node* offset, Node* value); 833 834 Node* AtomicAnd(MachineType type, Node* base, Node* offset, Node* value); 835 836 Node* AtomicOr(MachineType type, Node* base, Node* offset, Node* value); 837 838 Node* AtomicXor(MachineType type, Node* base, Node* offset, Node* value); 839 840 // Store a value to the root array. 841 Node* StoreRoot(Heap::RootListIndex root_index, Node* value); 842 843 // Basic arithmetic operations. 844 #define DECLARE_CODE_ASSEMBLER_BINARY_OP(name, ResType, Arg1Type, Arg2Type) \ 845 TNode<ResType> name(SloppyTNode<Arg1Type> a, SloppyTNode<Arg2Type> b); 846 CODE_ASSEMBLER_BINARY_OP_LIST(DECLARE_CODE_ASSEMBLER_BINARY_OP) 847 #undef DECLARE_CODE_ASSEMBLER_BINARY_OP 848 849 TNode<IntPtrT> WordShr(TNode<IntPtrT> left, TNode<IntegralT> right) { 850 return UncheckedCast<IntPtrT>( 851 WordShr(static_cast<Node*>(left), static_cast<Node*>(right))); 852 } 853 854 TNode<IntPtrT> WordAnd(TNode<IntPtrT> left, TNode<IntPtrT> right) { 855 return UncheckedCast<IntPtrT>( 856 WordAnd(static_cast<Node*>(left), static_cast<Node*>(right))); 857 } 858 859 template <class Left, class Right, 860 class = typename std::enable_if< 861 std::is_base_of<Object, Left>::value && 862 std::is_base_of<Object, Right>::value>::type> 863 TNode<BoolT> WordEqual(TNode<Left> left, TNode<Right> right) { 864 return WordEqual(ReinterpretCast<WordT>(left), 865 ReinterpretCast<WordT>(right)); 866 } 867 TNode<BoolT> WordEqual(TNode<Object> left, Node* right) { 868 return WordEqual(ReinterpretCast<WordT>(left), 869 ReinterpretCast<WordT>(right)); 870 } 871 TNode<BoolT> WordEqual(Node* left, TNode<Object> right) { 872 return WordEqual(ReinterpretCast<WordT>(left), 873 ReinterpretCast<WordT>(right)); 874 } 875 template <class Left, class Right, 876 class = typename std::enable_if< 877 std::is_base_of<Object, Left>::value && 878 std::is_base_of<Object, Right>::value>::type> 879 TNode<BoolT> WordNotEqual(TNode<Left> left, TNode<Right> right) { 880 return WordNotEqual(ReinterpretCast<WordT>(left), 881 ReinterpretCast<WordT>(right)); 882 } 883 TNode<BoolT> WordNotEqual(TNode<Object> left, Node* right) { 884 return WordNotEqual(ReinterpretCast<WordT>(left), 885 ReinterpretCast<WordT>(right)); 886 } 887 TNode<BoolT> WordNotEqual(Node* left, TNode<Object> right) { 888 return WordNotEqual(ReinterpretCast<WordT>(left), 889 ReinterpretCast<WordT>(right)); 890 } 891 892 TNode<BoolT> IntPtrEqual(SloppyTNode<WordT> left, SloppyTNode<WordT> right); 893 TNode<BoolT> WordEqual(SloppyTNode<WordT> left, SloppyTNode<WordT> right); 894 TNode<BoolT> WordNotEqual(SloppyTNode<WordT> left, SloppyTNode<WordT> right); 895 TNode<BoolT> Word32Equal(SloppyTNode<Word32T> left, 896 SloppyTNode<Word32T> right); 897 TNode<BoolT> Word32NotEqual(SloppyTNode<Word32T> left, 898 SloppyTNode<Word32T> right); 899 TNode<BoolT> Word64Equal(SloppyTNode<Word64T> left, 900 SloppyTNode<Word64T> right); 901 TNode<BoolT> Word64NotEqual(SloppyTNode<Word64T> left, 902 SloppyTNode<Word64T> right); 903 904 TNode<Int32T> Int32Add(TNode<Int32T> left, TNode<Int32T> right) { 905 return Signed( 906 Int32Add(static_cast<Node*>(left), static_cast<Node*>(right))); 907 } 908 909 TNode<WordT> IntPtrAdd(SloppyTNode<WordT> left, SloppyTNode<WordT> right); 910 TNode<WordT> IntPtrSub(SloppyTNode<WordT> left, SloppyTNode<WordT> right); 911 TNode<WordT> IntPtrMul(SloppyTNode<WordT> left, SloppyTNode<WordT> right); 912 TNode<IntPtrT> IntPtrAdd(TNode<IntPtrT> left, TNode<IntPtrT> right) { 913 return Signed( 914 IntPtrAdd(static_cast<Node*>(left), static_cast<Node*>(right))); 915 } 916 TNode<IntPtrT> IntPtrSub(TNode<IntPtrT> left, TNode<IntPtrT> right) { 917 return Signed( 918 IntPtrSub(static_cast<Node*>(left), static_cast<Node*>(right))); 919 } 920 TNode<IntPtrT> IntPtrMul(TNode<IntPtrT> left, TNode<IntPtrT> right) { 921 return Signed( 922 IntPtrMul(static_cast<Node*>(left), static_cast<Node*>(right))); 923 } 924 925 TNode<WordT> WordShl(SloppyTNode<WordT> value, int shift); 926 TNode<WordT> WordShr(SloppyTNode<WordT> value, int shift); 927 TNode<WordT> WordSar(SloppyTNode<WordT> value, int shift); 928 TNode<IntPtrT> WordShr(TNode<IntPtrT> value, int shift) { 929 return UncheckedCast<IntPtrT>(WordShr(static_cast<Node*>(value), shift)); 930 } 931 TNode<Word32T> Word32Shr(SloppyTNode<Word32T> value, int shift); 932 933 TNode<WordT> WordOr(SloppyTNode<WordT> left, SloppyTNode<WordT> right); 934 TNode<WordT> WordAnd(SloppyTNode<WordT> left, SloppyTNode<WordT> right); 935 TNode<WordT> WordXor(SloppyTNode<WordT> left, SloppyTNode<WordT> right); 936 TNode<WordT> WordShl(SloppyTNode<WordT> left, SloppyTNode<IntegralT> right); 937 TNode<WordT> WordShr(SloppyTNode<WordT> left, SloppyTNode<IntegralT> right); 938 TNode<WordT> WordSar(SloppyTNode<WordT> left, SloppyTNode<IntegralT> right); 939 TNode<Word32T> Word32Or(SloppyTNode<Word32T> left, 940 SloppyTNode<Word32T> right); 941 TNode<Word32T> Word32And(SloppyTNode<Word32T> left, 942 SloppyTNode<Word32T> right); 943 TNode<Word32T> Word32Xor(SloppyTNode<Word32T> left, 944 SloppyTNode<Word32T> right); 945 TNode<Word32T> Word32Shl(SloppyTNode<Word32T> left, 946 SloppyTNode<Word32T> right); 947 TNode<Word32T> Word32Shr(SloppyTNode<Word32T> left, 948 SloppyTNode<Word32T> right); 949 TNode<Word32T> Word32Sar(SloppyTNode<Word32T> left, 950 SloppyTNode<Word32T> right); 951 TNode<Word64T> Word64Or(SloppyTNode<Word64T> left, 952 SloppyTNode<Word64T> right); 953 TNode<Word64T> Word64And(SloppyTNode<Word64T> left, 954 SloppyTNode<Word64T> right); 955 TNode<Word64T> Word64Xor(SloppyTNode<Word64T> left, 956 SloppyTNode<Word64T> right); 957 TNode<Word64T> Word64Shl(SloppyTNode<Word64T> left, 958 SloppyTNode<Word64T> right); 959 TNode<Word64T> Word64Shr(SloppyTNode<Word64T> left, 960 SloppyTNode<Word64T> right); 961 TNode<Word64T> Word64Sar(SloppyTNode<Word64T> left, 962 SloppyTNode<Word64T> right); 963 964 // Unary 965 #define DECLARE_CODE_ASSEMBLER_UNARY_OP(name, ResType, ArgType) \ 966 TNode<ResType> name(SloppyTNode<ArgType> a); 967 CODE_ASSEMBLER_UNARY_OP_LIST(DECLARE_CODE_ASSEMBLER_UNARY_OP) 968 #undef DECLARE_CODE_ASSEMBLER_UNARY_OP 969 970 // Changes a double to an inptr_t for pointer arithmetic outside of Smi range. 971 // Assumes that the double can be exactly represented as an int. 972 TNode<UintPtrT> ChangeFloat64ToUintPtr(SloppyTNode<Float64T> value); 973 974 // Changes an intptr_t to a double, e.g. for storing an element index 975 // outside Smi range in a HeapNumber. Lossless on 32-bit, 976 // rounds on 64-bit (which doesn't affect valid element indices). 977 Node* RoundIntPtrToFloat64(Node* value); 978 // No-op on 32-bit, otherwise zero extend. 979 TNode<UintPtrT> ChangeUint32ToWord(SloppyTNode<Word32T> value); 980 // No-op on 32-bit, otherwise sign extend. 981 TNode<IntPtrT> ChangeInt32ToIntPtr(SloppyTNode<Word32T> value); 982 983 // No-op that guarantees that the value is kept alive till this point even 984 // if GC happens. 985 Node* Retain(Node* value); 986 987 // Projections 988 Node* Projection(int index, Node* value); 989 990 template <int index, class T1, class T2> 991 TNode<typename std::tuple_element<index, std::tuple<T1, T2>>::type> 992 Projection(TNode<PairT<T1, T2>> value) { 993 return UncheckedCast< 994 typename std::tuple_element<index, std::tuple<T1, T2>>::type>( 995 Projection(index, value)); 996 } 997 998 // Calls 999 template <class... TArgs> 1000 TNode<Object> CallRuntime(Runtime::FunctionId function, 1001 SloppyTNode<Object> context, TArgs... args) { 1002 return CallRuntimeImpl(function, context, 1003 {implicit_cast<SloppyTNode<Object>>(args)...}); 1004 } 1005 1006 template <class... TArgs> 1007 TNode<Object> CallRuntimeWithCEntry(Runtime::FunctionId function, 1008 TNode<Code> centry, 1009 SloppyTNode<Object> context, 1010 TArgs... args) { 1011 return CallRuntimeWithCEntryImpl(function, centry, context, {args...}); 1012 } 1013 1014 template <class... TArgs> 1015 void TailCallRuntime(Runtime::FunctionId function, 1016 SloppyTNode<Object> context, TArgs... args) { 1017 int argc = static_cast<int>(sizeof...(args)); 1018 TNode<Int32T> arity = Int32Constant(argc); 1019 return TailCallRuntimeImpl(function, arity, context, 1020 {implicit_cast<SloppyTNode<Object>>(args)...}); 1021 } 1022 1023 template <class... TArgs> 1024 void TailCallRuntime(Runtime::FunctionId function, TNode<Int32T> arity, 1025 SloppyTNode<Object> context, TArgs... args) { 1026 return TailCallRuntimeImpl(function, arity, context, 1027 {implicit_cast<SloppyTNode<Object>>(args)...}); 1028 } 1029 1030 template <class... TArgs> 1031 void TailCallRuntimeWithCEntry(Runtime::FunctionId function, 1032 TNode<Code> centry, TNode<Object> context, 1033 TArgs... args) { 1034 int argc = sizeof...(args); 1035 TNode<Int32T> arity = Int32Constant(argc); 1036 return TailCallRuntimeWithCEntryImpl( 1037 function, arity, centry, context, 1038 {implicit_cast<SloppyTNode<Object>>(args)...}); 1039 } 1040 1041 // 1042 // If context passed to CallStub is nullptr, it won't be passed to the stub. 1043 // 1044 1045 template <class T = Object, class... TArgs> 1046 TNode<T> CallStub(Callable const& callable, SloppyTNode<Object> context, 1047 TArgs... args) { 1048 TNode<Code> target = HeapConstant(callable.code()); 1049 return CallStub<T>(callable.descriptor(), target, context, args...); 1050 } 1051 1052 template <class T = Object, class... TArgs> 1053 TNode<T> CallStub(const CallInterfaceDescriptor& descriptor, 1054 SloppyTNode<Code> target, SloppyTNode<Object> context, 1055 TArgs... args) { 1056 return UncheckedCast<T>(CallStubR(descriptor, 1, target, context, args...)); 1057 } 1058 1059 template <class... TArgs> 1060 Node* CallStubR(const CallInterfaceDescriptor& descriptor, size_t result_size, 1061 SloppyTNode<Code> target, SloppyTNode<Object> context, 1062 TArgs... args) { 1063 return CallStubRImpl(descriptor, result_size, target, context, {args...}); 1064 } 1065 1066 Node* CallStubN(const CallInterfaceDescriptor& descriptor, size_t result_size, 1067 int input_count, Node* const* inputs); 1068 1069 template <class... TArgs> 1070 void TailCallStub(Callable const& callable, SloppyTNode<Object> context, 1071 TArgs... args) { 1072 TNode<Code> target = HeapConstant(callable.code()); 1073 return TailCallStub(callable.descriptor(), target, context, args...); 1074 } 1075 1076 template <class... TArgs> 1077 void TailCallStub(const CallInterfaceDescriptor& descriptor, 1078 SloppyTNode<Code> target, SloppyTNode<Object> context, 1079 TArgs... args) { 1080 return TailCallStubImpl(descriptor, target, context, {args...}); 1081 } 1082 1083 template <class... TArgs> 1084 Node* TailCallBytecodeDispatch(const CallInterfaceDescriptor& descriptor, 1085 Node* target, TArgs... args); 1086 1087 template <class... TArgs> 1088 Node* TailCallStubThenBytecodeDispatch( 1089 const CallInterfaceDescriptor& descriptor, Node* target, Node* context, 1090 TArgs... args) { 1091 return TailCallStubThenBytecodeDispatchImpl(descriptor, target, context, 1092 {args...}); 1093 } 1094 1095 // Tailcalls to the given code object with JSCall linkage. The JS arguments 1096 // (including receiver) are supposed to be already on the stack. 1097 // This is a building block for implementing trampoline stubs that are 1098 // installed instead of code objects with JSCall linkage. 1099 // Note that no arguments adaption is going on here - all the JavaScript 1100 // arguments are left on the stack unmodified. Therefore, this tail call can 1101 // only be used after arguments adaptation has been performed already. 1102 TNode<Object> TailCallJSCode(TNode<Code> code, TNode<Context> context, 1103 TNode<JSFunction> function, 1104 TNode<Object> new_target, 1105 TNode<Int32T> arg_count); 1106 1107 template <class... TArgs> 1108 Node* CallJS(Callable const& callable, Node* context, Node* function, 1109 Node* receiver, TArgs... args) { 1110 int argc = static_cast<int>(sizeof...(args)); 1111 Node* arity = Int32Constant(argc); 1112 return CallStub(callable, context, function, arity, receiver, args...); 1113 } 1114 1115 template <class... TArgs> 1116 Node* ConstructJS(Callable const& callable, Node* context, Node* new_target, 1117 TArgs... args) { 1118 int argc = static_cast<int>(sizeof...(args)); 1119 Node* arity = Int32Constant(argc); 1120 Node* receiver = LoadRoot(Heap::kUndefinedValueRootIndex); 1121 1122 // Construct(target, new_target, arity, receiver, arguments...) 1123 return CallStub(callable, context, new_target, new_target, arity, receiver, 1124 args...); 1125 } 1126 1127 Node* CallCFunctionN(Signature<MachineType>* signature, int input_count, 1128 Node* const* inputs); 1129 1130 // Call to a C function with one argument. 1131 Node* CallCFunction1(MachineType return_type, MachineType arg0_type, 1132 Node* function, Node* arg0); 1133 1134 // Call to a C function with one argument, while saving/restoring caller 1135 // registers except the register used for return value. 1136 Node* CallCFunction1WithCallerSavedRegisters(MachineType return_type, 1137 MachineType arg0_type, 1138 Node* function, Node* arg0, 1139 SaveFPRegsMode mode); 1140 1141 // Call to a C function with two arguments. 1142 Node* CallCFunction2(MachineType return_type, MachineType arg0_type, 1143 MachineType arg1_type, Node* function, Node* arg0, 1144 Node* arg1); 1145 1146 // Call to a C function with three arguments. 1147 Node* CallCFunction3(MachineType return_type, MachineType arg0_type, 1148 MachineType arg1_type, MachineType arg2_type, 1149 Node* function, Node* arg0, Node* arg1, Node* arg2); 1150 1151 // Call to a C function with three arguments, while saving/restoring caller 1152 // registers except the register used for return value. 1153 Node* CallCFunction3WithCallerSavedRegisters( 1154 MachineType return_type, MachineType arg0_type, MachineType arg1_type, 1155 MachineType arg2_type, Node* function, Node* arg0, Node* arg1, Node* arg2, 1156 SaveFPRegsMode mode); 1157 1158 // Call to a C function with four arguments. 1159 Node* CallCFunction4(MachineType return_type, MachineType arg0_type, 1160 MachineType arg1_type, MachineType arg2_type, 1161 MachineType arg3_type, Node* function, Node* arg0, 1162 Node* arg1, Node* arg2, Node* arg3); 1163 1164 // Call to a C function with five arguments. 1165 Node* CallCFunction5(MachineType return_type, MachineType arg0_type, 1166 MachineType arg1_type, MachineType arg2_type, 1167 MachineType arg3_type, MachineType arg4_type, 1168 Node* function, Node* arg0, Node* arg1, Node* arg2, 1169 Node* arg3, Node* arg4); 1170 1171 // Call to a C function with six arguments. 1172 Node* CallCFunction6(MachineType return_type, MachineType arg0_type, 1173 MachineType arg1_type, MachineType arg2_type, 1174 MachineType arg3_type, MachineType arg4_type, 1175 MachineType arg5_type, Node* function, Node* arg0, 1176 Node* arg1, Node* arg2, Node* arg3, Node* arg4, 1177 Node* arg5); 1178 1179 // Call to a C function with nine arguments. 1180 Node* CallCFunction9(MachineType return_type, MachineType arg0_type, 1181 MachineType arg1_type, MachineType arg2_type, 1182 MachineType arg3_type, MachineType arg4_type, 1183 MachineType arg5_type, MachineType arg6_type, 1184 MachineType arg7_type, MachineType arg8_type, 1185 Node* function, Node* arg0, Node* arg1, Node* arg2, 1186 Node* arg3, Node* arg4, Node* arg5, Node* arg6, 1187 Node* arg7, Node* arg8); 1188 1189 // Exception handling support. 1190 void GotoIfException(Node* node, Label* if_exception, 1191 Variable* exception_var = nullptr); 1192 1193 // Helpers which delegate to RawMachineAssembler. 1194 Factory* factory() const; 1195 Isolate* isolate() const; 1196 Zone* zone() const; 1197 1198 CodeAssemblerState* state() { return state_; } 1199 1200 void BreakOnNode(int node_id); 1201 1202 bool UnalignedLoadSupported(MachineRepresentation rep) const; 1203 bool UnalignedStoreSupported(MachineRepresentation rep) const; 1204 1205 protected: 1206 void RegisterCallGenerationCallbacks( 1207 const CodeAssemblerCallback& call_prologue, 1208 const CodeAssemblerCallback& call_epilogue); 1209 void UnregisterCallGenerationCallbacks(); 1210 1211 bool Word32ShiftIsSafe() const; 1212 PoisoningMitigationLevel poisoning_level() const; 1213 1214 bool IsJSFunctionCall() const; 1215 1216 private: 1217 TNode<Object> CallRuntimeImpl(Runtime::FunctionId function, 1218 TNode<Object> context, 1219 std::initializer_list<TNode<Object>> args); 1220 1221 TNode<Object> CallRuntimeWithCEntryImpl( 1222 Runtime::FunctionId function, TNode<Code> centry, TNode<Object> context, 1223 std::initializer_list<TNode<Object>> args); 1224 1225 void TailCallRuntimeImpl(Runtime::FunctionId function, TNode<Int32T> arity, 1226 TNode<Object> context, 1227 std::initializer_list<TNode<Object>> args); 1228 1229 void TailCallRuntimeWithCEntryImpl(Runtime::FunctionId function, 1230 TNode<Int32T> arity, TNode<Code> centry, 1231 TNode<Object> context, 1232 std::initializer_list<TNode<Object>> args); 1233 1234 void TailCallStubImpl(const CallInterfaceDescriptor& descriptor, 1235 TNode<Code> target, TNode<Object> context, 1236 std::initializer_list<Node*> args); 1237 1238 Node* TailCallStubThenBytecodeDispatchImpl( 1239 const CallInterfaceDescriptor& descriptor, Node* target, Node* context, 1240 std::initializer_list<Node*> args); 1241 1242 Node* CallStubRImpl(const CallInterfaceDescriptor& descriptor, 1243 size_t result_size, SloppyTNode<Code> target, 1244 SloppyTNode<Object> context, 1245 std::initializer_list<Node*> args); 1246 1247 // These two don't have definitions and are here only for catching use cases 1248 // where the cast is not necessary. 1249 TNode<Int32T> Signed(TNode<Int32T> x); 1250 TNode<Uint32T> Unsigned(TNode<Uint32T> x); 1251 1252 RawMachineAssembler* raw_assembler() const; 1253 1254 // Calls respective callback registered in the state. 1255 void CallPrologue(); 1256 void CallEpilogue(); 1257 1258 CodeAssemblerState* state_; 1259 1260 DISALLOW_COPY_AND_ASSIGN(CodeAssembler); 1261 }; 1262 1263 class CodeAssemblerVariable { 1264 public: 1265 explicit CodeAssemblerVariable(CodeAssembler* assembler, 1266 MachineRepresentation rep); 1267 CodeAssemblerVariable(CodeAssembler* assembler, MachineRepresentation rep, 1268 Node* initial_value); 1269 #if DEBUG 1270 CodeAssemblerVariable(CodeAssembler* assembler, AssemblerDebugInfo debug_info, 1271 MachineRepresentation rep); 1272 CodeAssemblerVariable(CodeAssembler* assembler, AssemblerDebugInfo debug_info, 1273 MachineRepresentation rep, Node* initial_value); 1274 #endif // DEBUG 1275 1276 ~CodeAssemblerVariable(); 1277 void Bind(Node* value); 1278 Node* value() const; 1279 MachineRepresentation rep() const; 1280 bool IsBound() const; 1281 1282 private: 1283 class Impl; 1284 friend class CodeAssemblerLabel; 1285 friend class CodeAssemblerState; 1286 friend std::ostream& operator<<(std::ostream&, const Impl&); 1287 friend std::ostream& operator<<(std::ostream&, const CodeAssemblerVariable&); 1288 Impl* impl_; 1289 CodeAssemblerState* state_; 1290 DISALLOW_COPY_AND_ASSIGN(CodeAssemblerVariable); 1291 }; 1292 1293 std::ostream& operator<<(std::ostream&, const CodeAssemblerVariable&); 1294 std::ostream& operator<<(std::ostream&, const CodeAssemblerVariable::Impl&); 1295 1296 template <class T> 1297 class TypedCodeAssemblerVariable : public CodeAssemblerVariable { 1298 public: 1299 TypedCodeAssemblerVariable(TNode<T> initial_value, CodeAssembler* assembler) 1300 : CodeAssemblerVariable(assembler, MachineRepresentationOf<T>::value, 1301 initial_value) {} 1302 explicit TypedCodeAssemblerVariable(CodeAssembler* assembler) 1303 : CodeAssemblerVariable(assembler, MachineRepresentationOf<T>::value) {} 1304 #if DEBUG 1305 TypedCodeAssemblerVariable(AssemblerDebugInfo debug_info, 1306 CodeAssembler* assembler) 1307 : CodeAssemblerVariable(assembler, debug_info, 1308 MachineRepresentationOf<T>::value) {} 1309 TypedCodeAssemblerVariable(AssemblerDebugInfo debug_info, 1310 TNode<T> initial_value, CodeAssembler* assembler) 1311 : CodeAssemblerVariable(assembler, debug_info, 1312 MachineRepresentationOf<T>::value, 1313 initial_value) {} 1314 #endif // DEBUG 1315 1316 TNode<T> value() const { 1317 return TNode<T>::UncheckedCast(CodeAssemblerVariable::value()); 1318 } 1319 1320 void operator=(TNode<T> value) { Bind(value); } 1321 void operator=(const TypedCodeAssemblerVariable<T>& variable) { 1322 Bind(variable.value()); 1323 } 1324 1325 private: 1326 using CodeAssemblerVariable::Bind; 1327 }; 1328 1329 class CodeAssemblerLabel { 1330 public: 1331 enum Type { kDeferred, kNonDeferred }; 1332 1333 explicit CodeAssemblerLabel( 1334 CodeAssembler* assembler, 1335 CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred) 1336 : CodeAssemblerLabel(assembler, 0, nullptr, type) {} 1337 CodeAssemblerLabel( 1338 CodeAssembler* assembler, 1339 const CodeAssemblerVariableList& merged_variables, 1340 CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred) 1341 : CodeAssemblerLabel(assembler, merged_variables.size(), 1342 &(merged_variables[0]), type) {} 1343 CodeAssemblerLabel( 1344 CodeAssembler* assembler, size_t count, 1345 CodeAssemblerVariable* const* vars, 1346 CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred); 1347 CodeAssemblerLabel( 1348 CodeAssembler* assembler, 1349 std::initializer_list<CodeAssemblerVariable*> vars, 1350 CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred) 1351 : CodeAssemblerLabel(assembler, vars.size(), vars.begin(), type) {} 1352 CodeAssemblerLabel( 1353 CodeAssembler* assembler, CodeAssemblerVariable* merged_variable, 1354 CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred) 1355 : CodeAssemblerLabel(assembler, 1, &merged_variable, type) {} 1356 ~CodeAssemblerLabel(); 1357 1358 inline bool is_bound() const { return bound_; } 1359 inline bool is_used() const { return merge_count_ != 0; } 1360 1361 private: 1362 friend class CodeAssembler; 1363 1364 void Bind(); 1365 #if DEBUG 1366 void Bind(AssemblerDebugInfo debug_info); 1367 #endif // DEBUG 1368 void UpdateVariablesAfterBind(); 1369 void MergeVariables(); 1370 1371 bool bound_; 1372 size_t merge_count_; 1373 CodeAssemblerState* state_; 1374 RawMachineLabel* label_; 1375 // Map of variables that need to be merged to their phi nodes (or placeholders 1376 // for those phis). 1377 std::map<CodeAssemblerVariable::Impl*, Node*> variable_phis_; 1378 // Map of variables to the list of value nodes that have been added from each 1379 // merge path in their order of merging. 1380 std::map<CodeAssemblerVariable::Impl*, std::vector<Node*>> variable_merges_; 1381 }; 1382 1383 class V8_EXPORT_PRIVATE CodeAssemblerState { 1384 public: 1385 // Create with CallStub linkage. 1386 // |result_size| specifies the number of results returned by the stub. 1387 // TODO(rmcilroy): move result_size to the CallInterfaceDescriptor. 1388 CodeAssemblerState(Isolate* isolate, Zone* zone, 1389 const CallInterfaceDescriptor& descriptor, Code::Kind kind, 1390 const char* name, PoisoningMitigationLevel poisoning_level, 1391 uint32_t stub_key = 0, 1392 int32_t builtin_index = Builtins::kNoBuiltinId); 1393 1394 // Create with JSCall linkage. 1395 CodeAssemblerState(Isolate* isolate, Zone* zone, int parameter_count, 1396 Code::Kind kind, const char* name, 1397 PoisoningMitigationLevel poisoning_level, 1398 int32_t builtin_index = Builtins::kNoBuiltinId); 1399 1400 ~CodeAssemblerState(); 1401 1402 const char* name() const { return name_; } 1403 int parameter_count() const; 1404 1405 #if DEBUG 1406 void PrintCurrentBlock(std::ostream& os); 1407 bool InsideBlock(); 1408 #endif // DEBUG 1409 void SetInitialDebugInformation(const char* msg, const char* file, int line); 1410 1411 private: 1412 friend class CodeAssembler; 1413 friend class CodeAssemblerLabel; 1414 friend class CodeAssemblerVariable; 1415 friend class CodeAssemblerTester; 1416 1417 CodeAssemblerState(Isolate* isolate, Zone* zone, 1418 CallDescriptor* call_descriptor, Code::Kind kind, 1419 const char* name, PoisoningMitigationLevel poisoning_level, 1420 uint32_t stub_key, int32_t builtin_index); 1421 1422 std::unique_ptr<RawMachineAssembler> raw_assembler_; 1423 Code::Kind kind_; 1424 const char* name_; 1425 uint32_t stub_key_; 1426 int32_t builtin_index_; 1427 bool code_generated_; 1428 ZoneSet<CodeAssemblerVariable::Impl*> variables_; 1429 CodeAssemblerCallback call_prologue_; 1430 CodeAssemblerCallback call_epilogue_; 1431 1432 DISALLOW_COPY_AND_ASSIGN(CodeAssemblerState); 1433 }; 1434 1435 } // namespace compiler 1436 } // namespace internal 1437 } // namespace v8 1438 1439 #endif // V8_COMPILER_CODE_ASSEMBLER_H_ 1440