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