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