1 // Copyright 2017 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 <algorithm>
6
7 #include "src/torque/implementation-visitor.h"
8 #include "src/torque/parameter-difference.h"
9
10 namespace v8 {
11 namespace internal {
12 namespace torque {
13
Visit(Expression * expr)14 VisitResult ImplementationVisitor::Visit(Expression* expr) {
15 CurrentSourcePosition::Scope scope(expr->pos);
16 switch (expr->kind) {
17 #define ENUM_ITEM(name) \
18 case AstNode::Kind::k##name: \
19 return Visit(name::cast(expr));
20 AST_EXPRESSION_NODE_KIND_LIST(ENUM_ITEM)
21 #undef ENUM_ITEM
22 default:
23 UNREACHABLE();
24 }
25 }
26
Visit(Statement * stmt)27 const Type* ImplementationVisitor::Visit(Statement* stmt) {
28 CurrentSourcePosition::Scope scope(stmt->pos);
29 GenerateIndent();
30 source_out() << "// " << CurrentPositionAsString() << "\n";
31 switch (stmt->kind) {
32 #define ENUM_ITEM(name) \
33 case AstNode::Kind::k##name: \
34 return Visit(name::cast(stmt));
35 AST_STATEMENT_NODE_KIND_LIST(ENUM_ITEM)
36 #undef ENUM_ITEM
37 default:
38 UNIMPLEMENTED();
39 }
40 UNREACHABLE();
41 return nullptr;
42 }
43
Visit(Declaration * decl)44 void ImplementationVisitor::Visit(Declaration* decl) {
45 CurrentSourcePosition::Scope scope(decl->pos);
46 switch (decl->kind) {
47 #define ENUM_ITEM(name) \
48 case AstNode::Kind::k##name: \
49 return Visit(name::cast(decl));
50 AST_DECLARATION_NODE_KIND_LIST(ENUM_ITEM)
51 #undef ENUM_ITEM
52 default:
53 UNIMPLEMENTED();
54 }
55 }
56
Visit(CallableNode * decl,const Signature & signature,Statement * body)57 void ImplementationVisitor::Visit(CallableNode* decl,
58 const Signature& signature, Statement* body) {
59 switch (decl->kind) {
60 #define ENUM_ITEM(name) \
61 case AstNode::Kind::k##name: \
62 return Visit(name::cast(decl), signature, body);
63 AST_CALLABLE_NODE_KIND_LIST(ENUM_ITEM)
64 #undef ENUM_ITEM
65 default:
66 UNIMPLEMENTED();
67 }
68 }
69
BeginModuleFile(Module * module)70 void ImplementationVisitor::BeginModuleFile(Module* module) {
71 std::ostream& source = module->source_stream();
72 std::ostream& header = module->header_stream();
73
74 if (module->IsDefault()) {
75 source << "#include \"src/code-stub-assembler.h\"";
76 } else {
77 source << "#include \"src/builtins/builtins-" +
78 DashifyString(module->name()) + "-gen.h\"";
79 }
80 source << "\n";
81 source << "#include \"src/builtins/builtins-utils-gen.h\"\n";
82 source << "#include \"src/builtins/builtins.h\"\n";
83 source << "#include \"src/code-factory.h\"\n";
84 source << "#include \"src/elements-kind.h\"\n";
85 source << "#include \"src/heap/factory-inl.h\"\n";
86 source << "#include \"src/objects.h\"\n";
87 source << "#include \"src/objects/bigint.h\"\n";
88
89 source << "#include \"builtins-" + DashifyString(module->name()) +
90 "-from-dsl-gen.h\"\n\n";
91
92 source << "namespace v8 {\n"
93 << "namespace internal {\n"
94 << "\n"
95 << "using Node = compiler::Node;\n"
96 << "\n";
97
98 std::string upper_name(module->name());
99 transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
100 ::toupper);
101 std::string headerDefine =
102 std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";
103 header << "#ifndef " << headerDefine << "\n";
104 header << "#define " << headerDefine << "\n\n";
105 if (module->IsDefault()) {
106 header << "#include \"src/code-stub-assembler.h\"";
107 } else {
108 header << "#include \"src/builtins/builtins-" +
109 DashifyString(module->name()) + "-gen.h\"\n";
110 }
111 header << "\n\n ";
112
113 header << "namespace v8 {\n"
114 << "namespace internal {\n"
115 << "\n";
116
117 header << "class " << GetDSLAssemblerName(module) << ": public "
118 << GetBaseAssemblerName(module) << " {\n";
119 header << " public:\n";
120 header << " explicit " << GetDSLAssemblerName(module)
121 << "(compiler::CodeAssemblerState* state) : "
122 << GetBaseAssemblerName(module) << "(state) {}\n";
123
124 header << "\n";
125 header << " using Node = compiler::Node;\n";
126 header << " template <class T>\n";
127 header << " using TNode = compiler::TNode<T>;\n";
128 header << " template <class T>\n";
129 header << " using SloppyTNode = compiler::SloppyTNode<T>;\n\n";
130 }
131
EndModuleFile(Module * module)132 void ImplementationVisitor::EndModuleFile(Module* module) {
133 std::ostream& source = module->source_stream();
134 std::ostream& header = module->header_stream();
135
136 DrainSpecializationQueue();
137
138 std::string upper_name(module->name());
139 transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
140 ::toupper);
141 std::string headerDefine =
142 std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";
143
144 source << "} // namespace internal\n"
145 << "} // namespace v8\n"
146 << "\n";
147
148 header << "};\n\n";
149 header << "} // namespace internal\n"
150 << "} // namespace v8\n"
151 << "\n";
152 header << "#endif // " << headerDefine << "\n";
153 }
154
Visit(ModuleDeclaration * decl)155 void ImplementationVisitor::Visit(ModuleDeclaration* decl) {
156 Module* module = decl->GetModule();
157 Module* saved_module = module_;
158 module_ = module;
159 Declarations::ModuleScopeActivator scope(declarations(), decl->GetModule());
160 for (auto& child : decl->declarations) Visit(child);
161 module_ = saved_module;
162 }
163
Visit(ConstDeclaration * decl)164 void ImplementationVisitor::Visit(ConstDeclaration* decl) {
165 Signature signature = MakeSignatureFromReturnType(decl->type);
166 std::string name = decl->name;
167
168 header_out() << " ";
169 GenerateFunctionDeclaration(header_out(), "", name, signature, {});
170 header_out() << ";\n";
171
172 GenerateFunctionDeclaration(source_out(),
173 GetDSLAssemblerName(CurrentModule()) + "::", name,
174 signature, {});
175 source_out() << " {\n";
176
177 DCHECK(!signature.return_type->IsVoidOrNever());
178
179 VisitResult expression_result = Visit(decl->expression);
180 VisitResult return_result =
181 GenerateImplicitConvert(signature.return_type, expression_result);
182
183 GenerateIndent();
184 source_out() << "return " << return_result.RValue() << ";\n";
185 source_out() << "}\n\n";
186 }
187
Visit(StructDeclaration * decl)188 void ImplementationVisitor::Visit(StructDeclaration* decl) {
189 header_out() << " struct " << decl->name << " {\n";
190 const StructType* struct_type =
191 static_cast<const StructType*>(declarations()->LookupType(decl->name));
192 for (auto& field : struct_type->fields()) {
193 header_out() << " " << field.type->GetGeneratedTypeName();
194 header_out() << " " << field.name << ";\n";
195 }
196 header_out() << " } "
197 << ";\n";
198 }
199
Visit(TorqueMacroDeclaration * decl,const Signature & sig,Statement * body)200 void ImplementationVisitor::Visit(TorqueMacroDeclaration* decl,
201 const Signature& sig, Statement* body) {
202 Signature signature = MakeSignature(decl->signature.get());
203 std::string name = GetGeneratedCallableName(
204 decl->name, declarations()->GetCurrentSpecializationTypeNamesVector());
205 const TypeVector& list = signature.types();
206 Macro* macro = declarations()->LookupMacro(name, list);
207
208 CurrentCallableActivator activator(global_context_, macro, decl);
209
210 if (body != nullptr) {
211 header_out() << " ";
212 GenerateMacroFunctionDeclaration(header_out(), "", macro);
213 header_out() << ";\n";
214
215 GenerateMacroFunctionDeclaration(
216 source_out(), GetDSLAssemblerName(CurrentModule()) + "::", macro);
217 source_out() << " {\n";
218
219 const Variable* result_var = nullptr;
220 if (macro->HasReturnValue()) {
221 result_var =
222 GeneratePredeclaredVariableDeclaration(kReturnValueVariable, {});
223 }
224 Label* macro_end = declarations()->DeclareLabel("macro_end");
225 GenerateLabelDefinition(macro_end, decl);
226
227 const Type* result = Visit(body);
228 if (result->IsNever()) {
229 if (!macro->signature().return_type->IsNever() && !macro->HasReturns()) {
230 std::stringstream s;
231 s << "macro " << decl->name
232 << " that never returns must have return type never";
233 ReportError(s.str());
234 }
235 } else {
236 if (macro->signature().return_type->IsNever()) {
237 std::stringstream s;
238 s << "macro " << decl->name
239 << " has implicit return at end of its declartion but return type "
240 "never";
241 ReportError(s.str());
242 } else if (!macro->signature().return_type->IsVoid()) {
243 std::stringstream s;
244 s << "macro " << decl->name
245 << " expects to return a value but doesn't on all paths";
246 ReportError(s.str());
247 }
248 }
249 if (macro->HasReturns()) {
250 if (!result->IsNever()) {
251 GenerateLabelGoto(macro_end);
252 }
253 GenerateLabelBind(macro_end);
254 }
255 if (result_var != nullptr) {
256 GenerateIndent();
257 source_out() << "return "
258 << RValueFlattenStructs(
259 VisitResult(result_var->type(), result_var))
260 << ";\n";
261 }
262 source_out() << "}\n\n";
263 }
264 }
265
Visit(TorqueBuiltinDeclaration * decl,const Signature & signature,Statement * body)266 void ImplementationVisitor::Visit(TorqueBuiltinDeclaration* decl,
267 const Signature& signature, Statement* body) {
268 std::string name = GetGeneratedCallableName(
269 decl->name, declarations()->GetCurrentSpecializationTypeNamesVector());
270 source_out() << "TF_BUILTIN(" << name << ", "
271 << GetDSLAssemblerName(CurrentModule()) << ") {\n";
272 Builtin* builtin = declarations()->LookupBuiltin(name);
273 CurrentCallableActivator activator(global_context_, builtin, decl);
274
275 // Context
276 const Value* val =
277 declarations()->LookupValue(decl->signature->parameters.names[0]);
278 GenerateIndent();
279 source_out() << "TNode<Context> " << val->value()
280 << " = UncheckedCast<Context>(Parameter("
281 << "Descriptor::kContext));\n";
282 GenerateIndent();
283 source_out() << "USE(" << val->value() << ");\n";
284
285 size_t first = 1;
286 if (builtin->IsVarArgsJavaScript()) {
287 assert(decl->signature->parameters.has_varargs);
288 ExternConstant* arguments =
289 ExternConstant::cast(declarations()->LookupValue(
290 decl->signature->parameters.arguments_variable));
291 std::string arguments_name = arguments->value();
292 GenerateIndent();
293 source_out()
294 << "Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);\n";
295 GenerateIndent();
296 source_out() << "CodeStubArguments arguments_impl(this, "
297 "ChangeInt32ToIntPtr(argc));\n";
298 const Value* receiver =
299 declarations()->LookupValue(decl->signature->parameters.names[1]);
300 GenerateIndent();
301 source_out() << "TNode<Object> " << receiver->value()
302 << " = arguments_impl.GetReceiver();\n";
303 GenerateIndent();
304 source_out() << "auto arguments = &arguments_impl;\n";
305 GenerateIndent();
306 source_out() << "USE(arguments);\n";
307 GenerateIndent();
308 source_out() << "USE(" << receiver->value() << ");\n";
309 first = 2;
310 }
311
312 GenerateParameterList(decl->signature->parameters.names, first);
313 Visit(body);
314 source_out() << "}\n\n";
315 }
316
Visit(VarDeclarationStatement * stmt)317 const Type* ImplementationVisitor::Visit(VarDeclarationStatement* stmt) {
318 base::Optional<VisitResult> init_result;
319 if (stmt->initializer) {
320 init_result = Visit(*stmt->initializer);
321 }
322 base::Optional<const Type*> type;
323 if (stmt->type) type = declarations()->GetType(*stmt->type);
324 GenerateVariableDeclaration(stmt, stmt->name, stmt->const_qualified, type,
325 init_result);
326 return TypeOracle::GetVoidType();
327 }
328
Visit(TailCallStatement * stmt)329 const Type* ImplementationVisitor::Visit(TailCallStatement* stmt) {
330 return Visit(stmt->call, true).type();
331 }
332
Visit(ConditionalExpression * expr)333 VisitResult ImplementationVisitor::Visit(ConditionalExpression* expr) {
334 std::string f1 = NewTempVariable();
335 std::string f2 = NewTempVariable();
336
337 // The code for both paths of the conditional need to be generated first in
338 // lambdas before evaluating the conditional expression because the common
339 // type of the result of both the true and false of the condition needs to be
340 // known when declaring the variable to hold the result of the conditional.
341 VisitResult left, right;
342 GenerateIndent();
343 source_out() << "auto " << f1 << " = [=]() ";
344 {
345 ScopedIndent indent(this, false);
346 source_out() << "\n";
347 left = Visit(expr->if_true);
348 GenerateIndent();
349 source_out() << "return " << RValueFlattenStructs(left) << ";\n";
350 }
351 source_out() << ";\n";
352 GenerateIndent();
353 source_out() << "auto " << f2 << " = [=]() ";
354 {
355 ScopedIndent indent(this, false);
356 source_out() << "\n";
357 right = Visit(expr->if_false);
358 GenerateIndent();
359 source_out() << "return " << RValueFlattenStructs(right) << ";\n";
360 }
361 source_out() << ";\n";
362
363 const Type* common_type = GetCommonType(left.type(), right.type());
364 std::string result_var = NewTempVariable();
365 Variable* result =
366 GenerateVariableDeclaration(expr, result_var, false, common_type);
367
368 {
369 ScopedIndent indent(this);
370 Declarations::NodeScopeActivator scope(declarations(), expr->condition);
371
372 Label* true_label = declarations()->LookupLabel(kTrueLabelName);
373 GenerateLabelDefinition(true_label);
374 Label* false_label = declarations()->LookupLabel(kFalseLabelName);
375 GenerateLabelDefinition(false_label);
376 Label* done_label = declarations()->DeclarePrivateLabel(kDoneLabelName);
377 GenerateLabelDefinition(done_label, expr);
378
379 VisitResult condition_result = Visit(expr->condition);
380 if (!condition_result.type()->IsNever()) {
381 condition_result =
382 GenerateImplicitConvert(TypeOracle::GetBoolType(), condition_result);
383 GenerateBranch(condition_result, true_label, false_label);
384 }
385 GenerateLabelBind(true_label);
386 GenerateIndent();
387 VisitResult left_result = {right.type(), f1 + "()"};
388 GenerateAssignToVariable(result, left_result);
389 GenerateLabelGoto(done_label);
390
391 GenerateLabelBind(false_label);
392 GenerateIndent();
393 VisitResult right_result = {right.type(), f2 + "()"};
394 GenerateAssignToVariable(result, right_result);
395 GenerateLabelGoto(done_label);
396
397 GenerateLabelBind(done_label);
398 }
399 return VisitResult(common_type, result);
400 }
401
Visit(LogicalOrExpression * expr)402 VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) {
403 VisitResult left_result;
404 {
405 Declarations::NodeScopeActivator scope(declarations(), expr->left);
406 Label* false_label = declarations()->LookupLabel(kFalseLabelName);
407 GenerateLabelDefinition(false_label);
408 left_result = Visit(expr->left);
409 if (left_result.type()->IsBool()) {
410 Label* true_label = declarations()->LookupLabel(kTrueLabelName);
411 GenerateIndent();
412 source_out() << "GotoIf(" << RValueFlattenStructs(left_result) << ", "
413 << true_label->generated() << ");\n";
414 } else if (!left_result.type()->IsConstexprBool()) {
415 GenerateLabelBind(false_label);
416 }
417 }
418 VisitResult right_result = Visit(expr->right);
419 if (right_result.type() != left_result.type()) {
420 std::stringstream stream;
421 stream << "types of left and right expression of logical OR don't match (\""
422 << *left_result.type() << "\" vs. \"" << *right_result.type()
423 << "\")";
424 ReportError(stream.str());
425 }
426 if (left_result.type()->IsConstexprBool()) {
427 return VisitResult(left_result.type(),
428 std::string("(") + RValueFlattenStructs(left_result) +
429 " || " + RValueFlattenStructs(right_result) + ")");
430 } else {
431 return right_result;
432 }
433 }
434
Visit(LogicalAndExpression * expr)435 VisitResult ImplementationVisitor::Visit(LogicalAndExpression* expr) {
436 VisitResult left_result;
437 {
438 Declarations::NodeScopeActivator scope(declarations(), expr->left);
439 Label* true_label = declarations()->LookupLabel(kTrueLabelName);
440 GenerateLabelDefinition(true_label);
441 left_result = Visit(expr->left);
442 if (left_result.type()->IsBool()) {
443 Label* false_label = declarations()->LookupLabel(kFalseLabelName);
444 GenerateIndent();
445 source_out() << "GotoIfNot(" << RValueFlattenStructs(left_result) << ", "
446 << false_label->generated() << ");\n";
447 } else if (!left_result.type()->IsConstexprBool()) {
448 GenerateLabelBind(true_label);
449 }
450 }
451 VisitResult right_result = Visit(expr->right);
452 if (right_result.type() != left_result.type()) {
453 std::stringstream stream;
454 stream
455 << "types of left and right expression of logical AND don't match (\""
456 << *left_result.type() << "\" vs. \"" << *right_result.type() << "\")";
457 ReportError(stream.str());
458 }
459 if (left_result.type()->IsConstexprBool()) {
460 return VisitResult(left_result.type(),
461 std::string("(") + RValueFlattenStructs(left_result) +
462 " && " + RValueFlattenStructs(right_result) + ")");
463 } else {
464 return right_result;
465 }
466 }
467
Visit(IncrementDecrementExpression * expr)468 VisitResult ImplementationVisitor::Visit(IncrementDecrementExpression* expr) {
469 VisitResult value_copy;
470 auto location_ref = GetLocationReference(expr->location);
471 VisitResult current_value =
472 GenerateFetchFromLocation(expr->location, location_ref);
473 if (expr->postfix) {
474 value_copy = GenerateCopy(current_value);
475 }
476 VisitResult one = {TypeOracle::GetConstInt31Type(), "1"};
477 Arguments args;
478 args.parameters = {current_value, one};
479 VisitResult assignment_value = GenerateCall(
480 expr->op == IncrementDecrementOperator::kIncrement ? "+" : "-", args);
481 GenerateAssignToLocation(expr->location, location_ref, assignment_value);
482 return expr->postfix ? value_copy : assignment_value;
483 }
484
Visit(AssignmentExpression * expr)485 VisitResult ImplementationVisitor::Visit(AssignmentExpression* expr) {
486 LocationReference location_ref = GetLocationReference(expr->location);
487 VisitResult assignment_value;
488 if (expr->op) {
489 VisitResult location_value =
490 GenerateFetchFromLocation(expr->location, location_ref);
491 assignment_value = Visit(expr->value);
492 Arguments args;
493 args.parameters = {location_value, assignment_value};
494 assignment_value = GenerateCall(*expr->op, args);
495 GenerateAssignToLocation(expr->location, location_ref, assignment_value);
496 } else {
497 assignment_value = Visit(expr->value);
498 GenerateAssignToLocation(expr->location, location_ref, assignment_value);
499 }
500 return assignment_value;
501 }
502
Visit(NumberLiteralExpression * expr)503 VisitResult ImplementationVisitor::Visit(NumberLiteralExpression* expr) {
504 // TODO(tebbi): Do not silently loose precision; support 64bit literals.
505 double d = std::stod(expr->number.c_str());
506 int32_t i = static_cast<int32_t>(d);
507 const Type* result_type =
508 declarations()->LookupType(CONST_FLOAT64_TYPE_STRING);
509 if (i == d) {
510 if ((i >> 30) == (i >> 31)) {
511 result_type = declarations()->LookupType(CONST_INT31_TYPE_STRING);
512 } else {
513 result_type = declarations()->LookupType(CONST_INT32_TYPE_STRING);
514 }
515 }
516 std::string temp = GenerateNewTempVariable(result_type);
517 source_out() << expr->number << ";\n";
518 return VisitResult{result_type, temp};
519 }
520
Visit(AssumeTypeImpossibleExpression * expr)521 VisitResult ImplementationVisitor::Visit(AssumeTypeImpossibleExpression* expr) {
522 VisitResult result = Visit(expr->expression);
523 const Type* result_type =
524 SubtractType(result.type(), declarations()->GetType(expr->excluded_type));
525 if (result_type->IsNever()) {
526 ReportError("unreachable code");
527 }
528 return VisitResult{result_type, "UncheckedCast<" +
529 result_type->GetGeneratedTNodeTypeName() +
530 ">(" + result.RValue() + ")"};
531 }
532
Visit(StringLiteralExpression * expr)533 VisitResult ImplementationVisitor::Visit(StringLiteralExpression* expr) {
534 std::string temp = GenerateNewTempVariable(TypeOracle::GetConstStringType());
535 source_out() << "\"" << expr->literal.substr(1, expr->literal.size() - 2)
536 << "\";\n";
537 return VisitResult{TypeOracle::GetConstStringType(), temp};
538 }
539
GetBuiltinCode(Builtin * builtin)540 VisitResult ImplementationVisitor::GetBuiltinCode(Builtin* builtin) {
541 if (builtin->IsExternal() || builtin->kind() != Builtin::kStub) {
542 ReportError(
543 "creating function pointers is only allowed for internal builtins with "
544 "stub linkage");
545 }
546 const Type* type = TypeOracle::GetFunctionPointerType(
547 builtin->signature().parameter_types.types,
548 builtin->signature().return_type);
549 std::string code =
550 "HeapConstant(Builtins::CallableFor(isolate(), Builtins::k" +
551 builtin->name() + ").code())";
552 return VisitResult(type, code);
553 }
554
Visit(IdentifierExpression * expr)555 VisitResult ImplementationVisitor::Visit(IdentifierExpression* expr) {
556 std::string name = expr->name;
557 if (expr->generic_arguments.size() != 0) {
558 GenericList* generic_list = declarations()->LookupGeneric(expr->name);
559 for (Generic* generic : generic_list->list()) {
560 TypeVector specialization_types = GetTypeVector(expr->generic_arguments);
561 name = GetGeneratedCallableName(name, specialization_types);
562 CallableNode* callable = generic->declaration()->callable;
563 QueueGenericSpecialization({generic, specialization_types}, callable,
564 callable->signature.get(),
565 generic->declaration()->body);
566 }
567 }
568
569 if (Builtin* builtin = Builtin::DynamicCast(declarations()->Lookup(name))) {
570 return GetBuiltinCode(builtin);
571 }
572
573 return GenerateFetchFromLocation(expr, GetLocationReference(expr));
574 }
575
Visit(GotoStatement * stmt)576 const Type* ImplementationVisitor::Visit(GotoStatement* stmt) {
577 Label* label = declarations()->LookupLabel(stmt->label);
578
579 if (stmt->arguments.size() != label->GetParameterCount()) {
580 std::stringstream stream;
581 stream << "goto to label has incorrect number of parameters (expected "
582 << std::to_string(label->GetParameterCount()) << " found "
583 << std::to_string(stmt->arguments.size()) << ")";
584 ReportError(stream.str());
585 }
586
587 size_t i = 0;
588 for (Expression* e : stmt->arguments) {
589 VisitResult result = Visit(e);
590 Variable* var = label->GetParameter(i++);
591 GenerateAssignToVariable(var, result);
592 }
593
594 GenerateLabelGoto(label);
595 label->MarkUsed();
596 return TypeOracle::GetNeverType();
597 }
598
Visit(IfStatement * stmt)599 const Type* ImplementationVisitor::Visit(IfStatement* stmt) {
600 ScopedIndent indent(this);
601
602 bool has_else = stmt->if_false.has_value();
603
604 if (stmt->is_constexpr) {
605 VisitResult expression_result = Visit(stmt->condition);
606
607 if (!(expression_result.type() == TypeOracle::GetConstexprBoolType())) {
608 std::stringstream stream;
609 stream << "expression should return type constexpr bool "
610 << "but returns type " << *expression_result.type();
611 ReportError(stream.str());
612 }
613
614 const Type* left_result;
615 const Type* right_result = TypeOracle::GetVoidType();
616 {
617 GenerateIndent();
618 source_out() << "if ((" << RValueFlattenStructs(expression_result)
619 << ")) ";
620 ScopedIndent indent(this, false);
621 source_out() << "\n";
622 left_result = Visit(stmt->if_true);
623 }
624
625 if (has_else) {
626 source_out() << " else ";
627 ScopedIndent indent(this, false);
628 source_out() << "\n";
629 right_result = Visit(*stmt->if_false);
630 }
631 if (left_result->IsNever() != right_result->IsNever()) {
632 std::stringstream stream;
633 stream << "either both or neither branches in a constexpr if statement "
634 "must reach their end at"
635 << PositionAsString(stmt->pos);
636 ReportError(stream.str());
637 }
638
639 source_out() << "\n";
640
641 return left_result;
642 } else {
643 Label* true_label = nullptr;
644 Label* false_label = nullptr;
645 {
646 Declarations::NodeScopeActivator scope(declarations(), &*stmt->condition);
647 true_label = declarations()->LookupLabel(kTrueLabelName);
648 GenerateLabelDefinition(true_label);
649 false_label = declarations()->LookupLabel(kFalseLabelName);
650 GenerateLabelDefinition(false_label, !has_else ? stmt : nullptr);
651 }
652
653 Label* done_label = nullptr;
654 bool live = false;
655 if (has_else) {
656 done_label = declarations()->DeclarePrivateLabel("if_done_label");
657 GenerateLabelDefinition(done_label, stmt);
658 } else {
659 done_label = false_label;
660 live = true;
661 }
662 std::vector<Statement*> blocks = {stmt->if_true};
663 std::vector<Label*> labels = {true_label, false_label};
664 if (has_else) blocks.push_back(*stmt->if_false);
665 if (GenerateExpressionBranch(stmt->condition, labels, blocks, done_label)) {
666 live = true;
667 }
668 if (live) {
669 GenerateLabelBind(done_label);
670 }
671 return live ? TypeOracle::GetVoidType() : TypeOracle::GetNeverType();
672 }
673 }
674
Visit(WhileStatement * stmt)675 const Type* ImplementationVisitor::Visit(WhileStatement* stmt) {
676 ScopedIndent indent(this);
677
678 Label* body_label = nullptr;
679 Label* exit_label = nullptr;
680 {
681 Declarations::NodeScopeActivator scope(declarations(), stmt->condition);
682 body_label = declarations()->LookupLabel(kTrueLabelName);
683 GenerateLabelDefinition(body_label);
684 exit_label = declarations()->LookupLabel(kFalseLabelName);
685 GenerateLabelDefinition(exit_label);
686 }
687
688 Label* header_label = declarations()->DeclarePrivateLabel("header");
689 GenerateLabelDefinition(header_label, stmt);
690 GenerateLabelGoto(header_label);
691 GenerateLabelBind(header_label);
692
693 Declarations::NodeScopeActivator scope(declarations(), stmt->body);
694 BreakContinueActivator activator(global_context_, exit_label, header_label);
695
696 GenerateExpressionBranch(stmt->condition, {body_label, exit_label},
697 {stmt->body}, header_label);
698
699 GenerateLabelBind(exit_label);
700 return TypeOracle::GetVoidType();
701 }
702
Visit(BlockStatement * block)703 const Type* ImplementationVisitor::Visit(BlockStatement* block) {
704 Declarations::NodeScopeActivator scope(declarations(), block);
705 ScopedIndent indent(this);
706 const Type* type = TypeOracle::GetVoidType();
707 for (Statement* s : block->statements) {
708 if (type->IsNever()) {
709 std::stringstream stream;
710 stream << "statement after non-returning statement";
711 ReportError(stream.str());
712 }
713 type = Visit(s);
714 }
715 return type;
716 }
717
Visit(DebugStatement * stmt)718 const Type* ImplementationVisitor::Visit(DebugStatement* stmt) {
719 #if defined(DEBUG)
720 GenerateIndent();
721 source_out() << "Print(\""
722 << "halting because of '" << stmt->reason << "' at "
723 << PositionAsString(stmt->pos) << "\");\n";
724 #endif
725 GenerateIndent();
726 if (stmt->never_continues) {
727 source_out() << "Unreachable();\n";
728 return TypeOracle::GetNeverType();
729 } else {
730 source_out() << "DebugBreak();\n";
731 return TypeOracle::GetVoidType();
732 }
733 }
734
735 namespace {
736
FormatAssertSource(const std::string & str)737 std::string FormatAssertSource(const std::string& str) {
738 // Replace all whitespace characters with a space character.
739 std::string str_no_newlines = str;
740 std::replace_if(str_no_newlines.begin(), str_no_newlines.end(),
741 [](unsigned char c) { return isspace(c); }, ' ');
742
743 // str might include indentation, squash multiple space characters into one.
744 std::string result;
745 std::unique_copy(str_no_newlines.begin(), str_no_newlines.end(),
746 std::back_inserter(result),
747 [](char a, char b) { return a == ' ' && b == ' '; });
748 return result;
749 }
750
751 } // namespace
752
Visit(AssertStatement * stmt)753 const Type* ImplementationVisitor::Visit(AssertStatement* stmt) {
754 bool do_check = !stmt->debug_only;
755 #if defined(DEBUG)
756 do_check = true;
757 #endif
758 if (do_check) {
759 // CSA_ASSERT & co. are not used here on purpose for two reasons. First,
760 // Torque allows and handles two types of expressions in the if protocol
761 // automagically, ones that return TNode<BoolT> and those that use the
762 // BranchIf(..., Label* true, Label* false) idiom. Because the machinery to
763 // handle this is embedded in the expression handling and to it's not
764 // possible to make the decision to use CSA_ASSERT or CSA_ASSERT_BRANCH
765 // isn't trivial up-front. Secondly, on failure, the assert text should be
766 // the corresponding Torque code, not the -gen.cc code, which would be the
767 // case when using CSA_ASSERT_XXX.
768 Label* true_label = nullptr;
769 Label* false_label = nullptr;
770 Declarations::NodeScopeActivator scope(declarations(), stmt->expression);
771 true_label = declarations()->LookupLabel(kTrueLabelName);
772 GenerateLabelDefinition(true_label);
773 false_label = declarations()->LookupLabel(kFalseLabelName);
774 GenerateLabelDefinition(false_label);
775
776 VisitResult expression_result = Visit(stmt->expression);
777 if (expression_result.type() == TypeOracle::GetBoolType()) {
778 GenerateBranch(expression_result, true_label, false_label);
779 } else {
780 if (expression_result.type() != TypeOracle::GetNeverType()) {
781 std::stringstream s;
782 s << "unexpected return type " << *expression_result.type()
783 << " for branch expression";
784 ReportError(s.str());
785 }
786 }
787
788 GenerateLabelBind(false_label);
789 GenerateIndent();
790 source_out() << "Print(\""
791 << "assert '" << FormatAssertSource(stmt->source)
792 << "' failed at " << PositionAsString(stmt->pos) << "\");\n";
793 GenerateIndent();
794 source_out() << "Unreachable();\n";
795
796 GenerateLabelBind(true_label);
797 }
798 return TypeOracle::GetVoidType();
799 }
800
Visit(ExpressionStatement * stmt)801 const Type* ImplementationVisitor::Visit(ExpressionStatement* stmt) {
802 const Type* type = Visit(stmt->expression).type();
803 return type->IsNever() ? type : TypeOracle::GetVoidType();
804 }
805
Visit(ReturnStatement * stmt)806 const Type* ImplementationVisitor::Visit(ReturnStatement* stmt) {
807 Callable* current_callable = global_context_.GetCurrentCallable();
808 if (current_callable->signature().return_type->IsNever()) {
809 std::stringstream s;
810 s << "cannot return from a function with return type never";
811 ReportError(s.str());
812 }
813 Label* end = current_callable->IsMacro()
814 ? declarations()->LookupLabel("macro_end")
815 : nullptr;
816 if (current_callable->HasReturnValue()) {
817 if (!stmt->value) {
818 std::stringstream s;
819 s << "return expression needs to be specified for a return type of "
820 << *current_callable->signature().return_type;
821 ReportError(s.str());
822 }
823 VisitResult expression_result = Visit(*stmt->value);
824 VisitResult return_result = GenerateImplicitConvert(
825 current_callable->signature().return_type, expression_result);
826 if (current_callable->IsMacro()) {
827 Variable* var =
828 Variable::cast(declarations()->LookupValue(kReturnValueVariable));
829 GenerateAssignToVariable(var, return_result);
830 GenerateLabelGoto(end);
831 } else if (current_callable->IsBuiltin()) {
832 if (Builtin::cast(current_callable)->IsVarArgsJavaScript()) {
833 GenerateIndent();
834 source_out() << "arguments->PopAndReturn("
835 << RValueFlattenStructs(return_result) << ");\n";
836 } else {
837 GenerateIndent();
838 source_out() << "Return(" << RValueFlattenStructs(return_result)
839 << ");\n";
840 }
841 } else {
842 UNREACHABLE();
843 }
844 } else {
845 if (stmt->value) {
846 std::stringstream s;
847 s << "return expression can't be specified for a void or never return "
848 "type";
849 ReportError(s.str());
850 }
851 GenerateLabelGoto(end);
852 }
853 current_callable->IncrementReturns();
854 return TypeOracle::GetNeverType();
855 }
856
Visit(ForOfLoopStatement * stmt)857 const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
858 Declarations::NodeScopeActivator scope(declarations(), stmt);
859
860 VisitResult expression_result = Visit(stmt->iterable);
861 VisitResult begin = stmt->begin
862 ? Visit(*stmt->begin)
863 : VisitResult(TypeOracle::GetConstInt31Type(), "0");
864
865 VisitResult end = stmt->end
866 ? Visit(*stmt->end)
867 : GenerateCall(".length", {{expression_result}, {}});
868
869 Label* body_label = declarations()->DeclarePrivateLabel("body");
870 GenerateLabelDefinition(body_label);
871 Label* increment_label = declarations()->DeclarePrivateLabel("increment");
872 GenerateLabelDefinition(increment_label);
873 Label* exit_label = declarations()->DeclarePrivateLabel("exit");
874 GenerateLabelDefinition(exit_label);
875
876 const Type* common_type = GetCommonType(begin.type(), end.type());
877 Variable* index_var = GenerateVariableDeclaration(
878 stmt, std::string(kForIndexValueVariable) + "_" + NewTempVariable(),
879 false, common_type, begin);
880
881 VisitResult index_for_read = {index_var->type(), index_var};
882
883 Label* header_label = declarations()->DeclarePrivateLabel("header");
884 GenerateLabelDefinition(header_label, stmt);
885
886 GenerateLabelGoto(header_label);
887
888 GenerateLabelBind(header_label);
889
890 BreakContinueActivator activator(global_context_, exit_label,
891 increment_label);
892
893 VisitResult result = GenerateCall("<", {{index_for_read, end}, {}});
894 GenerateBranch(result, body_label, exit_label);
895
896 GenerateLabelBind(body_label);
897 VisitResult element_result =
898 GenerateCall("[]", {{expression_result, index_for_read}, {}});
899 base::Optional<const Type*> declared_type;
900 if (stmt->var_declaration->type)
901 declared_type = declarations()->GetType(*stmt->var_declaration->type);
902 GenerateVariableDeclaration(
903 stmt->var_declaration, stmt->var_declaration->name,
904 stmt->var_declaration->const_qualified, declared_type, element_result);
905 Visit(stmt->body);
906 GenerateLabelGoto(increment_label);
907
908 GenerateLabelBind(increment_label);
909 Arguments increment_args;
910 increment_args.parameters = {index_for_read,
911 {TypeOracle::GetConstInt31Type(), "1"}};
912 VisitResult increment_result = GenerateCall("+", increment_args);
913
914 GenerateAssignToVariable(index_var, increment_result);
915
916 GenerateLabelGoto(header_label);
917
918 GenerateLabelBind(exit_label);
919 return TypeOracle::GetVoidType();
920 }
921
Visit(TryLabelStatement * stmt)922 const Type* ImplementationVisitor::Visit(TryLabelStatement* stmt) {
923 ScopedIndent indent(this);
924 Label* try_done = declarations()->DeclarePrivateLabel("try_done");
925 GenerateLabelDefinition(try_done);
926 const Type* try_result = TypeOracle::GetNeverType();
927 std::vector<Label*> labels;
928
929 // Output labels for the goto handlers and for the merge after the try.
930 {
931 // Activate a new scope to see handler labels
932 Declarations::NodeScopeActivator scope(declarations(), stmt);
933 for (LabelBlock* block : stmt->label_blocks) {
934 CurrentSourcePosition::Scope scope(block->pos);
935 Label* label = declarations()->LookupLabel(block->label);
936 labels.push_back(label);
937 GenerateLabelDefinition(label);
938 }
939
940 size_t i = 0;
941 for (auto label : labels) {
942 Declarations::NodeScopeActivator scope(declarations(),
943 stmt->label_blocks[i]->body);
944 for (auto& v : label->GetParameters()) {
945 GenerateVariableDeclaration(stmt, v->name(), false, v->type());
946 v->Define();
947 }
948 ++i;
949 }
950
951 Label* try_begin_label = declarations()->DeclarePrivateLabel("try_begin");
952 GenerateLabelDefinition(try_begin_label);
953 GenerateLabelGoto(try_begin_label);
954
955 // Visit try
956 if (GenerateLabeledStatementBlocks({stmt->try_block},
957 std::vector<Label*>({try_begin_label}),
958 try_done)) {
959 try_result = TypeOracle::GetVoidType();
960 }
961 }
962
963 // Make sure that each label clause is actually used. It's not just a friendly
964 // thing to do, it will cause problems downstream in the compiler if there are
965 // bound labels that are never jumped to.
966 auto label_iterator = stmt->label_blocks.begin();
967 for (auto label : labels) {
968 CurrentSourcePosition::Scope scope((*label_iterator)->pos);
969 if (!label->IsUsed()) {
970 std::stringstream s;
971 s << "label ";
972 s << (*label_iterator)->label;
973 s << " has a handler block but is never referred to in try block";
974 ReportError(s.str());
975 }
976 label_iterator++;
977 }
978
979 // Visit and output the code for each catch block, one-by-one.
980 std::vector<Statement*> bodies;
981 for (LabelBlock* block : stmt->label_blocks) bodies.push_back(block->body);
982 if (GenerateLabeledStatementBlocks(bodies, labels, try_done)) {
983 try_result = TypeOracle::GetVoidType();
984 }
985
986 if (!try_result->IsNever()) {
987 GenerateLabelBind(try_done);
988 }
989 return try_result;
990 }
991
Visit(BreakStatement * stmt)992 const Type* ImplementationVisitor::Visit(BreakStatement* stmt) {
993 Label* break_label = global_context_.GetCurrentBreak();
994 if (break_label == nullptr) {
995 ReportError("break used outside of loop");
996 }
997 GenerateLabelGoto(break_label);
998 return TypeOracle::GetNeverType();
999 }
1000
Visit(ContinueStatement * stmt)1001 const Type* ImplementationVisitor::Visit(ContinueStatement* stmt) {
1002 Label* continue_label = global_context_.GetCurrentContinue();
1003 if (continue_label == nullptr) {
1004 ReportError("continue used outside of loop");
1005 }
1006 GenerateLabelGoto(continue_label);
1007 return TypeOracle::GetNeverType();
1008 }
1009
Visit(ForLoopStatement * stmt)1010 const Type* ImplementationVisitor::Visit(ForLoopStatement* stmt) {
1011 Declarations::NodeScopeActivator scope(declarations(), stmt);
1012
1013 if (stmt->var_declaration) Visit(*stmt->var_declaration);
1014
1015 Label* body_label = declarations()->LookupLabel(kTrueLabelName);
1016 GenerateLabelDefinition(body_label);
1017 Label* exit_label = declarations()->LookupLabel(kFalseLabelName);
1018 GenerateLabelDefinition(exit_label);
1019
1020 Label* header_label = declarations()->DeclarePrivateLabel("header");
1021 GenerateLabelDefinition(header_label, stmt);
1022 GenerateLabelGoto(header_label);
1023 GenerateLabelBind(header_label);
1024
1025 // The continue label is where "continue" statements jump to. If no action
1026 // expression is provided, we jump directly to the header.
1027 Label* continue_label = header_label;
1028
1029 // The action label is only needed when an action expression was provided.
1030 Label* action_label = nullptr;
1031 if (stmt->action) {
1032 action_label = declarations()->DeclarePrivateLabel("action");
1033 GenerateLabelDefinition(action_label);
1034
1035 // The action expression needs to be executed on a continue.
1036 continue_label = action_label;
1037 }
1038
1039 BreakContinueActivator activator(global_context_, exit_label, continue_label);
1040
1041 std::vector<Label*> labels = {body_label, exit_label};
1042 bool generate_action = true;
1043 if (stmt->test) {
1044 generate_action = GenerateExpressionBranch(*stmt->test, labels,
1045 {stmt->body}, continue_label);
1046 } else {
1047 GenerateLabelGoto(body_label);
1048 generate_action =
1049 GenerateLabeledStatementBlocks({stmt->body}, labels, continue_label);
1050 }
1051
1052 if (generate_action && stmt->action) {
1053 ScopedIndent indent(this);
1054 GenerateLabelBind(action_label);
1055 Visit(*stmt->action);
1056 GenerateLabelGoto(header_label);
1057 }
1058
1059 GenerateLabelBind(exit_label);
1060 return TypeOracle::GetVoidType();
1061 }
1062
GenerateImplementation(const std::string & dir,Module * module)1063 void ImplementationVisitor::GenerateImplementation(const std::string& dir,
1064 Module* module) {
1065 std::string new_source(module->source());
1066 std::string base_file_name =
1067 "builtins-" + DashifyString(module->name()) + "-from-dsl-gen";
1068
1069 std::string source_file_name = dir + "/" + base_file_name + ".cc";
1070 ReplaceFileContentsIfDifferent(source_file_name, new_source);
1071 std::string new_header(module->header());
1072 std::string header_file_name = dir + "/" + base_file_name + ".h";
1073 ReplaceFileContentsIfDifferent(header_file_name, new_header);
1074 }
1075
GetBaseAssemblerName(Module * module)1076 std::string ImplementationVisitor::GetBaseAssemblerName(Module* module) {
1077 if (module == global_context_.GetDefaultModule()) {
1078 return "CodeStubAssembler";
1079 } else {
1080 std::string assembler_name(CamelifyString(module->name()) +
1081 "BuiltinsAssembler");
1082 return assembler_name;
1083 }
1084 }
1085
GetDSLAssemblerName(Module * module)1086 std::string ImplementationVisitor::GetDSLAssemblerName(Module* module) {
1087 std::string assembler_name(CamelifyString(module->name()) +
1088 "BuiltinsFromDSLAssembler");
1089 return assembler_name;
1090 }
1091
GenerateIndent()1092 void ImplementationVisitor::GenerateIndent() {
1093 for (size_t i = 0; i <= indent_; ++i) {
1094 source_out() << " ";
1095 }
1096 }
1097
GenerateMacroFunctionDeclaration(std::ostream & o,const std::string & macro_prefix,Macro * macro)1098 void ImplementationVisitor::GenerateMacroFunctionDeclaration(
1099 std::ostream& o, const std::string& macro_prefix, Macro* macro) {
1100 GenerateFunctionDeclaration(o, macro_prefix, macro->name(),
1101 macro->signature(), macro->parameter_names());
1102 }
1103
GenerateFunctionDeclaration(std::ostream & o,const std::string & macro_prefix,const std::string & name,const Signature & signature,const NameVector & parameter_names)1104 void ImplementationVisitor::GenerateFunctionDeclaration(
1105 std::ostream& o, const std::string& macro_prefix, const std::string& name,
1106 const Signature& signature, const NameVector& parameter_names) {
1107 if (global_context_.verbose()) {
1108 std::cout << "generating source for declaration " << name << "\n";
1109 }
1110
1111 // Quite a hack here. Make sure that TNode is namespace qualified if the
1112 // macro/constant name is also qualified.
1113 std::string return_type_name(signature.return_type->GetGeneratedTypeName());
1114 if (const StructType* struct_type =
1115 StructType::DynamicCast(signature.return_type)) {
1116 o << GetDSLAssemblerName(struct_type->module()) << "::";
1117 } else if (macro_prefix != "" && (return_type_name.length() > 5) &&
1118 (return_type_name.substr(0, 5) == "TNode")) {
1119 o << "compiler::";
1120 }
1121 o << return_type_name;
1122 o << " " << macro_prefix << name << "(";
1123
1124 DCHECK_EQ(signature.types().size(), parameter_names.size());
1125 auto type_iterator = signature.types().begin();
1126 bool first = true;
1127 for (const std::string& name : parameter_names) {
1128 if (!first) {
1129 o << ", ";
1130 }
1131 const Value* parameter = declarations()->LookupValue(name);
1132 const Type* parameter_type = *type_iterator;
1133 const std::string& generated_type_name =
1134 parameter_type->GetGeneratedTypeName();
1135 o << generated_type_name << " " << parameter->value();
1136 type_iterator++;
1137 first = false;
1138 }
1139
1140 for (const LabelDeclaration& label_info : signature.labels) {
1141 Label* label = declarations()->LookupLabel(label_info.name);
1142 if (!first) {
1143 o << ", ";
1144 }
1145 o << "Label* " << label->generated();
1146 for (Variable* var : label->GetParameters()) {
1147 std::string generated_type_name("TVariable<");
1148 generated_type_name += var->type()->GetGeneratedTNodeTypeName();
1149 generated_type_name += ">*";
1150 o << ", ";
1151 o << generated_type_name << " " << var->value();
1152 }
1153 }
1154
1155 o << ")";
1156 }
1157
1158 namespace {
1159
PrintMacroSignatures(std::stringstream & s,const std::string & name,const std::vector<Macro * > & macros)1160 void PrintMacroSignatures(std::stringstream& s, const std::string& name,
1161 const std::vector<Macro*>& macros) {
1162 for (Macro* m : macros) {
1163 s << "\n " << name;
1164 PrintSignature(s, m->signature(), false);
1165 }
1166 }
1167
FailMacroLookup(const std::string & reason,const std::string & name,const Arguments & arguments,const std::vector<Macro * > & candidates)1168 void FailMacroLookup(const std::string& reason, const std::string& name,
1169 const Arguments& arguments,
1170 const std::vector<Macro*>& candidates) {
1171 std::stringstream stream;
1172 stream << "\n"
1173 << reason << ": \n " << name << "("
1174 << arguments.parameters.GetTypeVector() << ")";
1175 if (arguments.labels.size() != 0) {
1176 stream << " labels ";
1177 for (auto l : arguments.labels) {
1178 PrintLabel(stream, *l, false);
1179 }
1180 }
1181 stream << "\ncandidates are:";
1182 PrintMacroSignatures(stream, name, candidates);
1183 ReportError(stream.str());
1184 }
1185
1186 } // namespace
1187
LookupCall(const std::string & name,const Arguments & arguments,const TypeVector & specialization_types)1188 Callable* ImplementationVisitor::LookupCall(
1189 const std::string& name, const Arguments& arguments,
1190 const TypeVector& specialization_types) {
1191 Callable* result = nullptr;
1192 TypeVector parameter_types(arguments.parameters.GetTypeVector());
1193 bool has_template_arguments = !specialization_types.empty();
1194 std::string mangled_name = name;
1195 if (has_template_arguments) {
1196 mangled_name = GetGeneratedCallableName(name, specialization_types);
1197 }
1198 Declarable* declarable = declarations()->Lookup(mangled_name);
1199 if (declarable->IsBuiltin()) {
1200 result = Builtin::cast(declarable);
1201 } else if (declarable->IsRuntimeFunction()) {
1202 result = RuntimeFunction::cast(declarable);
1203 } else if (declarable->IsMacroList()) {
1204 std::vector<Macro*> candidates;
1205 std::vector<Macro*> macros_with_same_name;
1206 for (Macro* m : MacroList::cast(declarable)->list()) {
1207 bool try_bool_context =
1208 arguments.labels.size() == 0 &&
1209 m->signature().return_type == TypeOracle::GetNeverType();
1210 Label* true_label = nullptr;
1211 Label* false_label = nullptr;
1212 if (try_bool_context) {
1213 true_label = declarations()->TryLookupLabel(kTrueLabelName);
1214 false_label = declarations()->TryLookupLabel(kFalseLabelName);
1215 }
1216 if (IsCompatibleSignature(m->signature(), parameter_types,
1217 arguments.labels) ||
1218 (true_label && false_label &&
1219 IsCompatibleSignature(m->signature(), parameter_types,
1220 {true_label, false_label}))) {
1221 candidates.push_back(m);
1222 } else {
1223 macros_with_same_name.push_back(m);
1224 }
1225 }
1226
1227 if (candidates.empty() && macros_with_same_name.empty()) {
1228 std::stringstream stream;
1229 stream << "no matching declaration found for " << name;
1230 ReportError(stream.str());
1231 } else if (candidates.empty()) {
1232 FailMacroLookup("cannot find macro with name", name, arguments,
1233 macros_with_same_name);
1234 }
1235
1236 auto is_better_candidate = [&](Macro* a, Macro* b) {
1237 return ParameterDifference(a->signature().parameter_types.types,
1238 parameter_types)
1239 .StrictlyBetterThan(ParameterDifference(
1240 b->signature().parameter_types.types, parameter_types));
1241 };
1242
1243 Macro* best = *std::min_element(candidates.begin(), candidates.end(),
1244 is_better_candidate);
1245 for (Macro* candidate : candidates) {
1246 if (candidate != best && !is_better_candidate(best, candidate)) {
1247 FailMacroLookup("ambiguous macro", name, arguments, candidates);
1248 }
1249 }
1250 result = best;
1251 } else {
1252 std::stringstream stream;
1253 stream << "can't call " << declarable->type_name() << " " << name
1254 << " because it's not callable"
1255 << ": call parameters were (" << parameter_types << ")";
1256 ReportError(stream.str());
1257 }
1258
1259 size_t caller_size = parameter_types.size();
1260 size_t callee_size = result->signature().types().size();
1261 if (caller_size != callee_size &&
1262 !result->signature().parameter_types.var_args) {
1263 std::stringstream stream;
1264 stream << "parameter count mismatch calling " << *result << " - expected "
1265 << std::to_string(callee_size) << ", found "
1266 << std::to_string(caller_size);
1267 ReportError(stream.str());
1268 }
1269
1270 if (has_template_arguments) {
1271 Generic* generic = *result->generic();
1272 CallableNode* callable = generic->declaration()->callable;
1273 if (generic->declaration()->body) {
1274 QueueGenericSpecialization({generic, specialization_types}, callable,
1275 callable->signature.get(),
1276 generic->declaration()->body);
1277 }
1278 }
1279
1280 return result;
1281 }
1282
GetFlattenedStructsVars(const Variable * base,std::set<const Variable * > * vars)1283 void ImplementationVisitor::GetFlattenedStructsVars(
1284 const Variable* base, std::set<const Variable*>* vars) {
1285 const Type* type = base->type();
1286 if (base->IsConst()) return;
1287 if (type->IsStructType()) {
1288 const StructType* struct_type = StructType::cast(type);
1289 for (auto& field : struct_type->fields()) {
1290 std::string field_var_name = base->name() + "." + field.name;
1291 GetFlattenedStructsVars(
1292 Variable::cast(declarations()->LookupValue(field_var_name)), vars);
1293 }
1294 } else {
1295 vars->insert(base);
1296 }
1297 }
1298
GenerateChangedVarsFromControlSplit(AstNode * node)1299 void ImplementationVisitor::GenerateChangedVarsFromControlSplit(AstNode* node) {
1300 const std::set<const Variable*>& changed_vars =
1301 global_context_.GetControlSplitChangedVariables(
1302 node, declarations()->GetCurrentSpecializationTypeNamesVector());
1303 std::set<const Variable*> flattened_vars;
1304 for (auto v : changed_vars) {
1305 GetFlattenedStructsVars(v, &flattened_vars);
1306 }
1307 std::vector<const Variable*> flattened_vars_sorted(flattened_vars.begin(),
1308 flattened_vars.end());
1309 auto compare_variables = [](const Variable* a, const Variable* b) {
1310 return a->value() < b->value();
1311 };
1312 std::sort(flattened_vars_sorted.begin(), flattened_vars_sorted.end(),
1313 compare_variables);
1314 source_out() << "{";
1315 PrintCommaSeparatedList(source_out(), flattened_vars_sorted,
1316 [](const Variable* v) { return v->value(); });
1317 source_out() << "}";
1318 }
1319
GetCommonType(const Type * left,const Type * right)1320 const Type* ImplementationVisitor::GetCommonType(const Type* left,
1321 const Type* right) {
1322 const Type* common_type;
1323 if (IsAssignableFrom(left, right)) {
1324 common_type = left;
1325 } else if (IsAssignableFrom(right, left)) {
1326 common_type = right;
1327 } else {
1328 common_type = TypeOracle::GetUnionType(left, right);
1329 }
1330 common_type = common_type->NonConstexprVersion();
1331 return common_type;
1332 }
1333
GenerateCopy(const VisitResult & to_copy)1334 VisitResult ImplementationVisitor::GenerateCopy(const VisitResult& to_copy) {
1335 std::string temp = GenerateNewTempVariable(to_copy.type());
1336 source_out() << RValueFlattenStructs(to_copy) << ";\n";
1337 GenerateIndent();
1338 source_out() << "USE(" << temp << ");\n";
1339 return VisitResult(to_copy.type(), temp);
1340 }
1341
Visit(StructExpression * decl)1342 VisitResult ImplementationVisitor::Visit(StructExpression* decl) {
1343 const Type* raw_type = declarations()->LookupType(decl->name);
1344 if (!raw_type->IsStructType()) {
1345 std::stringstream s;
1346 s << decl->name << " is not a struct but used like one ";
1347 ReportError(s.str());
1348 }
1349 const StructType* struct_type = StructType::cast(raw_type);
1350 if (struct_type->fields().size() != decl->expressions.size()) {
1351 std::stringstream s;
1352 s << "initializer count mismatch for struct " << decl->name << " (expected "
1353 << struct_type->fields().size() << ", found " << decl->expressions.size()
1354 << ")";
1355 ReportError(s.str());
1356 }
1357 std::vector<VisitResult> expression_results;
1358 for (auto& field : struct_type->fields()) {
1359 VisitResult value = Visit(decl->expressions[expression_results.size()]);
1360 value = GenerateImplicitConvert(field.type, value);
1361 expression_results.push_back(value);
1362 }
1363 std::string result_var_name = GenerateNewTempVariable(struct_type);
1364 source_out() << "{";
1365 PrintCommaSeparatedList(
1366 source_out(), expression_results,
1367 [&](const VisitResult& result) { return RValueFlattenStructs(result); });
1368 source_out() << "};\n";
1369 return VisitResult(struct_type, result_var_name);
1370 }
1371
GetLocationReference(LocationExpression * location)1372 LocationReference ImplementationVisitor::GetLocationReference(
1373 LocationExpression* location) {
1374 switch (location->kind) {
1375 case AstNode::Kind::kIdentifierExpression:
1376 return GetLocationReference(static_cast<IdentifierExpression*>(location));
1377 case AstNode::Kind::kFieldAccessExpression:
1378 return GetLocationReference(
1379 static_cast<FieldAccessExpression*>(location));
1380 case AstNode::Kind::kElementAccessExpression:
1381 return GetLocationReference(
1382 static_cast<ElementAccessExpression*>(location));
1383 default:
1384 UNREACHABLE();
1385 }
1386 }
1387
GetLocationReference(FieldAccessExpression * expr)1388 LocationReference ImplementationVisitor::GetLocationReference(
1389 FieldAccessExpression* expr) {
1390 VisitResult result = Visit(expr->object);
1391 if (result.type()->IsStructType()) {
1392 if (result.declarable()) {
1393 return LocationReference(
1394 declarations()->LookupValue((*result.declarable())->name() + "." +
1395 expr->field),
1396 {}, {});
1397 }
1398 }
1399 return LocationReference(nullptr, result, {});
1400 }
1401
RValueFlattenStructs(VisitResult result)1402 std::string ImplementationVisitor::RValueFlattenStructs(VisitResult result) {
1403 if (result.declarable()) {
1404 const Value* value = *result.declarable();
1405 const Type* type = value->type();
1406 if (const StructType* struct_type = StructType::DynamicCast(type)) {
1407 std::stringstream s;
1408 s << struct_type->name() << "{";
1409 PrintCommaSeparatedList(
1410 s, struct_type->fields(), [&](const NameAndType& field) {
1411 std::string field_declaration = value->name() + "." + field.name;
1412 Variable* field_variable =
1413 Variable::cast(declarations()->LookupValue(field_declaration));
1414 return RValueFlattenStructs(
1415 VisitResult(field_variable->type(), field_variable));
1416 });
1417 s << "}";
1418 return s.str();
1419 }
1420 }
1421 return result.RValue();
1422 }
1423
GenerateFetchFromLocation(LocationExpression * location,LocationReference reference)1424 VisitResult ImplementationVisitor::GenerateFetchFromLocation(
1425 LocationExpression* location, LocationReference reference) {
1426 switch (location->kind) {
1427 case AstNode::Kind::kIdentifierExpression:
1428 return GenerateFetchFromLocation(
1429 static_cast<IdentifierExpression*>(location), reference);
1430 case AstNode::Kind::kFieldAccessExpression:
1431 return GenerateFetchFromLocation(
1432 static_cast<FieldAccessExpression*>(location), reference);
1433 case AstNode::Kind::kElementAccessExpression:
1434 return GenerateFetchFromLocation(
1435 static_cast<ElementAccessExpression*>(location), reference);
1436 default:
1437 UNREACHABLE();
1438 }
1439 }
1440
GenerateFetchFromLocation(FieldAccessExpression * expr,LocationReference reference)1441 VisitResult ImplementationVisitor::GenerateFetchFromLocation(
1442 FieldAccessExpression* expr, LocationReference reference) {
1443 if (reference.value != nullptr) {
1444 return GenerateFetchFromLocation(reference);
1445 }
1446 const Type* type = reference.base.type();
1447 if (const StructType* struct_type = StructType::DynamicCast(type)) {
1448 return VisitResult(struct_type->GetFieldType(expr->field),
1449 reference.base.RValue() + "." + expr->field);
1450 } else {
1451 Arguments arguments;
1452 arguments.parameters = {reference.base};
1453 return GenerateCall(std::string(".") + expr->field, arguments);
1454 }
1455 }
1456
GenerateAssignToVariable(Variable * var,VisitResult value)1457 void ImplementationVisitor::GenerateAssignToVariable(Variable* var,
1458 VisitResult value) {
1459 if (var->type()->IsStructType()) {
1460 if (value.type() != var->type()) {
1461 std::stringstream s;
1462 s << "incompatable assignment from type " << *value.type() << " to "
1463 << *var->type();
1464 ReportError(s.str());
1465 }
1466 const StructType* struct_type = StructType::cast(var->type());
1467 for (auto& field : struct_type->fields()) {
1468 std::string field_declaration = var->name() + "." + field.name;
1469 Variable* field_variable =
1470 Variable::cast(declarations()->LookupValue(field_declaration));
1471 if (value.declarable() && (*value.declarable())->IsVariable()) {
1472 Variable* source_field = Variable::cast(declarations()->LookupValue(
1473 Variable::cast((*value.declarable()))->name() + "." + field.name));
1474 GenerateAssignToVariable(
1475 field_variable, VisitResult{source_field->type(), source_field});
1476 } else {
1477 GenerateAssignToVariable(
1478 field_variable, VisitResult{field_variable->type(),
1479 value.RValue() + "." + field.name});
1480 }
1481 }
1482 } else {
1483 VisitResult casted_value = GenerateImplicitConvert(var->type(), value);
1484 GenerateIndent();
1485 VisitResult var_value = {var->type(), var};
1486 source_out() << var_value.LValue() << " = "
1487 << RValueFlattenStructs(casted_value) << ";\n";
1488 }
1489 var->Define();
1490 }
1491
GenerateAssignToLocation(LocationExpression * location,const LocationReference & reference,VisitResult assignment_value)1492 void ImplementationVisitor::GenerateAssignToLocation(
1493 LocationExpression* location, const LocationReference& reference,
1494 VisitResult assignment_value) {
1495 if (reference.value != nullptr) {
1496 Value* value = reference.value;
1497 Variable* var = Variable::cast(value);
1498 if (var->IsConst()) {
1499 std::stringstream s;
1500 s << "\"" << var->name()
1501 << "\" is declared const (maybe implicitly) and cannot be assigned to";
1502 ReportError(s.str());
1503 }
1504 GenerateAssignToVariable(var, assignment_value);
1505 } else if (auto access = FieldAccessExpression::DynamicCast(location)) {
1506 GenerateCall(std::string(".") + access->field + "=",
1507 {{reference.base, assignment_value}, {}});
1508 } else {
1509 DCHECK_NOT_NULL(ElementAccessExpression::cast(location));
1510 GenerateCall("[]=",
1511 {{reference.base, reference.index, assignment_value}, {}});
1512 }
1513 }
1514
GenerateVariableDeclaration(const Variable * var)1515 void ImplementationVisitor::GenerateVariableDeclaration(const Variable* var) {
1516 const Type* var_type = var->type();
1517 if (var_type->IsStructType()) {
1518 const StructType* struct_type = StructType::cast(var_type);
1519 for (auto& field : struct_type->fields()) {
1520 GenerateVariableDeclaration(Variable::cast(
1521 declarations()->LookupValue(var->name() + "." + field.name)));
1522 }
1523 } else {
1524 std::string value = var->value();
1525 GenerateIndent();
1526 if (var_type->IsConstexpr()) {
1527 source_out() << var_type->GetGeneratedTypeName();
1528 source_out() << " " << value << "_impl;\n";
1529 } else if (var->IsConst()) {
1530 source_out() << "TNode<" << var->type()->GetGeneratedTNodeTypeName();
1531 source_out() << "> " << var->value() << "_impl;\n";
1532 } else {
1533 source_out() << "TVARIABLE(";
1534 source_out() << var_type->GetGeneratedTNodeTypeName();
1535 source_out() << ", " << value << "_impl);\n";
1536 }
1537 GenerateIndent();
1538 source_out() << "auto " << value << " = &" << value << "_impl;\n";
1539 GenerateIndent();
1540 source_out() << "USE(" << value << ");\n";
1541 }
1542 }
1543
GeneratePredeclaredVariableDeclaration(const std::string & name,const base::Optional<VisitResult> & initialization)1544 Variable* ImplementationVisitor::GeneratePredeclaredVariableDeclaration(
1545 const std::string& name,
1546 const base::Optional<VisitResult>& initialization) {
1547 Variable* variable = Variable::cast(declarations()->LookupValue(name));
1548 GenerateVariableDeclaration(variable);
1549 if (initialization) {
1550 GenerateAssignToVariable(variable, *initialization);
1551 }
1552 return variable;
1553 }
1554
GenerateVariableDeclaration(AstNode * node,const std::string & name,bool is_const,const base::Optional<const Type * > & type,const base::Optional<VisitResult> & initialization)1555 Variable* ImplementationVisitor::GenerateVariableDeclaration(
1556 AstNode* node, const std::string& name, bool is_const,
1557 const base::Optional<const Type*>& type,
1558 const base::Optional<VisitResult>& initialization) {
1559 Variable* variable = nullptr;
1560 if (declarations()->IsDeclaredInCurrentScope(name)) {
1561 variable = Variable::cast(declarations()->LookupValue(name));
1562 } else {
1563 variable = declarations()->DeclareVariable(
1564 name, type ? *type : initialization->type(), is_const);
1565 if (!is_const) {
1566 // Because the variable is being defined during code generation, it must
1567 // be assumed that it changes along all control split paths because it's
1568 // no longer possible to run the control-flow anlaysis in the declaration
1569 // pass over the variable.
1570 global_context_.MarkVariableChanged(
1571 node, declarations()->GetCurrentSpecializationTypeNamesVector(),
1572 variable);
1573 }
1574 }
1575 GenerateVariableDeclaration(variable);
1576 if (initialization) {
1577 GenerateAssignToVariable(variable, *initialization);
1578 }
1579 return variable;
1580 }
1581
GenerateParameter(const std::string & parameter_name)1582 void ImplementationVisitor::GenerateParameter(
1583 const std::string& parameter_name) {
1584 const Value* val = declarations()->LookupValue(parameter_name);
1585 std::string var = val->value();
1586 GenerateIndent();
1587 source_out() << val->type()->GetGeneratedTypeName() << " " << var << " = ";
1588
1589 source_out() << "UncheckedCast<" << val->type()->GetGeneratedTNodeTypeName()
1590 << ">(Parameter(Descriptor::k" << CamelifyString(parameter_name)
1591 << "));\n";
1592 GenerateIndent();
1593 source_out() << "USE(" << var << ");\n";
1594 }
1595
GenerateParameterList(const NameVector & list,size_t first)1596 void ImplementationVisitor::GenerateParameterList(const NameVector& list,
1597 size_t first) {
1598 for (auto p : list) {
1599 if (first == 0) {
1600 GenerateParameter(p);
1601 } else {
1602 first--;
1603 }
1604 }
1605 }
1606
GeneratePointerCall(Expression * callee,const Arguments & arguments,bool is_tailcall)1607 VisitResult ImplementationVisitor::GeneratePointerCall(
1608 Expression* callee, const Arguments& arguments, bool is_tailcall) {
1609 TypeVector parameter_types(arguments.parameters.GetTypeVector());
1610 VisitResult callee_result = Visit(callee);
1611 if (!callee_result.type()->IsFunctionPointerType()) {
1612 std::stringstream stream;
1613 stream << "Expected a function pointer type but found "
1614 << *callee_result.type();
1615 ReportError(stream.str());
1616 }
1617 const FunctionPointerType* type =
1618 FunctionPointerType::cast(callee_result.type());
1619
1620 if (type->parameter_types().size() != parameter_types.size()) {
1621 std::stringstream stream;
1622 stream << "parameter count mismatch calling function pointer with Type: "
1623 << *type << " - expected "
1624 << std::to_string(type->parameter_types().size()) << ", found "
1625 << std::to_string(parameter_types.size());
1626 ReportError(stream.str());
1627 }
1628
1629 ParameterTypes types{type->parameter_types(), false};
1630 Signature sig;
1631 sig.parameter_types = types;
1632 if (!IsCompatibleSignature(sig, parameter_types, {})) {
1633 std::stringstream stream;
1634 stream << "parameters do not match function pointer signature. Expected: ("
1635 << type->parameter_types() << ") but got: (" << parameter_types
1636 << ")";
1637 ReportError(stream.str());
1638 }
1639
1640 std::vector<std::string> variables;
1641 for (size_t current = 0; current < arguments.parameters.size(); ++current) {
1642 const Type* to_type = type->parameter_types()[current];
1643 VisitResult result =
1644 GenerateImplicitConvert(to_type, arguments.parameters[current]);
1645 variables.push_back(RValueFlattenStructs(result));
1646 }
1647
1648 std::string result_variable_name;
1649 bool no_result = type->return_type()->IsVoidOrNever() || is_tailcall;
1650 if (no_result) {
1651 GenerateIndent();
1652 } else {
1653 const Type* return_type = type->return_type();
1654 result_variable_name = GenerateNewTempVariable(return_type);
1655 if (return_type->IsStructType()) {
1656 source_out() << "(";
1657 } else {
1658 source_out() << "UncheckedCast<";
1659 source_out() << type->return_type()->GetGeneratedTNodeTypeName();
1660 source_out() << ">(";
1661 }
1662 }
1663
1664 Builtin* example_builtin =
1665 declarations()->FindSomeInternalBuiltinWithType(type);
1666 if (!example_builtin) {
1667 std::stringstream stream;
1668 stream << "unable to find any builtin with type \"" << *type << "\"";
1669 ReportError(stream.str());
1670 }
1671
1672 if (is_tailcall) {
1673 source_out() << "TailCallStub(";
1674 } else {
1675 source_out() << "CallStub(";
1676 }
1677 source_out() << "Builtins::CallableFor(isolate(), Builtins::k"
1678 << example_builtin->name() << ").descriptor(), "
1679 << RValueFlattenStructs(callee_result) << ", ";
1680
1681 size_t total_parameters = 0;
1682 for (size_t i = 0; i < arguments.parameters.size(); ++i) {
1683 if (total_parameters++ != 0) {
1684 source_out() << ", ";
1685 }
1686 source_out() << variables[i];
1687 }
1688 if (!no_result) {
1689 source_out() << ")";
1690 }
1691 source_out() << ");\n";
1692 return VisitResult(type->return_type(), result_variable_name);
1693 }
1694
GenerateCall(const std::string & callable_name,Arguments arguments,const TypeVector & specialization_types,bool is_tailcall)1695 VisitResult ImplementationVisitor::GenerateCall(
1696 const std::string& callable_name, Arguments arguments,
1697 const TypeVector& specialization_types, bool is_tailcall) {
1698 Callable* callable =
1699 LookupCall(callable_name, arguments, specialization_types);
1700
1701 // Operators used in a branching context can also be function calls that never
1702 // return but have a True and False label
1703 if (arguments.labels.size() == 0 &&
1704 callable->signature().labels.size() == 2) {
1705 Label* true_label = declarations()->LookupLabel(kTrueLabelName);
1706 arguments.labels.push_back(true_label);
1707 Label* false_label = declarations()->LookupLabel(kFalseLabelName);
1708 arguments.labels.push_back(false_label);
1709 }
1710
1711 const Type* result_type = callable->signature().return_type;
1712
1713 std::vector<std::string> variables;
1714 for (size_t current = 0; current < arguments.parameters.size(); ++current) {
1715 const Type* to_type = (current >= callable->signature().types().size())
1716 ? TypeOracle::GetObjectType()
1717 : callable->signature().types()[current];
1718 VisitResult result =
1719 GenerateImplicitConvert(to_type, arguments.parameters[current]);
1720 variables.push_back(RValueFlattenStructs(result));
1721 }
1722
1723 std::string result_variable_name;
1724 if (result_type->IsVoidOrNever() || is_tailcall) {
1725 GenerateIndent();
1726 } else {
1727 result_variable_name = GenerateNewTempVariable(result_type);
1728 if (!result_type->IsConstexpr()) {
1729 if (result_type->IsStructType()) {
1730 source_out() << "(";
1731 } else {
1732 source_out() << "UncheckedCast<";
1733 source_out() << result_type->GetGeneratedTNodeTypeName();
1734 source_out() << ">(";
1735 }
1736 }
1737 }
1738 if (callable->IsBuiltin()) {
1739 if (is_tailcall) {
1740 source_out() << "TailCallBuiltin(Builtins::k" << callable->name() << ", ";
1741 } else {
1742 source_out() << "CallBuiltin(Builtins::k" << callable->name() << ", ";
1743 }
1744 } else if (callable->IsMacro()) {
1745 if (is_tailcall) {
1746 std::stringstream stream;
1747 stream << "can't tail call a macro";
1748 ReportError(stream.str());
1749 }
1750 source_out() << callable->name() << "(";
1751 } else if (callable->IsRuntimeFunction()) {
1752 if (is_tailcall) {
1753 source_out() << "TailCallRuntime(Runtime::k" << callable->name() << ", ";
1754 } else {
1755 source_out() << "CallRuntime(Runtime::k" << callable->name() << ", ";
1756 }
1757 } else {
1758 UNREACHABLE();
1759 }
1760 if (global_context_.verbose()) {
1761 std::cout << "generating code for call to " << callable_name << "\n";
1762 }
1763
1764 size_t total_parameters = 0;
1765 for (size_t i = 0; i < arguments.parameters.size(); ++i) {
1766 if (total_parameters++ != 0) {
1767 source_out() << ", ";
1768 }
1769 source_out() << variables[i];
1770 }
1771
1772 size_t label_count = callable->signature().labels.size();
1773 if (label_count != arguments.labels.size()) {
1774 std::stringstream s;
1775 s << "unexpected number of otherwise labels for " << callable->name()
1776 << " (expected " << std::to_string(label_count) << " found "
1777 << std::to_string(arguments.labels.size()) << ")";
1778 ReportError(s.str());
1779 }
1780 for (size_t i = 0; i < label_count; ++i) {
1781 if (total_parameters++ != 0) {
1782 source_out() << ", ";
1783 }
1784 Label* label = arguments.labels[i];
1785 size_t callee_label_parameters =
1786 callable->signature().labels[i].types.size();
1787 if (label->GetParameterCount() != callee_label_parameters) {
1788 std::stringstream s;
1789 s << "label " << label->name()
1790 << " doesn't have the right number of parameters (found "
1791 << std::to_string(label->GetParameterCount()) << " expected "
1792 << std::to_string(callee_label_parameters) << ")";
1793 ReportError(s.str());
1794 }
1795 source_out() << label->generated();
1796 size_t j = 0;
1797 for (auto t : callable->signature().labels[i].types) {
1798 source_out() << ", ";
1799 Variable* variable = label->GetParameter(j);
1800 if (!(variable->type() == t)) {
1801 std::stringstream s;
1802 s << "mismatch of label parameters (expected " << *t << " got "
1803 << *label->GetParameter(j)->type() << " for parameter "
1804 << std::to_string(i + 1) << ")";
1805 ReportError(s.str());
1806 }
1807 j++;
1808 source_out() << variable->value();
1809 }
1810 label->MarkUsed();
1811 }
1812
1813 if (global_context_.verbose()) {
1814 std::cout << "finished generating code for call to " << callable_name
1815 << "\n";
1816 }
1817 if (!result_type->IsVoidOrNever() && !is_tailcall &&
1818 !result_type->IsConstexpr()) {
1819 source_out() << ")";
1820 }
1821 source_out() << ");\n";
1822 return VisitResult(result_type, result_variable_name);
1823 }
1824
Visit(StandardDeclaration * decl)1825 void ImplementationVisitor::Visit(StandardDeclaration* decl) {
1826 Signature signature = MakeSignature(decl->callable->signature.get());
1827 Visit(decl->callable, signature, decl->body);
1828 }
1829
Visit(SpecializationDeclaration * decl)1830 void ImplementationVisitor::Visit(SpecializationDeclaration* decl) {
1831 Signature signature_with_types = MakeSignature(decl->signature.get());
1832 Declarations::NodeScopeActivator specialization_activator(declarations(),
1833 decl);
1834 GenericList* generic_list = declarations()->LookupGeneric(decl->name);
1835 for (Generic* generic : generic_list->list()) {
1836 CallableNode* callable = generic->declaration()->callable;
1837 Signature generic_signature_with_types =
1838 MakeSignature(callable->signature.get());
1839 if (signature_with_types.HasSameTypesAs(generic_signature_with_types)) {
1840 TypeVector specialization_types = GetTypeVector(decl->generic_parameters);
1841 SpecializeGeneric({{generic, specialization_types},
1842 callable,
1843 decl->signature.get(),
1844 decl->body,
1845 decl->pos});
1846 return;
1847 }
1848 }
1849 // Because the DeclarationVisitor already performed the same lookup
1850 // as above to find aspecialization match and already threw if it didn't
1851 // find one, failure to find a match here should never happen.
1852 // TODO(danno): Remember the specialization found in the declaration visitor
1853 // so that the lookup doesn't have to be repeated here.
1854 UNREACHABLE();
1855 }
1856
Visit(CallExpression * expr,bool is_tailcall)1857 VisitResult ImplementationVisitor::Visit(CallExpression* expr,
1858 bool is_tailcall) {
1859 Arguments arguments;
1860 std::string name = expr->callee.name;
1861 TypeVector specialization_types =
1862 GetTypeVector(expr->callee.generic_arguments);
1863 bool has_template_arguments = !specialization_types.empty();
1864 for (Expression* arg : expr->arguments)
1865 arguments.parameters.push_back(Visit(arg));
1866 arguments.labels = LabelsFromIdentifiers(expr->labels);
1867 VisitResult result;
1868 if (!has_template_arguments &&
1869 declarations()->Lookup(expr->callee.name)->IsValue()) {
1870 result = GeneratePointerCall(&expr->callee, arguments, is_tailcall);
1871 } else {
1872 result = GenerateCall(name, arguments, specialization_types, is_tailcall);
1873 }
1874 if (!result.type()->IsVoidOrNever()) {
1875 GenerateIndent();
1876 source_out() << "USE(" << RValueFlattenStructs(result) << ");\n";
1877 }
1878 if (is_tailcall) {
1879 result = {TypeOracle::GetNeverType(), ""};
1880 }
1881 return result;
1882 }
1883
GenerateLabeledStatementBlocks(const std::vector<Statement * > & blocks,const std::vector<Label * > & statement_labels,Label * merge_label)1884 bool ImplementationVisitor::GenerateLabeledStatementBlocks(
1885 const std::vector<Statement*>& blocks,
1886 const std::vector<Label*>& statement_labels, Label* merge_label) {
1887 bool live = false;
1888 auto label_iterator = statement_labels.begin();
1889 for (Statement* block : blocks) {
1890 GenerateIndent();
1891 source_out() << "if (" << (*label_iterator)->generated()
1892 << "->is_used())\n";
1893 ScopedIndent indent(this);
1894
1895 GenerateLabelBind(*label_iterator++);
1896 if (!Visit(block)->IsNever()) {
1897 GenerateLabelGoto(merge_label);
1898 live = true;
1899 }
1900 }
1901 return live;
1902 }
1903
GenerateBranch(const VisitResult & condition,Label * true_label,Label * false_label)1904 void ImplementationVisitor::GenerateBranch(const VisitResult& condition,
1905 Label* true_label,
1906 Label* false_label) {
1907 GenerateIndent();
1908 source_out() << "Branch(" << RValueFlattenStructs(condition) << ", "
1909 << true_label->generated() << ", " << false_label->generated()
1910 << ");\n";
1911 }
1912
GenerateExpressionBranch(Expression * expression,const std::vector<Label * > & statement_labels,const std::vector<Statement * > & statement_blocks,Label * merge_label)1913 bool ImplementationVisitor::GenerateExpressionBranch(
1914 Expression* expression, const std::vector<Label*>& statement_labels,
1915 const std::vector<Statement*>& statement_blocks, Label* merge_label) {
1916 // Activate a new scope to define True/False catch labels
1917 Declarations::NodeScopeActivator scope(declarations(), expression);
1918
1919 VisitResult expression_result = Visit(expression);
1920 if (expression_result.type() == TypeOracle::GetBoolType()) {
1921 GenerateBranch(expression_result, statement_labels[0], statement_labels[1]);
1922 } else {
1923 if (expression_result.type() != TypeOracle::GetNeverType()) {
1924 std::stringstream s;
1925 s << "unexpected return type " << *expression_result.type()
1926 << " for branch expression";
1927 ReportError(s.str());
1928 }
1929 }
1930
1931 return GenerateLabeledStatementBlocks(statement_blocks, statement_labels,
1932 merge_label);
1933 }
1934
GenerateImplicitConvert(const Type * destination_type,VisitResult source)1935 VisitResult ImplementationVisitor::GenerateImplicitConvert(
1936 const Type* destination_type, VisitResult source) {
1937 if (destination_type == source.type()) {
1938 return source;
1939 }
1940
1941 if (TypeOracle::IsImplicitlyConvertableFrom(destination_type,
1942 source.type())) {
1943 std::string name =
1944 GetGeneratedCallableName(kFromConstexprMacroName, {destination_type});
1945 return GenerateCall(name, {{source}, {}}, {}, false);
1946 } else if (IsAssignableFrom(destination_type, source.type())) {
1947 source.SetType(destination_type);
1948 return source;
1949 } else {
1950 std::stringstream s;
1951 s << "cannot use expression of type " << *source.type()
1952 << " as a value of type " << *destination_type;
1953 ReportError(s.str());
1954 }
1955 }
1956
NewTempVariable()1957 std::string ImplementationVisitor::NewTempVariable() {
1958 std::string name("t");
1959 name += std::to_string(next_temp_++);
1960 return name;
1961 }
1962
GenerateNewTempVariable(const Type * type)1963 std::string ImplementationVisitor::GenerateNewTempVariable(const Type* type) {
1964 std::string temp = NewTempVariable();
1965 GenerateIndent();
1966 source_out() << type->GetGeneratedTypeName() << " " << temp << " = ";
1967 return temp;
1968 }
1969
GenerateLabelDefinition(Label * label,AstNode * node)1970 void ImplementationVisitor::GenerateLabelDefinition(Label* label,
1971 AstNode* node) {
1972 std::string label_string = label->generated();
1973 std::string label_string_impl = label_string + "_impl";
1974 GenerateIndent();
1975 source_out() << "Label " + label_string_impl + "(this";
1976 if (node != nullptr) {
1977 source_out() << ", ";
1978 GenerateChangedVarsFromControlSplit(node);
1979 }
1980 source_out() << ");\n";
1981 GenerateIndent();
1982 source_out() << "Label* " + label_string + " = &" << label_string_impl
1983 << ";\n";
1984 GenerateIndent();
1985 source_out() << "USE(" << label_string << ");\n";
1986 }
1987
GenerateLabelBind(Label * label)1988 void ImplementationVisitor::GenerateLabelBind(Label* label) {
1989 GenerateIndent();
1990 source_out() << "BIND(" << label->generated() << ");\n";
1991 }
1992
GenerateLabelGoto(Label * label)1993 void ImplementationVisitor::GenerateLabelGoto(Label* label) {
1994 GenerateIndent();
1995 source_out() << "Goto(" << label->generated() << ");\n";
1996 }
1997
LabelsFromIdentifiers(const std::vector<std::string> & names)1998 std::vector<Label*> ImplementationVisitor::LabelsFromIdentifiers(
1999 const std::vector<std::string>& names) {
2000 std::vector<Label*> result;
2001 for (auto name : names) {
2002 result.push_back(declarations()->LookupLabel(name));
2003 }
2004 return result;
2005 }
2006
2007 } // namespace torque
2008 } // namespace internal
2009 } // namespace v8
2010