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