1// Copyright 2018 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/torque/instructions.h"
6#include "src/torque/cfg.h"
7#include "src/torque/type-oracle.h"
8
9namespace v8 {
10namespace internal {
11namespace torque {
12
13#define TORQUE_INSTRUCTION_BOILERPLATE_DEFINITIONS(Name)        \
14  const InstructionKind Name::kKind = InstructionKind::k##Name; \
15  std::unique_ptr<InstructionBase> Name::Clone() const {        \
16    return std::unique_ptr<InstructionBase>(new Name(*this));   \
17  }                                                             \
18  void Name::Assign(const InstructionBase& other) {             \
19    *this = static_cast<const Name&>(other);                    \
20  }
21TORQUE_INSTRUCTION_LIST(TORQUE_INSTRUCTION_BOILERPLATE_DEFINITIONS)
22#undef TORQUE_INSTRUCTION_BOILERPLATE_DEFINITIONS
23
24namespace {
25void ExpectType(const Type* expected, const Type* actual) {
26  if (expected != actual) {
27    ReportError("expected type ", *expected, " but found ", *actual);
28  }
29}
30void ExpectSubtype(const Type* subtype, const Type* supertype) {
31  if (!subtype->IsSubtypeOf(supertype)) {
32    ReportError("type ", *subtype, " is not a subtype of ", *supertype);
33  }
34}
35}  // namespace
36
37void PeekInstruction::TypeInstruction(Stack<const Type*>* stack,
38                                      ControlFlowGraph* cfg) const {
39  const Type* type = stack->Peek(slot);
40  if (widened_type) {
41    if (type->IsTopType()) {
42      const TopType* top_type = TopType::cast(type);
43      ReportError("use of " + top_type->reason());
44    }
45    ExpectSubtype(type, *widened_type);
46    type = *widened_type;
47  }
48  stack->Push(type);
49}
50
51void PeekInstruction::RecomputeDefinitionLocations(
52    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
53  locations->Push(locations->Peek(slot));
54}
55
56void PokeInstruction::TypeInstruction(Stack<const Type*>* stack,
57                                      ControlFlowGraph* cfg) const {
58  const Type* type = stack->Top();
59  if (widened_type) {
60    ExpectSubtype(type, *widened_type);
61    type = *widened_type;
62  }
63  stack->Poke(slot, type);
64  stack->Pop();
65}
66
67void PokeInstruction::RecomputeDefinitionLocations(
68    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
69  locations->Poke(slot, locations->Pop());
70}
71
72void DeleteRangeInstruction::TypeInstruction(Stack<const Type*>* stack,
73                                             ControlFlowGraph* cfg) const {
74  stack->DeleteRange(range);
75}
76
77void DeleteRangeInstruction::RecomputeDefinitionLocations(
78    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
79  locations->DeleteRange(range);
80}
81
82void PushUninitializedInstruction::TypeInstruction(
83    Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
84  stack->Push(type);
85}
86
87void PushUninitializedInstruction::RecomputeDefinitionLocations(
88    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
89  locations->Push(GetValueDefinition());
90}
91
92DefinitionLocation PushUninitializedInstruction::GetValueDefinition() const {
93  return DefinitionLocation::Instruction(this, 0);
94}
95
96void PushBuiltinPointerInstruction::TypeInstruction(
97    Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
98  stack->Push(type);
99}
100
101void PushBuiltinPointerInstruction::RecomputeDefinitionLocations(
102    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
103  locations->Push(GetValueDefinition());
104}
105
106DefinitionLocation PushBuiltinPointerInstruction::GetValueDefinition() const {
107  return DefinitionLocation::Instruction(this, 0);
108}
109
110void NamespaceConstantInstruction::TypeInstruction(
111    Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
112  stack->PushMany(LowerType(constant->type()));
113}
114
115void NamespaceConstantInstruction::RecomputeDefinitionLocations(
116    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
117  for (std::size_t i = 0; i < GetValueDefinitionCount(); ++i) {
118    locations->Push(GetValueDefinition(i));
119  }
120}
121
122std::size_t NamespaceConstantInstruction::GetValueDefinitionCount() const {
123  return LowerType(constant->type()).size();
124}
125
126DefinitionLocation NamespaceConstantInstruction::GetValueDefinition(
127    std::size_t index) const {
128  DCHECK_LT(index, GetValueDefinitionCount());
129  return DefinitionLocation::Instruction(this, index);
130}
131
132std::ostream& operator<<(std::ostream& os,
133                         const NamespaceConstantInstruction& instruction) {
134  return os << "NamespaceConstant " << instruction.constant->external_name();
135}
136
137void InstructionBase::InvalidateTransientTypes(
138    Stack<const Type*>* stack) const {
139  auto current = stack->begin();
140  while (current != stack->end()) {
141    if ((*current)->IsTransient()) {
142      std::stringstream stream;
143      stream << "type " << **current
144             << " is made invalid by transitioning callable invocation at "
145             << PositionAsString(pos);
146      *current = TypeOracle::GetTopType(stream.str(), *current);
147    }
148    ++current;
149  }
150}
151
152void CallIntrinsicInstruction::TypeInstruction(Stack<const Type*>* stack,
153                                               ControlFlowGraph* cfg) const {
154  std::vector<const Type*> parameter_types =
155      LowerParameterTypes(intrinsic->signature().parameter_types);
156  for (intptr_t i = parameter_types.size() - 1; i >= 0; --i) {
157    const Type* arg_type = stack->Pop();
158    const Type* parameter_type = parameter_types.back();
159    parameter_types.pop_back();
160    if (arg_type != parameter_type) {
161      ReportError("parameter ", i, ": expected type ", *parameter_type,
162                  " but found type ", *arg_type);
163    }
164  }
165  if (intrinsic->IsTransitioning()) {
166    InvalidateTransientTypes(stack);
167  }
168  stack->PushMany(LowerType(intrinsic->signature().return_type));
169}
170
171void CallIntrinsicInstruction::RecomputeDefinitionLocations(
172    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
173  auto parameter_types =
174      LowerParameterTypes(intrinsic->signature().parameter_types);
175  locations->PopMany(parameter_types.size());
176  for (std::size_t i = 0; i < GetValueDefinitionCount(); ++i) {
177    locations->Push(DefinitionLocation::Instruction(this, i));
178  }
179}
180
181std::size_t CallIntrinsicInstruction::GetValueDefinitionCount() const {
182  return LowerType(intrinsic->signature().return_type).size();
183}
184
185DefinitionLocation CallIntrinsicInstruction::GetValueDefinition(
186    std::size_t index) const {
187  DCHECK_LT(index, GetValueDefinitionCount());
188  return DefinitionLocation::Instruction(this, index);
189}
190
191std::ostream& operator<<(std::ostream& os,
192                         const CallIntrinsicInstruction& instruction) {
193  os << "CallIntrinsic " << instruction.intrinsic->ReadableName();
194  if (!instruction.specialization_types.empty()) {
195    os << "<";
196    PrintCommaSeparatedList(
197        os, instruction.specialization_types,
198        [](const Type* type) -> const Type& { return *type; });
199    os << ">";
200  }
201  os << "(";
202  PrintCommaSeparatedList(os, instruction.constexpr_arguments);
203  os << ")";
204  return os;
205}
206
207void CallCsaMacroInstruction::TypeInstruction(Stack<const Type*>* stack,
208                                              ControlFlowGraph* cfg) const {
209  std::vector<const Type*> parameter_types =
210      LowerParameterTypes(macro->signature().parameter_types);
211  for (intptr_t i = parameter_types.size() - 1; i >= 0; --i) {
212    const Type* arg_type = stack->Pop();
213    const Type* parameter_type = parameter_types.back();
214    parameter_types.pop_back();
215    if (arg_type != parameter_type) {
216      ReportError("parameter ", i, ": expected type ", *parameter_type,
217                  " but found type ", *arg_type);
218    }
219  }
220
221  if (macro->IsTransitioning()) {
222    InvalidateTransientTypes(stack);
223  }
224
225  if (catch_block) {
226    Stack<const Type*> catch_stack = *stack;
227    catch_stack.Push(TypeOracle::GetJSAnyType());
228    (*catch_block)->SetInputTypes(catch_stack);
229  }
230
231  stack->PushMany(LowerType(macro->signature().return_type));
232}
233
234void CallCsaMacroInstruction::RecomputeDefinitionLocations(
235    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
236  auto parameter_types =
237      LowerParameterTypes(macro->signature().parameter_types);
238  locations->PopMany(parameter_types.size());
239
240  if (catch_block) {
241    locations->Push(*GetExceptionObjectDefinition());
242    (*catch_block)->MergeInputDefinitions(*locations, worklist);
243    locations->Pop();
244  }
245
246  for (std::size_t i = 0; i < GetValueDefinitionCount(); ++i) {
247    locations->Push(GetValueDefinition(i));
248  }
249}
250
251base::Optional<DefinitionLocation>
252CallCsaMacroInstruction::GetExceptionObjectDefinition() const {
253  if (!catch_block) return base::nullopt;
254  return DefinitionLocation::Instruction(this, GetValueDefinitionCount());
255}
256
257std::size_t CallCsaMacroInstruction::GetValueDefinitionCount() const {
258  return LowerType(macro->signature().return_type).size();
259}
260
261DefinitionLocation CallCsaMacroInstruction::GetValueDefinition(
262    std::size_t index) const {
263  DCHECK_LT(index, GetValueDefinitionCount());
264  return DefinitionLocation::Instruction(this, index);
265}
266
267std::ostream& operator<<(std::ostream& os,
268                         const CallCsaMacroInstruction& instruction) {
269  os << "CallCsaMacro " << instruction.macro->ReadableName();
270  os << "(";
271  PrintCommaSeparatedList(os, instruction.constexpr_arguments);
272  os << ")";
273  if (instruction.catch_block) {
274    os << ", catch block " << (*instruction.catch_block)->id();
275  }
276  return os;
277}
278
279void CallCsaMacroAndBranchInstruction::TypeInstruction(
280    Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
281  std::vector<const Type*> parameter_types =
282      LowerParameterTypes(macro->signature().parameter_types);
283  for (intptr_t i = parameter_types.size() - 1; i >= 0; --i) {
284    const Type* arg_type = stack->Pop();
285    const Type* parameter_type = parameter_types.back();
286    parameter_types.pop_back();
287    if (arg_type != parameter_type) {
288      ReportError("parameter ", i, ": expected type ", *parameter_type,
289                  " but found type ", *arg_type);
290    }
291  }
292
293  if (label_blocks.size() != macro->signature().labels.size()) {
294    ReportError("wrong number of labels");
295  }
296  for (size_t i = 0; i < label_blocks.size(); ++i) {
297    Stack<const Type*> continuation_stack = *stack;
298    continuation_stack.PushMany(
299        LowerParameterTypes(macro->signature().labels[i].types));
300    label_blocks[i]->SetInputTypes(std::move(continuation_stack));
301  }
302
303  if (macro->IsTransitioning()) {
304    InvalidateTransientTypes(stack);
305  }
306
307  if (catch_block) {
308    Stack<const Type*> catch_stack = *stack;
309    catch_stack.Push(TypeOracle::GetJSAnyType());
310    (*catch_block)->SetInputTypes(catch_stack);
311  }
312
313  if (macro->signature().return_type != TypeOracle::GetNeverType()) {
314    Stack<const Type*> return_stack = *stack;
315    return_stack.PushMany(LowerType(macro->signature().return_type));
316    if (return_continuation == base::nullopt) {
317      ReportError("missing return continuation.");
318    }
319    (*return_continuation)->SetInputTypes(return_stack);
320  } else {
321    if (return_continuation != base::nullopt) {
322      ReportError("unreachable return continuation.");
323    }
324  }
325}
326
327void CallCsaMacroAndBranchInstruction::RecomputeDefinitionLocations(
328    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
329  auto parameter_types =
330      LowerParameterTypes(macro->signature().parameter_types);
331  locations->PopMany(parameter_types.size());
332
333  for (std::size_t label_index = 0; label_index < label_blocks.size();
334       ++label_index) {
335    const std::size_t count = GetLabelValueDefinitionCount(label_index);
336    for (std::size_t i = 0; i < count; ++i) {
337      locations->Push(GetLabelValueDefinition(label_index, i));
338    }
339    label_blocks[label_index]->MergeInputDefinitions(*locations, worklist);
340    locations->PopMany(count);
341  }
342
343  if (catch_block) {
344    locations->Push(*GetExceptionObjectDefinition());
345    (*catch_block)->MergeInputDefinitions(*locations, worklist);
346    locations->Pop();
347  }
348
349  if (macro->signature().return_type != TypeOracle::GetNeverType()) {
350    if (return_continuation) {
351      const std::size_t count = GetValueDefinitionCount();
352      for (std::size_t i = 0; i < count; ++i) {
353        locations->Push(GetValueDefinition(i));
354      }
355      (*return_continuation)->MergeInputDefinitions(*locations, worklist);
356      locations->PopMany(count);
357    }
358  }
359}
360
361std::size_t CallCsaMacroAndBranchInstruction::GetLabelCount() const {
362  return label_blocks.size();
363}
364
365std::size_t CallCsaMacroAndBranchInstruction::GetLabelValueDefinitionCount(
366    std::size_t label) const {
367  DCHECK_LT(label, GetLabelCount());
368  return LowerParameterTypes(macro->signature().labels[label].types).size();
369}
370
371DefinitionLocation CallCsaMacroAndBranchInstruction::GetLabelValueDefinition(
372    std::size_t label, std::size_t index) const {
373  DCHECK_LT(index, GetLabelValueDefinitionCount(label));
374  std::size_t offset = GetValueDefinitionCount() + (catch_block ? 1 : 0);
375  for (std::size_t label_index = 0; label_index < label; ++label_index) {
376    offset += GetLabelValueDefinitionCount(label_index);
377  }
378  return DefinitionLocation::Instruction(this, offset + index);
379}
380
381std::size_t CallCsaMacroAndBranchInstruction::GetValueDefinitionCount() const {
382  if (macro->signature().return_type == TypeOracle::GetNeverType()) return 0;
383  if (!return_continuation) return 0;
384  return LowerType(macro->signature().return_type).size();
385}
386
387DefinitionLocation CallCsaMacroAndBranchInstruction::GetValueDefinition(
388    std::size_t index) const {
389  DCHECK_LT(index, GetValueDefinitionCount());
390  return DefinitionLocation::Instruction(this, index);
391}
392
393base::Optional<DefinitionLocation>
394CallCsaMacroAndBranchInstruction::GetExceptionObjectDefinition() const {
395  if (!catch_block) return base::nullopt;
396  return DefinitionLocation::Instruction(this, GetValueDefinitionCount());
397}
398
399std::ostream& operator<<(std::ostream& os,
400                         const CallCsaMacroAndBranchInstruction& instruction) {
401  os << "CallCsaMacroAndBranch " << instruction.macro->ReadableName();
402  os << "(";
403  PrintCommaSeparatedList(os, instruction.constexpr_arguments);
404  os << ")";
405  if (instruction.return_continuation) {
406    os << ", return continuation " << (*instruction.return_continuation)->id();
407  }
408  if (!instruction.label_blocks.empty()) {
409    os << ", label blocks ";
410    PrintCommaSeparatedList(os, instruction.label_blocks,
411                            [](Block* block) { return block->id(); });
412  }
413  if (instruction.catch_block) {
414    os << ", catch block " << (*instruction.catch_block)->id();
415  }
416  return os;
417}
418
419void CallBuiltinInstruction::TypeInstruction(Stack<const Type*>* stack,
420                                             ControlFlowGraph* cfg) const {
421  std::vector<const Type*> argument_types = stack->PopMany(argc);
422  if (argument_types !=
423      LowerParameterTypes(builtin->signature().parameter_types)) {
424    ReportError("wrong argument types");
425  }
426  if (builtin->IsTransitioning()) {
427    InvalidateTransientTypes(stack);
428  }
429
430  if (catch_block) {
431    Stack<const Type*> catch_stack = *stack;
432    catch_stack.Push(TypeOracle::GetJSAnyType());
433    (*catch_block)->SetInputTypes(catch_stack);
434  }
435
436  stack->PushMany(LowerType(builtin->signature().return_type));
437}
438
439void CallBuiltinInstruction::RecomputeDefinitionLocations(
440    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
441  locations->PopMany(argc);
442
443  if (catch_block) {
444    locations->Push(*GetExceptionObjectDefinition());
445    (*catch_block)->MergeInputDefinitions(*locations, worklist);
446    locations->Pop();
447  }
448
449  for (std::size_t i = 0; i < GetValueDefinitionCount(); ++i) {
450    locations->Push(GetValueDefinition(i));
451  }
452}
453
454std::size_t CallBuiltinInstruction::GetValueDefinitionCount() const {
455  return LowerType(builtin->signature().return_type).size();
456}
457
458DefinitionLocation CallBuiltinInstruction::GetValueDefinition(
459    std::size_t index) const {
460  DCHECK_LT(index, GetValueDefinitionCount());
461  return DefinitionLocation::Instruction(this, index);
462}
463
464base::Optional<DefinitionLocation>
465CallBuiltinInstruction::GetExceptionObjectDefinition() const {
466  if (!catch_block) return base::nullopt;
467  return DefinitionLocation::Instruction(this, GetValueDefinitionCount());
468}
469
470void CallBuiltinPointerInstruction::TypeInstruction(
471    Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
472  std::vector<const Type*> argument_types = stack->PopMany(argc);
473  const BuiltinPointerType* f = BuiltinPointerType::DynamicCast(stack->Pop());
474  if (!f) ReportError("expected function pointer type");
475  if (argument_types != LowerParameterTypes(f->parameter_types())) {
476    ReportError("wrong argument types");
477  }
478  DCHECK_EQ(type, f);
479  // TODO(turbofan): Only invalidate transient types if the function pointer
480  // type is transitioning.
481  InvalidateTransientTypes(stack);
482  stack->PushMany(LowerType(f->return_type()));
483}
484
485void CallBuiltinPointerInstruction::RecomputeDefinitionLocations(
486    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
487  locations->PopMany(argc + 1);
488  for (std::size_t i = 0; i < GetValueDefinitionCount(); ++i) {
489    locations->Push(GetValueDefinition(i));
490  }
491}
492
493std::size_t CallBuiltinPointerInstruction::GetValueDefinitionCount() const {
494  return LowerType(type->return_type()).size();
495}
496
497DefinitionLocation CallBuiltinPointerInstruction::GetValueDefinition(
498    std::size_t index) const {
499  DCHECK_LT(index, GetValueDefinitionCount());
500  return DefinitionLocation::Instruction(this, index);
501}
502
503std::ostream& operator<<(std::ostream& os,
504                         const CallBuiltinInstruction& instruction) {
505  os << "CallBuiltin " << instruction.builtin->ReadableName()
506     << ", argc: " << instruction.argc;
507  if (instruction.is_tailcall) {
508    os << ", is_tailcall";
509  }
510  if (instruction.catch_block) {
511    os << ", catch block " << (*instruction.catch_block)->id();
512  }
513  return os;
514}
515
516void CallRuntimeInstruction::TypeInstruction(Stack<const Type*>* stack,
517                                             ControlFlowGraph* cfg) const {
518  std::vector<const Type*> argument_types = stack->PopMany(argc);
519  if (argument_types !=
520      LowerParameterTypes(runtime_function->signature().parameter_types,
521                          argc)) {
522    ReportError("wrong argument types");
523  }
524  if (runtime_function->IsTransitioning()) {
525    InvalidateTransientTypes(stack);
526  }
527
528  if (catch_block) {
529    Stack<const Type*> catch_stack = *stack;
530    catch_stack.Push(TypeOracle::GetJSAnyType());
531    (*catch_block)->SetInputTypes(catch_stack);
532  }
533
534  const Type* return_type = runtime_function->signature().return_type;
535  if (return_type != TypeOracle::GetNeverType()) {
536    stack->PushMany(LowerType(return_type));
537  }
538}
539
540void CallRuntimeInstruction::RecomputeDefinitionLocations(
541    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
542  locations->PopMany(argc);
543
544  if (catch_block) {
545    locations->Push(*GetExceptionObjectDefinition());
546    (*catch_block)->MergeInputDefinitions(*locations, worklist);
547    locations->Pop();
548  }
549
550  const Type* return_type = runtime_function->signature().return_type;
551  if (return_type != TypeOracle::GetNeverType()) {
552    for (std::size_t i = 0; i < GetValueDefinitionCount(); ++i) {
553      locations->Push(GetValueDefinition(i));
554    }
555  }
556}
557
558std::size_t CallRuntimeInstruction::GetValueDefinitionCount() const {
559  const Type* return_type = runtime_function->signature().return_type;
560  if (return_type == TypeOracle::GetNeverType()) return 0;
561  return LowerType(return_type).size();
562}
563
564DefinitionLocation CallRuntimeInstruction::GetValueDefinition(
565    std::size_t index) const {
566  DCHECK_LT(index, GetValueDefinitionCount());
567  return DefinitionLocation::Instruction(this, index);
568}
569
570base::Optional<DefinitionLocation>
571CallRuntimeInstruction::GetExceptionObjectDefinition() const {
572  if (!catch_block) return base::nullopt;
573  return DefinitionLocation::Instruction(this, GetValueDefinitionCount());
574}
575
576std::ostream& operator<<(std::ostream& os,
577                         const CallRuntimeInstruction& instruction) {
578  os << "CallRuntime " << instruction.runtime_function->ReadableName()
579     << ", argc: " << instruction.argc;
580  if (instruction.is_tailcall) {
581    os << ", is_tailcall";
582  }
583  if (instruction.catch_block) {
584    os << ", catch block " << (*instruction.catch_block)->id();
585  }
586  return os;
587}
588
589void BranchInstruction::TypeInstruction(Stack<const Type*>* stack,
590                                        ControlFlowGraph* cfg) const {
591  const Type* condition_type = stack->Pop();
592  if (condition_type != TypeOracle::GetBoolType()) {
593    ReportError("condition has to have type bool");
594  }
595  if_true->SetInputTypes(*stack);
596  if_false->SetInputTypes(*stack);
597}
598
599void BranchInstruction::RecomputeDefinitionLocations(
600    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
601  locations->Pop();
602  if_true->MergeInputDefinitions(*locations, worklist);
603  if_false->MergeInputDefinitions(*locations, worklist);
604}
605
606std::ostream& operator<<(std::ostream& os,
607                         const BranchInstruction& instruction) {
608  return os << "Branch true: " << instruction.if_true->id()
609            << ", false: " << instruction.if_false->id();
610}
611
612void ConstexprBranchInstruction::TypeInstruction(Stack<const Type*>* stack,
613                                                 ControlFlowGraph* cfg) const {
614  if_true->SetInputTypes(*stack);
615  if_false->SetInputTypes(*stack);
616}
617
618void ConstexprBranchInstruction::RecomputeDefinitionLocations(
619    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
620  if_true->MergeInputDefinitions(*locations, worklist);
621  if_false->MergeInputDefinitions(*locations, worklist);
622}
623
624std::ostream& operator<<(std::ostream& os,
625                         const ConstexprBranchInstruction& instruction) {
626  return os << "ConstexprBranch " << instruction.condition
627            << ", true: " << instruction.if_true->id()
628            << ", false: " << instruction.if_false->id();
629}
630
631void GotoInstruction::TypeInstruction(Stack<const Type*>* stack,
632                                      ControlFlowGraph* cfg) const {
633  destination->SetInputTypes(*stack);
634}
635
636void GotoInstruction::RecomputeDefinitionLocations(
637    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
638  destination->MergeInputDefinitions(*locations, worklist);
639}
640
641std::ostream& operator<<(std::ostream& os, const GotoInstruction& instruction) {
642  return os << "Goto " << instruction.destination->id();
643}
644
645void GotoExternalInstruction::TypeInstruction(Stack<const Type*>* stack,
646                                              ControlFlowGraph* cfg) const {
647  if (variable_names.size() != stack->Size()) {
648    ReportError("goto external label with wrong parameter count.");
649  }
650}
651
652void GotoExternalInstruction::RecomputeDefinitionLocations(
653    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {}
654
655void ReturnInstruction::TypeInstruction(Stack<const Type*>* stack,
656                                        ControlFlowGraph* cfg) const {
657  cfg->SetReturnType(stack->PopMany(count));
658}
659
660void ReturnInstruction::RecomputeDefinitionLocations(
661    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
662  locations->PopMany(count);
663}
664
665void PrintConstantStringInstruction::TypeInstruction(
666    Stack<const Type*>* stack, ControlFlowGraph* cfg) const {}
667
668void PrintConstantStringInstruction::RecomputeDefinitionLocations(
669    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {}
670
671void AbortInstruction::TypeInstruction(Stack<const Type*>* stack,
672                                       ControlFlowGraph* cfg) const {}
673
674void AbortInstruction::RecomputeDefinitionLocations(
675    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {}
676
677void UnsafeCastInstruction::TypeInstruction(Stack<const Type*>* stack,
678                                            ControlFlowGraph* cfg) const {
679  stack->Poke(stack->AboveTop() - 1, destination_type);
680}
681
682void UnsafeCastInstruction::RecomputeDefinitionLocations(
683    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
684  locations->Poke(locations->AboveTop() - 1, GetValueDefinition());
685}
686
687DefinitionLocation UnsafeCastInstruction::GetValueDefinition() const {
688  return DefinitionLocation::Instruction(this, 0);
689}
690
691void LoadReferenceInstruction::TypeInstruction(Stack<const Type*>* stack,
692                                               ControlFlowGraph* cfg) const {
693  ExpectType(TypeOracle::GetIntPtrType(), stack->Pop());
694  ExpectSubtype(stack->Pop(), TypeOracle::GetUnionType(
695                                  TypeOracle::GetHeapObjectType(),
696                                  TypeOracle::GetTaggedZeroPatternType()));
697  DCHECK_EQ(std::vector<const Type*>{type}, LowerType(type));
698  stack->Push(type);
699}
700
701void LoadReferenceInstruction::RecomputeDefinitionLocations(
702    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
703  locations->Pop();
704  locations->Pop();
705  locations->Push(GetValueDefinition());
706}
707
708DefinitionLocation LoadReferenceInstruction::GetValueDefinition() const {
709  return DefinitionLocation::Instruction(this, 0);
710}
711
712void StoreReferenceInstruction::TypeInstruction(Stack<const Type*>* stack,
713                                                ControlFlowGraph* cfg) const {
714  ExpectSubtype(stack->Pop(), type);
715  ExpectType(TypeOracle::GetIntPtrType(), stack->Pop());
716  ExpectSubtype(stack->Pop(), TypeOracle::GetUnionType(
717                                  TypeOracle::GetHeapObjectType(),
718                                  TypeOracle::GetTaggedZeroPatternType()));
719}
720
721void StoreReferenceInstruction::RecomputeDefinitionLocations(
722    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
723  locations->Pop();
724  locations->Pop();
725  locations->Pop();
726}
727
728void LoadBitFieldInstruction::TypeInstruction(Stack<const Type*>* stack,
729                                              ControlFlowGraph* cfg) const {
730  ExpectType(bit_field_struct_type, stack->Pop());
731  stack->Push(bit_field.name_and_type.type);
732}
733
734void LoadBitFieldInstruction::RecomputeDefinitionLocations(
735    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
736  locations->Pop();
737  locations->Push(GetValueDefinition());
738}
739
740DefinitionLocation LoadBitFieldInstruction::GetValueDefinition() const {
741  return DefinitionLocation::Instruction(this, 0);
742}
743
744void StoreBitFieldInstruction::TypeInstruction(Stack<const Type*>* stack,
745                                               ControlFlowGraph* cfg) const {
746  ExpectSubtype(bit_field.name_and_type.type, stack->Pop());
747  ExpectType(bit_field_struct_type, stack->Pop());
748  stack->Push(bit_field_struct_type);
749}
750
751void StoreBitFieldInstruction::RecomputeDefinitionLocations(
752    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
753  locations->Pop();
754  locations->Pop();
755  locations->Push(GetValueDefinition());
756}
757
758DefinitionLocation StoreBitFieldInstruction::GetValueDefinition() const {
759  return DefinitionLocation::Instruction(this, 0);
760}
761
762void MakeLazyNodeInstruction::TypeInstruction(Stack<const Type*>* stack,
763                                              ControlFlowGraph* cfg) const {
764  std::vector<const Type*> parameter_types =
765      LowerParameterTypes(macro->signature().parameter_types);
766  for (intptr_t i = parameter_types.size() - 1; i >= 0; --i) {
767    const Type* arg_type = stack->Pop();
768    const Type* parameter_type = parameter_types.back();
769    parameter_types.pop_back();
770    if (arg_type != parameter_type) {
771      ReportError("parameter ", i, ": expected type ", *parameter_type,
772                  " but found type ", *arg_type);
773    }
774  }
775
776  stack->Push(result_type);
777}
778
779void MakeLazyNodeInstruction::RecomputeDefinitionLocations(
780    Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
781  auto parameter_types =
782      LowerParameterTypes(macro->signature().parameter_types);
783  locations->PopMany(parameter_types.size());
784
785  locations->Push(GetValueDefinition());
786}
787
788DefinitionLocation MakeLazyNodeInstruction::GetValueDefinition() const {
789  return DefinitionLocation::Instruction(this, 0);
790}
791
792std::ostream& operator<<(std::ostream& os,
793                         const MakeLazyNodeInstruction& instruction) {
794  os << "MakeLazyNode " << instruction.macro->ReadableName() << ", "
795     << *instruction.result_type;
796  for (const std::string& arg : instruction.constexpr_arguments) {
797    os << ", " << arg;
798  }
799  return os;
800}
801
802bool CallRuntimeInstruction::IsBlockTerminator() const {
803  return is_tailcall || runtime_function->signature().return_type ==
804                            TypeOracle::GetNeverType();
805}
806
807}  // namespace torque
808}  // namespace internal
809}  // namespace v8
810