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