Line data Source code
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/csa-generator.h"
8 : #include "src/torque/declaration-visitor.h"
9 : #include "src/torque/implementation-visitor.h"
10 : #include "src/torque/parameter-difference.h"
11 :
12 : namespace v8 {
13 : namespace internal {
14 : namespace torque {
15 :
16 9692 : VisitResult ImplementationVisitor::Visit(Expression* expr) {
17 9692 : CurrentSourcePosition::Scope scope(expr->pos);
18 9692 : switch (expr->kind) {
19 : #define ENUM_ITEM(name) \
20 : case AstNode::Kind::k##name: \
21 : return Visit(name::cast(expr));
22 9557 : AST_EXPRESSION_NODE_KIND_LIST(ENUM_ITEM)
23 : #undef ENUM_ITEM
24 : default:
25 0 : UNREACHABLE();
26 : }
27 : }
28 :
29 3672 : const Type* ImplementationVisitor::Visit(Statement* stmt) {
30 3672 : CurrentSourcePosition::Scope scope(stmt->pos);
31 : StackScope stack_scope(this);
32 : const Type* result;
33 3672 : switch (stmt->kind) {
34 : #define ENUM_ITEM(name) \
35 : case AstNode::Kind::k##name: \
36 : result = Visit(name::cast(stmt)); \
37 : break;
38 3672 : AST_STATEMENT_NODE_KIND_LIST(ENUM_ITEM)
39 : #undef ENUM_ITEM
40 : default:
41 0 : UNREACHABLE();
42 : }
43 : DCHECK_EQ(result == TypeOracle::GetNeverType(),
44 : assembler().CurrentBlockIsComplete());
45 3672 : return result;
46 : }
47 :
48 10 : void ImplementationVisitor::BeginNamespaceFile(Namespace* nspace) {
49 10 : std::ostream& source = nspace->source_stream();
50 10 : std::ostream& header = nspace->header_stream();
51 :
52 150 : for (const std::string& include_path : GlobalContext::CppIncludes()) {
53 390 : source << "#include " << StringLiteralQuote(include_path) << "\n";
54 : }
55 :
56 120 : for (Namespace* n : GlobalContext::Get().GetNamespaces()) {
57 300 : source << "#include \"torque-generated/builtins-" +
58 100 : DashifyString(n->name()) + "-from-dsl-gen.h\"\n";
59 : }
60 10 : source << "\n";
61 :
62 10 : source << "namespace v8 {\n"
63 10 : << "namespace internal {\n"
64 10 : << "\n";
65 :
66 10 : std::string upper_name(nspace->name());
67 : transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
68 10 : ::toupper);
69 : std::string headerDefine =
70 30 : std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";
71 20 : header << "#ifndef " << headerDefine << "\n";
72 20 : header << "#define " << headerDefine << "\n\n";
73 10 : header << "#include \"src/compiler/code-assembler.h\"\n";
74 10 : if (nspace != GlobalContext::GetDefaultNamespace()) {
75 9 : header << "#include \"src/code-stub-assembler.h\"\n";
76 : }
77 10 : header << "\n";
78 :
79 10 : header << "namespace v8 {\n"
80 10 : << "namespace internal {\n"
81 10 : << "\n";
82 :
83 30 : header << "class " << nspace->ExternalName() << " {\n";
84 10 : header << " public:\n";
85 20 : header << " explicit " << nspace->ExternalName()
86 : << "(compiler::CodeAssemblerState* state) : state_(state), ca_(state) "
87 10 : "{ USE(state_, ca_); }\n";
88 10 : }
89 :
90 10 : void ImplementationVisitor::EndNamespaceFile(Namespace* nspace) {
91 10 : std::ostream& source = nspace->source_stream();
92 10 : std::ostream& header = nspace->header_stream();
93 :
94 10 : std::string upper_name(nspace->name());
95 : transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
96 10 : ::toupper);
97 : std::string headerDefine =
98 30 : std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";
99 :
100 10 : source << "} // namespace internal\n"
101 10 : << "} // namespace v8\n"
102 10 : << "\n";
103 :
104 10 : header << " private:\n"
105 10 : << " compiler::CodeAssemblerState* const state_;\n"
106 10 : << " compiler::CodeAssembler ca_;"
107 10 : << "}; \n\n";
108 10 : header << "} // namespace internal\n"
109 10 : << "} // namespace v8\n"
110 10 : << "\n";
111 20 : header << "#endif // " << headerDefine << "\n";
112 10 : }
113 :
114 80 : void ImplementationVisitor::Visit(NamespaceConstant* decl) {
115 200 : Signature signature{{}, base::nullopt, {{}, false}, 0, decl->type(), {}};
116 40 : const std::string& name = decl->name();
117 :
118 : BindingsManagersScope bindings_managers_scope;
119 :
120 40 : header_out() << " ";
121 120 : GenerateFunctionDeclaration(header_out(), "", name, signature, {});
122 40 : header_out() << ";\n";
123 :
124 40 : GenerateFunctionDeclaration(source_out(),
125 120 : CurrentNamespace()->ExternalName() + "::", name,
126 80 : signature, {});
127 40 : source_out() << " {\n";
128 :
129 : DCHECK(!signature.return_type->IsVoidOrNever());
130 :
131 120 : assembler_ = CfgAssembler(Stack<const Type*>{});
132 :
133 40 : VisitResult expression_result = Visit(decl->body());
134 : VisitResult return_result =
135 80 : GenerateImplicitConvert(signature.return_type, expression_result);
136 :
137 40 : CSAGenerator csa_generator{assembler().Result(), source_out()};
138 120 : Stack<std::string> values = *csa_generator.EmitGraph(Stack<std::string>{});
139 :
140 : assembler_ = base::nullopt;
141 :
142 40 : source_out() << "return ";
143 80 : CSAGenerator::EmitCSAValue(return_result, values, source_out());
144 40 : source_out() << ";\n";
145 80 : source_out() << "}\n\n";
146 40 : }
147 :
148 3977 : void ImplementationVisitor::Visit(TypeAlias* alias) {
149 3845 : if (alias->IsRedeclaration()) return;
150 : const StructType* struct_type = StructType::DynamicCast(alias->type());
151 132 : if (!struct_type) return;
152 : const std::string& name = struct_type->name();
153 20 : header_out() << " struct " << name << " {\n";
154 45 : for (auto& field : struct_type->fields()) {
155 75 : header_out() << " " << field.name_and_type.type->GetGeneratedTypeName();
156 50 : header_out() << " " << field.name_and_type.name << ";\n";
157 : }
158 10 : header_out() << "\n std::tuple<";
159 : bool first = true;
160 62 : for (const Type* type : LowerType(struct_type)) {
161 32 : if (!first) {
162 22 : header_out() << ", ";
163 : }
164 : first = false;
165 96 : header_out() << type->GetGeneratedTypeName();
166 : }
167 10 : header_out() << "> Flatten() const {\n"
168 10 : << " return std::tuple_cat(";
169 : first = true;
170 45 : for (auto& field : struct_type->fields()) {
171 25 : if (!first) {
172 15 : header_out() << ", ";
173 : }
174 : first = false;
175 50 : if (field.name_and_type.type->IsStructType()) {
176 8 : header_out() << field.name_and_type.name << ".Flatten()";
177 : } else {
178 42 : header_out() << "std::make_tuple(" << field.name_and_type.name << ")";
179 : }
180 : }
181 10 : header_out() << ");\n";
182 10 : header_out() << " }\n";
183 10 : header_out() << " };\n";
184 : }
185 :
186 452 : VisitResult ImplementationVisitor::InlineMacro(
187 452 : Macro* macro, base::Optional<LocationReference> this_reference,
188 : const std::vector<VisitResult>& arguments,
189 130 : const std::vector<Block*> label_blocks) {
190 452 : CurrentScope::Scope current_scope(macro);
191 : BindingsManagersScope bindings_managers_scope;
192 : CurrentCallable::Scope current_callable(macro);
193 452 : CurrentReturnValue::Scope current_return_value;
194 1230 : const Signature& signature = macro->signature();
195 452 : const Type* return_type = macro->signature().return_type;
196 452 : bool can_return = return_type != TypeOracle::GetNeverType();
197 :
198 : BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
199 : BlockBindings<LocalLabel> label_bindings(&LabelBindingsManager::Get());
200 : DCHECK_EQ(macro->signature().parameter_names.size(),
201 : arguments.size() + (this_reference ? 1 : 0));
202 : DCHECK_EQ(this_reference.has_value(), macro->IsMethod());
203 :
204 : {
205 : size_t i = 0;
206 : // Bind the this for methods. Methods that modify a struct-type "this" must
207 : // only be called if the this is in a variable, in which case the
208 : // LocalValue is non-const. Otherwise, the LocalValue used for the parameter
209 : // binding is const, and thus read-only, which will cause errors if
210 : // modified, e.g. when called by a struct method that sets the structs
211 : // fields. This prevents using temporary struct values for anything other
212 : // than read operations.
213 452 : if (this_reference) {
214 : DCHECK(macro->IsMethod());
215 25 : LocalValue this_value = LocalValue{!this_reference->IsVariableAccess(),
216 50 : this_reference->GetVisitResult()};
217 75 : parameter_bindings.Add(kThisParameterName, this_value);
218 : i++;
219 : }
220 :
221 1904 : for (auto arg : arguments) {
222 1000 : const std::string& name = macro->parameter_names()[i++];
223 3000 : parameter_bindings.Add(name, LocalValue{true, arg});
224 : }
225 : }
226 :
227 : DCHECK_EQ(label_blocks.size(), signature.labels.size());
228 1164 : for (size_t i = 0; i < signature.labels.size(); ++i) {
229 582 : const LabelDeclaration& label_info = signature.labels[i];
230 : label_bindings.Add(label_info.name,
231 780 : LocalLabel{label_blocks[i], label_info.types});
232 : }
233 :
234 : Block* macro_end;
235 452 : base::Optional<Binding<LocalLabel>> macro_end_binding;
236 452 : if (can_return) {
237 : Stack<const Type*> stack = assembler().CurrentStack();
238 432 : std::vector<const Type*> lowered_return_types = LowerType(return_type);
239 432 : stack.PushMany(lowered_return_types);
240 432 : if (!return_type->IsConstexpr()) {
241 : SetReturnValue(VisitResult(return_type,
242 840 : stack.TopRange(lowered_return_types.size())));
243 : }
244 864 : macro_end = assembler().NewBlock(std::move(stack));
245 : macro_end_binding.emplace(&LabelBindingsManager::Get(), "_macro_end",
246 1728 : LocalLabel{macro_end, {return_type}});
247 : } else {
248 40 : SetReturnValue(VisitResult::NeverResult());
249 : }
250 :
251 904 : const Type* result = Visit(*macro->body());
252 :
253 452 : if (result->IsNever()) {
254 672 : if (!return_type->IsNever() && !macro->HasReturns()) {
255 0 : std::stringstream s;
256 0 : s << "macro " << macro->ReadableName()
257 0 : << " that never returns must have return type never";
258 0 : ReportError(s.str());
259 : }
260 : } else {
261 106 : if (return_type->IsNever()) {
262 0 : std::stringstream s;
263 0 : s << "macro " << macro->ReadableName()
264 : << " has implicit return at end of its declartion but return type "
265 0 : "never";
266 0 : ReportError(s.str());
267 106 : } else if (!macro->signature().return_type->IsVoid()) {
268 0 : std::stringstream s;
269 0 : s << "macro " << macro->ReadableName()
270 0 : << " expects to return a value but doesn't on all paths";
271 0 : ReportError(s.str());
272 : }
273 : }
274 452 : if (!result->IsNever()) {
275 106 : assembler().Goto(macro_end);
276 : }
277 :
278 904 : if (macro->HasReturns() || !result->IsNever()) {
279 432 : assembler().Bind(macro_end);
280 : }
281 :
282 452 : return GetAndClearReturnValue();
283 : }
284 :
285 434 : void ImplementationVisitor::VisitMacroCommon(Macro* macro) {
286 : CurrentCallable::Scope current_callable(macro);
287 : const Signature& signature = macro->signature();
288 434 : const Type* return_type = macro->signature().return_type;
289 434 : bool can_return = return_type != TypeOracle::GetNeverType();
290 : bool has_return_value =
291 434 : can_return && return_type != TypeOracle::GetVoidType();
292 :
293 : // Struct methods should never generate code, they should always be inlined
294 : DCHECK(!macro->IsMethod() ||
295 : Method::cast(macro)->aggregate_type()->IsClassType());
296 :
297 434 : header_out() << " ";
298 1302 : GenerateMacroFunctionDeclaration(header_out(), "", macro);
299 434 : header_out() << ";\n";
300 :
301 : GenerateMacroFunctionDeclaration(
302 1736 : source_out(), CurrentNamespace()->ExternalName() + "::", macro);
303 434 : source_out() << " {\n";
304 :
305 : Stack<std::string> lowered_parameters;
306 : Stack<const Type*> lowered_parameter_types;
307 :
308 434 : std::vector<VisitResult> arguments;
309 :
310 : size_t i = 0;
311 434 : base::Optional<LocationReference> this_reference;
312 434 : if (Method* method = Method::DynamicCast(macro)) {
313 : const Type* this_type = method->aggregate_type();
314 : DCHECK(this_type->IsClassType());
315 : lowered_parameter_types.Push(this_type);
316 24 : lowered_parameters.Push(ExternalParameterName(kThisParameterName));
317 : VisitResult this_result =
318 : VisitResult(this_type, lowered_parameters.TopRange(1));
319 : // Mark the this as a temporary to prevent assignment to it.
320 32 : this_reference =
321 : LocationReference::Temporary(this_result, "this parameter");
322 : ++i;
323 : }
324 :
325 2342 : for (; i < macro->signature().parameter_names.size(); ++i) {
326 : const std::string& name = macro->parameter_names()[i];
327 954 : std::string external_name = ExternalParameterName(name);
328 1908 : const Type* type = macro->signature().types()[i];
329 :
330 954 : if (type->IsConstexpr()) {
331 63 : arguments.push_back(VisitResult(type, external_name));
332 : } else {
333 891 : LowerParameter(type, external_name, &lowered_parameters);
334 1782 : StackRange range = lowered_parameter_types.PushMany(LowerType(type));
335 891 : arguments.push_back(VisitResult(type, range));
336 : }
337 : }
338 :
339 : DCHECK_EQ(lowered_parameters.Size(), lowered_parameter_types.Size());
340 1302 : assembler_ = CfgAssembler(lowered_parameter_types);
341 :
342 : std::vector<Block*> label_blocks;
343 997 : for (const LabelDeclaration& label_info : signature.labels) {
344 : Stack<const Type*> label_input_stack;
345 270 : for (const Type* type : label_info.types) {
346 24 : label_input_stack.PushMany(LowerType(type));
347 : }
348 258 : Block* block = assembler().NewBlock(std::move(label_input_stack));
349 129 : label_blocks.push_back(block);
350 : }
351 :
352 : VisitResult return_value =
353 1736 : InlineMacro(macro, this_reference, arguments, label_blocks);
354 868 : Block* end = assembler().NewBlock();
355 434 : if (return_type != TypeOracle::GetNeverType()) {
356 415 : assembler().Goto(end);
357 : }
358 :
359 692 : for (size_t i = 0; i < label_blocks.size(); ++i) {
360 129 : Block* label_block = label_blocks[i];
361 129 : const LabelDeclaration& label_info = signature.labels[i];
362 129 : assembler().Bind(label_block);
363 : std::vector<std::string> label_parameter_variables;
364 282 : for (size_t i = 0; i < label_info.types.size(); ++i) {
365 : label_parameter_variables.push_back(
366 24 : ExternalLabelParameterName(label_info.name, i));
367 : }
368 : assembler().Emit(GotoExternalInstruction{ExternalLabelName(label_info.name),
369 516 : label_parameter_variables});
370 129 : }
371 :
372 434 : if (return_type != TypeOracle::GetNeverType()) {
373 415 : assembler().Bind(end);
374 : }
375 :
376 434 : CSAGenerator csa_generator{assembler().Result(), source_out()};
377 : base::Optional<Stack<std::string>> values =
378 868 : csa_generator.EmitGraph(lowered_parameters);
379 :
380 : assembler_ = base::nullopt;
381 :
382 434 : if (has_return_value) {
383 310 : source_out() << " return ";
384 620 : CSAGenerator::EmitCSAValue(return_value, *values, source_out());
385 310 : source_out() << ";\n";
386 : }
387 434 : source_out() << "}\n\n";
388 434 : }
389 :
390 783 : void ImplementationVisitor::Visit(Macro* macro) {
391 783 : if (macro->IsExternal()) return;
392 : // Do not generate code for inlined macros.
393 427 : if (macro->ShouldBeInlined()) return;
394 426 : VisitMacroCommon(macro);
395 : }
396 :
397 20 : void ImplementationVisitor::Visit(Method* method) {
398 : DCHECK(!method->IsExternal());
399 : // Do not generate code for inlined methods, they have to be inlined in order
400 : // to get reference semantics for the 'this' argument.
401 32 : if (method->ShouldBeInlined()) return;
402 : CurrentConstructorInfo::Scope current_constructor;
403 8 : if (method->IsConstructor())
404 : CurrentConstructorInfo::Get() = ConstructorInfo{0, false};
405 8 : VisitMacroCommon(method);
406 : }
407 :
408 : namespace {
409 :
410 404 : std::string AddParameter(size_t i, Builtin* builtin,
411 : Stack<std::string>* parameters,
412 : Stack<const Type*>* parameter_types,
413 : BlockBindings<LocalValue>* parameter_bindings) {
414 404 : const std::string& name = builtin->signature().parameter_names[i];
415 808 : const Type* type = builtin->signature().types()[i];
416 404 : std::string external_name = "parameter" + std::to_string(i);
417 808 : parameters->Push(external_name);
418 808 : StackRange range = parameter_types->PushMany(LowerType(type));
419 1616 : parameter_bindings->Add(name, LocalValue{true, VisitResult(type, range)});
420 404 : return external_name;
421 : }
422 :
423 : } // namespace
424 :
425 134 : void ImplementationVisitor::Visit(Builtin* builtin) {
426 522 : if (builtin->IsExternal()) return;
427 120 : CurrentScope::Scope current_scope(builtin);
428 120 : const std::string& name = builtin->ExternalName();
429 : const Signature& signature = builtin->signature();
430 240 : source_out() << "TF_BUILTIN(" << name << ", CodeStubAssembler) {\n"
431 120 : << " compiler::CodeAssemblerState* state_ = state();"
432 120 : << " compiler::CodeAssembler ca_(state());\n";
433 :
434 : CurrentCallable::Scope current_callable(builtin);
435 120 : CurrentReturnValue::Scope current_return_value;
436 :
437 : Stack<const Type*> parameter_types;
438 : Stack<std::string> parameters;
439 :
440 : BindingsManagersScope bindings_managers_scope;
441 :
442 : BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
443 :
444 : // Context
445 : std::string parameter0 = AddParameter(0, builtin, ¶meters,
446 120 : ¶meter_types, ¶meter_bindings);
447 120 : source_out() << " TNode<Context> " << parameter0
448 120 : << " = UncheckedCast<Context>(Parameter("
449 120 : << "Descriptor::kContext));\n";
450 240 : source_out() << " USE(" << parameter0 << ");\n";
451 :
452 : size_t first = 1;
453 240 : if (builtin->IsVarArgsJavaScript()) {
454 : DCHECK(signature.parameter_types.var_args);
455 43 : source_out()
456 43 : << " Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);\n";
457 43 : source_out() << " CodeStubArguments arguments_impl(this, "
458 43 : "ChangeInt32ToIntPtr(argc));\n";
459 : std::string parameter1 = AddParameter(
460 43 : 1, builtin, ¶meters, ¶meter_types, ¶meter_bindings);
461 :
462 43 : source_out() << " TNode<Object> " << parameter1
463 43 : << " = arguments_impl.GetReceiver();\n";
464 43 : source_out() << "auto " << CSAGenerator::ARGUMENTS_VARIABLE_STRING
465 43 : << " = &arguments_impl;\n";
466 43 : source_out() << "USE(arguments);\n";
467 86 : source_out() << "USE(" << parameter1 << ");\n";
468 : parameter_bindings.Add(
469 43 : *signature.arguments_variable,
470 : LocalValue{true,
471 215 : VisitResult(TypeOracle::GetArgumentsType(), "arguments")});
472 : first = 2;
473 : }
474 :
475 1048 : for (size_t i = 0; i < signature.parameter_names.size(); ++i) {
476 567 : if (i < first) continue;
477 524 : const std::string& parameter_name = signature.parameter_names[i];
478 482 : const Type* type = signature.types()[i];
479 : std::string var = AddParameter(i, builtin, ¶meters, ¶meter_types,
480 241 : ¶meter_bindings);
481 1205 : source_out() << " " << type->GetGeneratedTypeName() << " " << var << " = "
482 723 : << "UncheckedCast<" << type->GetGeneratedTNodeTypeName()
483 241 : << ">(Parameter(Descriptor::k"
484 723 : << CamelifyString(parameter_name) << "));\n";
485 482 : source_out() << " USE(" << var << ");\n";
486 : }
487 :
488 360 : assembler_ = CfgAssembler(parameter_types);
489 240 : const Type* body_result = Visit(*builtin->body());
490 120 : if (body_result != TypeOracle::GetNeverType()) {
491 0 : ReportError("control reaches end of builtin, expected return of a value");
492 : }
493 120 : CSAGenerator csa_generator{assembler().Result(), source_out(),
494 120 : builtin->kind()};
495 360 : csa_generator.EmitGraph(parameters);
496 : assembler_ = base::nullopt;
497 120 : source_out() << "}\n\n";
498 : }
499 :
500 0 : const Type* ImplementationVisitor::Visit(VarDeclarationStatement* stmt) {
501 : BlockBindings<LocalValue> block_bindings(&ValueBindingsManager::Get());
502 0 : return Visit(stmt, &block_bindings);
503 : }
504 :
505 918 : const Type* ImplementationVisitor::Visit(
506 : VarDeclarationStatement* stmt, BlockBindings<LocalValue>* block_bindings) {
507 1836 : if (!stmt->const_qualified && !stmt->type) {
508 : ReportError(
509 : "variable declaration is missing type. Only 'const' bindings can "
510 0 : "infer the type.");
511 : }
512 : // const qualified variables are required to be initialized properly.
513 1836 : if (stmt->const_qualified && !stmt->initializer) {
514 0 : ReportError("local constant \"", stmt->name, "\" is not initialized.");
515 : }
516 :
517 : base::Optional<const Type*> type;
518 918 : if (stmt->type) {
519 901 : type = Declarations::GetType(*stmt->type);
520 901 : if ((*type)->IsConstexpr() && !stmt->const_qualified) {
521 : ReportError(
522 0 : "cannot declare variable with constexpr type. Use 'const' instead.");
523 : }
524 : }
525 918 : base::Optional<VisitResult> init_result;
526 918 : if (stmt->initializer) {
527 : StackScope scope(this);
528 1790 : init_result = Visit(*stmt->initializer);
529 895 : if (type) {
530 2634 : init_result = GenerateImplicitConvert(*type, *init_result);
531 : }
532 2685 : init_result = scope.Yield(*init_result);
533 : } else {
534 : DCHECK(type.has_value());
535 23 : if ((*type)->IsConstexpr()) {
536 0 : ReportError("constexpr variables need an initializer");
537 : }
538 23 : TypeVector lowered_types = LowerType(*type);
539 72 : for (const Type* type : lowered_types) {
540 26 : assembler().Emit(PushUninitializedInstruction{TypeOracle::GetTopType(
541 156 : "unitialized variable '" + stmt->name + "' of type " +
542 130 : type->ToString() + " originally defined at " +
543 : PositionAsString(stmt->pos),
544 130 : type)});
545 : }
546 46 : init_result =
547 : VisitResult(*type, assembler().TopRange(lowered_types.size()));
548 : }
549 : block_bindings->Add(stmt->name,
550 2754 : LocalValue{stmt->const_qualified, *init_result});
551 1836 : return TypeOracle::GetVoidType();
552 : }
553 :
554 1 : const Type* ImplementationVisitor::Visit(TailCallStatement* stmt) {
555 2 : return Visit(stmt->call, true).type();
556 : }
557 :
558 172 : VisitResult ImplementationVisitor::Visit(ConditionalExpression* expr) {
559 172 : Block* true_block = assembler().NewBlock(assembler().CurrentStack());
560 172 : Block* false_block = assembler().NewBlock(assembler().CurrentStack());
561 172 : Block* done_block = assembler().NewBlock();
562 172 : Block* true_conversion_block = assembler().NewBlock();
563 86 : GenerateExpressionBranch(expr->condition, true_block, false_block);
564 :
565 86 : VisitResult left;
566 86 : VisitResult right;
567 :
568 : {
569 : // The code for both paths of the conditional need to be generated first
570 : // before evaluating the conditional expression because the common type of
571 : // the result of both the true and false of the condition needs to be known
572 : // to convert both branches to a common type.
573 86 : assembler().Bind(true_block);
574 : StackScope left_scope(this);
575 172 : left = Visit(expr->if_true);
576 86 : assembler().Goto(true_conversion_block);
577 :
578 : const Type* common_type;
579 : {
580 86 : assembler().Bind(false_block);
581 : StackScope right_scope(this);
582 172 : right = Visit(expr->if_false);
583 172 : common_type = GetCommonType(left.type(), right.type());
584 344 : right = right_scope.Yield(GenerateImplicitConvert(common_type, right));
585 86 : assembler().Goto(done_block);
586 : }
587 :
588 86 : assembler().Bind(true_conversion_block);
589 344 : left = left_scope.Yield(GenerateImplicitConvert(common_type, left));
590 86 : assembler().Goto(done_block);
591 : }
592 :
593 86 : assembler().Bind(done_block);
594 86 : CHECK_EQ(left, right);
595 86 : return left;
596 : }
597 :
598 21 : VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) {
599 21 : VisitResult left_result;
600 : {
601 42 : Block* false_block = assembler().NewBlock(assembler().CurrentStack());
602 : Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
603 84 : kFalseLabelName, LocalLabel{false_block}};
604 42 : left_result = Visit(expr->left);
605 21 : if (left_result.type()->IsBool()) {
606 14 : Block* true_block = LookupSimpleLabel(kTrueLabelName);
607 7 : assembler().Branch(true_block, false_block);
608 7 : assembler().Bind(false_block);
609 14 : } else if (left_result.type()->IsNever()) {
610 7 : assembler().Bind(false_block);
611 7 : } else if (!left_result.type()->IsConstexprBool()) {
612 : ReportError(
613 : "expected type bool, constexpr bool, or never on left-hand side of "
614 0 : "operator ||");
615 21 : }
616 : }
617 :
618 21 : if (left_result.type()->IsConstexprBool()) {
619 7 : VisitResult right_result = Visit(expr->right);
620 7 : if (!right_result.type()->IsConstexprBool()) {
621 : ReportError(
622 : "expected type constexpr bool on right-hand side of operator "
623 0 : "||");
624 : }
625 : return VisitResult(TypeOracle::GetConstexprBoolType(),
626 28 : std::string("(") + left_result.constexpr_value() +
627 21 : " || " + right_result.constexpr_value() + ")");
628 : }
629 :
630 14 : VisitResult right_result = Visit(expr->right);
631 14 : if (right_result.type()->IsBool()) {
632 18 : Block* true_block = LookupSimpleLabel(kTrueLabelName);
633 18 : Block* false_block = LookupSimpleLabel(kFalseLabelName);
634 9 : assembler().Branch(true_block, false_block);
635 9 : return VisitResult::NeverResult();
636 5 : } else if (!right_result.type()->IsNever()) {
637 : ReportError(
638 0 : "expected type bool or never on right-hand side of operator ||");
639 : }
640 5 : return right_result;
641 : }
642 :
643 24 : VisitResult ImplementationVisitor::Visit(LogicalAndExpression* expr) {
644 24 : VisitResult left_result;
645 : {
646 48 : Block* true_block = assembler().NewBlock(assembler().CurrentStack());
647 : Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
648 96 : kTrueLabelName, LocalLabel{true_block}};
649 48 : left_result = Visit(expr->left);
650 24 : if (left_result.type()->IsBool()) {
651 36 : Block* false_block = LookupSimpleLabel(kFalseLabelName);
652 18 : assembler().Branch(true_block, false_block);
653 18 : assembler().Bind(true_block);
654 6 : } else if (left_result.type()->IsNever()) {
655 6 : assembler().Bind(true_block);
656 0 : } else if (!left_result.type()->IsConstexprBool()) {
657 : ReportError(
658 : "expected type bool, constexpr bool, or never on left-hand side of "
659 0 : "operator &&");
660 24 : }
661 : }
662 :
663 24 : if (left_result.type()->IsConstexprBool()) {
664 0 : VisitResult right_result = Visit(expr->right);
665 0 : if (!right_result.type()->IsConstexprBool()) {
666 : ReportError(
667 : "expected type constexpr bool on right-hand side of operator "
668 0 : "&&");
669 : }
670 : return VisitResult(TypeOracle::GetConstexprBoolType(),
671 0 : std::string("(") + left_result.constexpr_value() +
672 0 : " && " + right_result.constexpr_value() + ")");
673 : }
674 :
675 24 : VisitResult right_result = Visit(expr->right);
676 24 : if (right_result.type()->IsBool()) {
677 38 : Block* true_block = LookupSimpleLabel(kTrueLabelName);
678 38 : Block* false_block = LookupSimpleLabel(kFalseLabelName);
679 19 : assembler().Branch(true_block, false_block);
680 19 : return VisitResult::NeverResult();
681 5 : } else if (!right_result.type()->IsNever()) {
682 : ReportError(
683 0 : "expected type bool or never on right-hand side of operator &&");
684 : }
685 5 : return right_result;
686 : }
687 :
688 118 : VisitResult ImplementationVisitor::Visit(IncrementDecrementExpression* expr) {
689 : StackScope scope(this);
690 236 : LocationReference location_ref = GetLocationReference(expr->location);
691 118 : VisitResult current_value = GenerateFetchFromLocation(location_ref);
692 236 : VisitResult one = {TypeOracle::GetConstInt31Type(), "1"};
693 118 : Arguments args;
694 354 : args.parameters = {current_value, one};
695 : VisitResult assignment_value = GenerateCall(
696 354 : expr->op == IncrementDecrementOperator::kIncrement ? "+" : "-", args);
697 118 : GenerateAssignToLocation(location_ref, assignment_value);
698 354 : return scope.Yield(expr->postfix ? current_value : assignment_value);
699 : }
700 :
701 388 : VisitResult ImplementationVisitor::Visit(AssignmentExpression* expr) {
702 : StackScope scope(this);
703 776 : LocationReference location_ref = GetLocationReference(expr->location);
704 388 : VisitResult assignment_value;
705 388 : if (expr->op) {
706 11 : VisitResult location_value = GenerateFetchFromLocation(location_ref);
707 22 : assignment_value = Visit(expr->value);
708 11 : Arguments args;
709 33 : args.parameters = {location_value, assignment_value};
710 44 : assignment_value = GenerateCall(*expr->op, args);
711 11 : GenerateAssignToLocation(location_ref, assignment_value);
712 : } else {
713 754 : assignment_value = Visit(expr->value);
714 377 : GenerateAssignToLocation(location_ref, assignment_value);
715 : }
716 1164 : return scope.Yield(assignment_value);
717 : }
718 :
719 747 : VisitResult ImplementationVisitor::Visit(NumberLiteralExpression* expr) {
720 : // TODO(tebbi): Do not silently loose precision; support 64bit literals.
721 1494 : double d = std::stod(expr->number.c_str());
722 747 : int32_t i = static_cast<int32_t>(d);
723 1494 : const Type* result_type = Declarations::LookupType(CONST_FLOAT64_TYPE_STRING);
724 747 : if (i == d) {
725 746 : if ((i >> 30) == (i >> 31)) {
726 1488 : result_type = Declarations::LookupType(CONST_INT31_TYPE_STRING);
727 : } else {
728 4 : result_type = Declarations::LookupType(CONST_INT32_TYPE_STRING);
729 : }
730 : }
731 1494 : return VisitResult{result_type, expr->number};
732 : }
733 :
734 58 : VisitResult ImplementationVisitor::Visit(AssumeTypeImpossibleExpression* expr) {
735 29 : VisitResult result = Visit(expr->expression);
736 : const Type* result_type =
737 58 : SubtractType(result.type(), Declarations::GetType(expr->excluded_type));
738 29 : if (result_type->IsNever()) {
739 0 : ReportError("unreachable code");
740 : }
741 116 : CHECK_EQ(LowerType(result_type), TypeVector{result_type});
742 58 : assembler().Emit(UnsafeCastInstruction{result_type});
743 : result.SetType(result_type);
744 29 : return result;
745 : }
746 :
747 38 : VisitResult ImplementationVisitor::Visit(StringLiteralExpression* expr) {
748 : return VisitResult{
749 : TypeOracle::GetConstStringType(),
750 190 : "\"" + expr->literal.substr(1, expr->literal.size() - 2) + "\""};
751 : }
752 :
753 126 : VisitResult ImplementationVisitor::GetBuiltinCode(Builtin* builtin) {
754 126 : if (builtin->IsExternal() || builtin->kind() != Builtin::kStub) {
755 : ReportError(
756 : "creating function pointers is only allowed for internal builtins with "
757 0 : "stub linkage");
758 : }
759 : const Type* type = TypeOracle::GetBuiltinPointerType(
760 : builtin->signature().parameter_types.types,
761 126 : builtin->signature().return_type);
762 63 : assembler().Emit(
763 378 : PushBuiltinPointerInstruction{builtin->ExternalName(), type});
764 63 : return VisitResult(type, assembler().TopRange(1));
765 : }
766 :
767 4934 : VisitResult ImplementationVisitor::Visit(IdentifierExpression* expr) {
768 : StackScope scope(this);
769 14802 : return scope.Yield(GenerateFetchFromLocation(GetLocationReference(expr)));
770 : }
771 :
772 131 : const Type* ImplementationVisitor::Visit(GotoStatement* stmt) {
773 131 : LocalLabel* label = LookupLabel(stmt->label);
774 302 : size_t parameter_count = label->parameter_types.size();
775 262 : if (stmt->arguments.size() != parameter_count) {
776 : ReportError("goto to label has incorrect number of parameters (expected ",
777 0 : parameter_count, " found ", stmt->arguments.size(), ")");
778 : }
779 :
780 : size_t i = 0;
781 : StackRange arguments = assembler().TopRange(0);
782 302 : for (Expression* e : stmt->arguments) {
783 : StackScope scope(this);
784 40 : VisitResult result = Visit(e);
785 80 : const Type* parameter_type = label->parameter_types[i++];
786 120 : result = GenerateImplicitConvert(parameter_type, result);
787 120 : arguments.Extend(scope.Yield(result).stack_range());
788 : }
789 :
790 131 : assembler().Goto(label->block, arguments.Size());
791 131 : return TypeOracle::GetNeverType();
792 : }
793 :
794 391 : const Type* ImplementationVisitor::Visit(IfStatement* stmt) {
795 733 : bool has_else = stmt->if_false.has_value();
796 :
797 391 : if (stmt->is_constexpr) {
798 49 : VisitResult expression_result = Visit(stmt->condition);
799 :
800 49 : if (!(expression_result.type() == TypeOracle::GetConstexprBoolType())) {
801 0 : std::stringstream stream;
802 0 : stream << "expression should return type constexpr bool "
803 0 : << "but returns type " << *expression_result.type();
804 0 : ReportError(stream.str());
805 : }
806 :
807 98 : Block* true_block = assembler().NewBlock();
808 98 : Block* false_block = assembler().NewBlock();
809 98 : Block* done_block = assembler().NewBlock();
810 :
811 : assembler().Emit(ConstexprBranchInstruction{
812 245 : expression_result.constexpr_value(), true_block, false_block});
813 :
814 49 : assembler().Bind(true_block);
815 49 : const Type* left_result = Visit(stmt->if_true);
816 49 : if (left_result == TypeOracle::GetVoidType()) {
817 11 : assembler().Goto(done_block);
818 : }
819 :
820 49 : assembler().Bind(false_block);
821 49 : const Type* right_result = TypeOracle::GetVoidType();
822 49 : if (has_else) {
823 47 : right_result = Visit(*stmt->if_false);
824 : }
825 49 : if (right_result == TypeOracle::GetVoidType()) {
826 11 : assembler().Goto(done_block);
827 : }
828 :
829 49 : if (left_result->IsNever() != right_result->IsNever()) {
830 0 : std::stringstream stream;
831 : stream << "either both or neither branches in a constexpr if statement "
832 0 : "must reach their end at"
833 0 : << PositionAsString(stmt->pos);
834 0 : ReportError(stream.str());
835 : }
836 :
837 49 : if (left_result != TypeOracle::GetNeverType()) {
838 11 : assembler().Bind(done_block);
839 : }
840 : return left_result;
841 : } else {
842 342 : Block* true_block = assembler().NewBlock(assembler().CurrentStack(),
843 1026 : IsDeferred(stmt->if_true));
844 : Block* false_block =
845 : assembler().NewBlock(assembler().CurrentStack(),
846 1026 : stmt->if_false && IsDeferred(*stmt->if_false));
847 342 : GenerateExpressionBranch(stmt->condition, true_block, false_block);
848 :
849 : Block* done_block;
850 : bool live = false;
851 342 : if (has_else) {
852 194 : done_block = assembler().NewBlock();
853 : } else {
854 : done_block = false_block;
855 : live = true;
856 : }
857 :
858 342 : assembler().Bind(true_block);
859 : {
860 342 : const Type* result = Visit(stmt->if_true);
861 342 : if (result == TypeOracle::GetVoidType()) {
862 : live = true;
863 152 : assembler().Goto(done_block);
864 : }
865 : }
866 :
867 342 : if (has_else) {
868 97 : assembler().Bind(false_block);
869 97 : const Type* result = Visit(*stmt->if_false);
870 97 : if (result == TypeOracle::GetVoidType()) {
871 : live = true;
872 81 : assembler().Goto(done_block);
873 : }
874 : }
875 :
876 342 : if (live) {
877 334 : assembler().Bind(done_block);
878 : }
879 342 : return live ? TypeOracle::GetVoidType() : TypeOracle::GetNeverType();
880 : }
881 : }
882 :
883 43 : const Type* ImplementationVisitor::Visit(WhileStatement* stmt) {
884 86 : Block* body_block = assembler().NewBlock(assembler().CurrentStack());
885 86 : Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
886 :
887 86 : Block* header_block = assembler().NewBlock();
888 43 : assembler().Goto(header_block);
889 :
890 43 : assembler().Bind(header_block);
891 43 : GenerateExpressionBranch(stmt->condition, body_block, exit_block);
892 :
893 43 : assembler().Bind(body_block);
894 : {
895 43 : BreakContinueActivator activator{exit_block, header_block};
896 43 : const Type* body_result = Visit(stmt->body);
897 43 : if (body_result != TypeOracle::GetNeverType()) {
898 43 : assembler().Goto(header_block);
899 : }
900 : }
901 :
902 43 : assembler().Bind(exit_block);
903 43 : return TypeOracle::GetVoidType();
904 : }
905 :
906 1226 : const Type* ImplementationVisitor::Visit(BlockStatement* block) {
907 : BlockBindings<LocalValue> block_bindings(&ValueBindingsManager::Get());
908 1226 : const Type* type = TypeOracle::GetVoidType();
909 5497 : for (Statement* s : block->statements) {
910 3045 : CurrentSourcePosition::Scope source_position(s->pos);
911 3045 : if (type->IsNever()) {
912 0 : ReportError("statement after non-returning statement");
913 : }
914 3045 : if (auto* var_declaration = VarDeclarationStatement::DynamicCast(s)) {
915 900 : type = Visit(var_declaration, &block_bindings);
916 : } else {
917 2145 : type = Visit(s);
918 : }
919 : }
920 1226 : return type;
921 : }
922 :
923 67 : const Type* ImplementationVisitor::Visit(DebugStatement* stmt) {
924 : #if defined(DEBUG)
925 : assembler().Emit(PrintConstantStringInstruction{"halting because of '" +
926 : stmt->reason + "' at " +
927 : PositionAsString(stmt->pos)});
928 : #endif
929 67 : assembler().Emit(AbortInstruction{stmt->never_continues
930 : ? AbortInstruction::Kind::kUnreachable
931 402 : : AbortInstruction::Kind::kDebugBreak});
932 67 : if (stmt->never_continues) {
933 67 : return TypeOracle::GetNeverType();
934 : } else {
935 0 : return TypeOracle::GetVoidType();
936 : }
937 : }
938 :
939 : namespace {
940 :
941 106 : std::string FormatAssertSource(const std::string& str) {
942 : // Replace all whitespace characters with a space character.
943 106 : std::string str_no_newlines = str;
944 : std::replace_if(str_no_newlines.begin(), str_no_newlines.end(),
945 3477 : [](unsigned char c) { return isspace(c); }, ' ');
946 :
947 : // str might include indentation, squash multiple space characters into one.
948 : std::string result;
949 : std::unique_copy(str_no_newlines.begin(), str_no_newlines.end(),
950 : std::back_inserter(result),
951 3265 : [](char a, char b) { return a == ' ' && b == ' '; });
952 106 : return result;
953 : }
954 :
955 : } // namespace
956 :
957 237 : const Type* ImplementationVisitor::Visit(AssertStatement* stmt) {
958 237 : bool do_check = !stmt->debug_only;
959 : #if defined(DEBUG)
960 : do_check = true;
961 : #endif
962 237 : if (do_check) {
963 : // CSA_ASSERT & co. are not used here on purpose for two reasons. First,
964 : // Torque allows and handles two types of expressions in the if protocol
965 : // automagically, ones that return TNode<BoolT> and those that use the
966 : // BranchIf(..., Label* true, Label* false) idiom. Because the machinery to
967 : // handle this is embedded in the expression handling and to it's not
968 : // possible to make the decision to use CSA_ASSERT or CSA_ASSERT_BRANCH
969 : // isn't trivial up-front. Secondly, on failure, the assert text should be
970 : // the corresponding Torque code, not the -gen.cc code, which would be the
971 : // case when using CSA_ASSERT_XXX.
972 212 : Block* true_block = assembler().NewBlock(assembler().CurrentStack());
973 212 : Block* false_block = assembler().NewBlock(assembler().CurrentStack(), true);
974 106 : GenerateExpressionBranch(stmt->expression, true_block, false_block);
975 :
976 106 : assembler().Bind(false_block);
977 :
978 : assembler().Emit(AbortInstruction{
979 : AbortInstruction::Kind::kAssertionFailure,
980 742 : "Torque assert '" + FormatAssertSource(stmt->source) + "' failed"});
981 :
982 106 : assembler().Bind(true_block);
983 : }
984 237 : return TypeOracle::GetVoidType();
985 : }
986 :
987 935 : const Type* ImplementationVisitor::Visit(ExpressionStatement* stmt) {
988 1870 : const Type* type = Visit(stmt->expression).type();
989 935 : return type->IsNever() ? type : TypeOracle::GetVoidType();
990 : }
991 :
992 574 : const Type* ImplementationVisitor::Visit(ReturnStatement* stmt) {
993 1148 : Callable* current_callable = CurrentCallable::Get();
994 574 : if (current_callable->signature().return_type->IsNever()) {
995 0 : std::stringstream s;
996 0 : s << "cannot return from a function with return type never";
997 0 : ReportError(s.str());
998 : }
999 : LocalLabel* end =
1000 985 : current_callable->IsMacro() ? LookupLabel("_macro_end") : nullptr;
1001 574 : if (current_callable->HasReturnValue()) {
1002 574 : if (!stmt->value) {
1003 0 : std::stringstream s;
1004 0 : s << "return expression needs to be specified for a return type of "
1005 0 : << *current_callable->signature().return_type;
1006 0 : ReportError(s.str());
1007 : }
1008 572 : VisitResult expression_result = Visit(*stmt->value);
1009 : VisitResult return_result = GenerateImplicitConvert(
1010 1144 : current_callable->signature().return_type, expression_result);
1011 572 : if (current_callable->IsMacro()) {
1012 409 : if (return_result.IsOnStack()) {
1013 : StackRange return_value_range =
1014 : GenerateLabelGoto(end, return_result.stack_range());
1015 794 : SetReturnValue(VisitResult(return_result.type(), return_value_range));
1016 : } else {
1017 : GenerateLabelGoto(end);
1018 24 : SetReturnValue(return_result);
1019 : }
1020 163 : } else if (current_callable->IsBuiltin()) {
1021 652 : assembler().Emit(ReturnInstruction{});
1022 : } else {
1023 0 : UNREACHABLE();
1024 : }
1025 : } else {
1026 2 : if (stmt->value) {
1027 0 : std::stringstream s;
1028 : s << "return expression can't be specified for a void or never return "
1029 0 : "type";
1030 0 : ReportError(s.str());
1031 : }
1032 : GenerateLabelGoto(end);
1033 : }
1034 : current_callable->IncrementReturns();
1035 574 : return TypeOracle::GetNeverType();
1036 : }
1037 :
1038 4 : const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
1039 4 : VisitResult expression_result = Visit(stmt->iterable);
1040 : VisitResult begin = stmt->begin
1041 : ? Visit(*stmt->begin)
1042 8 : : VisitResult(TypeOracle::GetConstInt31Type(), "0");
1043 :
1044 : VisitResult end = stmt->end
1045 : ? Visit(*stmt->end)
1046 24 : : GenerateCall(".length", {{expression_result}, {}});
1047 :
1048 4 : const Type* common_type = GetCommonType(begin.type(), end.type());
1049 8 : VisitResult index = GenerateImplicitConvert(common_type, begin);
1050 :
1051 8 : Block* body_block = assembler().NewBlock();
1052 8 : Block* increment_block = assembler().NewBlock(assembler().CurrentStack());
1053 8 : Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
1054 :
1055 8 : Block* header_block = assembler().NewBlock();
1056 :
1057 4 : assembler().Goto(header_block);
1058 :
1059 4 : assembler().Bind(header_block);
1060 :
1061 4 : BreakContinueActivator activator(exit_block, increment_block);
1062 :
1063 : {
1064 : StackScope comparison_scope(this);
1065 20 : VisitResult result = GenerateCall("<", {{index, end}, {}});
1066 4 : if (result.type() != TypeOracle::GetBoolType()) {
1067 0 : ReportError("operator < with arguments(", *index.type(), ", ",
1068 0 : *end.type(),
1069 : ") used in for-of loop has to return type bool, but "
1070 : "returned type ",
1071 0 : *result.type());
1072 : }
1073 12 : comparison_scope.Yield(result);
1074 : }
1075 4 : assembler().Branch(body_block, exit_block);
1076 :
1077 4 : assembler().Bind(body_block);
1078 : {
1079 4 : VisitResult element_result;
1080 : {
1081 : StackScope element_scope(this);
1082 20 : VisitResult result = GenerateCall("[]", {{expression_result, index}, {}});
1083 4 : if (stmt->var_declaration->type) {
1084 : const Type* declared_type =
1085 4 : Declarations::GetType(*stmt->var_declaration->type);
1086 12 : result = GenerateImplicitConvert(declared_type, result);
1087 : }
1088 12 : element_result = element_scope.Yield(result);
1089 : }
1090 : Binding<LocalValue> element_var_binding{&ValueBindingsManager::Get(),
1091 : stmt->var_declaration->name,
1092 16 : LocalValue{true, element_result}};
1093 4 : Visit(stmt->body);
1094 : }
1095 4 : assembler().Goto(increment_block);
1096 :
1097 4 : assembler().Bind(increment_block);
1098 : {
1099 : Arguments increment_args;
1100 16 : increment_args.parameters = {index, {TypeOracle::GetConstInt31Type(), "1"}};
1101 12 : VisitResult increment_result = GenerateCall("+", increment_args);
1102 :
1103 : GenerateAssignToLocation(LocationReference::VariableAccess(index),
1104 16 : increment_result);
1105 : }
1106 :
1107 4 : assembler().Goto(header_block);
1108 :
1109 4 : assembler().Bind(exit_block);
1110 8 : return TypeOracle::GetVoidType();
1111 : }
1112 :
1113 768 : VisitResult ImplementationVisitor::Visit(TryLabelExpression* expr) {
1114 197 : size_t parameter_count = expr->label_block->parameters.names.size();
1115 : std::vector<VisitResult> parameters;
1116 :
1117 : Block* label_block = nullptr;
1118 362 : Block* done_block = assembler().NewBlock();
1119 181 : VisitResult try_result;
1120 :
1121 : {
1122 181 : CurrentSourcePosition::Scope source_position(expr->label_block->pos);
1123 181 : if (expr->label_block->parameters.has_varargs) {
1124 0 : ReportError("cannot use ... for label parameters");
1125 : }
1126 : Stack<const Type*> label_input_stack = assembler().CurrentStack();
1127 : TypeVector parameter_types;
1128 197 : for (size_t i = 0; i < parameter_count; ++i) {
1129 : const Type* type =
1130 32 : Declarations::GetType(expr->label_block->parameters.types[i]);
1131 16 : parameter_types.push_back(type);
1132 16 : if (type->IsConstexpr()) {
1133 0 : ReportError("no constexpr type allowed for label arguments");
1134 : }
1135 32 : StackRange range = label_input_stack.PushMany(LowerType(type));
1136 32 : parameters.push_back(VisitResult(type, range));
1137 : }
1138 : label_block = assembler().NewBlock(label_input_stack,
1139 543 : IsDeferred(expr->label_block->body));
1140 :
1141 : Binding<LocalLabel> label_binding{&LabelBindingsManager::Get(),
1142 : expr->label_block->label,
1143 1086 : LocalLabel{label_block, parameter_types}};
1144 :
1145 : // Visit try
1146 : StackScope stack_scope(this);
1147 362 : try_result = Visit(expr->try_expression);
1148 181 : if (try_result.type() != TypeOracle::GetNeverType()) {
1149 255 : try_result = stack_scope.Yield(try_result);
1150 85 : assembler().Goto(done_block);
1151 : }
1152 : }
1153 :
1154 : // Visit and output the code for the label block. If the label block falls
1155 : // through, then the try must not return a value. Also, if the try doesn't
1156 : // fall through, but the label does, then overall the try-label block
1157 : // returns type void.
1158 181 : assembler().Bind(label_block);
1159 : const Type* label_result;
1160 : {
1161 : BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
1162 197 : for (size_t i = 0; i < parameter_count; ++i) {
1163 16 : parameter_bindings.Add(expr->label_block->parameters.names[i],
1164 80 : LocalValue{true, parameters[i]});
1165 : }
1166 :
1167 181 : label_result = Visit(expr->label_block->body);
1168 : }
1169 181 : if (!try_result.type()->IsVoidOrNever() && label_result->IsVoid()) {
1170 : ReportError(
1171 0 : "otherwise clauses cannot fall through in a non-void expression");
1172 : }
1173 181 : if (label_result != TypeOracle::GetNeverType()) {
1174 44 : assembler().Goto(done_block);
1175 : }
1176 225 : if (label_result->IsVoid() && try_result.type()->IsNever()) {
1177 22 : try_result =
1178 11 : VisitResult(TypeOracle::GetVoidType(), try_result.stack_range());
1179 : }
1180 :
1181 181 : if (!try_result.type()->IsNever()) {
1182 96 : assembler().Bind(done_block);
1183 : }
1184 181 : return try_result;
1185 : }
1186 :
1187 0 : VisitResult ImplementationVisitor::Visit(StatementExpression* expr) {
1188 135 : return VisitResult{Visit(expr->statement), assembler().TopRange(0)};
1189 : }
1190 :
1191 1 : VisitResult ImplementationVisitor::Visit(NewExpression* expr) {
1192 : StackScope stack_scope(this);
1193 1 : const Type* type = Declarations::GetType(expr->type);
1194 1 : const ClassType* class_type = ClassType::DynamicCast(type);
1195 1 : if (class_type == nullptr) {
1196 : ReportError("type for new expression must be a class, \"", *type,
1197 0 : "\" is not");
1198 : }
1199 1 : Arguments allocate_arguments;
1200 : allocate_arguments.parameters.push_back(VisitResult(
1201 3 : TypeOracle::GetConstInt31Type(), std::to_string(class_type->size())));
1202 : VisitResult allocate_result =
1203 4 : GenerateCall("%Allocate", allocate_arguments, {class_type}, false);
1204 1 : Arguments constructor_arguments;
1205 2 : for (auto p : expr->parameters) {
1206 0 : constructor_arguments.parameters.push_back(Visit(p));
1207 : }
1208 : Callable* callable =
1209 : LookupCall({{}, kConstructMethodName}, class_type->Constructors(),
1210 5 : constructor_arguments, {});
1211 : return stack_scope.Yield(
1212 : GenerateCall(callable,
1213 : LocationReference::Temporary(allocate_result,
1214 : "unitialized object from new"),
1215 9 : constructor_arguments, {class_type}, false));
1216 : }
1217 :
1218 21 : const Type* ImplementationVisitor::Visit(BreakStatement* stmt) {
1219 42 : base::Optional<Binding<LocalLabel>*> break_label = TryLookupLabel("_break");
1220 21 : if (!break_label) {
1221 0 : ReportError("break used outside of loop");
1222 : }
1223 21 : assembler().Goto((*break_label)->block);
1224 21 : return TypeOracle::GetNeverType();
1225 : }
1226 :
1227 11 : const Type* ImplementationVisitor::Visit(ContinueStatement* stmt) {
1228 : base::Optional<Binding<LocalLabel>*> continue_label =
1229 22 : TryLookupLabel("_continue");
1230 11 : if (!continue_label) {
1231 0 : ReportError("continue used outside of loop");
1232 : }
1233 11 : assembler().Goto((*continue_label)->block);
1234 11 : return TypeOracle::GetNeverType();
1235 : }
1236 :
1237 31 : const Type* ImplementationVisitor::Visit(ForLoopStatement* stmt) {
1238 : BlockBindings<LocalValue> loop_bindings(&ValueBindingsManager::Get());
1239 :
1240 31 : if (stmt->var_declaration) Visit(*stmt->var_declaration, &loop_bindings);
1241 :
1242 62 : Block* body_block = assembler().NewBlock(assembler().CurrentStack());
1243 62 : Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
1244 :
1245 62 : Block* header_block = assembler().NewBlock();
1246 31 : assembler().Goto(header_block);
1247 31 : assembler().Bind(header_block);
1248 :
1249 : // The continue label is where "continue" statements jump to. If no action
1250 : // expression is provided, we jump directly to the header.
1251 : Block* continue_block = header_block;
1252 :
1253 : // The action label is only needed when an action expression was provided.
1254 : Block* action_block = nullptr;
1255 62 : if (stmt->action) {
1256 52 : action_block = assembler().NewBlock();
1257 :
1258 : // The action expression needs to be executed on a continue.
1259 : continue_block = action_block;
1260 : }
1261 :
1262 31 : if (stmt->test) {
1263 26 : GenerateExpressionBranch(*stmt->test, body_block, exit_block);
1264 : } else {
1265 5 : assembler().Goto(body_block);
1266 : }
1267 :
1268 31 : assembler().Bind(body_block);
1269 : {
1270 31 : BreakContinueActivator activator(exit_block, continue_block);
1271 31 : const Type* body_result = Visit(stmt->body);
1272 31 : if (body_result != TypeOracle::GetNeverType()) {
1273 31 : assembler().Goto(continue_block);
1274 : }
1275 : }
1276 :
1277 31 : if (stmt->action) {
1278 26 : assembler().Bind(action_block);
1279 26 : const Type* action_result = Visit(*stmt->action);
1280 26 : if (action_result != TypeOracle::GetNeverType()) {
1281 26 : assembler().Goto(header_block);
1282 : }
1283 : }
1284 :
1285 31 : assembler().Bind(exit_block);
1286 62 : return TypeOracle::GetVoidType();
1287 : }
1288 :
1289 10 : void ImplementationVisitor::GenerateImplementation(const std::string& dir,
1290 : Namespace* nspace) {
1291 : std::string new_source(nspace->source());
1292 : std::string base_file_name =
1293 30 : "builtins-" + DashifyString(nspace->name()) + "-from-dsl-gen";
1294 :
1295 20 : std::string source_file_name = dir + "/" + base_file_name + ".cc";
1296 10 : ReplaceFileContentsIfDifferent(source_file_name, new_source);
1297 : std::string new_header(nspace->header());
1298 20 : std::string header_file_name = dir + "/" + base_file_name + ".h";
1299 10 : ReplaceFileContentsIfDifferent(header_file_name, new_header);
1300 10 : }
1301 :
1302 0 : void ImplementationVisitor::GenerateMacroFunctionDeclaration(
1303 : std::ostream& o, const std::string& macro_prefix, Macro* macro) {
1304 434 : GenerateFunctionDeclaration(o, macro_prefix, macro->ExternalName(),
1305 1302 : macro->signature(), macro->parameter_names());
1306 0 : }
1307 :
1308 948 : void ImplementationVisitor::GenerateFunctionDeclaration(
1309 : std::ostream& o, const std::string& macro_prefix, const std::string& name,
1310 : const Signature& signature, const NameVector& parameter_names) {
1311 948 : if (GlobalContext::verbose()) {
1312 0 : std::cout << "generating source for declaration " << name << "\n";
1313 : }
1314 :
1315 948 : if (signature.return_type->IsVoidOrNever()) {
1316 248 : o << "void";
1317 : } else {
1318 1400 : o << signature.return_type->GetGeneratedTypeName();
1319 : }
1320 1896 : o << " " << macro_prefix << name << "(";
1321 :
1322 : DCHECK_EQ(signature.types().size(), parameter_names.size());
1323 948 : auto type_iterator = signature.types().begin();
1324 : bool first = true;
1325 3820 : for (const std::string& name : parameter_names) {
1326 1924 : if (!first) {
1327 1124 : o << ", ";
1328 : }
1329 1924 : const Type* parameter_type = *type_iterator;
1330 : const std::string& generated_type_name =
1331 1924 : parameter_type->GetGeneratedTypeName();
1332 5772 : o << generated_type_name << " " << ExternalParameterName(name);
1333 : type_iterator++;
1334 : first = false;
1335 : }
1336 :
1337 2154 : for (const LabelDeclaration& label_info : signature.labels) {
1338 258 : if (!first) {
1339 252 : o << ", ";
1340 : }
1341 774 : o << "compiler::CodeAssemblerLabel* " << ExternalLabelName(label_info.name);
1342 : size_t i = 0;
1343 540 : for (const Type* type : label_info.types) {
1344 24 : std::string generated_type_name("compiler::TypedCodeAssemblerVariable<");
1345 48 : generated_type_name += type->GetGeneratedTNodeTypeName();
1346 : generated_type_name += ">*";
1347 24 : o << ", ";
1348 24 : o << generated_type_name << " "
1349 48 : << ExternalLabelParameterName(label_info.name, i);
1350 24 : ++i;
1351 : }
1352 : }
1353 :
1354 948 : o << ")";
1355 948 : }
1356 :
1357 : namespace {
1358 :
1359 0 : void FailCallableLookup(const std::string& reason, const QualifiedName& name,
1360 : const Arguments& arguments,
1361 : const std::vector<Signature>& candidates) {
1362 0 : std::stringstream stream;
1363 0 : stream << "\n"
1364 0 : << reason << ": \n " << name << "("
1365 0 : << arguments.parameters.GetTypeVector() << ")";
1366 0 : if (arguments.labels.size() != 0) {
1367 0 : stream << " labels ";
1368 0 : for (size_t i = 0; i < arguments.labels.size(); ++i) {
1369 0 : stream << arguments.labels[i]->name() << "("
1370 0 : << arguments.labels[i]->parameter_types << ")";
1371 : }
1372 : }
1373 0 : stream << "\ncandidates are:";
1374 0 : for (const Signature& signature : candidates) {
1375 0 : stream << "\n " << name;
1376 0 : PrintSignature(stream, signature, false);
1377 : }
1378 0 : ReportError(stream.str());
1379 : }
1380 :
1381 1698 : Callable* GetOrCreateSpecialization(const SpecializationKey& key) {
1382 1698 : if (base::Optional<Callable*> specialization =
1383 1698 : key.generic->GetSpecialization(key.specialized_types)) {
1384 1527 : return *specialization;
1385 : }
1386 171 : return DeclarationVisitor().SpecializeImplicit(key);
1387 : }
1388 :
1389 : } // namespace
1390 :
1391 0 : base::Optional<Binding<LocalValue>*> ImplementationVisitor::TryLookupLocalValue(
1392 : const std::string& name) {
1393 8125 : return ValueBindingsManager::Get().TryLookup(name);
1394 : }
1395 :
1396 0 : base::Optional<Binding<LocalLabel>*> ImplementationVisitor::TryLookupLabel(
1397 : const std::string& name) {
1398 5910 : return LabelBindingsManager::Get().TryLookup(name);
1399 : }
1400 :
1401 1090 : Binding<LocalLabel>* ImplementationVisitor::LookupLabel(
1402 : const std::string& name) {
1403 : base::Optional<Binding<LocalLabel>*> label = TryLookupLabel(name);
1404 1090 : if (!label) ReportError("cannot find label ", name);
1405 1090 : return *label;
1406 : }
1407 :
1408 81 : Block* ImplementationVisitor::LookupSimpleLabel(const std::string& name) {
1409 81 : LocalLabel* label = LookupLabel(name);
1410 81 : if (!label->parameter_types.empty()) {
1411 : ReportError("label ", name,
1412 : "was expected to have no parameters, but has parameters (",
1413 0 : label->parameter_types, ")");
1414 : }
1415 81 : return label->block;
1416 : }
1417 :
1418 : template <class Container>
1419 4230 : Callable* ImplementationVisitor::LookupCall(
1420 : const QualifiedName& name, const Container& declaration_container,
1421 : const Arguments& arguments, const TypeVector& specialization_types) {
1422 : Callable* result = nullptr;
1423 4230 : TypeVector parameter_types(arguments.parameters.GetTypeVector());
1424 :
1425 : std::vector<Declarable*> overloads;
1426 4230 : std::vector<Signature> overload_signatures;
1427 22346 : for (auto* declarable : declaration_container) {
1428 13886 : if (Generic* generic = Generic::DynamicCast(declarable)) {
1429 : base::Optional<TypeVector> inferred_specialization_types =
1430 : generic->InferSpecializationTypes(specialization_types,
1431 1849 : parameter_types);
1432 1849 : if (!inferred_specialization_types) continue;
1433 3698 : overloads.push_back(generic);
1434 : overload_signatures.push_back(
1435 : DeclarationVisitor().MakeSpecializedSignature(
1436 5547 : SpecializationKey{generic, *inferred_specialization_types}));
1437 12037 : } else if (Callable* callable = Callable::DynamicCast(declarable)) {
1438 24074 : overloads.push_back(callable);
1439 12037 : overload_signatures.push_back(callable->signature());
1440 : }
1441 : }
1442 : // Indices of candidates in overloads/overload_signatures.
1443 : std::vector<size_t> candidates;
1444 36232 : for (size_t i = 0; i < overloads.size(); ++i) {
1445 13886 : const Signature& signature = overload_signatures[i];
1446 13886 : bool try_bool_context = arguments.labels.size() == 0 &&
1447 13886 : signature.return_type == TypeOracle::GetNeverType();
1448 : base::Optional<Binding<LocalLabel>*> true_label;
1449 : base::Optional<Binding<LocalLabel>*> false_label;
1450 13886 : if (try_bool_context) {
1451 1071 : true_label = TryLookupLabel(kTrueLabelName);
1452 1071 : false_label = TryLookupLabel(kFalseLabelName);
1453 : }
1454 37428 : if (IsCompatibleSignature(signature, parameter_types, arguments.labels) ||
1455 9385 : (true_label && false_label &&
1456 : IsCompatibleSignature(signature, parameter_types,
1457 14699 : {*true_label, *false_label}))) {
1458 4955 : candidates.push_back(i);
1459 : }
1460 : }
1461 :
1462 4230 : if (overloads.empty()) {
1463 0 : std::stringstream stream;
1464 0 : stream << "no matching declaration found for " << name;
1465 0 : ReportError(stream.str());
1466 4230 : } else if (candidates.empty()) {
1467 0 : FailCallableLookup("cannot find suitable callable with name", name,
1468 0 : arguments, overload_signatures);
1469 : }
1470 :
1471 1450 : auto is_better_candidate = [&](size_t a, size_t b) {
1472 1450 : return ParameterDifference(overload_signatures[a].GetExplicitTypes(),
1473 : parameter_types)
1474 : .StrictlyBetterThan(ParameterDifference(
1475 11600 : overload_signatures[b].GetExplicitTypes(), parameter_types));
1476 7130 : };
1477 :
1478 8460 : size_t best = *std::min_element(candidates.begin(), candidates.end(),
1479 4230 : is_better_candidate);
1480 : // This check is contained in libstdc++'s std::min_element.
1481 : DCHECK(!is_better_candidate(best, best));
1482 13415 : for (size_t candidate : candidates) {
1483 4955 : if (candidate != best && !is_better_candidate(best, candidate)) {
1484 : std::vector<Signature> candidate_signatures;
1485 0 : for (size_t i : candidates) {
1486 0 : candidate_signatures.push_back(overload_signatures[i]);
1487 : }
1488 0 : FailCallableLookup("ambiguous callable", name, arguments,
1489 0 : candidate_signatures);
1490 : }
1491 : }
1492 :
1493 12690 : if (Generic* generic = Generic::DynamicCast(overloads[best])) {
1494 1639 : result = GetOrCreateSpecialization(
1495 : SpecializationKey{generic, *generic->InferSpecializationTypes(
1496 4917 : specialization_types, parameter_types)});
1497 : } else {
1498 : result = Callable::cast(overloads[best]);
1499 : }
1500 :
1501 4230 : size_t caller_size = parameter_types.size();
1502 : size_t callee_size =
1503 8460 : result->signature().types().size() - result->signature().implicit_count;
1504 4230 : if (caller_size != callee_size &&
1505 : !result->signature().parameter_types.var_args) {
1506 0 : std::stringstream stream;
1507 0 : stream << "parameter count mismatch calling " << *result << " - expected "
1508 0 : << std::to_string(callee_size) << ", found "
1509 0 : << std::to_string(caller_size);
1510 0 : ReportError(stream.str());
1511 : }
1512 :
1513 4230 : return result;
1514 : }
1515 :
1516 90 : const Type* ImplementationVisitor::GetCommonType(const Type* left,
1517 : const Type* right) {
1518 : const Type* common_type;
1519 90 : if (IsAssignableFrom(left, right)) {
1520 : common_type = left;
1521 11 : } else if (IsAssignableFrom(right, left)) {
1522 : common_type = right;
1523 : } else {
1524 0 : common_type = TypeOracle::GetUnionType(left, right);
1525 : }
1526 90 : common_type = common_type->NonConstexprVersion();
1527 90 : return common_type;
1528 : }
1529 :
1530 39063 : VisitResult ImplementationVisitor::GenerateCopy(const VisitResult& to_copy) {
1531 14731 : if (to_copy.IsOnStack()) {
1532 : return VisitResult(to_copy.type(),
1533 24332 : assembler().Peek(to_copy.stack_range(), to_copy.type()));
1534 : }
1535 2565 : return to_copy;
1536 : }
1537 :
1538 16 : VisitResult ImplementationVisitor::Visit(StructExpression* decl) {
1539 : StackScope stack_scope(this);
1540 : const Type* raw_type = Declarations::LookupType(
1541 48 : QualifiedName(decl->namespace_qualification, decl->name));
1542 16 : if (!raw_type->IsStructType()) {
1543 0 : std::stringstream s;
1544 0 : s << decl->name << " is not a struct but used like one ";
1545 0 : ReportError(s.str());
1546 : }
1547 : const StructType* struct_type = StructType::cast(raw_type);
1548 48 : if (struct_type->fields().size() != decl->expressions.size()) {
1549 0 : std::stringstream s;
1550 0 : s << "initializer count mismatch for struct " << decl->name << " (expected "
1551 0 : << struct_type->fields().size() << ", found " << decl->expressions.size()
1552 0 : << ")";
1553 0 : ReportError(s.str());
1554 : }
1555 : // Push uninitialized 'this'
1556 16 : TypeVector lowered_types = LowerType(struct_type);
1557 83 : for (const Type* type : lowered_types) {
1558 51 : assembler().Emit(PushUninitializedInstruction{TypeOracle::GetTopType(
1559 408 : "unitialized struct field at " + PositionAsString(decl->pos), type)});
1560 : }
1561 : VisitResult uninitialized_struct =
1562 16 : VisitResult(struct_type, assembler().TopRange(lowered_types.size()));
1563 16 : Arguments constructor_arguments;
1564 76 : for (auto p : decl->expressions) {
1565 88 : constructor_arguments.parameters.push_back(Visit(p));
1566 : }
1567 : Callable* callable =
1568 : LookupCall({{}, kConstructMethodName}, struct_type->Constructors(),
1569 80 : constructor_arguments, {});
1570 : return stack_scope.Yield(GenerateCall(
1571 : callable, LocationReference::VariableAccess(uninitialized_struct),
1572 112 : constructor_arguments, {}, false));
1573 : }
1574 :
1575 836 : LocationReference ImplementationVisitor::GetLocationReference(
1576 : Expression* location) {
1577 836 : switch (location->kind) {
1578 : case AstNode::Kind::kIdentifierExpression:
1579 708 : return GetLocationReference(static_cast<IdentifierExpression*>(location));
1580 : case AstNode::Kind::kFieldAccessExpression:
1581 : return GetLocationReference(
1582 64 : static_cast<FieldAccessExpression*>(location));
1583 : case AstNode::Kind::kElementAccessExpression:
1584 : return GetLocationReference(
1585 61 : static_cast<ElementAccessExpression*>(location));
1586 : default:
1587 9 : return LocationReference::Temporary(Visit(location), "expression");
1588 : }
1589 : }
1590 :
1591 323 : LocationReference ImplementationVisitor::GetLocationReference(
1592 : FieldAccessExpression* expr) {
1593 323 : LocationReference reference = GetLocationReference(expr->object);
1594 401 : if (reference.IsVariableAccess() &&
1595 78 : reference.variable().type()->IsStructType()) {
1596 : return LocationReference::VariableAccess(
1597 168 : ProjectStructField(reference.variable(), expr->field));
1598 : }
1599 507 : if (reference.IsTemporary() && reference.temporary().type()->IsStructType()) {
1600 : return LocationReference::Temporary(
1601 : ProjectStructField(reference.temporary(), expr->field),
1602 92 : reference.temporary_description());
1603 : }
1604 : return LocationReference::FieldAccess(GenerateFetchFromLocation(reference),
1605 732 : expr->field);
1606 : }
1607 :
1608 195 : LocationReference ImplementationVisitor::GetLocationReference(
1609 : ElementAccessExpression* expr) {
1610 195 : VisitResult array = Visit(expr->array);
1611 195 : VisitResult index = Visit(expr->index);
1612 780 : return LocationReference::ArrayAccess(array, index);
1613 : }
1614 :
1615 5642 : LocationReference ImplementationVisitor::GetLocationReference(
1616 : IdentifierExpression* expr) {
1617 5642 : if (expr->namespace_qualification.empty()) {
1618 5642 : if (expr->IsThis()) {
1619 88 : if (CurrentConstructorInfo::Get()) {
1620 26 : CurrentConstructorInfo::Get()->accessed_this = true;
1621 : }
1622 : }
1623 5642 : if (base::Optional<Binding<LocalValue>*> value =
1624 5642 : TryLookupLocalValue(expr->name)) {
1625 10430 : if (expr->generic_arguments.size() != 0) {
1626 : ReportError("cannot have generic parameters on local name ",
1627 0 : expr->name);
1628 : }
1629 4792 : if ((*value)->is_const) {
1630 : return LocationReference::Temporary((*value)->value,
1631 9663 : "constant value " + expr->name);
1632 : }
1633 3142 : return LocationReference::VariableAccess((*value)->value);
1634 : }
1635 : }
1636 :
1637 850 : if (expr->IsThis()) {
1638 0 : ReportError("\"this\" cannot be qualified");
1639 : }
1640 2550 : QualifiedName name = QualifiedName(expr->namespace_qualification, expr->name);
1641 850 : if (base::Optional<Builtin*> builtin = Declarations::TryLookupBuiltin(name)) {
1642 : return LocationReference::Temporary(GetBuiltinCode(*builtin),
1643 12 : "builtin " + expr->name);
1644 : }
1645 846 : if (expr->generic_arguments.size() != 0) {
1646 59 : Generic* generic = Declarations::LookupUniqueGeneric(name);
1647 : Callable* specialization = GetOrCreateSpecialization(
1648 118 : SpecializationKey{generic, GetTypeVector(expr->generic_arguments)});
1649 59 : if (Builtin* builtin = Builtin::DynamicCast(specialization)) {
1650 : DCHECK(!builtin->IsExternal());
1651 : return LocationReference::Temporary(GetBuiltinCode(builtin),
1652 177 : "builtin " + expr->name);
1653 : } else {
1654 : ReportError("cannot create function pointer for non-builtin ",
1655 0 : generic->name());
1656 : }
1657 : }
1658 787 : Value* value = Declarations::LookupValue(name);
1659 787 : if (auto* constant = NamespaceConstant::DynamicCast(value)) {
1660 879 : if (constant->type()->IsConstexpr()) {
1661 : return LocationReference::Temporary(
1662 144 : VisitResult(constant->type(), constant->ExternalAssemblerName() +
1663 72 : "(state_)." +
1664 144 : constant->constant_name() + "()"),
1665 216 : "namespace constant " + expr->name);
1666 : }
1667 735 : assembler().Emit(NamespaceConstantInstruction{constant});
1668 : StackRange stack_range =
1669 245 : assembler().TopRange(LoweredSlotCount(constant->type()));
1670 : return LocationReference::Temporary(
1671 : VisitResult(constant->type(), stack_range),
1672 735 : "namespace constant " + expr->name);
1673 : }
1674 : ExternConstant* constant = ExternConstant::cast(value);
1675 : return LocationReference::Temporary(constant->value(),
1676 1410 : "extern value " + expr->name);
1677 : }
1678 :
1679 5706 : VisitResult ImplementationVisitor::GenerateFetchFromLocation(
1680 : const LocationReference& reference) {
1681 5706 : if (reference.IsTemporary()) {
1682 4074 : return GenerateCopy(reference.temporary());
1683 1632 : } else if (reference.IsVariableAccess()) {
1684 1263 : return GenerateCopy(reference.variable());
1685 : } else {
1686 : DCHECK(reference.IsCallAccess());
1687 369 : return GenerateCall(reference.eval_function(),
1688 1107 : Arguments{reference.call_arguments(), {}});
1689 : }
1690 : }
1691 :
1692 510 : void ImplementationVisitor::GenerateAssignToLocation(
1693 : const LocationReference& reference, const VisitResult& assignment_value) {
1694 510 : if (reference.IsCallAccess()) {
1695 : Arguments arguments{reference.call_arguments(), {}};
1696 70 : arguments.parameters.push_back(assignment_value);
1697 280 : GenerateCall(reference.assign_function(), arguments);
1698 440 : } else if (reference.IsVariableAccess()) {
1699 440 : VisitResult variable = reference.variable();
1700 : VisitResult converted_value =
1701 880 : GenerateImplicitConvert(variable.type(), assignment_value);
1702 440 : assembler().Poke(variable.stack_range(), converted_value.stack_range(),
1703 880 : variable.type());
1704 : } else {
1705 : DCHECK(reference.IsTemporary());
1706 : ReportError("cannot assign to temporary ",
1707 0 : reference.temporary_description());
1708 : }
1709 510 : }
1710 :
1711 36 : VisitResult ImplementationVisitor::GeneratePointerCall(
1712 : Expression* callee, const Arguments& arguments, bool is_tailcall) {
1713 : StackScope scope(this);
1714 36 : TypeVector parameter_types(arguments.parameters.GetTypeVector());
1715 36 : VisitResult callee_result = Visit(callee);
1716 72 : if (!callee_result.type()->IsBuiltinPointerType()) {
1717 0 : std::stringstream stream;
1718 0 : stream << "Expected a function pointer type but found "
1719 0 : << *callee_result.type();
1720 0 : ReportError(stream.str());
1721 : }
1722 36 : const BuiltinPointerType* type =
1723 : BuiltinPointerType::cast(callee_result.type());
1724 :
1725 108 : if (type->parameter_types().size() != parameter_types.size()) {
1726 0 : std::stringstream stream;
1727 0 : stream << "parameter count mismatch calling function pointer with Type: "
1728 0 : << *type << " - expected "
1729 0 : << std::to_string(type->parameter_types().size()) << ", found "
1730 0 : << std::to_string(parameter_types.size());
1731 0 : ReportError(stream.str());
1732 : }
1733 :
1734 36 : ParameterTypes types{type->parameter_types(), false};
1735 36 : Signature sig;
1736 : sig.parameter_types = types;
1737 72 : if (!IsCompatibleSignature(sig, parameter_types, {})) {
1738 0 : std::stringstream stream;
1739 0 : stream << "parameters do not match function pointer signature. Expected: ("
1740 0 : << type->parameter_types() << ") but got: (" << parameter_types
1741 0 : << ")";
1742 0 : ReportError(stream.str());
1743 : }
1744 :
1745 72 : callee_result = GenerateCopy(callee_result);
1746 : StackRange arg_range = assembler().TopRange(0);
1747 310 : for (size_t current = 0; current < arguments.parameters.size(); ++current) {
1748 238 : const Type* to_type = type->parameter_types()[current];
1749 : arg_range.Extend(
1750 155 : GenerateImplicitConvert(to_type, arguments.parameters[current])
1751 357 : .stack_range());
1752 : }
1753 :
1754 36 : assembler().Emit(
1755 144 : CallBuiltinPointerInstruction{is_tailcall, type, arg_range.Size()});
1756 :
1757 36 : if (is_tailcall) {
1758 0 : return VisitResult::NeverResult();
1759 : }
1760 : DCHECK_EQ(1, LoweredSlotCount(type->return_type()));
1761 72 : return scope.Yield(VisitResult(type->return_type(), assembler().TopRange(1)));
1762 : }
1763 :
1764 7689 : void ImplementationVisitor::AddCallParameter(
1765 : Callable* callable, VisitResult parameter, const Type* parameter_type,
1766 : std::vector<VisitResult>* converted_arguments, StackRange* argument_range,
1767 : std::vector<std::string>* constexpr_arguments) {
1768 15378 : VisitResult converted = GenerateImplicitConvert(parameter_type, parameter);
1769 7689 : converted_arguments->push_back(converted);
1770 7689 : if (!callable->ShouldBeInlined()) {
1771 7643 : if (converted.IsOnStack()) {
1772 : argument_range->Extend(converted.stack_range());
1773 : } else {
1774 1722 : constexpr_arguments->push_back(converted.constexpr_value());
1775 : }
1776 : }
1777 7689 : }
1778 :
1779 4230 : VisitResult ImplementationVisitor::GenerateCall(
1780 8460 : Callable* callable, base::Optional<LocationReference> this_reference,
1781 : Arguments arguments, const TypeVector& specialization_types,
1782 : bool is_tailcall) {
1783 : // Operators used in a branching context can also be function calls that never
1784 : // return but have a True and False label
1785 17063 : if (arguments.labels.size() == 0 &&
1786 3907 : callable->signature().labels.size() == 2) {
1787 136 : Binding<LocalLabel>* true_label = LookupLabel(kTrueLabelName);
1788 68 : arguments.labels.push_back(true_label);
1789 136 : Binding<LocalLabel>* false_label = LookupLabel(kFalseLabelName);
1790 68 : arguments.labels.push_back(false_label);
1791 : }
1792 :
1793 4230 : const Type* return_type = callable->signature().return_type;
1794 :
1795 : std::vector<VisitResult> converted_arguments;
1796 4230 : StackRange argument_range = assembler().TopRange(0);
1797 4230 : std::vector<std::string> constexpr_arguments;
1798 :
1799 : size_t current = 0;
1800 4230 : if (this_reference) {
1801 : DCHECK(callable->IsMethod());
1802 24 : Method* method = Method::cast(callable);
1803 : // By now, the this reference should either be a variable or
1804 : // a temporary, in both cases the fetch of the VisitResult should succeed.
1805 24 : VisitResult this_value = this_reference->GetVisitResult();
1806 24 : if (method->ShouldBeInlined()) {
1807 34 : if (!this_value.type()->IsSubtypeOf(method->aggregate_type())) {
1808 : ReportError("this parameter must be a subtype of ",
1809 0 : *method->aggregate_type());
1810 : }
1811 : } else {
1812 : AddCallParameter(callable, this_value, method->aggregate_type(),
1813 : &converted_arguments, &argument_range,
1814 14 : &constexpr_arguments);
1815 : }
1816 : ++current;
1817 : }
1818 :
1819 492 : for (; current < callable->signature().implicit_count; ++current) {
1820 984 : std::string implicit_name = callable->signature().parameter_names[current];
1821 : base::Optional<Binding<LocalValue>*> val =
1822 : TryLookupLocalValue(implicit_name);
1823 492 : if (!val) {
1824 : ReportError("implicit parameter '", implicit_name,
1825 0 : "' required for call to '", callable->ReadableName(),
1826 0 : "' is not defined");
1827 : }
1828 : AddCallParameter(callable, (*val)->value,
1829 492 : callable->signature().parameter_types.types[current],
1830 : &converted_arguments, &argument_range,
1831 984 : &constexpr_arguments);
1832 : }
1833 :
1834 15650 : for (auto arg : arguments.parameters) {
1835 7190 : const Type* to_type = (current >= callable->signature().types().size())
1836 : ? TypeOracle::GetObjectType()
1837 14380 : : callable->signature().types()[current++];
1838 : AddCallParameter(callable, arg, to_type, &converted_arguments,
1839 14380 : &argument_range, &constexpr_arguments);
1840 : }
1841 :
1842 4230 : if (GlobalContext::verbose()) {
1843 0 : std::cout << "generating code for call to " << callable->ReadableName()
1844 0 : << "\n";
1845 : }
1846 :
1847 4230 : size_t label_count = callable->signature().labels.size();
1848 4230 : if (label_count != arguments.labels.size()) {
1849 0 : std::stringstream s;
1850 0 : s << "unexpected number of otherwise labels for "
1851 0 : << callable->ReadableName() << " (expected "
1852 0 : << std::to_string(label_count) << " found "
1853 0 : << std::to_string(arguments.labels.size()) << ")";
1854 0 : ReportError(s.str());
1855 : }
1856 :
1857 4230 : if (callable->IsTransitioning()) {
1858 153 : if (!CurrentCallable::Get()->IsTransitioning()) {
1859 0 : std::stringstream s;
1860 0 : s << *CurrentCallable::Get()
1861 0 : << " isn't marked transitioning but calls the transitioning "
1862 0 : << *callable;
1863 0 : ReportError(s.str());
1864 : }
1865 : }
1866 :
1867 4230 : if (auto* builtin = Builtin::DynamicCast(callable)) {
1868 71 : base::Optional<Block*> catch_block = GetCatchBlock();
1869 71 : assembler().Emit(CallBuiltinInstruction{
1870 284 : is_tailcall, builtin, argument_range.Size(), catch_block});
1871 71 : GenerateCatchBlock(catch_block);
1872 71 : if (is_tailcall) {
1873 1 : return VisitResult::NeverResult();
1874 : } else {
1875 70 : size_t slot_count = LoweredSlotCount(return_type);
1876 : DCHECK_LE(slot_count, 1);
1877 : // TODO(tebbi): Actually, builtins have to return a value, so we should
1878 : // assert slot_count == 1 here.
1879 : return VisitResult(return_type, assembler().TopRange(slot_count));
1880 : }
1881 4159 : } else if (auto* macro = Macro::DynamicCast(callable)) {
1882 4077 : if (is_tailcall) {
1883 0 : ReportError("can't tail call a macro");
1884 : }
1885 4077 : if (return_type->IsConstexpr()) {
1886 : DCHECK_EQ(0, arguments.labels.size());
1887 98 : std::stringstream result;
1888 196 : result << "(" << macro->external_assembler_name() << "(state_)."
1889 98 : << macro->ExternalName() << "(";
1890 : bool first = true;
1891 313 : for (VisitResult arg : arguments.parameters) {
1892 : DCHECK(!arg.IsOnStack());
1893 117 : if (!first) {
1894 54 : result << ", ";
1895 : }
1896 : first = false;
1897 : result << arg.constexpr_value();
1898 : }
1899 98 : result << "))";
1900 98 : return VisitResult(return_type, result.str());
1901 3979 : } else if (macro->ShouldBeInlined()) {
1902 : std::vector<Block*> label_blocks;
1903 37 : for (Binding<LocalLabel>* label : arguments.labels) {
1904 1 : label_blocks.push_back(label->block);
1905 : }
1906 : return InlineMacro(macro, this_reference, converted_arguments,
1907 72 : label_blocks);
1908 7532 : } else if (arguments.labels.empty() &&
1909 3571 : return_type != TypeOracle::GetNeverType()) {
1910 3541 : base::Optional<Block*> catch_block = GetCatchBlock();
1911 3541 : assembler().Emit(
1912 14164 : CallCsaMacroInstruction{macro, constexpr_arguments, catch_block});
1913 3541 : GenerateCatchBlock(catch_block);
1914 3541 : size_t return_slot_count = LoweredSlotCount(return_type);
1915 : return VisitResult(return_type, assembler().TopRange(return_slot_count));
1916 : } else {
1917 : base::Optional<Block*> return_continuation;
1918 420 : if (return_type != TypeOracle::GetNeverType()) {
1919 626 : return_continuation = assembler().NewBlock();
1920 : }
1921 :
1922 : std::vector<Block*> label_blocks;
1923 :
1924 886 : for (size_t i = 0; i < label_count; ++i) {
1925 1398 : label_blocks.push_back(assembler().NewBlock());
1926 : }
1927 420 : base::Optional<Block*> catch_block = GetCatchBlock();
1928 420 : assembler().Emit(CallCsaMacroAndBranchInstruction{
1929 : macro, constexpr_arguments, return_continuation, label_blocks,
1930 2100 : catch_block});
1931 420 : GenerateCatchBlock(catch_block);
1932 :
1933 886 : for (size_t i = 0; i < label_count; ++i) {
1934 466 : Binding<LocalLabel>* label = arguments.labels[i];
1935 : size_t callee_label_parameters =
1936 932 : callable->signature().labels[i].types.size();
1937 946 : if (label->parameter_types.size() != callee_label_parameters) {
1938 0 : std::stringstream s;
1939 0 : s << "label " << label->name()
1940 0 : << " doesn't have the right number of parameters (found "
1941 0 : << std::to_string(label->parameter_types.size()) << " expected "
1942 0 : << std::to_string(callee_label_parameters) << ")";
1943 0 : ReportError(s.str());
1944 : }
1945 932 : assembler().Bind(label_blocks[i]);
1946 : assembler().Goto(
1947 : label->block,
1948 1864 : LowerParameterTypes(callable->signature().labels[i].types).size());
1949 :
1950 : size_t j = 0;
1951 1412 : for (auto t : callable->signature().labels[i].types) {
1952 14 : const Type* parameter_type = label->parameter_types[j];
1953 14 : if (parameter_type != t) {
1954 : ReportError("mismatch of label parameters (expected ", *t, " got ",
1955 0 : parameter_type, " for parameter ", i + 1, ")");
1956 : }
1957 14 : j++;
1958 : }
1959 : }
1960 :
1961 420 : if (return_continuation) {
1962 313 : assembler().Bind(*return_continuation);
1963 313 : size_t return_slot_count = LoweredSlotCount(return_type);
1964 : return VisitResult(return_type,
1965 : assembler().TopRange(return_slot_count));
1966 : } else {
1967 107 : return VisitResult::NeverResult();
1968 : }
1969 : }
1970 82 : } else if (auto* runtime_function = RuntimeFunction::DynamicCast(callable)) {
1971 20 : base::Optional<Block*> catch_block = GetCatchBlock();
1972 20 : assembler().Emit(CallRuntimeInstruction{
1973 80 : is_tailcall, runtime_function, argument_range.Size(), catch_block});
1974 20 : GenerateCatchBlock(catch_block);
1975 20 : if (is_tailcall || return_type == TypeOracle::GetNeverType()) {
1976 5 : return VisitResult::NeverResult();
1977 : } else {
1978 15 : size_t slot_count = LoweredSlotCount(return_type);
1979 : DCHECK_LE(slot_count, 1);
1980 : // TODO(tebbi): Actually, runtime functions have to return a value, so
1981 : // we should assert slot_count == 1 here.
1982 : return VisitResult(return_type, assembler().TopRange(slot_count));
1983 : }
1984 62 : } else if (auto* intrinsic = Intrinsic::DynamicCast(callable)) {
1985 124 : if (intrinsic->ExternalName() == "%RawConstexprCast") {
1986 3 : if (intrinsic->signature().parameter_types.types.size() != 1 ||
1987 1 : constexpr_arguments.size() != 1) {
1988 : ReportError(
1989 : "%RawConstexprCast must take a single parameter with constexpr "
1990 0 : "type");
1991 : }
1992 1 : if (!return_type->IsConstexpr()) {
1993 0 : std::stringstream s;
1994 0 : s << *return_type
1995 0 : << " return type for %RawConstexprCast is not constexpr";
1996 0 : ReportError(s.str());
1997 : }
1998 1 : std::stringstream result;
1999 3 : result << "static_cast<" << return_type->GetGeneratedTypeName() << ">(";
2000 1 : result << constexpr_arguments[0];
2001 1 : result << ")";
2002 1 : return VisitResult(return_type, result.str());
2003 : } else {
2004 61 : assembler().Emit(
2005 305 : CallIntrinsicInstruction{intrinsic, constexpr_arguments});
2006 : size_t return_slot_count =
2007 61 : LoweredSlotCount(intrinsic->signature().return_type);
2008 : return VisitResult(return_type, assembler().TopRange(return_slot_count));
2009 : }
2010 : } else {
2011 0 : UNREACHABLE();
2012 4230 : }
2013 : }
2014 :
2015 4206 : VisitResult ImplementationVisitor::GenerateCall(
2016 : const QualifiedName& callable_name, Arguments arguments,
2017 : const TypeVector& specialization_types, bool is_tailcall) {
2018 : Callable* callable =
2019 : LookupCall(callable_name, Declarations::Lookup(callable_name), arguments,
2020 8412 : specialization_types);
2021 : return GenerateCall(callable, base::nullopt, arguments, specialization_types,
2022 12618 : is_tailcall);
2023 : }
2024 :
2025 2476 : VisitResult ImplementationVisitor::Visit(CallExpression* expr,
2026 : bool is_tailcall) {
2027 : StackScope scope(this);
2028 2476 : Arguments arguments;
2029 : QualifiedName name =
2030 9904 : QualifiedName(expr->callee->namespace_qualification, expr->callee->name);
2031 : TypeVector specialization_types =
2032 2476 : GetTypeVector(expr->callee->generic_arguments);
2033 : bool has_template_arguments = !specialization_types.empty();
2034 10029 : for (Expression* arg : expr->arguments)
2035 10154 : arguments.parameters.push_back(Visit(arg));
2036 4952 : arguments.labels = LabelsFromIdentifiers(expr->labels);
2037 9452 : if (!has_template_arguments && name.namespace_qualification.empty() &&
2038 6458 : TryLookupLocalValue(name.name)) {
2039 : return scope.Yield(
2040 72 : GeneratePointerCall(expr->callee, arguments, is_tailcall));
2041 : } else {
2042 : return scope.Yield(
2043 7320 : GenerateCall(name, arguments, specialization_types, is_tailcall));
2044 : }
2045 : }
2046 :
2047 7 : VisitResult ImplementationVisitor::Visit(CallMethodExpression* expr) {
2048 : StackScope scope(this);
2049 7 : Arguments arguments;
2050 7 : std::string method_name = expr->method->name;
2051 : TypeVector specialization_types =
2052 7 : GetTypeVector(expr->method->generic_arguments);
2053 14 : if (method_name == kConstructMethodName || method_name == kSuperMethodName) {
2054 6 : if (CurrentConstructorInfo::Get()) {
2055 : ConstructorInfo& info = *CurrentConstructorInfo::Get();
2056 6 : if (method_name == kSuperMethodName) {
2057 6 : if (info.accessed_this) {
2058 0 : ReportError("cannot call super after accessing \"this\"");
2059 : }
2060 6 : if (info.super_calls != 0) {
2061 0 : ReportError("\"super\" can only be called once from a constructor");
2062 : }
2063 6 : ++info.super_calls;
2064 : } else {
2065 0 : ReportError("cannot call a constructor from a constructor");
2066 : }
2067 : } else {
2068 : ReportError(
2069 0 : "cannot call a constructor or \"super\" from a non-constructor");
2070 : }
2071 : }
2072 : const AggregateType* target_type;
2073 14 : LocationReference target = GetLocationReference(expr->target);
2074 7 : if (target.IsVariableAccess()) {
2075 1 : target_type = AggregateType::DynamicCast(target.variable().type());
2076 : } else {
2077 6 : VisitResult result = GenerateFetchFromLocation(target);
2078 24 : target = LocationReference::Temporary(result, "method target result");
2079 6 : target_type = AggregateType::DynamicCast(result.type());
2080 : }
2081 7 : if (!target_type) {
2082 0 : ReportError("target of method call not a struct or class type");
2083 : }
2084 30 : for (Expression* arg : expr->arguments)
2085 32 : arguments.parameters.push_back(Visit(arg));
2086 14 : arguments.labels = LabelsFromIdentifiers(expr->labels);
2087 7 : TypeVector argument_types = arguments.parameters.GetTypeVector();
2088 : DCHECK_EQ(expr->method->namespace_qualification.size(), 0);
2089 21 : QualifiedName qualified_name = QualifiedName(method_name);
2090 : Callable* callable = nullptr;
2091 7 : if (method_name == kConstructMethodName) {
2092 : callable =
2093 0 : LookupCall(qualified_name, target_type->Constructors(), arguments, {});
2094 7 : } else if (method_name == kSuperMethodName) {
2095 6 : if (!target_type->IsClassType()) {
2096 0 : ReportError("cannot call super in struct constructor");
2097 : }
2098 : target_type = ClassType::cast(target_type)->GetSuperClass();
2099 6 : if (!target_type) {
2100 0 : ReportError("cannot call \"super\" on a class with no superclass");
2101 : }
2102 : callable = LookupCall(QualifiedName(kConstructMethodName),
2103 24 : target_type->Constructors(), arguments, {});
2104 : } else {
2105 : callable = LookupCall(qualified_name, target_type->Methods(method_name),
2106 3 : arguments, {});
2107 : }
2108 35 : return scope.Yield(GenerateCall(callable, target, arguments, {}, false));
2109 : }
2110 :
2111 13 : VisitResult ImplementationVisitor::Visit(LoadObjectFieldExpression* expr) {
2112 13 : VisitResult base_result = Visit(expr->base);
2113 13 : auto class_type = ClassType::DynamicCast(base_result.type());
2114 13 : if (!class_type) {
2115 : ReportError(
2116 : "base expression for a LoadObjectFieldExpression is not a class type "
2117 : "but instead ",
2118 0 : *base_result.type());
2119 : }
2120 13 : VisitResult result = base_result;
2121 65 : assembler().Emit(LoadObjectFieldInstruction{class_type, expr->field_name});
2122 13 : const Field& field = class_type->LookupField(expr->field_name);
2123 13 : result.SetType(field.name_and_type.type);
2124 13 : return result;
2125 : }
2126 :
2127 25 : VisitResult ImplementationVisitor::Visit(StoreObjectFieldExpression* expr) {
2128 25 : VisitResult base_result = Visit(expr->base);
2129 25 : auto class_type = ClassType::DynamicCast(base_result.type());
2130 25 : if (!class_type) {
2131 : ReportError(
2132 : "base expression for a StoreObjectFieldExpression is not a class type "
2133 : "but instead ",
2134 0 : *base_result.type());
2135 : }
2136 25 : VisitResult value = Visit(expr->value);
2137 125 : assembler().Emit(StoreObjectFieldInstruction{class_type, expr->field_name});
2138 50 : return VisitResult(value.type(), assembler().TopRange(0));
2139 : }
2140 :
2141 61 : VisitResult ImplementationVisitor::Visit(IntrinsicCallExpression* expr) {
2142 : StackScope scope(this);
2143 61 : Arguments arguments;
2144 61 : TypeVector specialization_types = GetTypeVector(expr->generic_arguments);
2145 183 : for (Expression* arg : expr->arguments)
2146 122 : arguments.parameters.push_back(Visit(arg));
2147 : return scope.Yield(
2148 244 : GenerateCall(expr->name, arguments, specialization_types, false));
2149 : }
2150 :
2151 0 : void ImplementationVisitor::GenerateBranch(const VisitResult& condition,
2152 : Block* true_block,
2153 : Block* false_block) {
2154 : DCHECK_EQ(condition,
2155 : VisitResult(TypeOracle::GetBoolType(), assembler().TopRange(1)));
2156 520 : assembler().Branch(true_block, false_block);
2157 0 : }
2158 :
2159 603 : void ImplementationVisitor::GenerateExpressionBranch(Expression* expression,
2160 : Block* true_block,
2161 : Block* false_block) {
2162 : // Conditional expressions can either explicitly return a bit
2163 : // type, or they can be backed by macros that don't return but
2164 : // take a true and false label. By declaring the labels before
2165 : // visiting the conditional expression, those label-based
2166 : // macro conditionals will be able to find them through normal
2167 : // label lookups.
2168 : Binding<LocalLabel> true_binding{&LabelBindingsManager::Get(), kTrueLabelName,
2169 2412 : LocalLabel{true_block}};
2170 : Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
2171 3015 : kFalseLabelName, LocalLabel{false_block}};
2172 : StackScope stack_scope(this);
2173 603 : VisitResult expression_result = Visit(expression);
2174 603 : if (!expression_result.type()->IsNever()) {
2175 2080 : expression_result = stack_scope.Yield(
2176 520 : GenerateImplicitConvert(TypeOracle::GetBoolType(), expression_result));
2177 : GenerateBranch(expression_result, true_block, false_block);
2178 603 : }
2179 603 : }
2180 :
2181 10478 : VisitResult ImplementationVisitor::GenerateImplicitConvert(
2182 22904 : const Type* destination_type, VisitResult source) {
2183 : StackScope scope(this);
2184 10478 : if (source.type() == TypeOracle::GetNeverType()) {
2185 0 : ReportError("it is not allowed to use a value of type never");
2186 : }
2187 :
2188 10478 : if (destination_type == source.type()) {
2189 17060 : return scope.Yield(GenerateCopy(source));
2190 : }
2191 :
2192 1948 : if (TypeOracle::IsImplicitlyConvertableFrom(destination_type,
2193 : source.type())) {
2194 : return scope.Yield(GenerateCall(kFromConstexprMacroName, {{source}, {}},
2195 8960 : {destination_type, source.type()}, false));
2196 828 : } else if (IsAssignableFrom(destination_type, source.type())) {
2197 : source.SetType(destination_type);
2198 1656 : return scope.Yield(GenerateCopy(source));
2199 : } else {
2200 0 : std::stringstream s;
2201 0 : s << "cannot use expression of type " << *source.type()
2202 0 : << " as a value of type " << *destination_type;
2203 0 : ReportError(s.str());
2204 : }
2205 : }
2206 :
2207 0 : StackRange ImplementationVisitor::GenerateLabelGoto(
2208 0 : LocalLabel* label, base::Optional<StackRange> arguments) {
2209 411 : return assembler().Goto(label->block, arguments ? arguments->Size() : 0);
2210 : }
2211 :
2212 2483 : std::vector<Binding<LocalLabel>*> ImplementationVisitor::LabelsFromIdentifiers(
2213 2483 : const std::vector<std::string>& names) {
2214 : std::vector<Binding<LocalLabel>*> result;
2215 2483 : result.reserve(names.size());
2216 5297 : for (const auto& name : names) {
2217 662 : result.push_back(LookupLabel(name));
2218 : }
2219 2483 : return result;
2220 : }
2221 :
2222 908 : StackRange ImplementationVisitor::LowerParameter(
2223 : const Type* type, const std::string& parameter_name,
2224 : Stack<std::string>* lowered_parameters) {
2225 908 : if (type->IsStructType()) {
2226 : const StructType* struct_type = StructType::cast(type);
2227 : StackRange range = lowered_parameters->TopRange(0);
2228 27 : for (auto& field : struct_type->fields()) {
2229 : StackRange parameter_range = LowerParameter(
2230 : field.name_and_type.type,
2231 68 : parameter_name + "." + field.name_and_type.name, lowered_parameters);
2232 : range.Extend(parameter_range);
2233 : }
2234 5 : return range;
2235 : } else {
2236 1806 : lowered_parameters->Push(parameter_name);
2237 : return lowered_parameters->TopRange(1);
2238 : }
2239 : }
2240 :
2241 0 : std::string ImplementationVisitor::ExternalLabelName(
2242 : const std::string& label_name) {
2243 387 : return "label_" + label_name;
2244 : }
2245 :
2246 36 : std::string ImplementationVisitor::ExternalLabelParameterName(
2247 : const std::string& label_name, size_t i) {
2248 180 : return "label_" + label_name + "_parameter_" + std::to_string(i);
2249 : }
2250 :
2251 2886 : std::string ImplementationVisitor::ExternalParameterName(
2252 : const std::string& name) {
2253 5772 : return std::string("p_") + name;
2254 : }
2255 :
2256 0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::ValueBindingsManager);
2257 0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::LabelBindingsManager);
2258 0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentCallable);
2259 0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentReturnValue);
2260 0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentConstructorInfo);
2261 :
2262 28386 : bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
2263 14112 : const std::vector<Binding<LocalLabel>*>& labels) {
2264 46619 : auto i = sig.parameter_types.types.begin() + sig.implicit_count;
2265 28386 : if ((sig.parameter_types.types.size() - sig.implicit_count) > types.size())
2266 : return false;
2267 : // TODO(danno): The test below is actually insufficient. The labels'
2268 : // parameters must be checked too. ideally, the named part of
2269 : // LabelDeclarationVector would be factored out so that the label count and
2270 : // parameter types could be passed separately.
2271 28224 : if (sig.labels.size() != labels.size()) return false;
2272 41457 : for (auto current : types) {
2273 18233 : if (i == sig.parameter_types.types.end()) {
2274 55 : if (!sig.parameter_types.var_args) return false;
2275 0 : if (!IsAssignableFrom(TypeOracle::GetObjectType(), current)) return false;
2276 : } else {
2277 18178 : if (!IsAssignableFrom(*i++, current)) return false;
2278 : }
2279 : }
2280 : return true;
2281 : }
2282 :
2283 4052 : base::Optional<Block*> ImplementationVisitor::GetCatchBlock() {
2284 4052 : base::Optional<Block*> catch_block;
2285 4052 : if (base::Optional<Binding<LocalLabel>*> catch_handler =
2286 8104 : TryLookupLabel("_catch")) {
2287 44 : catch_block = assembler().NewBlock(base::nullopt, true);
2288 : }
2289 4052 : return catch_block;
2290 : }
2291 :
2292 4052 : void ImplementationVisitor::GenerateCatchBlock(
2293 4052 : base::Optional<Block*> catch_block) {
2294 4052 : if (catch_block) {
2295 : base::Optional<Binding<LocalLabel>*> catch_handler =
2296 44 : TryLookupLabel("_catch");
2297 44 : if (assembler().CurrentBlockIsComplete()) {
2298 4 : assembler().Bind(*catch_block);
2299 4 : assembler().Goto((*catch_handler)->block, 1);
2300 : } else {
2301 18 : CfgAssemblerScopedTemporaryBlock temp(&assembler(), *catch_block);
2302 18 : assembler().Goto((*catch_handler)->block, 1);
2303 : }
2304 : }
2305 4052 : }
2306 :
2307 1 : void ImplementationVisitor::VisitAllDeclarables() {
2308 5011 : const std::vector<std::unique_ptr<Declarable>>& all_declarables =
2309 : GlobalContext::AllDeclarables();
2310 : // This has to be an index-based loop because all_declarables can be extended
2311 : // during the loop.
2312 10022 : for (size_t i = 0; i < all_declarables.size(); ++i) {
2313 5010 : Visit(all_declarables[i].get());
2314 : }
2315 1 : }
2316 :
2317 15030 : void ImplementationVisitor::Visit(Declarable* declarable) {
2318 : CurrentConstructorInfo::Scope current_constructor(base::nullopt);
2319 5010 : CurrentScope::Scope current_scope(declarable->ParentScope());
2320 5010 : CurrentSourcePosition::Scope current_source_position(declarable->pos());
2321 5010 : switch (declarable->kind()) {
2322 : case Declarable::kMacro:
2323 783 : return Visit(Macro::cast(declarable));
2324 : case Declarable::kMethod:
2325 20 : return Visit(Method::cast(declarable));
2326 : case Declarable::kBuiltin:
2327 134 : return Visit(Builtin::cast(declarable));
2328 : case Declarable::kTypeAlias:
2329 3845 : return Visit(TypeAlias::cast(declarable));
2330 : case Declarable::kNamespaceConstant:
2331 40 : return Visit(NamespaceConstant::cast(declarable));
2332 : case Declarable::kRuntimeFunction:
2333 : case Declarable::kIntrinsic:
2334 : case Declarable::kExternConstant:
2335 : case Declarable::kNamespace:
2336 : case Declarable::kGeneric:
2337 : return;
2338 : }
2339 : }
2340 :
2341 1 : void ImplementationVisitor::GenerateBuiltinDefinitions(std::string& file_name) {
2342 1 : std::stringstream new_contents_stream;
2343 : new_contents_stream
2344 : << "#ifndef V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
2345 : "#define V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
2346 : "\n"
2347 : "#define BUILTIN_LIST_FROM_DSL(CPP, API, TFJ, TFC, TFS, TFH, ASM) "
2348 1 : "\\\n";
2349 5012 : for (auto& declarable : GlobalContext::AllDeclarables()) {
2350 167 : Builtin* builtin = Builtin::DynamicCast(declarable.get());
2351 5144 : if (!builtin || builtin->IsExternal()) continue;
2352 : int firstParameterIndex = 1;
2353 : bool declareParameters = true;
2354 120 : if (builtin->IsStub()) {
2355 73 : new_contents_stream << "TFS(" << builtin->ExternalName();
2356 : } else {
2357 47 : new_contents_stream << "TFJ(" << builtin->ExternalName();
2358 47 : if (builtin->IsVarArgsJavaScript()) {
2359 : new_contents_stream
2360 43 : << ", SharedFunctionInfo::kDontAdaptArgumentsSentinel";
2361 : declareParameters = false;
2362 : } else {
2363 : assert(builtin->IsFixedArgsJavaScript());
2364 : // FixedArg javascript builtins need to offer the parameter
2365 : // count.
2366 : assert(builtin->parameter_names().size() >= 2);
2367 8 : new_contents_stream << ", " << (builtin->parameter_names().size() - 2);
2368 : // And the receiver is explicitly declared.
2369 4 : new_contents_stream << ", kReceiver";
2370 : firstParameterIndex = 2;
2371 : }
2372 : }
2373 120 : if (declareParameters) {
2374 : int index = 0;
2375 472 : for (const auto& parameter : builtin->parameter_names()) {
2376 318 : if (index >= firstParameterIndex) {
2377 474 : new_contents_stream << ", k" << CamelifyString(parameter);
2378 : }
2379 318 : index++;
2380 : }
2381 : }
2382 120 : new_contents_stream << ") \\\n";
2383 : }
2384 1 : new_contents_stream << "\n";
2385 :
2386 : new_contents_stream
2387 1 : << "#define TORQUE_FUNCTION_POINTER_TYPE_TO_BUILTIN_MAP(V) \\\n";
2388 22 : for (const BuiltinPointerType* type : TypeOracle::AllBuiltinPointerTypes()) {
2389 : Builtin* example_builtin =
2390 10 : Declarations::FindSomeInternalBuiltinWithType(type);
2391 10 : if (!example_builtin) {
2392 : CurrentSourcePosition::Scope current_source_position(
2393 0 : SourcePosition{CurrentSourceFile::Get(), -1, -1});
2394 0 : ReportError("unable to find any builtin with type \"", *type, "\"");
2395 : }
2396 20 : new_contents_stream << " V(" << type->function_pointer_type_id() << ","
2397 10 : << example_builtin->ExternalName() << ")\\\n";
2398 : }
2399 1 : new_contents_stream << "\n";
2400 :
2401 : new_contents_stream
2402 1 : << "#endif // V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n";
2403 :
2404 : std::string new_contents(new_contents_stream.str());
2405 2 : ReplaceFileContentsIfDifferent(file_name, new_contents);
2406 1 : }
2407 :
2408 1 : void ImplementationVisitor::GenerateClassDefinitions(std::string& file_name) {
2409 1 : std::stringstream new_contents_stream;
2410 : new_contents_stream << "#ifndef V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
2411 : "#define V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
2412 1 : "\n\n";
2413 :
2414 9 : for (auto i : GlobalContext::GetClasses()) {
2415 : // TODO(danno): Ideally (and we've got several core V8 dev's feedback
2416 : // supporting this), Torque should generate the constants for the offsets
2417 : // directly and not go through the existing layer of macros, which actually
2418 : // currently just serves to additionally obfuscate where these values come
2419 : // from.
2420 7 : new_contents_stream << "#define ";
2421 14 : new_contents_stream << CapifyStringWithUnderscores(i.first)
2422 7 : << "_FIELDS(V) \\\n";
2423 7 : const ClassType* type = i.second;
2424 14 : std::vector<Field> fields = type->fields();
2425 7 : new_contents_stream << "V(kStartOfStrongFieldsOffset, 0) \\\n";
2426 27 : for (auto f : fields) {
2427 13 : if (!f.is_weak) {
2428 22 : new_contents_stream << "V(k" << CamelifyString(f.name_and_type.name)
2429 11 : << "Offset, kTaggedSize) \\\n";
2430 : }
2431 : }
2432 7 : new_contents_stream << "V(kEndOfStrongFieldsOffset, 0) \\\n";
2433 7 : new_contents_stream << "V(kStartOfWeakFieldsOffset, 0) \\\n";
2434 27 : for (auto f : fields) {
2435 13 : if (f.is_weak) {
2436 4 : new_contents_stream << "V(k" << CamelifyString(f.name_and_type.name)
2437 2 : << "Offset, kTaggedSize) \\\n";
2438 : }
2439 : }
2440 7 : new_contents_stream << "V(kEndOfWeakFieldsOffset, 0) \\\n";
2441 7 : new_contents_stream << "V(kSize, 0) \\\n";
2442 7 : new_contents_stream << "\n";
2443 : }
2444 :
2445 : new_contents_stream
2446 1 : << "\n#endif // V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n";
2447 :
2448 : std::string new_contents(new_contents_stream.str());
2449 2 : ReplaceFileContentsIfDifferent(file_name, new_contents);
2450 1 : }
2451 :
2452 : } // namespace torque
2453 : } // namespace internal
2454 9078 : } // namespace v8
|