Line data Source code
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/csa-generator.h"
6 :
7 : #include "src/torque/type-oracle.h"
8 : #include "src/torque/utils.h"
9 :
10 : namespace v8 {
11 : namespace internal {
12 : namespace torque {
13 :
14 594 : base::Optional<Stack<std::string>> CSAGenerator::EmitGraph(
15 : Stack<std::string> parameters) {
16 10558 : for (Block* block : cfg_.blocks()) {
17 4388 : out_ << " compiler::CodeAssemblerParameterizedLabel<";
18 4388 : PrintCommaSeparatedList(out_, block->InputTypes(), [](const Type* t) {
19 27205 : return t->GetGeneratedTNodeTypeName();
20 31593 : });
21 13164 : out_ << "> " << BlockName(block) << "(&ca_, compiler::CodeAssemblerLabel::"
22 8776 : << (block->IsDeferred() ? "kDeferred" : "kNonDeferred") << ");\n";
23 : }
24 :
25 1782 : EmitInstruction(GotoInstruction{cfg_.start()}, ¶meters);
26 5576 : for (Block* block : cfg_.blocks()) {
27 12159 : if (cfg_.end() && *cfg_.end() == block) continue;
28 11799 : out_ << "\n if (" << BlockName(block) << ".is_used()) {\n";
29 7866 : EmitBlock(block);
30 3933 : out_ << " }\n";
31 : }
32 1188 : if (cfg_.end()) {
33 455 : out_ << "\n";
34 1365 : return EmitBlock(*cfg_.end());
35 : }
36 : return base::nullopt;
37 : }
38 :
39 4388 : Stack<std::string> CSAGenerator::EmitBlock(const Block* block) {
40 : Stack<std::string> stack;
41 31593 : for (const Type* t : block->InputTypes()) {
42 54410 : stack.Push(FreshNodeName());
43 81615 : out_ << " compiler::TNode<" << t->GetGeneratedTNodeTypeName() << "> "
44 54410 : << stack.Top() << ";\n";
45 : }
46 8776 : out_ << " ca_.Bind(&" << BlockName(block);
47 31593 : for (const std::string& name : stack) {
48 27205 : out_ << ", &" << name;
49 : }
50 4388 : out_ << ");\n";
51 36004 : for (const Instruction& instruction : block->instructions()) {
52 27228 : EmitInstruction(instruction, &stack);
53 : }
54 4388 : return stack;
55 : }
56 :
57 27228 : void CSAGenerator::EmitInstruction(const Instruction& instruction,
58 : Stack<std::string>* stack) {
59 27228 : switch (instruction.kind()) {
60 : #define ENUM_ITEM(T) \
61 : case InstructionKind::k##T: \
62 : return EmitInstruction(instruction.Cast<T>(), stack);
63 20998 : TORQUE_INSTRUCTION_LIST(ENUM_ITEM)
64 : #undef ENUM_ITEM
65 : }
66 : }
67 :
68 12423 : void CSAGenerator::EmitInstruction(const PeekInstruction& instruction,
69 : Stack<std::string>* stack) {
70 24846 : stack->Push(stack->Peek(instruction.slot));
71 12423 : }
72 :
73 467 : void CSAGenerator::EmitInstruction(const PokeInstruction& instruction,
74 : Stack<std::string>* stack) {
75 934 : stack->Poke(instruction.slot, stack->Top());
76 934 : stack->Pop();
77 467 : }
78 :
79 0 : void CSAGenerator::EmitInstruction(const DeleteRangeInstruction& instruction,
80 : Stack<std::string>* stack) {
81 6230 : stack->DeleteRange(instruction.range);
82 0 : }
83 :
84 77 : void CSAGenerator::EmitInstruction(
85 : const PushUninitializedInstruction& instruction,
86 : Stack<std::string>* stack) {
87 : // TODO(tebbi): This can trigger an error in CSA if it is used. Instead, we
88 : // should prevent usage of uninitialized in the type system. This
89 : // requires "if constexpr" being evaluated at Torque time.
90 231 : stack->Push("ca_.Uninitialized<" +
91 154 : instruction.type->GetGeneratedTNodeTypeName() + ">()");
92 77 : }
93 :
94 63 : void CSAGenerator::EmitInstruction(
95 : const PushBuiltinPointerInstruction& instruction,
96 : Stack<std::string>* stack) {
97 126 : stack->Push("ca_.UncheckedCast<BuiltinPtr>(ca_.SmiConstant(Builtins::k" +
98 63 : instruction.external_name + "))");
99 63 : }
100 :
101 245 : void CSAGenerator::EmitInstruction(
102 : const NamespaceConstantInstruction& instruction,
103 : Stack<std::string>* stack) {
104 245 : const Type* type = instruction.constant->type();
105 : std::vector<std::string> results;
106 980 : for (const Type* lowered : LowerType(type)) {
107 490 : results.push_back(FreshNodeName());
108 490 : stack->Push(results.back());
109 490 : out_ << " compiler::TNode<" << lowered->GetGeneratedTNodeTypeName()
110 735 : << "> " << stack->Top() << ";\n";
111 490 : out_ << " USE(" << stack->Top() << ");\n";
112 : }
113 245 : out_ << " ";
114 245 : if (type->IsStructType()) {
115 0 : out_ << "std::tie(";
116 0 : PrintCommaSeparatedList(out_, results);
117 0 : out_ << ") = ";
118 490 : } else if (results.size() == 1) {
119 490 : out_ << results[0] << " = ";
120 : }
121 735 : out_ << instruction.constant->ExternalAssemblerName() << "(state_)."
122 490 : << instruction.constant->constant_name() << "()";
123 245 : if (type->IsStructType()) {
124 0 : out_ << ".Flatten();\n";
125 : } else {
126 245 : out_ << ";\n";
127 245 : }
128 245 : }
129 :
130 4022 : void CSAGenerator::ProcessArgumentsCommon(
131 : const TypeVector& parameter_types, std::vector<std::string>* args,
132 : std::vector<std::string>* constexpr_arguments, Stack<std::string>* stack) {
133 11194 : for (auto it = parameter_types.rbegin(); it != parameter_types.rend(); ++it) {
134 7172 : const Type* type = *it;
135 : VisitResult arg;
136 7172 : if (type->IsConstexpr()) {
137 1604 : args->push_back(std::move(constexpr_arguments->back()));
138 : constexpr_arguments->pop_back();
139 : } else {
140 5568 : std::stringstream s;
141 5568 : size_t slot_count = LoweredSlotCount(type);
142 : VisitResult arg = VisitResult(type, stack->TopRange(slot_count));
143 11136 : EmitCSAValue(arg, *stack, s);
144 5568 : args->push_back(s.str());
145 11136 : stack->PopMany(slot_count);
146 : }
147 : }
148 : std::reverse(args->begin(), args->end());
149 4022 : }
150 :
151 61 : void CSAGenerator::EmitInstruction(const CallIntrinsicInstruction& instruction,
152 : Stack<std::string>* stack) {
153 : std::vector<std::string> constexpr_arguments =
154 61 : instruction.constexpr_arguments;
155 61 : std::vector<std::string> args;
156 : TypeVector parameter_types =
157 61 : instruction.intrinsic->signature().parameter_types.types;
158 61 : ProcessArgumentsCommon(parameter_types, &args, &constexpr_arguments, stack);
159 :
160 : Stack<std::string> pre_call_stack = *stack;
161 61 : const Type* return_type = instruction.intrinsic->signature().return_type;
162 61 : std::vector<std::string> results;
163 244 : for (const Type* type : LowerType(return_type)) {
164 122 : results.push_back(FreshNodeName());
165 122 : stack->Push(results.back());
166 183 : out_ << " compiler::TNode<" << type->GetGeneratedTNodeTypeName() << "> "
167 122 : << stack->Top() << ";\n";
168 122 : out_ << " USE(" << stack->Top() << ");\n";
169 : }
170 61 : out_ << " ";
171 :
172 61 : if (return_type->IsStructType()) {
173 0 : out_ << "std::tie(";
174 0 : PrintCommaSeparatedList(out_, results);
175 0 : out_ << ") = ";
176 : } else {
177 122 : if (results.size() == 1) {
178 122 : out_ << results[0] << " = ";
179 : }
180 : }
181 :
182 122 : if (instruction.intrinsic->ExternalName() == "%RawObjectCast") {
183 86 : if (parameter_types.size() != 1) {
184 0 : ReportError("%RawObjectCast must take a single parameter");
185 : }
186 43 : if (return_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
187 172 : if (return_type->GetGeneratedTNodeTypeName() !=
188 86 : parameter_types[0]->GetGeneratedTNodeTypeName()) {
189 42 : out_ << "TORQUE_CAST";
190 : }
191 : } else {
192 0 : std::stringstream s;
193 0 : s << "%RawObjectCast must cast to subtype of Tagged (" << *return_type
194 0 : << " is not)";
195 0 : ReportError(s.str());
196 : }
197 36 : } else if (instruction.intrinsic->ExternalName() == "%RawPointerCast") {
198 6 : if (parameter_types.size() != 1) {
199 0 : ReportError("%RawPointerCast must take a single parameter");
200 : }
201 3 : if (!return_type->IsSubtypeOf(TypeOracle::GetRawPtrType())) {
202 0 : std::stringstream s;
203 0 : s << "%RawObjectCast must cast to subtype of RawPtr (" << *return_type
204 0 : << " is not)";
205 0 : ReportError(s.str());
206 : }
207 30 : } else if (instruction.intrinsic->ExternalName() == "%FromConstexpr") {
208 28 : if (parameter_types.size() != 1 || !parameter_types[0]->IsConstexpr()) {
209 : ReportError(
210 : "%FromConstexpr must take a single parameter with constexpr "
211 0 : "type");
212 : }
213 14 : if (return_type->IsConstexpr()) {
214 0 : ReportError("%FromConstexpr must return a non-constexpr type");
215 : }
216 14 : if (return_type->IsSubtypeOf(TypeOracle::GetSmiType())) {
217 2 : out_ << "ca_.SmiConstant";
218 12 : } else if (return_type->IsSubtypeOf(TypeOracle::GetNumberType())) {
219 4 : out_ << "ca_.NumberConstant";
220 8 : } else if (return_type->IsSubtypeOf(TypeOracle::GetStringType())) {
221 1 : out_ << "ca_.StringConstant";
222 7 : } else if (return_type->IsSubtypeOf(TypeOracle::GetObjectType())) {
223 : ReportError(
224 : "%FromConstexpr cannot cast to subclass of HeapObject unless it's a "
225 0 : "String or Number");
226 7 : } else if (return_type->IsSubtypeOf(TypeOracle::GetIntPtrType())) {
227 3 : out_ << "ca_.IntPtrConstant";
228 4 : } else if (return_type->IsSubtypeOf(TypeOracle::GetUIntPtrType())) {
229 1 : out_ << "ca_.UintPtrConstant";
230 3 : } else if (return_type->IsSubtypeOf(TypeOracle::GetInt32Type())) {
231 3 : out_ << "ca_.Int32Constant";
232 : } else {
233 0 : std::stringstream s;
234 0 : s << "%FromConstexpr does not support return type " << *return_type;
235 0 : ReportError(s.str());
236 : }
237 2 : } else if (instruction.intrinsic->ExternalName() == "%Allocate") {
238 2 : out_ << "ca_.UncheckedCast<" << return_type->GetGeneratedTNodeTypeName()
239 1 : << ">(CodeStubAssembler(state_).Allocate";
240 : } else {
241 0 : ReportError("no built in intrinsic with name " +
242 0 : instruction.intrinsic->ExternalName());
243 : }
244 :
245 61 : out_ << "(";
246 61 : PrintCommaSeparatedList(out_, args);
247 122 : if (instruction.intrinsic->ExternalName() == "%Allocate") out_ << ")";
248 61 : if (return_type->IsStructType()) {
249 0 : out_ << ").Flatten();\n";
250 : } else {
251 61 : out_ << ");\n";
252 61 : }
253 61 : }
254 :
255 3541 : void CSAGenerator::EmitInstruction(const CallCsaMacroInstruction& instruction,
256 : Stack<std::string>* stack) {
257 : std::vector<std::string> constexpr_arguments =
258 3541 : instruction.constexpr_arguments;
259 3541 : std::vector<std::string> args;
260 : TypeVector parameter_types =
261 3541 : instruction.macro->signature().parameter_types.types;
262 3541 : ProcessArgumentsCommon(parameter_types, &args, &constexpr_arguments, stack);
263 :
264 : Stack<std::string> pre_call_stack = *stack;
265 3541 : const Type* return_type = instruction.macro->signature().return_type;
266 3541 : std::vector<std::string> results;
267 14012 : for (const Type* type : LowerType(return_type)) {
268 6778 : results.push_back(FreshNodeName());
269 6778 : stack->Push(results.back());
270 10167 : out_ << " compiler::TNode<" << type->GetGeneratedTNodeTypeName() << "> "
271 6778 : << stack->Top() << ";\n";
272 6778 : out_ << " USE(" << stack->Top() << ");\n";
273 : }
274 : std::string catch_name =
275 3541 : PreCallableExceptionPreparation(instruction.catch_block);
276 3541 : out_ << " ";
277 3541 : if (return_type->IsStructType()) {
278 21 : out_ << "std::tie(";
279 21 : PrintCommaSeparatedList(out_, results);
280 21 : out_ << ") = ";
281 : } else {
282 7040 : if (results.size() == 1) {
283 6656 : out_ << results[0] << " = ca_.UncheckedCast<"
284 9984 : << return_type->GetGeneratedTNodeTypeName() << ">(";
285 : }
286 : }
287 7082 : out_ << instruction.macro->external_assembler_name() << "(state_)."
288 7082 : << instruction.macro->ExternalName() << "(";
289 3541 : PrintCommaSeparatedList(out_, args);
290 3541 : if (return_type->IsStructType()) {
291 21 : out_ << ").Flatten();\n";
292 : } else {
293 7040 : if (results.size() == 1) out_ << ")";
294 3520 : out_ << ");\n";
295 : }
296 : PostCallableExceptionPreparation(catch_name, return_type,
297 7082 : instruction.catch_block, &pre_call_stack);
298 3541 : }
299 :
300 420 : void CSAGenerator::EmitInstruction(
301 : const CallCsaMacroAndBranchInstruction& instruction,
302 : Stack<std::string>* stack) {
303 : std::vector<std::string> constexpr_arguments =
304 420 : instruction.constexpr_arguments;
305 420 : std::vector<std::string> args;
306 : TypeVector parameter_types =
307 420 : instruction.macro->signature().parameter_types.types;
308 420 : ProcessArgumentsCommon(parameter_types, &args, &constexpr_arguments, stack);
309 :
310 : Stack<std::string> pre_call_stack = *stack;
311 420 : std::vector<std::string> results;
312 420 : const Type* return_type = instruction.macro->signature().return_type;
313 420 : if (return_type != TypeOracle::GetNeverType()) {
314 877 : for (const Type* type :
315 564 : LowerType(instruction.macro->signature().return_type)) {
316 502 : results.push_back(FreshNodeName());
317 502 : out_ << " compiler::TNode<" << type->GetGeneratedTNodeTypeName()
318 502 : << "> " << results.back() << ";\n";
319 502 : out_ << " USE(" << results.back() << ");\n";
320 : }
321 : }
322 :
323 420 : std::vector<std::string> label_names;
324 420 : std::vector<std::vector<std::string>> var_names;
325 1306 : const LabelDeclarationVector& labels = instruction.macro->signature().labels;
326 : DCHECK_EQ(labels.size(), instruction.label_blocks.size());
327 1772 : for (size_t i = 0; i < labels.size(); ++i) {
328 466 : TypeVector label_parameters = labels[i].types;
329 932 : label_names.push_back("label" + std::to_string(i));
330 466 : var_names.push_back({});
331 960 : for (size_t j = 0; j < label_parameters.size(); ++j) {
332 84 : var_names[i].push_back("result_" + std::to_string(i) + "_" +
333 : std::to_string(j));
334 14 : out_ << " compiler::TypedCodeAssemblerVariable<"
335 56 : << label_parameters[j]->GetGeneratedTNodeTypeName() << "> "
336 42 : << var_names[i][j] << "(&ca_);\n";
337 : }
338 932 : out_ << " compiler::CodeAssemblerLabel " << label_names[i]
339 466 : << "(&ca_);\n";
340 : }
341 :
342 : std::string catch_name =
343 420 : PreCallableExceptionPreparation(instruction.catch_block);
344 420 : out_ << " ";
345 840 : if (results.size() == 1) {
346 494 : out_ << results[0] << " = ";
347 173 : } else if (results.size() > 1) {
348 2 : out_ << "std::tie(";
349 2 : PrintCommaSeparatedList(out_, results);
350 2 : out_ << ") = ";
351 : }
352 840 : out_ << instruction.macro->external_assembler_name() << "(state_)."
353 840 : << instruction.macro->ExternalName() << "(";
354 420 : PrintCommaSeparatedList(out_, args);
355 : bool first = args.empty();
356 1772 : for (size_t i = 0; i < label_names.size(); ++i) {
357 466 : if (!first) out_ << ", ";
358 932 : out_ << "&" << label_names[i];
359 : first = false;
360 1440 : for (size_t j = 0; j < var_names[i].size(); ++j) {
361 14 : out_ << ", &" << var_names[i][j];
362 : }
363 : }
364 420 : if (return_type->IsStructType()) {
365 2 : out_ << ").Flatten();\n";
366 : } else {
367 418 : out_ << ");\n";
368 : }
369 :
370 : PostCallableExceptionPreparation(catch_name, return_type,
371 420 : instruction.catch_block, &pre_call_stack);
372 :
373 420 : if (instruction.return_continuation) {
374 626 : out_ << " ca_.Goto(&" << BlockName(*instruction.return_continuation);
375 3631 : for (const std::string& value : *stack) {
376 3318 : out_ << ", " << value;
377 : }
378 877 : for (const std::string& result : results) {
379 251 : out_ << ", " << result;
380 : }
381 313 : out_ << ");\n";
382 : }
383 1352 : for (size_t i = 0; i < label_names.size(); ++i) {
384 932 : out_ << " if (" << label_names[i] << ".is_used()) {\n";
385 1398 : out_ << " ca_.Bind(&" << label_names[i] << ");\n";
386 1398 : out_ << " ca_.Goto(&" << BlockName(instruction.label_blocks[i]);
387 5339 : for (const std::string& value : *stack) {
388 4873 : out_ << ", " << value;
389 : }
390 1412 : for (const std::string& var : var_names[i]) {
391 28 : out_ << ", " << var << ".value()";
392 : }
393 466 : out_ << ");\n";
394 :
395 466 : out_ << " }\n";
396 420 : }
397 420 : }
398 :
399 71 : void CSAGenerator::EmitInstruction(const CallBuiltinInstruction& instruction,
400 : Stack<std::string>* stack) {
401 71 : std::vector<std::string> arguments = stack->PopMany(instruction.argc);
402 : std::vector<const Type*> result_types =
403 71 : LowerType(instruction.builtin->signature().return_type);
404 71 : if (instruction.is_tailcall) {
405 1 : out_ << " CodeStubAssembler(state_).TailCallBuiltin(Builtins::k"
406 2 : << instruction.builtin->ExternalName() << ", ";
407 1 : PrintCommaSeparatedList(out_, arguments);
408 1 : out_ << ");\n";
409 : } else {
410 70 : std::string result_name = FreshNodeName();
411 140 : if (result_types.size() == 1) {
412 48 : out_ << " compiler::TNode<"
413 144 : << result_types[0]->GetGeneratedTNodeTypeName() << "> "
414 48 : << result_name << ";\n";
415 : }
416 : std::string catch_name =
417 70 : PreCallableExceptionPreparation(instruction.catch_block);
418 : Stack<std::string> pre_call_stack = *stack;
419 140 : if (result_types.size() == 1) {
420 48 : std::string generated_type = result_types[0]->GetGeneratedTNodeTypeName();
421 96 : stack->Push(result_name);
422 96 : out_ << " " << result_name << " = ";
423 48 : if (generated_type != "Object") out_ << "TORQUE_CAST(";
424 48 : out_ << "CodeStubAssembler(state_).CallBuiltin(Builtins::k"
425 96 : << instruction.builtin->ExternalName() << ", ";
426 48 : PrintCommaSeparatedList(out_, arguments);
427 48 : if (generated_type != "Object") out_ << ")";
428 48 : out_ << ");\n";
429 96 : out_ << " USE(" << result_name << ");\n";
430 : } else {
431 : DCHECK_EQ(0, result_types.size());
432 : // TODO(tebbi): Actually, builtins have to return a value, so we should
433 : // not have to handle this case.
434 22 : out_ << " CodeStubAssembler(state_).CallBuiltin(Builtins::k"
435 44 : << instruction.builtin->ExternalName() << ", ";
436 22 : PrintCommaSeparatedList(out_, arguments);
437 22 : out_ << ");\n";
438 : }
439 : PostCallableExceptionPreparation(
440 : catch_name,
441 70 : result_types.size() == 0 ? TypeOracle::GetVoidType() : result_types[0],
442 70 : instruction.catch_block, &pre_call_stack);
443 71 : }
444 71 : }
445 :
446 36 : void CSAGenerator::EmitInstruction(
447 : const CallBuiltinPointerInstruction& instruction,
448 : Stack<std::string>* stack) {
449 : std::vector<std::string> function_and_arguments =
450 36 : stack->PopMany(1 + instruction.argc);
451 : std::vector<const Type*> result_types =
452 72 : LowerType(instruction.type->return_type());
453 72 : if (result_types.size() != 1) {
454 0 : ReportError("builtins must have exactly one result");
455 : }
456 36 : if (instruction.is_tailcall) {
457 0 : ReportError("tail-calls to builtin pointers are not supported");
458 : }
459 :
460 72 : stack->Push(FreshNodeName());
461 36 : std::string generated_type = result_types[0]->GetGeneratedTNodeTypeName();
462 72 : out_ << " compiler::TNode<" << generated_type << "> " << stack->Top()
463 36 : << " = ";
464 36 : if (generated_type != "Object") out_ << "TORQUE_CAST(";
465 : out_ << "CodeStubAssembler(state_).CallBuiltinPointer(Builtins::"
466 : "CallableFor(ca_."
467 : "isolate(),"
468 36 : "ExampleBuiltinForTorqueFunctionPointerType("
469 72 : << instruction.type->function_pointer_type_id() << ")).descriptor(), ";
470 36 : PrintCommaSeparatedList(out_, function_and_arguments);
471 36 : out_ << ")";
472 36 : if (generated_type != "Object") out_ << ")";
473 36 : out_ << "; \n";
474 108 : out_ << " USE(" << stack->Top() << ");\n";
475 36 : }
476 :
477 4051 : std::string CSAGenerator::PreCallableExceptionPreparation(
478 4051 : base::Optional<Block*> catch_block) {
479 : std::string catch_name;
480 4051 : if (catch_block) {
481 44 : catch_name = FreshCatchName();
482 22 : out_ << " compiler::CodeAssemblerExceptionHandlerLabel " << catch_name
483 22 : << "_label(&ca_, compiler::CodeAssemblerLabel::kDeferred);\n";
484 22 : out_ << " { compiler::CodeAssemblerScopedExceptionHandler s(&ca_, &"
485 22 : << catch_name << "_label);\n";
486 : }
487 4051 : return catch_name;
488 : }
489 :
490 4051 : void CSAGenerator::PostCallableExceptionPreparation(
491 : const std::string& catch_name, const Type* return_type,
492 4051 : base::Optional<Block*> catch_block, Stack<std::string>* stack) {
493 4051 : if (catch_block) {
494 22 : std::string block_name = BlockName(*catch_block);
495 22 : out_ << " }\n";
496 44 : out_ << " if (" << catch_name << "_label.is_used()) {\n";
497 22 : out_ << " compiler::CodeAssemblerLabel " << catch_name
498 22 : << "_skip(&ca_);\n";
499 22 : if (!return_type->IsNever()) {
500 38 : out_ << " ca_.Goto(&" << catch_name << "_skip);\n";
501 : }
502 22 : out_ << " compiler::TNode<Object> " << catch_name
503 22 : << "_exception_object;\n";
504 44 : out_ << " ca_.Bind(&" << catch_name << "_label, &" << catch_name
505 22 : << "_exception_object);\n";
506 22 : out_ << " ca_.Goto(&" << block_name;
507 370 : for (size_t i = 0; i < stack->Size(); ++i) {
508 163 : out_ << ", " << stack->begin()[i];
509 : }
510 44 : out_ << ", " << catch_name << "_exception_object);\n";
511 22 : if (!return_type->IsNever()) {
512 38 : out_ << " ca_.Bind(&" << catch_name << "_skip);\n";
513 : }
514 22 : out_ << " }\n";
515 : }
516 4051 : }
517 :
518 20 : void CSAGenerator::EmitInstruction(const CallRuntimeInstruction& instruction,
519 : Stack<std::string>* stack) {
520 20 : std::vector<std::string> arguments = stack->PopMany(instruction.argc);
521 : const Type* return_type =
522 20 : instruction.runtime_function->signature().return_type;
523 : std::vector<const Type*> result_types;
524 20 : if (return_type != TypeOracle::GetNeverType()) {
525 30 : result_types = LowerType(return_type);
526 : }
527 40 : if (result_types.size() > 1) {
528 0 : ReportError("runtime function must have at most one result");
529 : }
530 20 : if (instruction.is_tailcall) {
531 0 : out_ << " CodeStubAssembler(state_).TailCallRuntime(Runtime::k"
532 0 : << instruction.runtime_function->ExternalName() << ", ";
533 0 : PrintCommaSeparatedList(out_, arguments);
534 0 : out_ << ");\n";
535 : } else {
536 20 : std::string result_name = FreshNodeName();
537 40 : if (result_types.size() == 1) {
538 5 : out_ << " compiler::TNode<"
539 15 : << result_types[0]->GetGeneratedTNodeTypeName() << "> "
540 5 : << result_name << ";\n";
541 : }
542 : std::string catch_name =
543 20 : PreCallableExceptionPreparation(instruction.catch_block);
544 : Stack<std::string> pre_call_stack = *stack;
545 40 : if (result_types.size() == 1) {
546 10 : stack->Push(result_name);
547 5 : out_ << " " << result_name
548 5 : << " = TORQUE_CAST(CodeStubAssembler(state_).CallRuntime(Runtime::k"
549 10 : << instruction.runtime_function->ExternalName() << ", ";
550 5 : PrintCommaSeparatedList(out_, arguments);
551 5 : out_ << "));\n";
552 10 : out_ << " USE(" << result_name << ");\n";
553 : } else {
554 : DCHECK_EQ(0, result_types.size());
555 15 : out_ << " CodeStubAssembler(state_).CallRuntime(Runtime::k"
556 30 : << instruction.runtime_function->ExternalName() << ", ";
557 15 : PrintCommaSeparatedList(out_, arguments);
558 15 : out_ << ");\n";
559 15 : if (return_type == TypeOracle::GetNeverType()) {
560 5 : out_ << " CodeStubAssembler(state_).Unreachable();\n";
561 : } else {
562 : DCHECK(return_type == TypeOracle::GetVoidType());
563 : }
564 : }
565 : PostCallableExceptionPreparation(catch_name, return_type,
566 20 : instruction.catch_block, &pre_call_stack);
567 20 : }
568 20 : }
569 :
570 577 : void CSAGenerator::EmitInstruction(const BranchInstruction& instruction,
571 : Stack<std::string>* stack) {
572 1731 : out_ << " ca_.Branch(" << stack->Pop() << ", &"
573 1731 : << BlockName(instruction.if_true) << ", &"
574 1154 : << BlockName(instruction.if_false);
575 4496 : for (const std::string& value : *stack) {
576 3919 : out_ << ", " << value;
577 : }
578 577 : out_ << ");\n";
579 577 : }
580 :
581 49 : void CSAGenerator::EmitInstruction(
582 : const ConstexprBranchInstruction& instruction, Stack<std::string>* stack) {
583 98 : out_ << " if (" << instruction.condition << ") {\n";
584 98 : out_ << " ca_.Goto(&" << BlockName(instruction.if_true);
585 379 : for (const std::string& value : *stack) {
586 330 : out_ << ", " << value;
587 : }
588 49 : out_ << ");\n";
589 49 : out_ << " } else {\n";
590 98 : out_ << " ca_.Goto(&" << BlockName(instruction.if_false);
591 379 : for (const std::string& value : *stack) {
592 330 : out_ << ", " << value;
593 : }
594 49 : out_ << ");\n";
595 :
596 49 : out_ << " }\n";
597 49 : }
598 :
599 3010 : void CSAGenerator::EmitInstruction(const GotoInstruction& instruction,
600 : Stack<std::string>* stack) {
601 6020 : out_ << " ca_.Goto(&" << BlockName(instruction.destination);
602 17543 : for (const std::string& value : *stack) {
603 14533 : out_ << ", " << value;
604 : }
605 3010 : out_ << ");\n";
606 3010 : }
607 :
608 129 : void CSAGenerator::EmitInstruction(const GotoExternalInstruction& instruction,
609 : Stack<std::string>* stack) {
610 141 : for (auto it = instruction.variable_names.rbegin();
611 : it != instruction.variable_names.rend(); ++it) {
612 48 : out_ << " *" << *it << " = " << stack->Pop() << ";\n";
613 : }
614 258 : out_ << " ca_.Goto(" << instruction.destination << ");\n";
615 129 : }
616 :
617 163 : void CSAGenerator::EmitInstruction(const ReturnInstruction& instruction,
618 : Stack<std::string>* stack) {
619 163 : if (*linkage_ == Builtin::kVarArgsJavaScript) {
620 58 : out_ << " " << ARGUMENTS_VARIABLE_STRING << "->PopAndReturn(";
621 : } else {
622 105 : out_ << " CodeStubAssembler(state_).Return(";
623 : }
624 489 : out_ << stack->Pop() << ");\n";
625 163 : }
626 :
627 0 : void CSAGenerator::EmitInstruction(
628 : const PrintConstantStringInstruction& instruction,
629 : Stack<std::string>* stack) {
630 0 : out_ << " CodeStubAssembler(state_).Print("
631 0 : << StringLiteralQuote(instruction.message) << ");\n";
632 0 : }
633 :
634 173 : void CSAGenerator::EmitInstruction(const AbortInstruction& instruction,
635 : Stack<std::string>* stack) {
636 173 : switch (instruction.kind) {
637 : case AbortInstruction::Kind::kUnreachable:
638 : DCHECK(instruction.message.empty());
639 67 : out_ << " CodeStubAssembler(state_).Unreachable();\n";
640 67 : break;
641 : case AbortInstruction::Kind::kDebugBreak:
642 : DCHECK(instruction.message.empty());
643 0 : out_ << " CodeStubAssembler(state_).DebugBreak();\n";
644 0 : break;
645 : case AbortInstruction::Kind::kAssertionFailure: {
646 : std::string file =
647 106 : StringLiteralQuote(SourceFileMap::GetSource(instruction.pos.source));
648 106 : out_ << " CodeStubAssembler(state_).FailAssert("
649 424 : << StringLiteralQuote(instruction.message) << ", " << file << ", "
650 212 : << instruction.pos.line + 1 << ");\n";
651 : break;
652 : }
653 : }
654 173 : }
655 :
656 29 : void CSAGenerator::EmitInstruction(const UnsafeCastInstruction& instruction,
657 : Stack<std::string>* stack) {
658 : stack->Poke(stack->AboveTop() - 1,
659 87 : "ca_.UncheckedCast<" +
660 58 : instruction.destination_type->GetGeneratedTNodeTypeName() +
661 116 : ">(" + stack->Top() + ")");
662 29 : }
663 :
664 13 : void CSAGenerator::EmitInstruction(
665 : const LoadObjectFieldInstruction& instruction, Stack<std::string>* stack) {
666 : const Field& field =
667 13 : instruction.class_type->LookupField(instruction.field_name);
668 13 : std::string result_name = FreshNodeName();
669 : std::string type_string =
670 13 : field.name_and_type.type->IsSubtypeOf(TypeOracle::GetSmiType())
671 : ? "MachineType::TaggedSigned()"
672 13 : : "MachineType::AnyTagged()";
673 39 : out_ << field.name_and_type.type->GetGeneratedTypeName() << " " << result_name
674 13 : << " = "
675 13 : << "ca_.UncheckedCast<"
676 26 : << field.name_and_type.type->GetGeneratedTNodeTypeName()
677 13 : << ">(CodeStubAssembler(state_).LoadObjectField("
678 78 : << stack->Top() + ", " + std::to_string(field.offset) + ", "
679 13 : << type_string + "));\n";
680 39 : stack->Poke(stack->AboveTop() - 1, result_name);
681 13 : }
682 :
683 25 : void CSAGenerator::EmitInstruction(
684 : const StoreObjectFieldInstruction& instruction, Stack<std::string>* stack) {
685 25 : auto value = stack->Pop();
686 25 : auto object = stack->Pop();
687 50 : stack->Push(value);
688 : const Field& field =
689 25 : instruction.class_type->LookupField(instruction.field_name);
690 25 : if (field.offset == 0) {
691 8 : out_ << " CodeStubAssembler(state_).StoreMap(" + object + ", " + value +
692 2 : ");\n";
693 : } else {
694 138 : out_ << " CodeStubAssembler(state_).StoreObjectField(" + object + ", " +
695 69 : std::to_string(field.offset) + ", " + value + ");\n";
696 : }
697 25 : }
698 :
699 : // static
700 11977 : void CSAGenerator::EmitCSAValue(VisitResult result,
701 : const Stack<std::string>& values,
702 : std::ostream& out) {
703 6006 : if (!result.IsOnStack()) {
704 : out << result.constexpr_value();
705 5971 : } else if (auto* struct_type = StructType::DynamicCast(result.type())) {
706 93 : out << struct_type->GetGeneratedTypeName() << "{";
707 : bool first = true;
708 150 : for (auto& field : struct_type->fields()) {
709 88 : if (!first) {
710 57 : out << ", ";
711 : }
712 : first = false;
713 : EmitCSAValue(ProjectStructField(result, field.name_and_type.name), values,
714 264 : out);
715 : }
716 31 : out << "}";
717 : } else {
718 : DCHECK_EQ(1, result.stack_range().Size());
719 11880 : out << "compiler::TNode<" << result.type()->GetGeneratedTNodeTypeName()
720 11880 : << ">{" << values.Peek(result.stack_range().begin()) << "}";
721 : }
722 6006 : }
723 :
724 : } // namespace torque
725 : } // namespace internal
726 9078 : } // namespace v8
|