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