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