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