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