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