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