• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
9 namespace v8 {
10 namespace internal {
11 namespace 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   }
21 TORQUE_INSTRUCTION_LIST(TORQUE_INSTRUCTION_BOILERPLATE_DEFINITIONS)
22 #undef TORQUE_INSTRUCTION_BOILERPLATE_DEFINITIONS
23 
24 namespace {
ExpectType(const Type * expected,const Type * actual)25 void ExpectType(const Type* expected, const Type* actual) {
26   if (expected != actual) {
27     ReportError("expected type ", *expected, " but found ", *actual);
28   }
29 }
ExpectSubtype(const Type * subtype,const Type * supertype)30 void 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 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const37 void 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 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const51 void PeekInstruction::RecomputeDefinitionLocations(
52     Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
53   locations->Push(locations->Peek(slot));
54 }
55 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const56 void 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 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const67 void PokeInstruction::RecomputeDefinitionLocations(
68     Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
69   locations->Poke(slot, locations->Pop());
70 }
71 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const72 void DeleteRangeInstruction::TypeInstruction(Stack<const Type*>* stack,
73                                              ControlFlowGraph* cfg) const {
74   stack->DeleteRange(range);
75 }
76 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const77 void DeleteRangeInstruction::RecomputeDefinitionLocations(
78     Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
79   locations->DeleteRange(range);
80 }
81 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const82 void PushUninitializedInstruction::TypeInstruction(
83     Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
84   stack->Push(type);
85 }
86 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const87 void PushUninitializedInstruction::RecomputeDefinitionLocations(
88     Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
89   locations->Push(GetValueDefinition());
90 }
91 
GetValueDefinition() const92 DefinitionLocation PushUninitializedInstruction::GetValueDefinition() const {
93   return DefinitionLocation::Instruction(this, 0);
94 }
95 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const96 void PushBuiltinPointerInstruction::TypeInstruction(
97     Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
98   stack->Push(type);
99 }
100 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const101 void PushBuiltinPointerInstruction::RecomputeDefinitionLocations(
102     Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
103   locations->Push(GetValueDefinition());
104 }
105 
GetValueDefinition() const106 DefinitionLocation PushBuiltinPointerInstruction::GetValueDefinition() const {
107   return DefinitionLocation::Instruction(this, 0);
108 }
109 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const110 void NamespaceConstantInstruction::TypeInstruction(
111     Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
112   stack->PushMany(LowerType(constant->type()));
113 }
114 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const115 void 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 
GetValueDefinitionCount() const122 std::size_t NamespaceConstantInstruction::GetValueDefinitionCount() const {
123   return LowerType(constant->type()).size();
124 }
125 
GetValueDefinition(std::size_t index) const126 DefinitionLocation NamespaceConstantInstruction::GetValueDefinition(
127     std::size_t index) const {
128   DCHECK_LT(index, GetValueDefinitionCount());
129   return DefinitionLocation::Instruction(this, index);
130 }
131 
operator <<(std::ostream & os,const NamespaceConstantInstruction & instruction)132 std::ostream& operator<<(std::ostream& os,
133                          const NamespaceConstantInstruction& instruction) {
134   return os << "NamespaceConstant " << instruction.constant->external_name();
135 }
136 
InvalidateTransientTypes(Stack<const Type * > * stack) const137 void 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 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const152 void 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 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const171 void 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 
GetValueDefinitionCount() const181 std::size_t CallIntrinsicInstruction::GetValueDefinitionCount() const {
182   return LowerType(intrinsic->signature().return_type).size();
183 }
184 
GetValueDefinition(std::size_t index) const185 DefinitionLocation CallIntrinsicInstruction::GetValueDefinition(
186     std::size_t index) const {
187   DCHECK_LT(index, GetValueDefinitionCount());
188   return DefinitionLocation::Instruction(this, index);
189 }
190 
operator <<(std::ostream & os,const CallIntrinsicInstruction & instruction)191 std::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 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const207 void 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 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const234 void 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 
251 base::Optional<DefinitionLocation>
GetExceptionObjectDefinition() const252 CallCsaMacroInstruction::GetExceptionObjectDefinition() const {
253   if (!catch_block) return base::nullopt;
254   return DefinitionLocation::Instruction(this, GetValueDefinitionCount());
255 }
256 
GetValueDefinitionCount() const257 std::size_t CallCsaMacroInstruction::GetValueDefinitionCount() const {
258   return LowerType(macro->signature().return_type).size();
259 }
260 
GetValueDefinition(std::size_t index) const261 DefinitionLocation CallCsaMacroInstruction::GetValueDefinition(
262     std::size_t index) const {
263   DCHECK_LT(index, GetValueDefinitionCount());
264   return DefinitionLocation::Instruction(this, index);
265 }
266 
operator <<(std::ostream & os,const CallCsaMacroInstruction & instruction)267 std::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 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const279 void 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 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const327 void 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 
GetLabelCount() const361 std::size_t CallCsaMacroAndBranchInstruction::GetLabelCount() const {
362   return label_blocks.size();
363 }
364 
GetLabelValueDefinitionCount(std::size_t label) const365 std::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 
GetLabelValueDefinition(std::size_t label,std::size_t index) const371 DefinitionLocation 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 
GetValueDefinitionCount() const381 std::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 
GetValueDefinition(std::size_t index) const387 DefinitionLocation CallCsaMacroAndBranchInstruction::GetValueDefinition(
388     std::size_t index) const {
389   DCHECK_LT(index, GetValueDefinitionCount());
390   return DefinitionLocation::Instruction(this, index);
391 }
392 
393 base::Optional<DefinitionLocation>
GetExceptionObjectDefinition() const394 CallCsaMacroAndBranchInstruction::GetExceptionObjectDefinition() const {
395   if (!catch_block) return base::nullopt;
396   return DefinitionLocation::Instruction(this, GetValueDefinitionCount());
397 }
398 
operator <<(std::ostream & os,const CallCsaMacroAndBranchInstruction & instruction)399 std::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 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const419 void 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 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const439 void 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 
GetValueDefinitionCount() const454 std::size_t CallBuiltinInstruction::GetValueDefinitionCount() const {
455   return LowerType(builtin->signature().return_type).size();
456 }
457 
GetValueDefinition(std::size_t index) const458 DefinitionLocation CallBuiltinInstruction::GetValueDefinition(
459     std::size_t index) const {
460   DCHECK_LT(index, GetValueDefinitionCount());
461   return DefinitionLocation::Instruction(this, index);
462 }
463 
464 base::Optional<DefinitionLocation>
GetExceptionObjectDefinition() const465 CallBuiltinInstruction::GetExceptionObjectDefinition() const {
466   if (!catch_block) return base::nullopt;
467   return DefinitionLocation::Instruction(this, GetValueDefinitionCount());
468 }
469 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const470 void 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 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const485 void 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 
GetValueDefinitionCount() const493 std::size_t CallBuiltinPointerInstruction::GetValueDefinitionCount() const {
494   return LowerType(type->return_type()).size();
495 }
496 
GetValueDefinition(std::size_t index) const497 DefinitionLocation CallBuiltinPointerInstruction::GetValueDefinition(
498     std::size_t index) const {
499   DCHECK_LT(index, GetValueDefinitionCount());
500   return DefinitionLocation::Instruction(this, index);
501 }
502 
operator <<(std::ostream & os,const CallBuiltinInstruction & instruction)503 std::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 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const516 void 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 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const540 void 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 
GetValueDefinitionCount() const558 std::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 
GetValueDefinition(std::size_t index) const564 DefinitionLocation CallRuntimeInstruction::GetValueDefinition(
565     std::size_t index) const {
566   DCHECK_LT(index, GetValueDefinitionCount());
567   return DefinitionLocation::Instruction(this, index);
568 }
569 
570 base::Optional<DefinitionLocation>
GetExceptionObjectDefinition() const571 CallRuntimeInstruction::GetExceptionObjectDefinition() const {
572   if (!catch_block) return base::nullopt;
573   return DefinitionLocation::Instruction(this, GetValueDefinitionCount());
574 }
575 
operator <<(std::ostream & os,const CallRuntimeInstruction & instruction)576 std::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 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const589 void 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 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const599 void 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 
operator <<(std::ostream & os,const BranchInstruction & instruction)606 std::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 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const612 void ConstexprBranchInstruction::TypeInstruction(Stack<const Type*>* stack,
613                                                  ControlFlowGraph* cfg) const {
614   if_true->SetInputTypes(*stack);
615   if_false->SetInputTypes(*stack);
616 }
617 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const618 void ConstexprBranchInstruction::RecomputeDefinitionLocations(
619     Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
620   if_true->MergeInputDefinitions(*locations, worklist);
621   if_false->MergeInputDefinitions(*locations, worklist);
622 }
623 
operator <<(std::ostream & os,const ConstexprBranchInstruction & instruction)624 std::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 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const631 void GotoInstruction::TypeInstruction(Stack<const Type*>* stack,
632                                       ControlFlowGraph* cfg) const {
633   destination->SetInputTypes(*stack);
634 }
635 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const636 void GotoInstruction::RecomputeDefinitionLocations(
637     Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
638   destination->MergeInputDefinitions(*locations, worklist);
639 }
640 
operator <<(std::ostream & os,const GotoInstruction & instruction)641 std::ostream& operator<<(std::ostream& os, const GotoInstruction& instruction) {
642   return os << "Goto " << instruction.destination->id();
643 }
644 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const645 void 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 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const652 void GotoExternalInstruction::RecomputeDefinitionLocations(
653     Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {}
654 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const655 void ReturnInstruction::TypeInstruction(Stack<const Type*>* stack,
656                                         ControlFlowGraph* cfg) const {
657   cfg->SetReturnType(stack->PopMany(count));
658 }
659 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const660 void ReturnInstruction::RecomputeDefinitionLocations(
661     Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
662   locations->PopMany(count);
663 }
664 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const665 void PrintConstantStringInstruction::TypeInstruction(
666     Stack<const Type*>* stack, ControlFlowGraph* cfg) const {}
667 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const668 void PrintConstantStringInstruction::RecomputeDefinitionLocations(
669     Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {}
670 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const671 void AbortInstruction::TypeInstruction(Stack<const Type*>* stack,
672                                        ControlFlowGraph* cfg) const {}
673 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const674 void AbortInstruction::RecomputeDefinitionLocations(
675     Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {}
676 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const677 void UnsafeCastInstruction::TypeInstruction(Stack<const Type*>* stack,
678                                             ControlFlowGraph* cfg) const {
679   stack->Poke(stack->AboveTop() - 1, destination_type);
680 }
681 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const682 void UnsafeCastInstruction::RecomputeDefinitionLocations(
683     Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
684   locations->Poke(locations->AboveTop() - 1, GetValueDefinition());
685 }
686 
GetValueDefinition() const687 DefinitionLocation UnsafeCastInstruction::GetValueDefinition() const {
688   return DefinitionLocation::Instruction(this, 0);
689 }
690 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const691 void 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 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const701 void LoadReferenceInstruction::RecomputeDefinitionLocations(
702     Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
703   locations->Pop();
704   locations->Pop();
705   locations->Push(GetValueDefinition());
706 }
707 
GetValueDefinition() const708 DefinitionLocation LoadReferenceInstruction::GetValueDefinition() const {
709   return DefinitionLocation::Instruction(this, 0);
710 }
711 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const712 void 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 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const721 void StoreReferenceInstruction::RecomputeDefinitionLocations(
722     Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
723   locations->Pop();
724   locations->Pop();
725   locations->Pop();
726 }
727 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const728 void 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 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const734 void LoadBitFieldInstruction::RecomputeDefinitionLocations(
735     Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
736   locations->Pop();
737   locations->Push(GetValueDefinition());
738 }
739 
GetValueDefinition() const740 DefinitionLocation LoadBitFieldInstruction::GetValueDefinition() const {
741   return DefinitionLocation::Instruction(this, 0);
742 }
743 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const744 void 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 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const751 void StoreBitFieldInstruction::RecomputeDefinitionLocations(
752     Stack<DefinitionLocation>* locations, Worklist<Block*>* worklist) const {
753   locations->Pop();
754   locations->Pop();
755   locations->Push(GetValueDefinition());
756 }
757 
GetValueDefinition() const758 DefinitionLocation StoreBitFieldInstruction::GetValueDefinition() const {
759   return DefinitionLocation::Instruction(this, 0);
760 }
761 
TypeInstruction(Stack<const Type * > * stack,ControlFlowGraph * cfg) const762 void 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 
RecomputeDefinitionLocations(Stack<DefinitionLocation> * locations,Worklist<Block * > * worklist) const779 void 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 
GetValueDefinition() const788 DefinitionLocation MakeLazyNodeInstruction::GetValueDefinition() const {
789   return DefinitionLocation::Instruction(this, 0);
790 }
791 
operator <<(std::ostream & os,const MakeLazyNodeInstruction & instruction)792 std::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 
IsBlockTerminator() const802 bool 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