Home | History | Annotate | Download | only in compiler
      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