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