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