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