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