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#include "src/compiler/code-assembler.h"
6
7#include <ostream>
8
9#include "src/base/bits.h"
10#include "src/codegen/code-factory.h"
11#include "src/codegen/interface-descriptors-inl.h"
12#include "src/codegen/machine-type.h"
13#include "src/codegen/macro-assembler.h"
14#include "src/compiler/backend/instruction-selector.h"
15#include "src/compiler/graph.h"
16#include "src/compiler/js-graph.h"
17#include "src/compiler/linkage.h"
18#include "src/compiler/node-matchers.h"
19#include "src/compiler/pipeline.h"
20#include "src/compiler/raw-machine-assembler.h"
21#include "src/compiler/schedule.h"
22#include "src/execution/frames.h"
23#include "src/handles/handles-inl.h"
24#include "src/heap/factory-inl.h"
25#include "src/interpreter/bytecodes.h"
26#include "src/numbers/conversions-inl.h"
27#include "src/objects/smi.h"
28#include "src/utils/memcopy.h"
29#include "src/zone/zone.h"
30
31namespace v8 {
32namespace internal {
33
34constexpr MachineType MachineTypeOf<Smi>::value;
35constexpr MachineType MachineTypeOf<Object>::value;
36constexpr MachineType MachineTypeOf<MaybeObject>::value;
37
38namespace compiler {
39
40static_assert(std::is_convertible<TNode<Number>, TNode<Object>>::value,
41              "test subtyping");
42static_assert(
43    std::is_convertible<TNode<Number>, TNode<UnionT<Smi, HeapObject>>>::value,
44    "test subtyping");
45static_assert(
46    !std::is_convertible<TNode<UnionT<Smi, HeapObject>>, TNode<Number>>::value,
47    "test subtyping");
48
49CodeAssemblerState::CodeAssemblerState(
50    Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
51    CodeKind kind, const char* name, Builtin builtin)
52    // TODO(rmcilroy): Should we use Linkage::GetBytecodeDispatchDescriptor for
53    // bytecode handlers?
54    : CodeAssemblerState(
55          isolate, zone,
56          Linkage::GetStubCallDescriptor(
57              zone, descriptor, descriptor.GetStackParameterCount(),
58              CallDescriptor::kNoFlags, Operator::kNoProperties),
59          kind, name, builtin) {}
60
61CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone,
62                                       int parameter_count, CodeKind kind,
63                                       const char* name, Builtin builtin)
64    : CodeAssemblerState(
65          isolate, zone,
66          Linkage::GetJSCallDescriptor(zone, false, parameter_count,
67                                       CallDescriptor::kCanUseRoots),
68          kind, name, builtin) {}
69
70CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone,
71                                       CallDescriptor* call_descriptor,
72                                       CodeKind kind, const char* name,
73                                       Builtin builtin)
74    : raw_assembler_(new RawMachineAssembler(
75          isolate, zone->New<Graph>(zone), call_descriptor,
76          MachineType::PointerRepresentation(),
77          InstructionSelector::SupportedMachineOperatorFlags(),
78          InstructionSelector::AlignmentRequirements())),
79      kind_(kind),
80      name_(name),
81      builtin_(builtin),
82      code_generated_(false),
83      variables_(zone),
84      jsgraph_(zone->New<JSGraph>(
85          isolate, raw_assembler_->graph(), raw_assembler_->common(),
86          zone->New<JSOperatorBuilder>(zone), raw_assembler_->simplified(),
87          raw_assembler_->machine())) {}
88
89CodeAssemblerState::~CodeAssemblerState() = default;
90
91int CodeAssemblerState::parameter_count() const {
92  return static_cast<int>(raw_assembler_->call_descriptor()->ParameterCount());
93}
94
95CodeAssembler::~CodeAssembler() = default;
96
97#if DEBUG
98void CodeAssemblerState::PrintCurrentBlock(std::ostream& os) {
99  raw_assembler_->PrintCurrentBlock(os);
100}
101#endif
102
103bool CodeAssemblerState::InsideBlock() { return raw_assembler_->InsideBlock(); }
104
105void CodeAssemblerState::SetInitialDebugInformation(const char* msg,
106                                                    const char* file,
107                                                    int line) {
108#if DEBUG
109  AssemblerDebugInfo debug_info = {msg, file, line};
110  raw_assembler_->SetCurrentExternalSourcePosition({file, line});
111  raw_assembler_->SetInitialDebugInformation(debug_info);
112#endif  // DEBUG
113}
114
115class BreakOnNodeDecorator final : public GraphDecorator {
116 public:
117  explicit BreakOnNodeDecorator(NodeId node_id) : node_id_(node_id) {}
118
119  void Decorate(Node* node) final {
120    if (node->id() == node_id_) {
121      base::OS::DebugBreak();
122    }
123  }
124
125 private:
126  NodeId node_id_;
127};
128
129void CodeAssembler::BreakOnNode(int node_id) {
130  Graph* graph = raw_assembler()->graph();
131  Zone* zone = graph->zone();
132  GraphDecorator* decorator =
133      zone->New<BreakOnNodeDecorator>(static_cast<NodeId>(node_id));
134  graph->AddDecorator(decorator);
135}
136
137void CodeAssembler::RegisterCallGenerationCallbacks(
138    const CodeAssemblerCallback& call_prologue,
139    const CodeAssemblerCallback& call_epilogue) {
140  // The callback can be registered only once.
141  DCHECK(!state_->call_prologue_);
142  DCHECK(!state_->call_epilogue_);
143  state_->call_prologue_ = call_prologue;
144  state_->call_epilogue_ = call_epilogue;
145}
146
147void CodeAssembler::UnregisterCallGenerationCallbacks() {
148  state_->call_prologue_ = nullptr;
149  state_->call_epilogue_ = nullptr;
150}
151
152void CodeAssembler::CallPrologue() {
153  if (state_->call_prologue_) {
154    state_->call_prologue_();
155  }
156}
157
158void CodeAssembler::CallEpilogue() {
159  if (state_->call_epilogue_) {
160    state_->call_epilogue_();
161  }
162}
163
164bool CodeAssembler::Word32ShiftIsSafe() const {
165  return raw_assembler()->machine()->Word32ShiftIsSafe();
166}
167
168// static
169Handle<Code> CodeAssembler::GenerateCode(
170    CodeAssemblerState* state, const AssemblerOptions& options,
171    const ProfileDataFromFile* profile_data) {
172  DCHECK(!state->code_generated_);
173
174  RawMachineAssembler* rasm = state->raw_assembler_.get();
175
176  Handle<Code> code;
177  Graph* graph = rasm->ExportForOptimization();
178
179  code = Pipeline::GenerateCodeForCodeStub(
180             rasm->isolate(), rasm->call_descriptor(), graph, state->jsgraph_,
181             rasm->source_positions(), state->kind_, state->name_,
182             state->builtin_, options, profile_data)
183             .ToHandleChecked();
184
185  state->code_generated_ = true;
186  return code;
187}
188
189bool CodeAssembler::Is64() const { return raw_assembler()->machine()->Is64(); }
190bool CodeAssembler::Is32() const { return raw_assembler()->machine()->Is32(); }
191
192bool CodeAssembler::IsFloat64RoundUpSupported() const {
193  return raw_assembler()->machine()->Float64RoundUp().IsSupported();
194}
195
196bool CodeAssembler::IsFloat64RoundDownSupported() const {
197  return raw_assembler()->machine()->Float64RoundDown().IsSupported();
198}
199
200bool CodeAssembler::IsFloat64RoundTiesEvenSupported() const {
201  return raw_assembler()->machine()->Float64RoundTiesEven().IsSupported();
202}
203
204bool CodeAssembler::IsFloat64RoundTruncateSupported() const {
205  return raw_assembler()->machine()->Float64RoundTruncate().IsSupported();
206}
207
208bool CodeAssembler::IsInt32AbsWithOverflowSupported() const {
209  return raw_assembler()->machine()->Int32AbsWithOverflow().IsSupported();
210}
211
212bool CodeAssembler::IsInt64AbsWithOverflowSupported() const {
213  return raw_assembler()->machine()->Int64AbsWithOverflow().IsSupported();
214}
215
216bool CodeAssembler::IsIntPtrAbsWithOverflowSupported() const {
217  return Is64() ? IsInt64AbsWithOverflowSupported()
218                : IsInt32AbsWithOverflowSupported();
219}
220
221bool CodeAssembler::IsWord32PopcntSupported() const {
222  return raw_assembler()->machine()->Word32Popcnt().IsSupported();
223}
224
225bool CodeAssembler::IsWord64PopcntSupported() const {
226  return raw_assembler()->machine()->Word64Popcnt().IsSupported();
227}
228
229bool CodeAssembler::IsWord32CtzSupported() const {
230  return raw_assembler()->machine()->Word32Ctz().IsSupported();
231}
232
233bool CodeAssembler::IsWord64CtzSupported() const {
234  return raw_assembler()->machine()->Word64Ctz().IsSupported();
235}
236
237#ifdef DEBUG
238void CodeAssembler::GenerateCheckMaybeObjectIsObject(TNode<MaybeObject> node,
239                                                     const char* location) {
240  Label ok(this);
241  GotoIf(WordNotEqual(WordAnd(BitcastMaybeObjectToWord(node),
242                              IntPtrConstant(kHeapObjectTagMask)),
243                      IntPtrConstant(kWeakHeapObjectTag)),
244         &ok);
245  base::EmbeddedVector<char, 1024> message;
246  SNPrintF(message, "no Object: %s", location);
247  TNode<String> message_node = StringConstant(message.begin());
248  // This somewhat misuses the AbortCSADcheck runtime function. This will print
249  // "abort: CSA_DCHECK failed: <message>", which is good enough.
250  AbortCSADcheck(message_node);
251  Unreachable();
252  Bind(&ok);
253}
254#endif
255
256TNode<Int32T> CodeAssembler::Int32Constant(int32_t value) {
257  return UncheckedCast<Int32T>(jsgraph()->Int32Constant(value));
258}
259
260TNode<Int64T> CodeAssembler::Int64Constant(int64_t value) {
261  return UncheckedCast<Int64T>(jsgraph()->Int64Constant(value));
262}
263
264TNode<IntPtrT> CodeAssembler::IntPtrConstant(intptr_t value) {
265  return UncheckedCast<IntPtrT>(jsgraph()->IntPtrConstant(value));
266}
267
268TNode<TaggedIndex> CodeAssembler::TaggedIndexConstant(intptr_t value) {
269  DCHECK(TaggedIndex::IsValid(value));
270  return UncheckedCast<TaggedIndex>(raw_assembler()->IntPtrConstant(value));
271}
272
273TNode<Number> CodeAssembler::NumberConstant(double value) {
274  int smi_value;
275  if (DoubleToSmiInteger(value, &smi_value)) {
276    return UncheckedCast<Number>(SmiConstant(smi_value));
277  } else {
278    // We allocate the heap number constant eagerly at this point instead of
279    // deferring allocation to code generation
280    // (see AllocateAndInstallRequestedHeapObjects) since that makes it easier
281    // to generate constant lookups for embedded builtins.
282    return UncheckedCast<Number>(HeapConstant(
283        isolate()->factory()->NewHeapNumberForCodeAssembler(value)));
284  }
285}
286
287TNode<Smi> CodeAssembler::SmiConstant(Smi value) {
288  return UncheckedCast<Smi>(BitcastWordToTaggedSigned(
289      IntPtrConstant(static_cast<intptr_t>(value.ptr()))));
290}
291
292TNode<Smi> CodeAssembler::SmiConstant(int value) {
293  return SmiConstant(Smi::FromInt(value));
294}
295
296TNode<HeapObject> CodeAssembler::UntypedHeapConstant(
297    Handle<HeapObject> object) {
298  return UncheckedCast<HeapObject>(jsgraph()->HeapConstant(object));
299}
300
301TNode<String> CodeAssembler::StringConstant(const char* str) {
302  Handle<String> internalized_string =
303      factory()->InternalizeString(base::OneByteVector(str));
304  return UncheckedCast<String>(HeapConstant(internalized_string));
305}
306
307TNode<Oddball> CodeAssembler::BooleanConstant(bool value) {
308  Handle<Object> object = isolate()->factory()->ToBoolean(value);
309  return UncheckedCast<Oddball>(
310      jsgraph()->HeapConstant(Handle<HeapObject>::cast(object)));
311}
312
313TNode<ExternalReference> CodeAssembler::ExternalConstant(
314    ExternalReference address) {
315  return UncheckedCast<ExternalReference>(
316      raw_assembler()->ExternalConstant(address));
317}
318
319TNode<Float32T> CodeAssembler::Float32Constant(double value) {
320  return UncheckedCast<Float32T>(jsgraph()->Float32Constant(value));
321}
322
323TNode<Float64T> CodeAssembler::Float64Constant(double value) {
324  return UncheckedCast<Float64T>(jsgraph()->Float64Constant(value));
325}
326
327bool CodeAssembler::IsMapOffsetConstant(Node* node) {
328  return raw_assembler()->IsMapOffsetConstant(node);
329}
330
331bool CodeAssembler::TryToInt32Constant(TNode<IntegralT> node,
332                                       int32_t* out_value) {
333  {
334    Int64Matcher m(node);
335    if (m.HasResolvedValue() &&
336        m.IsInRange(std::numeric_limits<int32_t>::min(),
337                    std::numeric_limits<int32_t>::max())) {
338      *out_value = static_cast<int32_t>(m.ResolvedValue());
339      return true;
340    }
341  }
342
343  {
344    Int32Matcher m(node);
345    if (m.HasResolvedValue()) {
346      *out_value = m.ResolvedValue();
347      return true;
348    }
349  }
350
351  return false;
352}
353
354bool CodeAssembler::TryToInt64Constant(TNode<IntegralT> node,
355                                       int64_t* out_value) {
356  Int64Matcher m(node);
357  if (m.HasResolvedValue()) *out_value = m.ResolvedValue();
358  return m.HasResolvedValue();
359}
360
361bool CodeAssembler::TryToSmiConstant(TNode<Smi> tnode, Smi* out_value) {
362  Node* node = tnode;
363  if (node->opcode() == IrOpcode::kBitcastWordToTaggedSigned) {
364    node = node->InputAt(0);
365  }
366  return TryToSmiConstant(ReinterpretCast<IntPtrT>(tnode), out_value);
367}
368
369bool CodeAssembler::TryToSmiConstant(TNode<IntegralT> node, Smi* out_value) {
370  IntPtrMatcher m(node);
371  if (m.HasResolvedValue()) {
372    intptr_t value = m.ResolvedValue();
373    // Make sure that the value is actually a smi
374    CHECK_EQ(0, value & ((static_cast<intptr_t>(1) << kSmiShiftSize) - 1));
375    *out_value = Smi(static_cast<Address>(value));
376    return true;
377  }
378  return false;
379}
380
381bool CodeAssembler::TryToIntPtrConstant(TNode<Smi> tnode, intptr_t* out_value) {
382  Node* node = tnode;
383  if (node->opcode() == IrOpcode::kBitcastWordToTaggedSigned ||
384      node->opcode() == IrOpcode::kBitcastWordToTagged) {
385    node = node->InputAt(0);
386  }
387  return TryToIntPtrConstant(ReinterpretCast<IntPtrT>(tnode), out_value);
388}
389
390bool CodeAssembler::TryToIntPtrConstant(TNode<IntegralT> node,
391                                        intptr_t* out_value) {
392  IntPtrMatcher m(node);
393  if (m.HasResolvedValue()) *out_value = m.ResolvedValue();
394  return m.HasResolvedValue();
395}
396
397bool CodeAssembler::IsUndefinedConstant(TNode<Object> node) {
398  compiler::HeapObjectMatcher m(node);
399  return m.Is(isolate()->factory()->undefined_value());
400}
401
402bool CodeAssembler::IsNullConstant(TNode<Object> node) {
403  compiler::HeapObjectMatcher m(node);
404  return m.Is(isolate()->factory()->null_value());
405}
406
407Node* CodeAssembler::UntypedParameter(int index) {
408  if (index == kTargetParameterIndex) return raw_assembler()->TargetParameter();
409  return raw_assembler()->Parameter(index);
410}
411
412bool CodeAssembler::IsJSFunctionCall() const {
413  auto call_descriptor = raw_assembler()->call_descriptor();
414  return call_descriptor->IsJSFunctionCall();
415}
416
417TNode<Context> CodeAssembler::GetJSContextParameter() {
418  auto call_descriptor = raw_assembler()->call_descriptor();
419  DCHECK(call_descriptor->IsJSFunctionCall());
420  return Parameter<Context>(Linkage::GetJSCallContextParamIndex(
421      static_cast<int>(call_descriptor->JSParameterCount())));
422}
423
424void CodeAssembler::Return(TNode<Object> value) {
425  DCHECK_EQ(1, raw_assembler()->call_descriptor()->ReturnCount());
426  DCHECK(raw_assembler()->call_descriptor()->GetReturnType(0).IsTagged());
427  return raw_assembler()->Return(value);
428}
429
430void CodeAssembler::Return(TNode<Object> value1, TNode<Object> value2) {
431  DCHECK_EQ(2, raw_assembler()->call_descriptor()->ReturnCount());
432  DCHECK(raw_assembler()->call_descriptor()->GetReturnType(0).IsTagged());
433  DCHECK(raw_assembler()->call_descriptor()->GetReturnType(1).IsTagged());
434  return raw_assembler()->Return(value1, value2);
435}
436
437void CodeAssembler::Return(TNode<Object> value1, TNode<Object> value2,
438                           TNode<Object> value3) {
439  DCHECK_EQ(3, raw_assembler()->call_descriptor()->ReturnCount());
440  DCHECK(raw_assembler()->call_descriptor()->GetReturnType(0).IsTagged());
441  DCHECK(raw_assembler()->call_descriptor()->GetReturnType(1).IsTagged());
442  DCHECK(raw_assembler()->call_descriptor()->GetReturnType(2).IsTagged());
443  return raw_assembler()->Return(value1, value2, value3);
444}
445
446void CodeAssembler::Return(TNode<Int32T> value) {
447  DCHECK_EQ(1, raw_assembler()->call_descriptor()->ReturnCount());
448  DCHECK_EQ(MachineType::Int32(),
449            raw_assembler()->call_descriptor()->GetReturnType(0));
450  return raw_assembler()->Return(value);
451}
452
453void CodeAssembler::Return(TNode<Uint32T> value) {
454  DCHECK_EQ(1, raw_assembler()->call_descriptor()->ReturnCount());
455  DCHECK_EQ(MachineType::Uint32(),
456            raw_assembler()->call_descriptor()->GetReturnType(0));
457  return raw_assembler()->Return(value);
458}
459
460void CodeAssembler::Return(TNode<WordT> value) {
461  DCHECK_EQ(1, raw_assembler()->call_descriptor()->ReturnCount());
462  DCHECK_EQ(
463      MachineType::PointerRepresentation(),
464      raw_assembler()->call_descriptor()->GetReturnType(0).representation());
465  return raw_assembler()->Return(value);
466}
467
468void CodeAssembler::Return(TNode<Float32T> value) {
469  DCHECK_EQ(1, raw_assembler()->call_descriptor()->ReturnCount());
470  DCHECK_EQ(MachineType::Float32(),
471            raw_assembler()->call_descriptor()->GetReturnType(0));
472  return raw_assembler()->Return(value);
473}
474
475void CodeAssembler::Return(TNode<Float64T> value) {
476  DCHECK_EQ(1, raw_assembler()->call_descriptor()->ReturnCount());
477  DCHECK_EQ(MachineType::Float64(),
478            raw_assembler()->call_descriptor()->GetReturnType(0));
479  return raw_assembler()->Return(value);
480}
481
482void CodeAssembler::Return(TNode<WordT> value1, TNode<WordT> value2) {
483  DCHECK_EQ(2, raw_assembler()->call_descriptor()->ReturnCount());
484  DCHECK_EQ(
485      MachineType::PointerRepresentation(),
486      raw_assembler()->call_descriptor()->GetReturnType(0).representation());
487  DCHECK_EQ(
488      MachineType::PointerRepresentation(),
489      raw_assembler()->call_descriptor()->GetReturnType(1).representation());
490  return raw_assembler()->Return(value1, value2);
491}
492
493void CodeAssembler::Return(TNode<WordT> value1, TNode<Object> value2) {
494  DCHECK_EQ(2, raw_assembler()->call_descriptor()->ReturnCount());
495  DCHECK_EQ(
496      MachineType::PointerRepresentation(),
497      raw_assembler()->call_descriptor()->GetReturnType(0).representation());
498  DCHECK(raw_assembler()->call_descriptor()->GetReturnType(1).IsTagged());
499  return raw_assembler()->Return(value1, value2);
500}
501
502void CodeAssembler::PopAndReturn(Node* pop, Node* value) {
503  DCHECK_EQ(1, raw_assembler()->call_descriptor()->ReturnCount());
504  return raw_assembler()->PopAndReturn(pop, value);
505}
506
507void CodeAssembler::ReturnIf(TNode<BoolT> condition, TNode<Object> value) {
508  Label if_return(this), if_continue(this);
509  Branch(condition, &if_return, &if_continue);
510  Bind(&if_return);
511  Return(value);
512  Bind(&if_continue);
513}
514
515void CodeAssembler::AbortCSADcheck(Node* message) {
516  raw_assembler()->AbortCSADcheck(message);
517}
518
519void CodeAssembler::DebugBreak() { raw_assembler()->DebugBreak(); }
520
521void CodeAssembler::Unreachable() {
522  DebugBreak();
523  raw_assembler()->Unreachable();
524}
525
526void CodeAssembler::Comment(std::string str) {
527  if (!FLAG_code_comments) return;
528  raw_assembler()->Comment(str);
529}
530
531void CodeAssembler::StaticAssert(TNode<BoolT> value, const char* source) {
532  raw_assembler()->StaticAssert(value, source);
533}
534
535void CodeAssembler::SetSourcePosition(const char* file, int line) {
536  raw_assembler()->SetCurrentExternalSourcePosition({file, line});
537}
538
539void CodeAssembler::PushSourcePosition() {
540  auto position = raw_assembler()->GetCurrentExternalSourcePosition();
541  state_->macro_call_stack_.push_back(position);
542}
543
544void CodeAssembler::PopSourcePosition() {
545  state_->macro_call_stack_.pop_back();
546}
547
548const std::vector<FileAndLine>& CodeAssembler::GetMacroSourcePositionStack()
549    const {
550  return state_->macro_call_stack_;
551}
552
553void CodeAssembler::Bind(Label* label) { return label->Bind(); }
554
555#if DEBUG
556void CodeAssembler::Bind(Label* label, AssemblerDebugInfo debug_info) {
557  return label->Bind(debug_info);
558}
559#endif  // DEBUG
560
561TNode<RawPtrT> CodeAssembler::LoadFramePointer() {
562  return UncheckedCast<RawPtrT>(raw_assembler()->LoadFramePointer());
563}
564
565TNode<RawPtrT> CodeAssembler::LoadParentFramePointer() {
566  return UncheckedCast<RawPtrT>(raw_assembler()->LoadParentFramePointer());
567}
568
569#define DEFINE_CODE_ASSEMBLER_BINARY_OP(name, ResType, Arg1Type, Arg2Type)   \
570  TNode<ResType> CodeAssembler::name(TNode<Arg1Type> a, TNode<Arg2Type> b) { \
571    return UncheckedCast<ResType>(raw_assembler()->name(a, b));              \
572  }
573CODE_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_ASSEMBLER_BINARY_OP)
574#undef DEFINE_CODE_ASSEMBLER_BINARY_OP
575
576TNode<WordT> CodeAssembler::WordShl(TNode<WordT> value, int shift) {
577  return (shift != 0) ? WordShl(value, IntPtrConstant(shift)) : value;
578}
579
580TNode<WordT> CodeAssembler::WordShr(TNode<WordT> value, int shift) {
581  return (shift != 0) ? WordShr(value, IntPtrConstant(shift)) : value;
582}
583
584TNode<WordT> CodeAssembler::WordSar(TNode<WordT> value, int shift) {
585  return (shift != 0) ? WordSar(value, IntPtrConstant(shift)) : value;
586}
587
588TNode<Word32T> CodeAssembler::Word32Shr(TNode<Word32T> value, int shift) {
589  return (shift != 0) ? Word32Shr(value, Int32Constant(shift)) : value;
590}
591
592TNode<Word32T> CodeAssembler::Word32Sar(TNode<Word32T> value, int shift) {
593  return (shift != 0) ? Word32Sar(value, Int32Constant(shift)) : value;
594}
595
596#define CODE_ASSEMBLER_COMPARE(Name, ArgT, VarT, ToConstant, op)          \
597  TNode<BoolT> CodeAssembler::Name(TNode<ArgT> left, TNode<ArgT> right) { \
598    VarT lhs, rhs;                                                        \
599    if (ToConstant(left, &lhs) && ToConstant(right, &rhs)) {              \
600      return BoolConstant(lhs op rhs);                                    \
601    }                                                                     \
602    return UncheckedCast<BoolT>(raw_assembler()->Name(left, right));      \
603  }
604
605CODE_ASSEMBLER_COMPARE(IntPtrEqual, WordT, intptr_t, TryToIntPtrConstant, ==)
606CODE_ASSEMBLER_COMPARE(WordEqual, WordT, intptr_t, TryToIntPtrConstant, ==)
607CODE_ASSEMBLER_COMPARE(WordNotEqual, WordT, intptr_t, TryToIntPtrConstant, !=)
608CODE_ASSEMBLER_COMPARE(Word32Equal, Word32T, int32_t, TryToInt32Constant, ==)
609CODE_ASSEMBLER_COMPARE(Word32NotEqual, Word32T, int32_t, TryToInt32Constant, !=)
610CODE_ASSEMBLER_COMPARE(Word64Equal, Word64T, int64_t, TryToInt64Constant, ==)
611CODE_ASSEMBLER_COMPARE(Word64NotEqual, Word64T, int64_t, TryToInt64Constant, !=)
612#undef CODE_ASSEMBLER_COMPARE
613
614TNode<UintPtrT> CodeAssembler::ChangeUint32ToWord(TNode<Word32T> value) {
615  if (raw_assembler()->machine()->Is64()) {
616    return UncheckedCast<UintPtrT>(
617        raw_assembler()->ChangeUint32ToUint64(value));
618  }
619  return ReinterpretCast<UintPtrT>(value);
620}
621
622TNode<IntPtrT> CodeAssembler::ChangeInt32ToIntPtr(TNode<Word32T> value) {
623  if (raw_assembler()->machine()->Is64()) {
624    return UncheckedCast<IntPtrT>(raw_assembler()->ChangeInt32ToInt64(value));
625  }
626  return ReinterpretCast<IntPtrT>(value);
627}
628
629TNode<IntPtrT> CodeAssembler::ChangeFloat64ToIntPtr(TNode<Float64T> value) {
630  if (raw_assembler()->machine()->Is64()) {
631    return UncheckedCast<IntPtrT>(raw_assembler()->ChangeFloat64ToInt64(value));
632  }
633  return UncheckedCast<IntPtrT>(raw_assembler()->ChangeFloat64ToInt32(value));
634}
635
636TNode<UintPtrT> CodeAssembler::ChangeFloat64ToUintPtr(TNode<Float64T> value) {
637  if (raw_assembler()->machine()->Is64()) {
638    return UncheckedCast<UintPtrT>(
639        raw_assembler()->ChangeFloat64ToUint64(value));
640  }
641  return UncheckedCast<UintPtrT>(raw_assembler()->ChangeFloat64ToUint32(value));
642}
643
644TNode<Float64T> CodeAssembler::ChangeUintPtrToFloat64(TNode<UintPtrT> value) {
645  if (raw_assembler()->machine()->Is64()) {
646    // TODO(turbofan): Maybe we should introduce a ChangeUint64ToFloat64
647    // machine operator to TurboFan here?
648    return UncheckedCast<Float64T>(
649        raw_assembler()->RoundUint64ToFloat64(value));
650  }
651  return UncheckedCast<Float64T>(raw_assembler()->ChangeUint32ToFloat64(value));
652}
653
654TNode<Float64T> CodeAssembler::RoundIntPtrToFloat64(Node* value) {
655  if (raw_assembler()->machine()->Is64()) {
656    return UncheckedCast<Float64T>(raw_assembler()->RoundInt64ToFloat64(value));
657  }
658  return UncheckedCast<Float64T>(raw_assembler()->ChangeInt32ToFloat64(value));
659}
660
661TNode<Int32T> CodeAssembler::TruncateFloat32ToInt32(TNode<Float32T> value) {
662  return UncheckedCast<Int32T>(raw_assembler()->TruncateFloat32ToInt32(
663      value, TruncateKind::kSetOverflowToMin));
664}
665#define DEFINE_CODE_ASSEMBLER_UNARY_OP(name, ResType, ArgType) \
666  TNode<ResType> CodeAssembler::name(TNode<ArgType> a) {       \
667    return UncheckedCast<ResType>(raw_assembler()->name(a));   \
668  }
669CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP)
670#undef DEFINE_CODE_ASSEMBLER_UNARY_OP
671
672Node* CodeAssembler::Load(MachineType type, Node* base) {
673  return raw_assembler()->Load(type, base);
674}
675
676Node* CodeAssembler::Load(MachineType type, Node* base, Node* offset) {
677  return raw_assembler()->Load(type, base, offset);
678}
679
680TNode<Object> CodeAssembler::LoadFullTagged(Node* base) {
681  return BitcastWordToTagged(Load<RawPtrT>(base));
682}
683
684TNode<Object> CodeAssembler::LoadFullTagged(Node* base, TNode<IntPtrT> offset) {
685  // Please use LoadFromObject(MachineType::MapInHeader(), object,
686  // IntPtrConstant(-kHeapObjectTag)) instead.
687  DCHECK(!raw_assembler()->IsMapOffsetConstantMinusTag(offset));
688  return BitcastWordToTagged(Load<RawPtrT>(base, offset));
689}
690
691Node* CodeAssembler::AtomicLoad(MachineType type, AtomicMemoryOrder order,
692                                TNode<RawPtrT> base, TNode<WordT> offset) {
693  DCHECK(!raw_assembler()->IsMapOffsetConstantMinusTag(offset));
694  return raw_assembler()->AtomicLoad(AtomicLoadParameters(type, order), base,
695                                     offset);
696}
697
698template <class Type>
699TNode<Type> CodeAssembler::AtomicLoad64(AtomicMemoryOrder order,
700                                        TNode<RawPtrT> base,
701                                        TNode<WordT> offset) {
702  return UncheckedCast<Type>(raw_assembler()->AtomicLoad64(
703      AtomicLoadParameters(MachineType::Uint64(), order), base, offset));
704}
705
706template TNode<AtomicInt64> CodeAssembler::AtomicLoad64<AtomicInt64>(
707    AtomicMemoryOrder order, TNode<RawPtrT> base, TNode<WordT> offset);
708template TNode<AtomicUint64> CodeAssembler::AtomicLoad64<AtomicUint64>(
709    AtomicMemoryOrder order, TNode<RawPtrT> base, TNode<WordT> offset);
710
711Node* CodeAssembler::LoadFromObject(MachineType type, TNode<Object> object,
712                                    TNode<IntPtrT> offset) {
713  return raw_assembler()->LoadFromObject(type, object, offset);
714}
715
716#ifdef V8_MAP_PACKING
717Node* CodeAssembler::PackMapWord(Node* value) {
718  TNode<IntPtrT> map_word =
719      BitcastTaggedToWordForTagAndSmiBits(UncheckedCast<AnyTaggedT>(value));
720  TNode<WordT> packed = WordXor(UncheckedCast<WordT>(map_word),
721                                IntPtrConstant(Internals::kMapWordXorMask));
722  return BitcastWordToTaggedSigned(packed);
723}
724#endif
725
726TNode<AnyTaggedT> CodeAssembler::LoadRootMapWord(RootIndex root_index) {
727#ifdef V8_MAP_PACKING
728  Handle<Object> root = isolate()->root_handle(root_index);
729  Node* map = HeapConstant(Handle<Map>::cast(root));
730  map = PackMapWord(map);
731  return ReinterpretCast<AnyTaggedT>(map);
732#else
733  return LoadRoot(root_index);
734#endif
735}
736
737TNode<Object> CodeAssembler::LoadRoot(RootIndex root_index) {
738  if (RootsTable::IsImmortalImmovable(root_index)) {
739    Handle<Object> root = isolate()->root_handle(root_index);
740    if (root->IsSmi()) {
741      return SmiConstant(Smi::cast(*root));
742    } else {
743      return HeapConstant(Handle<HeapObject>::cast(root));
744    }
745  }
746
747  // TODO(jgruber): In theory we could generate better code for this by
748  // letting the macro assembler decide how to load from the roots list. In most
749  // cases, it would boil down to loading from a fixed kRootRegister offset.
750  TNode<ExternalReference> isolate_root =
751      ExternalConstant(ExternalReference::isolate_root(isolate()));
752  int offset = IsolateData::root_slot_offset(root_index);
753  return UncheckedCast<Object>(
754      LoadFullTagged(isolate_root, IntPtrConstant(offset)));
755}
756
757Node* CodeAssembler::UnalignedLoad(MachineType type, TNode<RawPtrT> base,
758                                   TNode<WordT> offset) {
759  return raw_assembler()->UnalignedLoad(type, static_cast<Node*>(base), offset);
760}
761
762void CodeAssembler::Store(Node* base, Node* value) {
763  raw_assembler()->Store(MachineRepresentation::kTagged, base, value,
764                         kFullWriteBarrier);
765}
766
767void CodeAssembler::StoreToObject(MachineRepresentation rep,
768                                  TNode<Object> object, TNode<IntPtrT> offset,
769                                  Node* value,
770                                  StoreToObjectWriteBarrier write_barrier) {
771  WriteBarrierKind write_barrier_kind;
772  switch (write_barrier) {
773    case StoreToObjectWriteBarrier::kFull:
774      write_barrier_kind = WriteBarrierKind::kFullWriteBarrier;
775      break;
776    case StoreToObjectWriteBarrier::kMap:
777      write_barrier_kind = WriteBarrierKind::kMapWriteBarrier;
778      break;
779    case StoreToObjectWriteBarrier::kNone:
780      if (CanBeTaggedPointer(rep)) {
781        write_barrier_kind = WriteBarrierKind::kAssertNoWriteBarrier;
782      } else {
783        write_barrier_kind = WriteBarrierKind::kNoWriteBarrier;
784      }
785      break;
786  }
787  raw_assembler()->StoreToObject(rep, object, offset, value,
788                                 write_barrier_kind);
789}
790
791void CodeAssembler::OptimizedStoreField(MachineRepresentation rep,
792                                        TNode<HeapObject> object, int offset,
793                                        Node* value) {
794  raw_assembler()->OptimizedStoreField(rep, object, offset, value,
795                                       WriteBarrierKind::kFullWriteBarrier);
796}
797
798void CodeAssembler::OptimizedStoreFieldAssertNoWriteBarrier(
799    MachineRepresentation rep, TNode<HeapObject> object, int offset,
800    Node* value) {
801  raw_assembler()->OptimizedStoreField(rep, object, offset, value,
802                                       WriteBarrierKind::kAssertNoWriteBarrier);
803}
804
805void CodeAssembler::OptimizedStoreFieldUnsafeNoWriteBarrier(
806    MachineRepresentation rep, TNode<HeapObject> object, int offset,
807    Node* value) {
808  raw_assembler()->OptimizedStoreField(rep, object, offset, value,
809                                       WriteBarrierKind::kNoWriteBarrier);
810}
811
812void CodeAssembler::OptimizedStoreMap(TNode<HeapObject> object,
813                                      TNode<Map> map) {
814  raw_assembler()->OptimizedStoreMap(object, map);
815}
816
817void CodeAssembler::Store(Node* base, Node* offset, Node* value) {
818  // Please use OptimizedStoreMap(base, value) instead.
819  DCHECK(!raw_assembler()->IsMapOffsetConstantMinusTag(offset));
820  raw_assembler()->Store(MachineRepresentation::kTagged, base, offset, value,
821                         kFullWriteBarrier);
822}
823
824void CodeAssembler::StoreEphemeronKey(Node* base, Node* offset, Node* value) {
825  DCHECK(!raw_assembler()->IsMapOffsetConstantMinusTag(offset));
826  raw_assembler()->Store(MachineRepresentation::kTagged, base, offset, value,
827                         kEphemeronKeyWriteBarrier);
828}
829
830void CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base,
831                                        Node* value) {
832  raw_assembler()->Store(
833      rep, base, value,
834      CanBeTaggedPointer(rep) ? kAssertNoWriteBarrier : kNoWriteBarrier);
835}
836
837void CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base,
838                                        Node* offset, Node* value) {
839  // Please use OptimizedStoreMap(base, value) instead.
840  DCHECK(!raw_assembler()->IsMapOffsetConstantMinusTag(offset));
841  raw_assembler()->Store(
842      rep, base, offset, value,
843      CanBeTaggedPointer(rep) ? kAssertNoWriteBarrier : kNoWriteBarrier);
844}
845
846void CodeAssembler::UnsafeStoreNoWriteBarrier(MachineRepresentation rep,
847                                              Node* base, Node* value) {
848  raw_assembler()->Store(rep, base, value, kNoWriteBarrier);
849}
850
851void CodeAssembler::UnsafeStoreNoWriteBarrier(MachineRepresentation rep,
852                                              Node* base, Node* offset,
853                                              Node* value) {
854  // Please use OptimizedStoreMap(base, value) instead.
855  DCHECK(!raw_assembler()->IsMapOffsetConstantMinusTag(offset));
856  raw_assembler()->Store(rep, base, offset, value, kNoWriteBarrier);
857}
858
859void CodeAssembler::StoreFullTaggedNoWriteBarrier(TNode<RawPtrT> base,
860                                                  TNode<Object> tagged_value) {
861  StoreNoWriteBarrier(MachineType::PointerRepresentation(), base,
862                      BitcastTaggedToWord(tagged_value));
863}
864
865void CodeAssembler::StoreFullTaggedNoWriteBarrier(TNode<RawPtrT> base,
866                                                  TNode<IntPtrT> offset,
867                                                  TNode<Object> tagged_value) {
868  // Please use OptimizedStoreMap(base, tagged_value) instead.
869  DCHECK(!raw_assembler()->IsMapOffsetConstantMinusTag(offset));
870  StoreNoWriteBarrier(MachineType::PointerRepresentation(), base, offset,
871                      BitcastTaggedToWord(tagged_value));
872}
873
874void CodeAssembler::AtomicStore(MachineRepresentation rep,
875                                AtomicMemoryOrder order, TNode<RawPtrT> base,
876                                TNode<WordT> offset, TNode<Word32T> value) {
877  DCHECK(!raw_assembler()->IsMapOffsetConstantMinusTag(offset));
878  raw_assembler()->AtomicStore(
879      AtomicStoreParameters(rep, WriteBarrierKind::kNoWriteBarrier, order),
880      base, offset, value);
881}
882
883void CodeAssembler::AtomicStore64(AtomicMemoryOrder order, TNode<RawPtrT> base,
884                                  TNode<WordT> offset, TNode<UintPtrT> value,
885                                  TNode<UintPtrT> value_high) {
886  raw_assembler()->AtomicStore64(
887      AtomicStoreParameters(MachineRepresentation::kWord64,
888                            WriteBarrierKind::kNoWriteBarrier, order),
889      base, offset, value, value_high);
890}
891
892#define ATOMIC_FUNCTION(name)                                                 \
893  TNode<Word32T> CodeAssembler::Atomic##name(                                 \
894      MachineType type, TNode<RawPtrT> base, TNode<UintPtrT> offset,          \
895      TNode<Word32T> value) {                                                 \
896    return UncheckedCast<Word32T>(                                            \
897        raw_assembler()->Atomic##name(type, base, offset, value));            \
898  }                                                                           \
899  template <class Type>                                                       \
900  TNode<Type> CodeAssembler::Atomic##name##64(                                \
901      TNode<RawPtrT> base, TNode<UintPtrT> offset, TNode<UintPtrT> value,     \
902      TNode<UintPtrT> value_high) {                                           \
903    return UncheckedCast<Type>(                                               \
904        raw_assembler()->Atomic##name##64(base, offset, value, value_high));  \
905  }                                                                           \
906  template TNode<AtomicInt64> CodeAssembler::Atomic##name##64 < AtomicInt64 > \
907      (TNode<RawPtrT> base, TNode<UintPtrT> offset, TNode<UintPtrT> value,    \
908       TNode<UintPtrT> value_high);                                           \
909  template TNode<AtomicUint64> CodeAssembler::Atomic##name##64 <              \
910      AtomicUint64 > (TNode<RawPtrT> base, TNode<UintPtrT> offset,            \
911                      TNode<UintPtrT> value, TNode<UintPtrT> value_high);
912ATOMIC_FUNCTION(Add)
913ATOMIC_FUNCTION(Sub)
914ATOMIC_FUNCTION(And)
915ATOMIC_FUNCTION(Or)
916ATOMIC_FUNCTION(Xor)
917ATOMIC_FUNCTION(Exchange)
918#undef ATOMIC_FUNCTION
919
920TNode<Word32T> CodeAssembler::AtomicCompareExchange(MachineType type,
921                                                    TNode<RawPtrT> base,
922                                                    TNode<WordT> offset,
923                                                    TNode<Word32T> old_value,
924                                                    TNode<Word32T> new_value) {
925  return UncheckedCast<Word32T>(raw_assembler()->AtomicCompareExchange(
926      type, base, offset, old_value, new_value));
927}
928
929template <class Type>
930TNode<Type> CodeAssembler::AtomicCompareExchange64(
931    TNode<RawPtrT> base, TNode<WordT> offset, TNode<UintPtrT> old_value,
932    TNode<UintPtrT> new_value, TNode<UintPtrT> old_value_high,
933    TNode<UintPtrT> new_value_high) {
934  // This uses Uint64() intentionally: AtomicCompareExchange is not implemented
935  // for Int64(), which is fine because the machine instruction only cares
936  // about words.
937  return UncheckedCast<Type>(raw_assembler()->AtomicCompareExchange64(
938      base, offset, old_value, old_value_high, new_value, new_value_high));
939}
940
941template TNode<AtomicInt64> CodeAssembler::AtomicCompareExchange64<AtomicInt64>(
942    TNode<RawPtrT> base, TNode<WordT> offset, TNode<UintPtrT> old_value,
943    TNode<UintPtrT> new_value, TNode<UintPtrT> old_value_high,
944    TNode<UintPtrT> new_value_high);
945template TNode<AtomicUint64>
946CodeAssembler::AtomicCompareExchange64<AtomicUint64>(
947    TNode<RawPtrT> base, TNode<WordT> offset, TNode<UintPtrT> old_value,
948    TNode<UintPtrT> new_value, TNode<UintPtrT> old_value_high,
949    TNode<UintPtrT> new_value_high);
950
951void CodeAssembler::StoreRoot(RootIndex root_index, TNode<Object> value) {
952  DCHECK(!RootsTable::IsImmortalImmovable(root_index));
953  TNode<ExternalReference> isolate_root =
954      ExternalConstant(ExternalReference::isolate_root(isolate()));
955  int offset = IsolateData::root_slot_offset(root_index);
956  StoreFullTaggedNoWriteBarrier(isolate_root, IntPtrConstant(offset), value);
957}
958
959Node* CodeAssembler::Projection(int index, Node* value) {
960  DCHECK_LT(index, value->op()->ValueOutputCount());
961  return raw_assembler()->Projection(index, value);
962}
963
964TNode<HeapObject> CodeAssembler::OptimizedAllocate(
965    TNode<IntPtrT> size, AllocationType allocation,
966    AllowLargeObjects allow_large_objects) {
967  return UncheckedCast<HeapObject>(raw_assembler()->OptimizedAllocate(
968      size, allocation, allow_large_objects));
969}
970
971void CodeAssembler::HandleException(Node* node) {
972  if (state_->exception_handler_labels_.size() == 0) return;
973  CodeAssemblerExceptionHandlerLabel* label =
974      state_->exception_handler_labels_.back();
975
976  if (node->op()->HasProperty(Operator::kNoThrow)) {
977    return;
978  }
979
980  Label success(this), exception(this, Label::kDeferred);
981  success.MergeVariables();
982  exception.MergeVariables();
983
984  raw_assembler()->Continuations(node, success.label_, exception.label_);
985
986  Bind(&exception);
987  const Operator* op = raw_assembler()->common()->IfException();
988  Node* exception_value = raw_assembler()->AddNode(op, node, node);
989  label->AddInputs({UncheckedCast<Object>(exception_value)});
990  Goto(label->plain_label());
991
992  Bind(&success);
993  raw_assembler()->AddNode(raw_assembler()->common()->IfSuccess(), node);
994}
995
996namespace {
997template <size_t kMaxSize>
998class NodeArray {
999 public:
1000  void Add(Node* node) {
1001    DCHECK_GT(kMaxSize, size());
1002    *ptr_++ = node;
1003  }
1004
1005  Node* const* data() const { return arr_; }
1006  int size() const { return static_cast<int>(ptr_ - arr_); }
1007
1008 private:
1009  Node* arr_[kMaxSize];
1010  Node** ptr_ = arr_;
1011};
1012}  // namespace
1013
1014Node* CodeAssembler::CallRuntimeImpl(
1015    Runtime::FunctionId function, TNode<Object> context,
1016    std::initializer_list<TNode<Object>> args) {
1017  int result_size = Runtime::FunctionForId(function)->result_size;
1018  TNode<CodeT> centry =
1019      HeapConstant(CodeFactory::RuntimeCEntry(isolate(), result_size));
1020  constexpr size_t kMaxNumArgs = 6;
1021  DCHECK_GE(kMaxNumArgs, args.size());
1022  int argc = static_cast<int>(args.size());
1023  auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
1024      zone(), function, argc, Operator::kNoProperties,
1025      Runtime::MayAllocate(function) ? CallDescriptor::kNoFlags
1026                                     : CallDescriptor::kNoAllocate);
1027
1028  TNode<ExternalReference> ref =
1029      ExternalConstant(ExternalReference::Create(function));
1030  TNode<Int32T> arity = Int32Constant(argc);
1031
1032  NodeArray<kMaxNumArgs + 4> inputs;
1033  inputs.Add(centry);
1034  for (auto arg : args) inputs.Add(arg);
1035  inputs.Add(ref);
1036  inputs.Add(arity);
1037  inputs.Add(context);
1038
1039  CallPrologue();
1040  Node* return_value =
1041      raw_assembler()->CallN(call_descriptor, inputs.size(), inputs.data());
1042  HandleException(return_value);
1043  CallEpilogue();
1044  return return_value;
1045}
1046
1047void CodeAssembler::TailCallRuntimeImpl(
1048    Runtime::FunctionId function, TNode<Int32T> arity, TNode<Object> context,
1049    std::initializer_list<TNode<Object>> args) {
1050  int result_size = Runtime::FunctionForId(function)->result_size;
1051  TNode<CodeT> centry =
1052      HeapConstant(CodeFactory::RuntimeCEntry(isolate(), result_size));
1053  constexpr size_t kMaxNumArgs = 6;
1054  DCHECK_GE(kMaxNumArgs, args.size());
1055  int argc = static_cast<int>(args.size());
1056  auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
1057      zone(), function, argc, Operator::kNoProperties,
1058      CallDescriptor::kNoFlags);
1059
1060  TNode<ExternalReference> ref =
1061      ExternalConstant(ExternalReference::Create(function));
1062
1063  NodeArray<kMaxNumArgs + 4> inputs;
1064  inputs.Add(centry);
1065  for (auto arg : args) inputs.Add(arg);
1066  inputs.Add(ref);
1067  inputs.Add(arity);
1068  inputs.Add(context);
1069
1070  raw_assembler()->TailCallN(call_descriptor, inputs.size(), inputs.data());
1071}
1072
1073Node* CodeAssembler::CallStubN(StubCallMode call_mode,
1074                               const CallInterfaceDescriptor& descriptor,
1075                               int input_count, Node* const* inputs) {
1076  DCHECK(call_mode == StubCallMode::kCallCodeObject ||
1077         call_mode == StubCallMode::kCallBuiltinPointer);
1078
1079  // implicit nodes are target and optionally context.
1080  int implicit_nodes = descriptor.HasContextParameter() ? 2 : 1;
1081  DCHECK_LE(implicit_nodes, input_count);
1082  int argc = input_count - implicit_nodes;
1083#ifdef DEBUG
1084  if (descriptor.AllowVarArgs()) {
1085    DCHECK_LE(descriptor.GetParameterCount(), argc);
1086  } else {
1087    DCHECK_EQ(descriptor.GetParameterCount(), argc);
1088  }
1089#endif
1090  // Extra arguments not mentioned in the descriptor are passed on the stack.
1091  int stack_parameter_count = argc - descriptor.GetRegisterParameterCount();
1092  DCHECK_LE(descriptor.GetStackParameterCount(), stack_parameter_count);
1093
1094  auto call_descriptor = Linkage::GetStubCallDescriptor(
1095      zone(), descriptor, stack_parameter_count, CallDescriptor::kNoFlags,
1096      Operator::kNoProperties, call_mode);
1097
1098  CallPrologue();
1099  Node* return_value =
1100      raw_assembler()->CallN(call_descriptor, input_count, inputs);
1101  HandleException(return_value);
1102  CallEpilogue();
1103  return return_value;
1104}
1105
1106void CodeAssembler::TailCallStubImpl(const CallInterfaceDescriptor& descriptor,
1107                                     TNode<CodeT> target, TNode<Object> context,
1108                                     std::initializer_list<Node*> args) {
1109  constexpr size_t kMaxNumArgs = 11;
1110  DCHECK_GE(kMaxNumArgs, args.size());
1111  DCHECK_EQ(descriptor.GetParameterCount(), args.size());
1112  auto call_descriptor = Linkage::GetStubCallDescriptor(
1113      zone(), descriptor, descriptor.GetStackParameterCount(),
1114      CallDescriptor::kNoFlags, Operator::kNoProperties);
1115
1116  NodeArray<kMaxNumArgs + 2> inputs;
1117  inputs.Add(target);
1118  for (auto arg : args) inputs.Add(arg);
1119  if (descriptor.HasContextParameter()) {
1120    inputs.Add(context);
1121  }
1122
1123  raw_assembler()->TailCallN(call_descriptor, inputs.size(), inputs.data());
1124}
1125
1126Node* CodeAssembler::CallStubRImpl(StubCallMode call_mode,
1127                                   const CallInterfaceDescriptor& descriptor,
1128                                   TNode<Object> target, TNode<Object> context,
1129                                   std::initializer_list<Node*> args) {
1130  DCHECK(call_mode == StubCallMode::kCallCodeObject ||
1131         call_mode == StubCallMode::kCallBuiltinPointer);
1132
1133  constexpr size_t kMaxNumArgs = 10;
1134  DCHECK_GE(kMaxNumArgs, args.size());
1135
1136  NodeArray<kMaxNumArgs + 2> inputs;
1137  inputs.Add(target);
1138  for (auto arg : args) inputs.Add(arg);
1139  if (descriptor.HasContextParameter()) {
1140    inputs.Add(context);
1141  }
1142
1143  return CallStubN(call_mode, descriptor, inputs.size(), inputs.data());
1144}
1145
1146Node* CodeAssembler::CallJSStubImpl(const CallInterfaceDescriptor& descriptor,
1147                                    TNode<Object> target, TNode<Object> context,
1148                                    TNode<Object> function,
1149                                    base::Optional<TNode<Object>> new_target,
1150                                    TNode<Int32T> arity,
1151                                    std::initializer_list<Node*> args) {
1152  constexpr size_t kMaxNumArgs = 10;
1153  DCHECK_GE(kMaxNumArgs, args.size());
1154  NodeArray<kMaxNumArgs + 5> inputs;
1155  inputs.Add(target);
1156  inputs.Add(function);
1157  if (new_target) {
1158    inputs.Add(*new_target);
1159  }
1160  inputs.Add(arity);
1161  for (auto arg : args) inputs.Add(arg);
1162  if (descriptor.HasContextParameter()) {
1163    inputs.Add(context);
1164  }
1165  return CallStubN(StubCallMode::kCallCodeObject, descriptor, inputs.size(),
1166                   inputs.data());
1167}
1168
1169void CodeAssembler::TailCallStubThenBytecodeDispatchImpl(
1170    const CallInterfaceDescriptor& descriptor, Node* target, Node* context,
1171    std::initializer_list<Node*> args) {
1172  constexpr size_t kMaxNumArgs = 6;
1173  DCHECK_GE(kMaxNumArgs, args.size());
1174
1175  DCHECK_LE(descriptor.GetParameterCount(), args.size());
1176  int argc = static_cast<int>(args.size());
1177  // Extra arguments not mentioned in the descriptor are passed on the stack.
1178  int stack_parameter_count = argc - descriptor.GetRegisterParameterCount();
1179  DCHECK_LE(descriptor.GetStackParameterCount(), stack_parameter_count);
1180  auto call_descriptor = Linkage::GetStubCallDescriptor(
1181      zone(), descriptor, stack_parameter_count, CallDescriptor::kNoFlags,
1182      Operator::kNoProperties);
1183
1184  NodeArray<kMaxNumArgs + 2> inputs;
1185  inputs.Add(target);
1186  for (auto arg : args) inputs.Add(arg);
1187  inputs.Add(context);
1188
1189  raw_assembler()->TailCallN(call_descriptor, inputs.size(), inputs.data());
1190}
1191
1192template <class... TArgs>
1193void CodeAssembler::TailCallBytecodeDispatch(
1194    const CallInterfaceDescriptor& descriptor, TNode<RawPtrT> target,
1195    TArgs... args) {
1196  DCHECK_EQ(descriptor.GetParameterCount(), sizeof...(args));
1197  auto call_descriptor = Linkage::GetBytecodeDispatchCallDescriptor(
1198      zone(), descriptor, descriptor.GetStackParameterCount());
1199
1200  Node* nodes[] = {target, args...};
1201  CHECK_EQ(descriptor.GetParameterCount() + 1, arraysize(nodes));
1202  raw_assembler()->TailCallN(call_descriptor, arraysize(nodes), nodes);
1203}
1204
1205// Instantiate TailCallBytecodeDispatch() for argument counts used by
1206// CSA-generated code
1207template V8_EXPORT_PRIVATE void CodeAssembler::TailCallBytecodeDispatch(
1208    const CallInterfaceDescriptor& descriptor, TNode<RawPtrT> target,
1209    TNode<Object>, TNode<IntPtrT>, TNode<BytecodeArray>,
1210    TNode<ExternalReference>);
1211
1212void CodeAssembler::TailCallJSCode(TNode<CodeT> code, TNode<Context> context,
1213                                   TNode<JSFunction> function,
1214                                   TNode<Object> new_target,
1215                                   TNode<Int32T> arg_count) {
1216  JSTrampolineDescriptor descriptor;
1217  auto call_descriptor = Linkage::GetStubCallDescriptor(
1218      zone(), descriptor, descriptor.GetStackParameterCount(),
1219      CallDescriptor::kFixedTargetRegister, Operator::kNoProperties);
1220
1221  Node* nodes[] = {code, function, new_target, arg_count, context};
1222  CHECK_EQ(descriptor.GetParameterCount() + 2, arraysize(nodes));
1223  raw_assembler()->TailCallN(call_descriptor, arraysize(nodes), nodes);
1224}
1225
1226Node* CodeAssembler::CallCFunctionN(Signature<MachineType>* signature,
1227                                    int input_count, Node* const* inputs) {
1228  auto call_descriptor = Linkage::GetSimplifiedCDescriptor(zone(), signature);
1229  return raw_assembler()->CallN(call_descriptor, input_count, inputs);
1230}
1231
1232Node* CodeAssembler::CallCFunction(
1233    Node* function, base::Optional<MachineType> return_type,
1234    std::initializer_list<CodeAssembler::CFunctionArg> args) {
1235  return raw_assembler()->CallCFunction(function, return_type, args);
1236}
1237
1238Node* CodeAssembler::CallCFunctionWithoutFunctionDescriptor(
1239    Node* function, MachineType return_type,
1240    std::initializer_list<CodeAssembler::CFunctionArg> args) {
1241  return raw_assembler()->CallCFunctionWithoutFunctionDescriptor(
1242      function, return_type, args);
1243}
1244
1245Node* CodeAssembler::CallCFunctionWithCallerSavedRegisters(
1246    Node* function, MachineType return_type, SaveFPRegsMode mode,
1247    std::initializer_list<CodeAssembler::CFunctionArg> args) {
1248  DCHECK(return_type.LessThanOrEqualPointerSize());
1249  return raw_assembler()->CallCFunctionWithCallerSavedRegisters(
1250      function, return_type, mode, args);
1251}
1252
1253void CodeAssembler::Goto(Label* label) {
1254  label->MergeVariables();
1255  raw_assembler()->Goto(label->label_);
1256}
1257
1258void CodeAssembler::GotoIf(TNode<IntegralT> condition, Label* true_label) {
1259  Label false_label(this);
1260  Branch(condition, true_label, &false_label);
1261  Bind(&false_label);
1262}
1263
1264void CodeAssembler::GotoIfNot(TNode<IntegralT> condition, Label* false_label) {
1265  Label true_label(this);
1266  Branch(condition, &true_label, false_label);
1267  Bind(&true_label);
1268}
1269
1270void CodeAssembler::Branch(TNode<IntegralT> condition, Label* true_label,
1271                           Label* false_label) {
1272  int32_t constant;
1273  if (TryToInt32Constant(condition, &constant)) {
1274    if ((true_label->is_used() || true_label->is_bound()) &&
1275        (false_label->is_used() || false_label->is_bound())) {
1276      return Goto(constant ? true_label : false_label);
1277    }
1278  }
1279  true_label->MergeVariables();
1280  false_label->MergeVariables();
1281  return raw_assembler()->Branch(condition, true_label->label_,
1282                                 false_label->label_);
1283}
1284
1285void CodeAssembler::Branch(TNode<BoolT> condition,
1286                           const std::function<void()>& true_body,
1287                           const std::function<void()>& false_body) {
1288  int32_t constant;
1289  if (TryToInt32Constant(condition, &constant)) {
1290    return constant ? true_body() : false_body();
1291  }
1292
1293  Label vtrue(this), vfalse(this);
1294  Branch(condition, &vtrue, &vfalse);
1295
1296  Bind(&vtrue);
1297  true_body();
1298
1299  Bind(&vfalse);
1300  false_body();
1301}
1302
1303void CodeAssembler::Branch(TNode<BoolT> condition, Label* true_label,
1304                           const std::function<void()>& false_body) {
1305  int32_t constant;
1306  if (TryToInt32Constant(condition, &constant)) {
1307    return constant ? Goto(true_label) : false_body();
1308  }
1309
1310  Label vfalse(this);
1311  Branch(condition, true_label, &vfalse);
1312  Bind(&vfalse);
1313  false_body();
1314}
1315
1316void CodeAssembler::Branch(TNode<BoolT> condition,
1317                           const std::function<void()>& true_body,
1318                           Label* false_label) {
1319  int32_t constant;
1320  if (TryToInt32Constant(condition, &constant)) {
1321    return constant ? true_body() : Goto(false_label);
1322  }
1323
1324  Label vtrue(this);
1325  Branch(condition, &vtrue, false_label);
1326  Bind(&vtrue);
1327  true_body();
1328}
1329
1330void CodeAssembler::Switch(Node* index, Label* default_label,
1331                           const int32_t* case_values, Label** case_labels,
1332                           size_t case_count) {
1333  RawMachineLabel** labels = zone()->NewArray<RawMachineLabel*>(case_count);
1334  for (size_t i = 0; i < case_count; ++i) {
1335    labels[i] = case_labels[i]->label_;
1336    case_labels[i]->MergeVariables();
1337  }
1338  default_label->MergeVariables();
1339  return raw_assembler()->Switch(index, default_label->label_, case_values,
1340                                 labels, case_count);
1341}
1342
1343bool CodeAssembler::UnalignedLoadSupported(MachineRepresentation rep) const {
1344  return raw_assembler()->machine()->UnalignedLoadSupported(rep);
1345}
1346bool CodeAssembler::UnalignedStoreSupported(MachineRepresentation rep) const {
1347  return raw_assembler()->machine()->UnalignedStoreSupported(rep);
1348}
1349
1350// RawMachineAssembler delegate helpers:
1351Isolate* CodeAssembler::isolate() const { return raw_assembler()->isolate(); }
1352
1353Factory* CodeAssembler::factory() const { return isolate()->factory(); }
1354
1355Zone* CodeAssembler::zone() const { return raw_assembler()->zone(); }
1356
1357bool CodeAssembler::IsExceptionHandlerActive() const {
1358  return state_->exception_handler_labels_.size() != 0;
1359}
1360
1361RawMachineAssembler* CodeAssembler::raw_assembler() const {
1362  return state_->raw_assembler_.get();
1363}
1364
1365JSGraph* CodeAssembler::jsgraph() const { return state_->jsgraph_; }
1366
1367// The core implementation of Variable is stored through an indirection so
1368// that it can outlive the often block-scoped Variable declarations. This is
1369// needed to ensure that variable binding and merging through phis can
1370// properly be verified.
1371class CodeAssemblerVariable::Impl : public ZoneObject {
1372 public:
1373  explicit Impl(MachineRepresentation rep, CodeAssemblerState::VariableId id)
1374      :
1375#if DEBUG
1376        debug_info_(AssemblerDebugInfo(nullptr, nullptr, -1)),
1377#endif
1378        value_(nullptr),
1379        rep_(rep),
1380        var_id_(id) {
1381  }
1382
1383#if DEBUG
1384  AssemblerDebugInfo debug_info() const { return debug_info_; }
1385  void set_debug_info(AssemblerDebugInfo debug_info) {
1386    debug_info_ = debug_info;
1387  }
1388
1389  AssemblerDebugInfo debug_info_;
1390#endif  // DEBUG
1391  bool operator<(const CodeAssemblerVariable::Impl& other) const {
1392    return var_id_ < other.var_id_;
1393  }
1394  Node* value_;
1395  MachineRepresentation rep_;
1396  CodeAssemblerState::VariableId var_id_;
1397};
1398
1399bool CodeAssemblerVariable::ImplComparator::operator()(
1400    const CodeAssemblerVariable::Impl* a,
1401    const CodeAssemblerVariable::Impl* b) const {
1402  return *a < *b;
1403}
1404
1405CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
1406                                             MachineRepresentation rep)
1407    : impl_(assembler->zone()->New<Impl>(rep,
1408                                         assembler->state()->NextVariableId())),
1409      state_(assembler->state()) {
1410  state_->variables_.insert(impl_);
1411}
1412
1413CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
1414                                             MachineRepresentation rep,
1415                                             Node* initial_value)
1416    : CodeAssemblerVariable(assembler, rep) {
1417  Bind(initial_value);
1418}
1419
1420#if DEBUG
1421CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
1422                                             AssemblerDebugInfo debug_info,
1423                                             MachineRepresentation rep)
1424    : impl_(assembler->zone()->New<Impl>(rep,
1425                                         assembler->state()->NextVariableId())),
1426      state_(assembler->state()) {
1427  impl_->set_debug_info(debug_info);
1428  state_->variables_.insert(impl_);
1429}
1430
1431CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
1432                                             AssemblerDebugInfo debug_info,
1433                                             MachineRepresentation rep,
1434                                             Node* initial_value)
1435    : CodeAssemblerVariable(assembler, debug_info, rep) {
1436  impl_->set_debug_info(debug_info);
1437  Bind(initial_value);
1438}
1439#endif  // DEBUG
1440
1441CodeAssemblerVariable::~CodeAssemblerVariable() {
1442  state_->variables_.erase(impl_);
1443}
1444
1445void CodeAssemblerVariable::Bind(Node* value) { impl_->value_ = value; }
1446
1447Node* CodeAssemblerVariable::value() const {
1448#if DEBUG
1449  if (!IsBound()) {
1450    std::stringstream str;
1451    str << "#Use of unbound variable:"
1452        << "#\n    Variable:      " << *this << "#\n    Current Block: ";
1453    state_->PrintCurrentBlock(str);
1454    FATAL("%s", str.str().c_str());
1455  }
1456  if (!state_->InsideBlock()) {
1457    std::stringstream str;
1458    str << "#Accessing variable value outside a block:"
1459        << "#\n    Variable:      " << *this;
1460    FATAL("%s", str.str().c_str());
1461  }
1462#endif  // DEBUG
1463  return impl_->value_;
1464}
1465
1466MachineRepresentation CodeAssemblerVariable::rep() const { return impl_->rep_; }
1467
1468bool CodeAssemblerVariable::IsBound() const { return impl_->value_ != nullptr; }
1469
1470std::ostream& operator<<(std::ostream& os,
1471                         const CodeAssemblerVariable::Impl& impl) {
1472#if DEBUG
1473  AssemblerDebugInfo info = impl.debug_info();
1474  if (info.name) os << "V" << info;
1475#endif  // DEBUG
1476  return os;
1477}
1478
1479std::ostream& operator<<(std::ostream& os,
1480                         const CodeAssemblerVariable& variable) {
1481  os << *variable.impl_;
1482  return os;
1483}
1484
1485CodeAssemblerLabel::CodeAssemblerLabel(CodeAssembler* assembler,
1486                                       size_t vars_count,
1487                                       CodeAssemblerVariable* const* vars,
1488                                       CodeAssemblerLabel::Type type)
1489    : bound_(false),
1490      merge_count_(0),
1491      state_(assembler->state()),
1492      label_(nullptr) {
1493  label_ = assembler->zone()->New<RawMachineLabel>(
1494      type == kDeferred ? RawMachineLabel::kDeferred
1495                        : RawMachineLabel::kNonDeferred);
1496  for (size_t i = 0; i < vars_count; ++i) {
1497    variable_phis_[vars[i]->impl_] = nullptr;
1498  }
1499}
1500
1501CodeAssemblerLabel::~CodeAssemblerLabel() { label_->~RawMachineLabel(); }
1502
1503void CodeAssemblerLabel::MergeVariables() {
1504  ++merge_count_;
1505  for (CodeAssemblerVariable::Impl* var : state_->variables_) {
1506    size_t count = 0;
1507    Node* node = var->value_;
1508    if (node != nullptr) {
1509      auto i = variable_merges_.find(var);
1510      if (i != variable_merges_.end()) {
1511        i->second.push_back(node);
1512        count = i->second.size();
1513      } else {
1514        count = 1;
1515        variable_merges_[var] = std::vector<Node*>(1, node);
1516      }
1517    }
1518    // If the following asserts, then you've jumped to a label without a bound
1519    // variable along that path that expects to merge its value into a phi.
1520    // This can also occur if a label is bound that is never jumped to.
1521    DCHECK(variable_phis_.find(var) == variable_phis_.end() ||
1522           count == merge_count_);
1523    USE(count);
1524
1525    // If the label is already bound, we already know the set of variables to
1526    // merge and phi nodes have already been created.
1527    if (bound_) {
1528      auto phi = variable_phis_.find(var);
1529      if (phi != variable_phis_.end()) {
1530        DCHECK_NOT_NULL(phi->second);
1531        state_->raw_assembler_->AppendPhiInput(phi->second, node);
1532      } else {
1533        auto i = variable_merges_.find(var);
1534        if (i != variable_merges_.end()) {
1535          // If the following assert fires, then you've declared a variable that
1536          // has the same bound value along all paths up until the point you
1537          // bound this label, but then later merged a path with a new value for
1538          // the variable after the label bind (it's not possible to add phis to
1539          // the bound label after the fact, just make sure to list the variable
1540          // in the label's constructor's list of merged variables).
1541#if DEBUG
1542          if (find_if(i->second.begin(), i->second.end(),
1543                      [node](Node* e) -> bool { return node != e; }) !=
1544              i->second.end()) {
1545            std::stringstream str;
1546            str << "Unmerged variable found when jumping to block. \n"
1547                << "#    Variable:      " << *var;
1548            if (bound_) {
1549              str << "\n#    Target block:  " << *label_->block();
1550            }
1551            str << "\n#    Current Block: ";
1552            state_->PrintCurrentBlock(str);
1553            FATAL("%s", str.str().c_str());
1554          }
1555#endif  // DEBUG
1556        }
1557      }
1558    }
1559  }
1560}
1561
1562#if DEBUG
1563void CodeAssemblerLabel::Bind(AssemblerDebugInfo debug_info) {
1564  if (bound_) {
1565    std::stringstream str;
1566    str << "Cannot bind the same label twice:"
1567        << "\n#    current:  " << debug_info
1568        << "\n#    previous: " << *label_->block();
1569    FATAL("%s", str.str().c_str());
1570  }
1571  if (FLAG_enable_source_at_csa_bind) {
1572    state_->raw_assembler_->SetCurrentExternalSourcePosition(
1573        {debug_info.file, debug_info.line});
1574  }
1575  state_->raw_assembler_->Bind(label_, debug_info);
1576  UpdateVariablesAfterBind();
1577}
1578#endif  // DEBUG
1579
1580void CodeAssemblerLabel::Bind() {
1581  DCHECK(!bound_);
1582  state_->raw_assembler_->Bind(label_);
1583  UpdateVariablesAfterBind();
1584}
1585
1586void CodeAssemblerLabel::UpdateVariablesAfterBind() {
1587  // Make sure that all variables that have changed along any path up to this
1588  // point are marked as merge variables.
1589  for (auto var : state_->variables_) {
1590    Node* shared_value = nullptr;
1591    auto i = variable_merges_.find(var);
1592    if (i != variable_merges_.end()) {
1593      for (auto value : i->second) {
1594        DCHECK_NOT_NULL(value);
1595        if (value != shared_value) {
1596          if (shared_value == nullptr) {
1597            shared_value = value;
1598          } else {
1599            variable_phis_[var] = nullptr;
1600          }
1601        }
1602      }
1603    }
1604  }
1605
1606  for (auto var : variable_phis_) {
1607    CodeAssemblerVariable::Impl* var_impl = var.first;
1608    auto i = variable_merges_.find(var_impl);
1609#if DEBUG
1610    bool not_found = i == variable_merges_.end();
1611    if (not_found || i->second.size() != merge_count_) {
1612      std::stringstream str;
1613      str << "A variable that has been marked as beeing merged at the label"
1614          << "\n# doesn't have a bound value along all of the paths that "
1615          << "\n# have been merged into the label up to this point."
1616          << "\n#"
1617          << "\n# This can happen in the following cases:"
1618          << "\n# - By explicitly marking it so in the label constructor"
1619          << "\n# - By having seen different bound values at branches"
1620          << "\n#"
1621          << "\n# Merge count:     expected=" << merge_count_
1622          << " vs. found=" << (not_found ? 0 : i->second.size())
1623          << "\n# Variable:      " << *var_impl
1624          << "\n# Current Block: " << *label_->block();
1625      FATAL("%s", str.str().c_str());
1626    }
1627#endif  // DEBUG
1628    Node* phi = state_->raw_assembler_->Phi(
1629        var.first->rep_, static_cast<int>(merge_count_), &(i->second[0]));
1630    variable_phis_[var_impl] = phi;
1631  }
1632
1633  // Bind all variables to a merge phi, the common value along all paths or
1634  // null.
1635  for (auto var : state_->variables_) {
1636    auto i = variable_phis_.find(var);
1637    if (i != variable_phis_.end()) {
1638      var->value_ = i->second;
1639    } else {
1640      auto j = variable_merges_.find(var);
1641      if (j != variable_merges_.end() && j->second.size() == merge_count_) {
1642        var->value_ = j->second.back();
1643      } else {
1644        var->value_ = nullptr;
1645      }
1646    }
1647  }
1648
1649  bound_ = true;
1650}
1651
1652void CodeAssemblerParameterizedLabelBase::AddInputs(std::vector<Node*> inputs) {
1653  if (!phi_nodes_.empty()) {
1654    DCHECK_EQ(inputs.size(), phi_nodes_.size());
1655    for (size_t i = 0; i < inputs.size(); ++i) {
1656      // We use {nullptr} as a sentinel for an uninitialized value.
1657      if (phi_nodes_[i] == nullptr) continue;
1658      state_->raw_assembler_->AppendPhiInput(phi_nodes_[i], inputs[i]);
1659    }
1660  } else {
1661    DCHECK_EQ(inputs.size(), phi_inputs_.size());
1662    for (size_t i = 0; i < inputs.size(); ++i) {
1663      phi_inputs_[i].push_back(inputs[i]);
1664    }
1665  }
1666}
1667
1668Node* CodeAssemblerParameterizedLabelBase::CreatePhi(
1669    MachineRepresentation rep, const std::vector<Node*>& inputs) {
1670  for (Node* input : inputs) {
1671    // We use {nullptr} as a sentinel for an uninitialized value. We must not
1672    // create phi nodes for these.
1673    if (input == nullptr) return nullptr;
1674  }
1675  return state_->raw_assembler_->Phi(rep, static_cast<int>(inputs.size()),
1676                                     &inputs.front());
1677}
1678
1679const std::vector<Node*>& CodeAssemblerParameterizedLabelBase::CreatePhis(
1680    std::vector<MachineRepresentation> representations) {
1681  DCHECK(is_used());
1682  DCHECK(phi_nodes_.empty());
1683  phi_nodes_.reserve(phi_inputs_.size());
1684  DCHECK_EQ(representations.size(), phi_inputs_.size());
1685  for (size_t i = 0; i < phi_inputs_.size(); ++i) {
1686    phi_nodes_.push_back(CreatePhi(representations[i], phi_inputs_[i]));
1687  }
1688  return phi_nodes_;
1689}
1690
1691void CodeAssemblerState::PushExceptionHandler(
1692    CodeAssemblerExceptionHandlerLabel* label) {
1693  exception_handler_labels_.push_back(label);
1694}
1695
1696void CodeAssemblerState::PopExceptionHandler() {
1697  exception_handler_labels_.pop_back();
1698}
1699
1700ScopedExceptionHandler::ScopedExceptionHandler(
1701    CodeAssembler* assembler, CodeAssemblerExceptionHandlerLabel* label)
1702    : has_handler_(label != nullptr),
1703      assembler_(assembler),
1704      compatibility_label_(nullptr),
1705      exception_(nullptr) {
1706  if (has_handler_) {
1707    assembler_->state()->PushExceptionHandler(label);
1708  }
1709}
1710
1711ScopedExceptionHandler::ScopedExceptionHandler(
1712    CodeAssembler* assembler, CodeAssemblerLabel* label,
1713    TypedCodeAssemblerVariable<Object>* exception)
1714    : has_handler_(label != nullptr),
1715      assembler_(assembler),
1716      compatibility_label_(label),
1717      exception_(exception) {
1718  if (has_handler_) {
1719    label_ = std::make_unique<CodeAssemblerExceptionHandlerLabel>(
1720        assembler, CodeAssemblerLabel::kDeferred);
1721    assembler_->state()->PushExceptionHandler(label_.get());
1722  }
1723}
1724
1725ScopedExceptionHandler::~ScopedExceptionHandler() {
1726  if (has_handler_) {
1727    assembler_->state()->PopExceptionHandler();
1728  }
1729  if (label_ && label_->is_used()) {
1730    CodeAssembler::Label skip(assembler_);
1731    bool inside_block = assembler_->state()->InsideBlock();
1732    if (inside_block) {
1733      assembler_->Goto(&skip);
1734    }
1735    TNode<Object> e;
1736    assembler_->Bind(label_.get(), &e);
1737    if (exception_ != nullptr) *exception_ = e;
1738    assembler_->Goto(compatibility_label_);
1739    if (inside_block) {
1740      assembler_->Bind(&skip);
1741    }
1742  }
1743}
1744
1745}  // namespace compiler
1746
1747}  // namespace internal
1748}  // namespace v8
1749