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