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