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/globals.h"
8 : #include "src/torque/csa-generator.h"
9 : #include "src/torque/declaration-visitor.h"
10 : #include "src/torque/implementation-visitor.h"
11 : #include "src/torque/parameter-difference.h"
12 : #include "src/torque/server-data.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 : namespace torque {
17 :
18 13495 : VisitResult ImplementationVisitor::Visit(Expression* expr) {
19 13495 : CurrentSourcePosition::Scope scope(expr->pos);
20 13495 : switch (expr->kind) {
21 : #define ENUM_ITEM(name) \
22 : case AstNode::Kind::k##name: \
23 : return Visit(name::cast(expr));
24 13495 : AST_EXPRESSION_NODE_KIND_LIST(ENUM_ITEM)
25 : #undef ENUM_ITEM
26 : default:
27 0 : UNREACHABLE();
28 : }
29 : }
30 :
31 5836 : const Type* ImplementationVisitor::Visit(Statement* stmt) {
32 5836 : CurrentSourcePosition::Scope scope(stmt->pos);
33 : StackScope stack_scope(this);
34 : const Type* result;
35 5836 : switch (stmt->kind) {
36 : #define ENUM_ITEM(name) \
37 : case AstNode::Kind::k##name: \
38 : result = Visit(name::cast(stmt)); \
39 : break;
40 5836 : AST_STATEMENT_NODE_KIND_LIST(ENUM_ITEM)
41 : #undef ENUM_ITEM
42 : default:
43 0 : UNREACHABLE();
44 : }
45 : DCHECK_EQ(result == TypeOracle::GetNeverType(),
46 : assembler().CurrentBlockIsComplete());
47 5836 : return result;
48 : }
49 :
50 44 : void ImplementationVisitor::BeginNamespaceFile(Namespace* nspace) {
51 : std::ostream& source = nspace->source_stream();
52 : std::ostream& header = nspace->header_stream();
53 :
54 1556 : for (const std::string& include_path : GlobalContext::CppIncludes()) {
55 4536 : source << "#include " << StringLiteralQuote(include_path) << "\n";
56 : }
57 :
58 44 : for (Namespace* n : GlobalContext::Get().GetNamespaces()) {
59 3532 : source << "#include \"torque-generated/builtins-" +
60 7064 : DashifyString(n->name()) + "-from-dsl-gen.h\"\n";
61 : }
62 44 : source << "\n";
63 :
64 : source << "namespace v8 {\n"
65 : << "namespace internal {\n"
66 44 : << "\n";
67 :
68 : std::string upper_name(nspace->name());
69 : transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
70 : ::toupper);
71 : std::string headerDefine =
72 132 : std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";
73 44 : header << "#ifndef " << headerDefine << "\n";
74 44 : header << "#define " << headerDefine << "\n\n";
75 44 : header << "#include \"src/compiler/code-assembler.h\"\n";
76 44 : if (nspace != GlobalContext::GetDefaultNamespace()) {
77 41 : header << "#include \"src/code-stub-assembler.h\"\n";
78 : }
79 44 : header << "#include \"src/utils.h\"\n";
80 44 : header << "#include \"torque-generated/class-definitions-from-dsl.h\"\n";
81 44 : header << "\n";
82 :
83 : header << "namespace v8 {\n"
84 : << "namespace internal {\n"
85 44 : << "\n";
86 :
87 44 : header << "class ";
88 44 : if (nspace->IsTestNamespace()) {
89 1 : header << "V8_EXPORT_PRIVATE ";
90 : }
91 132 : header << nspace->ExternalName() << " {\n";
92 44 : header << " public:\n";
93 88 : header << " explicit " << nspace->ExternalName()
94 : << "(compiler::CodeAssemblerState* state) : state_(state), ca_(state) "
95 44 : "{ USE(state_, ca_); }\n";
96 44 : }
97 :
98 42 : void ImplementationVisitor::EndNamespaceFile(Namespace* nspace) {
99 : std::ostream& source = nspace->source_stream();
100 : std::ostream& header = nspace->header_stream();
101 :
102 : std::string upper_name(nspace->name());
103 : transform(upper_name.begin(), upper_name.end(), upper_name.begin(),
104 : ::toupper);
105 : std::string headerDefine =
106 126 : std::string("V8_TORQUE_") + upper_name + "_FROM_DSL_BASE_H__";
107 :
108 : source << "} // namespace internal\n"
109 : << "} // namespace v8\n"
110 42 : << "\n";
111 :
112 : header << " private:\n"
113 : << " compiler::CodeAssemblerState* const state_;\n"
114 : << " compiler::CodeAssembler ca_;\n"
115 42 : << "};\n\n";
116 : header << "} // namespace internal\n"
117 : << "} // namespace v8\n"
118 42 : << "\n";
119 42 : header << "#endif // " << headerDefine << "\n";
120 42 : }
121 :
122 33 : void ImplementationVisitor::Visit(NamespaceConstant* decl) {
123 198 : Signature signature{{}, base::nullopt, {{}, false}, 0, decl->type(), {}};
124 33 : const std::string& name = decl->name()->value;
125 :
126 66 : BindingsManagersScope bindings_managers_scope;
127 :
128 33 : header_out() << " ";
129 99 : GenerateFunctionDeclaration(header_out(), "", name, signature, {});
130 33 : header_out() << ";\n";
131 :
132 66 : GenerateFunctionDeclaration(source_out(),
133 99 : CurrentNamespace()->ExternalName() + "::", name,
134 33 : signature, {});
135 33 : source_out() << " {\n";
136 :
137 : DCHECK(!signature.return_type->IsVoidOrNever());
138 :
139 99 : assembler_ = CfgAssembler(Stack<const Type*>{});
140 :
141 33 : VisitResult expression_result = Visit(decl->body());
142 : VisitResult return_result =
143 66 : GenerateImplicitConvert(signature.return_type, expression_result);
144 :
145 33 : CSAGenerator csa_generator{assembler().Result(), source_out()};
146 99 : Stack<std::string> values = *csa_generator.EmitGraph(Stack<std::string>{});
147 :
148 : assembler_ = base::nullopt;
149 :
150 33 : source_out() << "return ";
151 99 : CSAGenerator::EmitCSAValue(return_result, values, source_out());
152 33 : source_out() << ";\n";
153 33 : source_out() << "}\n\n";
154 33 : }
155 :
156 5526 : void ImplementationVisitor::Visit(TypeAlias* alias) {
157 5526 : if (alias->IsRedeclaration()) return;
158 : const ClassType* class_type = ClassType::DynamicCast(alias->type());
159 269 : if (class_type && class_type->IsExtern()) {
160 : // Classes that are in the default namespace are defined in the C++
161 : // world and all of their fields and methods are declared explicitly.
162 : // Internal classes (e.g. ones used for testing that are not in the default
163 : // name space) need to be defined by Torque.
164 : // TODO(danno): This is a pretty cheesy hack for now. There should be a more
165 : // robust mechanism for this, e.g. declaring classes 'extern' or something.
166 118 : if (class_type->nspace()->IsTestNamespace()) {
167 : std::string class_name{
168 1 : class_type->GetSuperClass()->GetGeneratedTNodeTypeName()};
169 1 : header_out() << " class " << class_type->name() << " : public "
170 1 : << class_name << " {\n";
171 1 : header_out() << " public:\n";
172 1 : header_out() << " DEFINE_FIELD_OFFSET_CONSTANTS(" << class_name
173 : << "::kSize, TORQUE_GENERATED_"
174 2 : << CapifyStringWithUnderscores(class_type->name())
175 1 : << "_FIELDS)\n";
176 1 : header_out() << " };\n";
177 117 : } else if (!class_type->nspace()->IsDefaultNamespace()) {
178 : ReportError(
179 : "extern classes are currently only supported in the default and test "
180 0 : "namespaces");
181 : }
182 : return;
183 : }
184 : const StructType* struct_type = StructType::DynamicCast(alias->type());
185 151 : if (!struct_type) return;
186 : const std::string& name = struct_type->name();
187 36 : header_out() << " struct " << name << " {\n";
188 66 : for (auto& field : struct_type->fields()) {
189 96 : header_out() << " " << field.name_and_type.type->GetGeneratedTypeName();
190 96 : header_out() << " " << field.name_and_type.name << ";\n";
191 : }
192 18 : header_out() << "\n std::tuple<";
193 : bool first = true;
194 91 : for (const Type* type : LowerType(struct_type)) {
195 55 : if (!first) {
196 38 : header_out() << ", ";
197 : }
198 : first = false;
199 110 : header_out() << type->GetGeneratedTypeName();
200 : }
201 18 : header_out() << "> Flatten() const {\n"
202 18 : << " return std::tuple_cat(";
203 : first = true;
204 66 : for (auto& field : struct_type->fields()) {
205 48 : if (!first) {
206 31 : header_out() << ", ";
207 : }
208 : first = false;
209 48 : if (field.name_and_type.type->IsStructType()) {
210 8 : header_out() << field.name_and_type.name << ".Flatten()";
211 : } else {
212 88 : header_out() << "std::make_tuple(" << field.name_and_type.name << ")";
213 : }
214 : }
215 18 : header_out() << ");\n";
216 18 : header_out() << " }\n";
217 18 : header_out() << " };\n";
218 : }
219 :
220 1229 : VisitResult ImplementationVisitor::InlineMacro(
221 : Macro* macro, base::Optional<LocationReference> this_reference,
222 : const std::vector<VisitResult>& arguments,
223 : const std::vector<Block*> label_blocks) {
224 1229 : CurrentScope::Scope current_scope(macro);
225 2458 : BindingsManagersScope bindings_managers_scope;
226 : CurrentCallable::Scope current_callable(macro);
227 : CurrentReturnValue::Scope current_return_value;
228 : const Signature& signature = macro->signature();
229 1229 : const Type* return_type = macro->signature().return_type;
230 1229 : bool can_return = return_type != TypeOracle::GetNeverType();
231 :
232 : BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
233 : BlockBindings<LocalLabel> label_bindings(&LabelBindingsManager::Get());
234 : DCHECK_EQ(macro->signature().parameter_names.size(),
235 : arguments.size() + (this_reference ? 1 : 0));
236 : DCHECK_EQ(this_reference.has_value(), macro->IsMethod());
237 :
238 : // Bind the this for methods. Methods that modify a struct-type "this" must
239 : // only be called if the this is in a variable, in which case the
240 : // LocalValue is non-const. Otherwise, the LocalValue used for the parameter
241 : // binding is const, and thus read-only, which will cause errors if
242 : // modified, e.g. when called by a struct method that sets the structs
243 : // fields. This prevents using temporary struct values for anything other
244 : // than read operations.
245 1229 : if (this_reference) {
246 : DCHECK(macro->IsMethod());
247 147 : LocalValue this_value = LocalValue{!this_reference->IsVariableAccess(),
248 147 : this_reference->GetVisitResult()};
249 441 : parameter_bindings.Add(kThisParameterName, this_value);
250 : }
251 :
252 : size_t i = 0;
253 3304 : for (auto arg : arguments) {
254 2075 : if (this_reference && i == signature.implicit_count) i++;
255 4150 : const Identifier* name = macro->parameter_names()[i++];
256 6225 : parameter_bindings.Add(name, LocalValue{true, arg});
257 : }
258 :
259 : DCHECK_EQ(label_blocks.size(), signature.labels.size());
260 1583 : for (size_t i = 0; i < signature.labels.size(); ++i) {
261 : const LabelDeclaration& label_info = signature.labels[i];
262 708 : label_bindings.Add(label_info.name,
263 177 : LocalLabel{label_blocks[i], label_info.types});
264 : }
265 :
266 : Block* macro_end;
267 1229 : base::Optional<Binding<LocalLabel>> macro_end_binding;
268 1229 : if (can_return) {
269 : Stack<const Type*> stack = assembler().CurrentStack();
270 1205 : std::vector<const Type*> lowered_return_types = LowerType(return_type);
271 1205 : stack.PushMany(lowered_return_types);
272 1205 : if (!return_type->IsConstexpr()) {
273 1192 : SetReturnValue(VisitResult(return_type,
274 : stack.TopRange(lowered_return_types.size())));
275 : }
276 : // The stack copy used to initialize the _macro_end block is only used
277 : // as a template for the actual gotos generated by return statements. It
278 : // doesn't correspond to any real return values, and thus shouldn't contain
279 : // top types, because these would pollute actual return value types that get
280 : // unioned with them for return statements, erroneously forcing them to top.
281 10275 : for (auto i = stack.begin(); i != stack.end(); ++i) {
282 4535 : if ((*i)->IsTopType()) {
283 44 : *i = TopType::cast(*i)->source_type();
284 : }
285 : }
286 2410 : macro_end = assembler().NewBlock(std::move(stack));
287 : macro_end_binding.emplace(&LabelBindingsManager::Get(), "_macro_end",
288 4820 : LocalLabel{macro_end, {return_type}});
289 : } else {
290 48 : SetReturnValue(VisitResult::NeverResult());
291 : }
292 :
293 2458 : const Type* result = Visit(*macro->body());
294 :
295 1229 : if (result->IsNever()) {
296 766 : if (!return_type->IsNever() && !macro->HasReturns()) {
297 0 : std::stringstream s;
298 0 : s << "macro " << macro->ReadableName()
299 0 : << " that never returns must have return type never";
300 0 : ReportError(s.str());
301 : }
302 : } else {
303 463 : if (return_type->IsNever()) {
304 0 : std::stringstream s;
305 0 : s << "macro " << macro->ReadableName()
306 : << " has implicit return at end of its declartion but return type "
307 0 : "never";
308 0 : ReportError(s.str());
309 463 : } else if (!macro->signature().return_type->IsVoid()) {
310 0 : std::stringstream s;
311 0 : s << "macro " << macro->ReadableName()
312 0 : << " expects to return a value but doesn't on all paths";
313 0 : ReportError(s.str());
314 : }
315 : }
316 1229 : if (!result->IsNever()) {
317 463 : assembler().Goto(macro_end);
318 : }
319 :
320 1229 : if (macro->HasReturns() || !result->IsNever()) {
321 1205 : assembler().Bind(macro_end);
322 : }
323 :
324 2458 : return GetAndClearReturnValue();
325 : }
326 :
327 1120 : void ImplementationVisitor::VisitMacroCommon(Macro* macro) {
328 : CurrentCallable::Scope current_callable(macro);
329 : const Signature& signature = macro->signature();
330 1120 : const Type* return_type = macro->signature().return_type;
331 1120 : bool can_return = return_type != TypeOracle::GetNeverType();
332 : bool has_return_value =
333 1120 : can_return && return_type != TypeOracle::GetVoidType();
334 :
335 1120 : header_out() << " ";
336 2240 : GenerateMacroFunctionDeclaration(header_out(), "", macro);
337 1120 : header_out() << ";\n";
338 :
339 : GenerateMacroFunctionDeclaration(
340 3360 : source_out(), CurrentNamespace()->ExternalName() + "::", macro);
341 1120 : source_out() << " {\n";
342 :
343 : Stack<std::string> lowered_parameters;
344 : Stack<const Type*> lowered_parameter_types;
345 :
346 1120 : std::vector<VisitResult> arguments;
347 :
348 1120 : base::Optional<LocationReference> this_reference;
349 1120 : if (Method* method = Method::DynamicCast(macro)) {
350 : const Type* this_type = method->aggregate_type();
351 117 : LowerParameter(this_type, ExternalParameterName(kThisParameterName),
352 39 : &lowered_parameters);
353 78 : StackRange range = lowered_parameter_types.PushMany(LowerType(this_type));
354 : VisitResult this_result = VisitResult(this_type, range);
355 : // For classes, mark 'this' as a temporary to prevent assignment to it.
356 : // Note that using a VariableAccess for non-class types is technically
357 : // incorrect because changes to the 'this' variable do not get reflected
358 : // to the caller. Therefore struct methods should always be inlined and a
359 : // C++ version should never be generated, since it would be incorrect.
360 : // However, in order to be able to type- and semantics-check even unused
361 : // struct methods, set the this_reference to be the local variable copy of
362 : // the passed-in this, which allows the visitor to at least find and report
363 : // errors.
364 135 : this_reference =
365 : (this_type->IsClassType())
366 : ? LocationReference::Temporary(this_result, "this parameter")
367 : : LocationReference::VariableAccess(this_result);
368 : }
369 :
370 5142 : for (size_t i = 0; i < macro->signature().parameter_names.size(); ++i) {
371 2050 : if (this_reference && i == macro->signature().implicit_count) continue;
372 1972 : const std::string& name = macro->parameter_names()[i]->value;
373 1972 : std::string external_name = ExternalParameterName(name);
374 1972 : const Type* type = macro->signature().types()[i];
375 :
376 1972 : if (type->IsConstexpr()) {
377 63 : arguments.push_back(VisitResult(type, external_name));
378 : } else {
379 1909 : LowerParameter(type, external_name, &lowered_parameters);
380 3818 : StackRange range = lowered_parameter_types.PushMany(LowerType(type));
381 1909 : arguments.push_back(VisitResult(type, range));
382 : }
383 : }
384 :
385 : DCHECK_EQ(lowered_parameters.Size(), lowered_parameter_types.Size());
386 3360 : assembler_ = CfgAssembler(lowered_parameter_types);
387 :
388 : std::vector<Block*> label_blocks;
389 1256 : for (const LabelDeclaration& label_info : signature.labels) {
390 : Stack<const Type*> label_input_stack;
391 162 : for (const Type* type : label_info.types) {
392 52 : label_input_stack.PushMany(LowerType(type));
393 : }
394 272 : Block* block = assembler().NewBlock(std::move(label_input_stack));
395 136 : label_blocks.push_back(block);
396 : }
397 :
398 : VisitResult return_value =
399 4480 : InlineMacro(macro, this_reference, arguments, label_blocks);
400 2240 : Block* end = assembler().NewBlock();
401 1120 : if (return_type != TypeOracle::GetNeverType()) {
402 1097 : assembler().Goto(end);
403 : }
404 :
405 1392 : for (size_t i = 0; i < label_blocks.size(); ++i) {
406 136 : Block* label_block = label_blocks[i];
407 : const LabelDeclaration& label_info = signature.labels[i];
408 136 : assembler().Bind(label_block);
409 136 : std::vector<std::string> label_parameter_variables;
410 188 : for (size_t i = 0; i < label_info.types.size(); ++i) {
411 26 : LowerLabelParameter(label_info.types[i],
412 52 : ExternalLabelParameterName(label_info.name, i),
413 26 : &label_parameter_variables);
414 : }
415 544 : assembler().Emit(GotoExternalInstruction{ExternalLabelName(label_info.name),
416 136 : label_parameter_variables});
417 : }
418 :
419 1120 : if (return_type != TypeOracle::GetNeverType()) {
420 1097 : assembler().Bind(end);
421 : }
422 :
423 1120 : CSAGenerator csa_generator{assembler().Result(), source_out()};
424 : base::Optional<Stack<std::string>> values =
425 2240 : csa_generator.EmitGraph(lowered_parameters);
426 :
427 : assembler_ = base::nullopt;
428 :
429 1120 : if (has_return_value) {
430 670 : source_out() << " return ";
431 2010 : CSAGenerator::EmitCSAValue(return_value, *values, source_out());
432 670 : source_out() << ";\n";
433 : }
434 1120 : source_out() << "}\n\n";
435 1120 : }
436 :
437 0 : void ImplementationVisitor::Visit(Macro* macro) {
438 1509 : if (macro->IsExternal()) return;
439 1081 : VisitMacroCommon(macro);
440 : }
441 :
442 0 : void ImplementationVisitor::Visit(Method* method) {
443 : DCHECK(!method->IsExternal());
444 39 : VisitMacroCommon(method);
445 0 : }
446 :
447 : namespace {
448 :
449 644 : std::string AddParameter(size_t i, Builtin* builtin,
450 : Stack<std::string>* parameters,
451 : Stack<const Type*>* parameter_types,
452 : BlockBindings<LocalValue>* parameter_bindings) {
453 644 : const Identifier* name = builtin->signature().parameter_names[i];
454 644 : const Type* type = builtin->signature().types()[i];
455 1288 : std::string external_name = "parameter" + std::to_string(i);
456 644 : parameters->Push(external_name);
457 1288 : StackRange range = parameter_types->PushMany(LowerType(type));
458 1932 : parameter_bindings->Add(name, LocalValue{true, VisitResult(type, range)});
459 644 : return external_name;
460 : }
461 :
462 : } // namespace
463 :
464 203 : void ImplementationVisitor::Visit(Builtin* builtin) {
465 425 : if (builtin->IsExternal()) return;
466 184 : CurrentScope::Scope current_scope(builtin);
467 184 : const std::string& name = builtin->ExternalName();
468 : const Signature& signature = builtin->signature();
469 184 : source_out() << "TF_BUILTIN(" << name << ", CodeStubAssembler) {\n"
470 : << " compiler::CodeAssemblerState* state_ = state();"
471 184 : << " compiler::CodeAssembler ca_(state());\n";
472 :
473 : CurrentCallable::Scope current_callable(builtin);
474 : CurrentReturnValue::Scope current_return_value;
475 :
476 : Stack<const Type*> parameter_types;
477 : Stack<std::string> parameters;
478 :
479 368 : BindingsManagersScope bindings_managers_scope;
480 :
481 : BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
482 :
483 : // Context
484 : std::string parameter0 = AddParameter(0, builtin, ¶meters,
485 184 : ¶meter_types, ¶meter_bindings);
486 184 : source_out() << " TNode<Context> " << parameter0
487 : << " = UncheckedCast<Context>(Parameter("
488 184 : << "Descriptor::kContext));\n";
489 368 : source_out() << " USE(" << parameter0 << ");\n";
490 :
491 : size_t first = 1;
492 184 : if (builtin->IsVarArgsJavaScript()) {
493 : DCHECK(signature.parameter_types.var_args);
494 77 : source_out()
495 77 : << " Node* argc = Parameter(Descriptor::kJSActualArgumentsCount);\n";
496 : std::string parameter1 = AddParameter(
497 77 : 1, builtin, ¶meters, ¶meter_types, ¶meter_bindings);
498 77 : source_out()
499 77 : << " TNode<IntPtrT> arguments_length(ChangeInt32ToIntPtr(argc));\n";
500 77 : source_out() << " TNode<RawPtrT> arguments_frame = "
501 77 : "UncheckedCast<RawPtrT>(LoadFramePointer());\n";
502 77 : source_out() << " BaseBuiltinsFromDSLAssembler::Arguments "
503 : "torque_arguments(GetFrameArguments(arguments_frame, "
504 77 : "arguments_length));\n";
505 77 : source_out() << " CodeStubArguments arguments(this, torque_arguments);\n";
506 :
507 77 : source_out() << " TNode<Object> " << parameter1
508 77 : << " = arguments.GetReceiver();\n";
509 154 : source_out() << "USE(" << parameter1 << ");\n";
510 154 : parameters.Push("torque_arguments.frame");
511 154 : parameters.Push("torque_arguments.base");
512 154 : parameters.Push("torque_arguments.length");
513 77 : const Type* arguments_type = TypeOracle::GetArgumentsType();
514 154 : StackRange range = parameter_types.PushMany(LowerType(arguments_type));
515 231 : parameter_bindings.Add(
516 : *signature.arguments_variable,
517 77 : LocalValue{true, VisitResult(arguments_type, range)});
518 :
519 : first = 2;
520 : }
521 :
522 1472 : for (size_t i = 0; i < signature.parameter_names.size(); ++i) {
523 905 : if (i < first) continue;
524 383 : const std::string& parameter_name = signature.parameter_names[i]->value;
525 383 : const Type* type = signature.types()[i];
526 : std::string var = AddParameter(i, builtin, ¶meters, ¶meter_types,
527 383 : ¶meter_bindings);
528 766 : source_out() << " " << type->GetGeneratedTypeName() << " " << var << " = "
529 766 : << "UncheckedCast<" << type->GetGeneratedTNodeTypeName()
530 : << ">(Parameter(Descriptor::k"
531 1149 : << CamelifyString(parameter_name) << "));\n";
532 766 : source_out() << " USE(" << var << ");\n";
533 : }
534 :
535 552 : assembler_ = CfgAssembler(parameter_types);
536 368 : const Type* body_result = Visit(*builtin->body());
537 184 : if (body_result != TypeOracle::GetNeverType()) {
538 0 : ReportError("control reaches end of builtin, expected return of a value");
539 : }
540 184 : CSAGenerator csa_generator{assembler().Result(), source_out(),
541 184 : builtin->kind()};
542 552 : csa_generator.EmitGraph(parameters);
543 : assembler_ = base::nullopt;
544 184 : source_out() << "}\n\n";
545 : }
546 :
547 0 : const Type* ImplementationVisitor::Visit(VarDeclarationStatement* stmt) {
548 : BlockBindings<LocalValue> block_bindings(&ValueBindingsManager::Get());
549 0 : return Visit(stmt, &block_bindings);
550 : }
551 :
552 1368 : const Type* ImplementationVisitor::Visit(
553 : VarDeclarationStatement* stmt, BlockBindings<LocalValue>* block_bindings) {
554 : // const qualified variables are required to be initialized properly.
555 1368 : if (stmt->const_qualified && !stmt->initializer) {
556 0 : ReportError("local constant \"", stmt->name, "\" is not initialized.");
557 : }
558 :
559 : base::Optional<const Type*> type;
560 1368 : if (stmt->type) {
561 1025 : type = Declarations::GetType(*stmt->type);
562 1025 : if ((*type)->IsConstexpr() && !stmt->const_qualified) {
563 : ReportError(
564 0 : "cannot declare variable with constexpr type. Use 'const' instead.");
565 : }
566 : }
567 1368 : base::Optional<VisitResult> init_result;
568 1368 : if (stmt->initializer) {
569 : StackScope scope(this);
570 2678 : init_result = Visit(*stmt->initializer);
571 1339 : if (type) {
572 2988 : init_result = GenerateImplicitConvert(*type, *init_result);
573 : }
574 4017 : init_result = scope.Yield(*init_result);
575 : } else {
576 : DCHECK(type.has_value());
577 29 : if ((*type)->IsConstexpr()) {
578 0 : ReportError("constexpr variables need an initializer");
579 : }
580 29 : TypeVector lowered_types = LowerType(*type);
581 61 : for (const Type* type : lowered_types) {
582 128 : assembler().Emit(PushUninitializedInstruction{TypeOracle::GetTopType(
583 128 : "uninitialized variable '" + stmt->name->value + "' of type " +
584 160 : type->ToString() + " originally defined at " +
585 64 : PositionAsString(stmt->pos),
586 32 : type)});
587 : }
588 29 : init_result =
589 : VisitResult(*type, assembler().TopRange(lowered_types.size()));
590 : }
591 4104 : block_bindings->Add(stmt->name,
592 2736 : LocalValue{stmt->const_qualified, *init_result});
593 2736 : return TypeOracle::GetVoidType();
594 : }
595 :
596 2 : const Type* ImplementationVisitor::Visit(TailCallStatement* stmt) {
597 4 : return Visit(stmt->call, true).type();
598 : }
599 :
600 102 : VisitResult ImplementationVisitor::Visit(ConditionalExpression* expr) {
601 204 : Block* true_block = assembler().NewBlock(assembler().CurrentStack());
602 204 : Block* false_block = assembler().NewBlock(assembler().CurrentStack());
603 204 : Block* done_block = assembler().NewBlock();
604 204 : Block* true_conversion_block = assembler().NewBlock();
605 102 : GenerateExpressionBranch(expr->condition, true_block, false_block);
606 :
607 102 : VisitResult left;
608 102 : VisitResult right;
609 :
610 : {
611 : // The code for both paths of the conditional need to be generated first
612 : // before evaluating the conditional expression because the common type of
613 : // the result of both the true and false of the condition needs to be known
614 : // to convert both branches to a common type.
615 102 : assembler().Bind(true_block);
616 : StackScope left_scope(this);
617 204 : left = Visit(expr->if_true);
618 102 : assembler().Goto(true_conversion_block);
619 :
620 : const Type* common_type;
621 : {
622 102 : assembler().Bind(false_block);
623 : StackScope right_scope(this);
624 204 : right = Visit(expr->if_false);
625 102 : common_type = GetCommonType(left.type(), right.type());
626 408 : right = right_scope.Yield(GenerateImplicitConvert(common_type, right));
627 102 : assembler().Goto(done_block);
628 : }
629 :
630 102 : assembler().Bind(true_conversion_block);
631 408 : left = left_scope.Yield(GenerateImplicitConvert(common_type, left));
632 102 : assembler().Goto(done_block);
633 : }
634 :
635 102 : assembler().Bind(done_block);
636 102 : CHECK_EQ(left, right);
637 102 : return left;
638 : }
639 :
640 33 : VisitResult ImplementationVisitor::Visit(LogicalOrExpression* expr) {
641 33 : VisitResult left_result;
642 : {
643 66 : Block* false_block = assembler().NewBlock(assembler().CurrentStack());
644 : Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
645 165 : kFalseLabelName, LocalLabel{false_block}};
646 66 : left_result = Visit(expr->left);
647 33 : if (left_result.type()->IsBool()) {
648 38 : Block* true_block = LookupSimpleLabel(kTrueLabelName);
649 19 : assembler().Branch(true_block, false_block);
650 19 : assembler().Bind(false_block);
651 14 : } else if (left_result.type()->IsNever()) {
652 7 : assembler().Bind(false_block);
653 7 : } else if (!left_result.type()->IsConstexprBool()) {
654 : ReportError(
655 : "expected type bool, constexpr bool, or never on left-hand side of "
656 0 : "operator ||");
657 : }
658 : }
659 :
660 33 : if (left_result.type()->IsConstexprBool()) {
661 7 : VisitResult right_result = Visit(expr->right);
662 7 : if (!right_result.type()->IsConstexprBool()) {
663 : ReportError(
664 : "expected type constexpr bool on right-hand side of operator "
665 0 : "||");
666 : }
667 : return VisitResult(TypeOracle::GetConstexprBoolType(),
668 28 : std::string("(") + left_result.constexpr_value() +
669 21 : " || " + right_result.constexpr_value() + ")");
670 : }
671 :
672 26 : VisitResult right_result = Visit(expr->right);
673 26 : if (right_result.type()->IsBool()) {
674 42 : Block* true_block = LookupSimpleLabel(kTrueLabelName);
675 42 : Block* false_block = LookupSimpleLabel(kFalseLabelName);
676 21 : assembler().Branch(true_block, false_block);
677 21 : return VisitResult::NeverResult();
678 5 : } else if (!right_result.type()->IsNever()) {
679 : ReportError(
680 0 : "expected type bool or never on right-hand side of operator ||");
681 : }
682 5 : return right_result;
683 : }
684 :
685 24 : VisitResult ImplementationVisitor::Visit(LogicalAndExpression* expr) {
686 24 : VisitResult left_result;
687 : {
688 48 : Block* true_block = assembler().NewBlock(assembler().CurrentStack());
689 : Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
690 120 : kTrueLabelName, LocalLabel{true_block}};
691 48 : left_result = Visit(expr->left);
692 24 : if (left_result.type()->IsBool()) {
693 36 : Block* false_block = LookupSimpleLabel(kFalseLabelName);
694 18 : assembler().Branch(true_block, false_block);
695 18 : assembler().Bind(true_block);
696 6 : } else if (left_result.type()->IsNever()) {
697 6 : assembler().Bind(true_block);
698 0 : } else if (!left_result.type()->IsConstexprBool()) {
699 : ReportError(
700 : "expected type bool, constexpr bool, or never on left-hand side of "
701 0 : "operator &&");
702 : }
703 : }
704 :
705 24 : if (left_result.type()->IsConstexprBool()) {
706 0 : VisitResult right_result = Visit(expr->right);
707 0 : if (!right_result.type()->IsConstexprBool()) {
708 : ReportError(
709 : "expected type constexpr bool on right-hand side of operator "
710 0 : "&&");
711 : }
712 : return VisitResult(TypeOracle::GetConstexprBoolType(),
713 0 : std::string("(") + left_result.constexpr_value() +
714 0 : " && " + right_result.constexpr_value() + ")");
715 : }
716 :
717 24 : VisitResult right_result = Visit(expr->right);
718 24 : if (right_result.type()->IsBool()) {
719 38 : Block* true_block = LookupSimpleLabel(kTrueLabelName);
720 38 : Block* false_block = LookupSimpleLabel(kFalseLabelName);
721 19 : assembler().Branch(true_block, false_block);
722 19 : return VisitResult::NeverResult();
723 5 : } else if (!right_result.type()->IsNever()) {
724 : ReportError(
725 0 : "expected type bool or never on right-hand side of operator &&");
726 : }
727 5 : return right_result;
728 : }
729 :
730 160 : VisitResult ImplementationVisitor::Visit(IncrementDecrementExpression* expr) {
731 : StackScope scope(this);
732 320 : LocationReference location_ref = GetLocationReference(expr->location);
733 160 : VisitResult current_value = GenerateFetchFromLocation(location_ref);
734 320 : VisitResult one = {TypeOracle::GetConstInt31Type(), "1"};
735 160 : Arguments args;
736 320 : args.parameters = {current_value, one};
737 : VisitResult assignment_value = GenerateCall(
738 480 : expr->op == IncrementDecrementOperator::kIncrement ? "+" : "-", args);
739 160 : GenerateAssignToLocation(location_ref, assignment_value);
740 640 : return scope.Yield(expr->postfix ? current_value : assignment_value);
741 : }
742 :
743 807 : VisitResult ImplementationVisitor::Visit(AssignmentExpression* expr) {
744 : StackScope scope(this);
745 1614 : LocationReference location_ref = GetLocationReference(expr->location);
746 807 : VisitResult assignment_value;
747 807 : if (expr->op) {
748 11 : VisitResult location_value = GenerateFetchFromLocation(location_ref);
749 22 : assignment_value = Visit(expr->value);
750 11 : Arguments args;
751 22 : args.parameters = {location_value, assignment_value};
752 55 : assignment_value = GenerateCall(*expr->op, args);
753 11 : GenerateAssignToLocation(location_ref, assignment_value);
754 : } else {
755 1592 : assignment_value = Visit(expr->value);
756 796 : GenerateAssignToLocation(location_ref, assignment_value);
757 : }
758 2421 : return scope.Yield(assignment_value);
759 : }
760 :
761 939 : VisitResult ImplementationVisitor::Visit(NumberLiteralExpression* expr) {
762 : // TODO(tebbi): Do not silently loose precision; support 64bit literals.
763 1878 : double d = std::stod(expr->number.c_str());
764 939 : int32_t i = static_cast<int32_t>(d);
765 1878 : const Type* result_type = Declarations::LookupType(CONST_FLOAT64_TYPE_STRING);
766 939 : if (i == d) {
767 934 : if ((i >> 30) == (i >> 31)) {
768 1864 : result_type = Declarations::LookupType(CONST_INT31_TYPE_STRING);
769 : } else {
770 4 : result_type = Declarations::LookupType(CONST_INT32_TYPE_STRING);
771 : }
772 : }
773 939 : return VisitResult{result_type, expr->number};
774 : }
775 :
776 42 : VisitResult ImplementationVisitor::Visit(AssumeTypeImpossibleExpression* expr) {
777 42 : VisitResult result = Visit(expr->expression);
778 : const Type* result_type =
779 42 : SubtractType(result.type(), Declarations::GetType(expr->excluded_type));
780 42 : if (result_type->IsNever()) {
781 0 : ReportError("unreachable code");
782 : }
783 126 : CHECK_EQ(LowerType(result_type), TypeVector{result_type});
784 168 : assembler().Emit(UnsafeCastInstruction{result_type});
785 : result.SetType(result_type);
786 42 : return result;
787 : }
788 :
789 107 : VisitResult ImplementationVisitor::Visit(StringLiteralExpression* expr) {
790 : return VisitResult{
791 : TypeOracle::GetConstStringType(),
792 428 : "\"" + expr->literal.substr(1, expr->literal.size() - 2) + "\""};
793 : }
794 :
795 74 : VisitResult ImplementationVisitor::GetBuiltinCode(Builtin* builtin) {
796 74 : if (builtin->IsExternal() || builtin->kind() != Builtin::kStub) {
797 : ReportError(
798 : "creating function pointers is only allowed for internal builtins with "
799 0 : "stub linkage");
800 : }
801 148 : const Type* type = TypeOracle::GetBuiltinPointerType(
802 : builtin->signature().parameter_types.types,
803 148 : builtin->signature().return_type);
804 296 : assembler().Emit(
805 74 : PushBuiltinPointerInstruction{builtin->ExternalName(), type});
806 74 : return VisitResult(type, assembler().TopRange(1));
807 : }
808 :
809 7203 : VisitResult ImplementationVisitor::Visit(LocationExpression* expr) {
810 : StackScope scope(this);
811 21609 : return scope.Yield(GenerateFetchFromLocation(GetLocationReference(expr)));
812 : }
813 :
814 237 : const Type* ImplementationVisitor::Visit(GotoStatement* stmt) {
815 237 : LocalLabel* label = LookupLabel(stmt->label);
816 237 : size_t parameter_count = label->parameter_types.size();
817 237 : if (stmt->arguments.size() != parameter_count) {
818 0 : ReportError("goto to label has incorrect number of parameters (expected ",
819 0 : parameter_count, " found ", stmt->arguments.size(), ")");
820 : }
821 :
822 : size_t i = 0;
823 : StackRange arguments = assembler().TopRange(0);
824 315 : for (Expression* e : stmt->arguments) {
825 : StackScope scope(this);
826 78 : VisitResult result = Visit(e);
827 156 : const Type* parameter_type = label->parameter_types[i++];
828 234 : result = GenerateImplicitConvert(parameter_type, result);
829 234 : arguments.Extend(scope.Yield(result).stack_range());
830 : }
831 :
832 474 : assembler().Goto(label->block, arguments.Size());
833 237 : return TypeOracle::GetNeverType();
834 : }
835 :
836 598 : const Type* ImplementationVisitor::Visit(IfStatement* stmt) {
837 : bool has_else = stmt->if_false.has_value();
838 :
839 598 : if (stmt->is_constexpr) {
840 53 : VisitResult expression_result = Visit(stmt->condition);
841 :
842 53 : if (!(expression_result.type() == TypeOracle::GetConstexprBoolType())) {
843 0 : std::stringstream stream;
844 : stream << "expression should return type constexpr bool "
845 0 : << "but returns type " << *expression_result.type();
846 0 : ReportError(stream.str());
847 : }
848 :
849 106 : Block* true_block = assembler().NewBlock();
850 106 : Block* false_block = assembler().NewBlock();
851 106 : Block* done_block = assembler().NewBlock();
852 :
853 212 : assembler().Emit(ConstexprBranchInstruction{
854 53 : expression_result.constexpr_value(), true_block, false_block});
855 :
856 53 : assembler().Bind(true_block);
857 53 : const Type* left_result = Visit(stmt->if_true);
858 53 : if (left_result == TypeOracle::GetVoidType()) {
859 14 : assembler().Goto(done_block);
860 : }
861 :
862 53 : assembler().Bind(false_block);
863 53 : const Type* right_result = TypeOracle::GetVoidType();
864 53 : if (has_else) {
865 49 : right_result = Visit(*stmt->if_false);
866 : }
867 53 : if (right_result == TypeOracle::GetVoidType()) {
868 14 : assembler().Goto(done_block);
869 : }
870 :
871 53 : if (left_result->IsNever() != right_result->IsNever()) {
872 0 : std::stringstream stream;
873 : stream << "either both or neither branches in a constexpr if statement "
874 : "must reach their end at"
875 0 : << PositionAsString(stmt->pos);
876 0 : ReportError(stream.str());
877 : }
878 :
879 53 : if (left_result != TypeOracle::GetNeverType()) {
880 14 : assembler().Bind(done_block);
881 : }
882 : return left_result;
883 : } else {
884 1090 : Block* true_block = assembler().NewBlock(assembler().CurrentStack(),
885 1090 : IsDeferred(stmt->if_true));
886 : Block* false_block =
887 1090 : assembler().NewBlock(assembler().CurrentStack(),
888 1236 : stmt->if_false && IsDeferred(*stmt->if_false));
889 545 : GenerateExpressionBranch(stmt->condition, true_block, false_block);
890 :
891 : Block* done_block;
892 : bool live = false;
893 545 : if (has_else) {
894 292 : done_block = assembler().NewBlock();
895 : } else {
896 : done_block = false_block;
897 : live = true;
898 : }
899 :
900 545 : assembler().Bind(true_block);
901 : {
902 545 : const Type* result = Visit(stmt->if_true);
903 545 : if (result == TypeOracle::GetVoidType()) {
904 : live = true;
905 204 : assembler().Goto(done_block);
906 : }
907 : }
908 :
909 545 : if (has_else) {
910 146 : assembler().Bind(false_block);
911 146 : const Type* result = Visit(*stmt->if_false);
912 146 : if (result == TypeOracle::GetVoidType()) {
913 : live = true;
914 107 : assembler().Goto(done_block);
915 : }
916 : }
917 :
918 545 : if (live) {
919 513 : assembler().Bind(done_block);
920 : }
921 545 : return live ? TypeOracle::GetVoidType() : TypeOracle::GetNeverType();
922 : }
923 : }
924 :
925 43 : const Type* ImplementationVisitor::Visit(WhileStatement* stmt) {
926 86 : Block* body_block = assembler().NewBlock(assembler().CurrentStack());
927 86 : Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
928 :
929 86 : Block* header_block = assembler().NewBlock();
930 43 : assembler().Goto(header_block);
931 :
932 43 : assembler().Bind(header_block);
933 43 : GenerateExpressionBranch(stmt->condition, body_block, exit_block);
934 :
935 43 : assembler().Bind(body_block);
936 : {
937 43 : BreakContinueActivator activator{exit_block, header_block};
938 43 : const Type* body_result = Visit(stmt->body);
939 43 : if (body_result != TypeOracle::GetNeverType()) {
940 43 : assembler().Goto(header_block);
941 : }
942 : }
943 :
944 43 : assembler().Bind(exit_block);
945 43 : return TypeOracle::GetVoidType();
946 : }
947 :
948 1804 : const Type* ImplementationVisitor::Visit(BlockStatement* block) {
949 : BlockBindings<LocalValue> block_bindings(&ValueBindingsManager::Get());
950 1804 : const Type* type = TypeOracle::GetVoidType();
951 6051 : for (Statement* s : block->statements) {
952 4247 : CurrentSourcePosition::Scope source_position(s->pos);
953 4247 : if (type->IsNever()) {
954 0 : ReportError("statement after non-returning statement");
955 : }
956 4247 : if (auto* var_declaration = VarDeclarationStatement::DynamicCast(s)) {
957 1322 : type = Visit(var_declaration, &block_bindings);
958 : } else {
959 2925 : type = Visit(s);
960 : }
961 : }
962 1804 : return type;
963 : }
964 :
965 125 : const Type* ImplementationVisitor::Visit(DebugStatement* stmt) {
966 : #if defined(DEBUG)
967 : assembler().Emit(PrintConstantStringInstruction{"halting because of '" +
968 : stmt->reason + "' at " +
969 : PositionAsString(stmt->pos)});
970 : #endif
971 500 : assembler().Emit(AbortInstruction{stmt->never_continues
972 : ? AbortInstruction::Kind::kUnreachable
973 125 : : AbortInstruction::Kind::kDebugBreak});
974 125 : if (stmt->never_continues) {
975 125 : return TypeOracle::GetNeverType();
976 : } else {
977 0 : return TypeOracle::GetVoidType();
978 : }
979 : }
980 :
981 : namespace {
982 :
983 111 : std::string FormatAssertSource(const std::string& str) {
984 : // Replace all whitespace characters with a space character.
985 : std::string str_no_newlines = str;
986 : std::replace_if(str_no_newlines.begin(), str_no_newlines.end(),
987 3251 : [](unsigned char c) { return isspace(c); }, ' ');
988 :
989 : // str might include indentation, squash multiple space characters into one.
990 : std::string result;
991 : std::unique_copy(str_no_newlines.begin(), str_no_newlines.end(),
992 : std::back_inserter(result),
993 3140 : [](char a, char b) { return a == ' ' && b == ' '; });
994 111 : return result;
995 : }
996 :
997 : } // namespace
998 :
999 291 : const Type* ImplementationVisitor::Visit(AssertStatement* stmt) {
1000 291 : bool do_check = !stmt->debug_only;
1001 : #if defined(DEBUG)
1002 : do_check = true;
1003 : #endif
1004 291 : if (do_check) {
1005 : // CSA_ASSERT & co. are not used here on purpose for two reasons. First,
1006 : // Torque allows and handles two types of expressions in the if protocol
1007 : // automagically, ones that return TNode<BoolT> and those that use the
1008 : // BranchIf(..., Label* true, Label* false) idiom. Because the machinery to
1009 : // handle this is embedded in the expression handling and to it's not
1010 : // possible to make the decision to use CSA_ASSERT or CSA_ASSERT_BRANCH
1011 : // isn't trivial up-front. Secondly, on failure, the assert text should be
1012 : // the corresponding Torque code, not the -gen.cc code, which would be the
1013 : // case when using CSA_ASSERT_XXX.
1014 222 : Block* true_block = assembler().NewBlock(assembler().CurrentStack());
1015 222 : Block* false_block = assembler().NewBlock(assembler().CurrentStack(), true);
1016 111 : GenerateExpressionBranch(stmt->expression, true_block, false_block);
1017 :
1018 111 : assembler().Bind(false_block);
1019 :
1020 333 : assembler().Emit(AbortInstruction{
1021 : AbortInstruction::Kind::kAssertionFailure,
1022 555 : "Torque assert '" + FormatAssertSource(stmt->source) + "' failed"});
1023 :
1024 111 : assembler().Bind(true_block);
1025 : }
1026 291 : return TypeOracle::GetVoidType();
1027 : }
1028 :
1029 1515 : const Type* ImplementationVisitor::Visit(ExpressionStatement* stmt) {
1030 3030 : const Type* type = Visit(stmt->expression).type();
1031 1515 : return type->IsNever() ? type : TypeOracle::GetVoidType();
1032 : }
1033 :
1034 1116 : const Type* ImplementationVisitor::Visit(ReturnStatement* stmt) {
1035 1116 : Callable* current_callable = CurrentCallable::Get();
1036 1116 : if (current_callable->signature().return_type->IsNever()) {
1037 0 : std::stringstream s;
1038 0 : s << "cannot return from a function with return type never";
1039 0 : ReportError(s.str());
1040 : }
1041 : LocalLabel* end =
1042 1989 : current_callable->IsMacro() ? LookupLabel("_macro_end") : nullptr;
1043 1116 : if (current_callable->HasReturnValue()) {
1044 1108 : if (!stmt->value) {
1045 0 : std::stringstream s;
1046 : s << "return expression needs to be specified for a return type of "
1047 0 : << *current_callable->signature().return_type;
1048 0 : ReportError(s.str());
1049 : }
1050 1108 : VisitResult expression_result = Visit(*stmt->value);
1051 : VisitResult return_result = GenerateImplicitConvert(
1052 2216 : current_callable->signature().return_type, expression_result);
1053 1108 : if (current_callable->IsMacro()) {
1054 865 : if (return_result.IsOnStack()) {
1055 : StackRange return_value_range =
1056 852 : GenerateLabelGoto(end, return_result.stack_range());
1057 852 : SetReturnValue(VisitResult(return_result.type(), return_value_range));
1058 : } else {
1059 : GenerateLabelGoto(end);
1060 13 : SetReturnValue(return_result);
1061 : }
1062 243 : } else if (current_callable->IsBuiltin()) {
1063 1215 : assembler().Emit(ReturnInstruction{});
1064 : } else {
1065 0 : UNREACHABLE();
1066 : }
1067 : } else {
1068 8 : if (stmt->value) {
1069 0 : std::stringstream s;
1070 : s << "return expression can't be specified for a void or never return "
1071 0 : "type";
1072 0 : ReportError(s.str());
1073 : }
1074 : GenerateLabelGoto(end);
1075 : }
1076 : current_callable->IncrementReturns();
1077 1116 : return TypeOracle::GetNeverType();
1078 : }
1079 :
1080 0 : const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
1081 0 : VisitResult expression_result = Visit(stmt->iterable);
1082 : VisitResult begin = stmt->begin
1083 : ? Visit(*stmt->begin)
1084 0 : : VisitResult(TypeOracle::GetConstInt31Type(), "0");
1085 :
1086 : VisitResult end = stmt->end
1087 : ? Visit(*stmt->end)
1088 0 : : GenerateCall(".length", {{expression_result}, {}});
1089 :
1090 0 : const Type* common_type = GetCommonType(begin.type(), end.type());
1091 0 : VisitResult index = GenerateImplicitConvert(common_type, begin);
1092 :
1093 0 : Block* body_block = assembler().NewBlock();
1094 0 : Block* increment_block = assembler().NewBlock(assembler().CurrentStack());
1095 0 : Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
1096 :
1097 0 : Block* header_block = assembler().NewBlock();
1098 :
1099 0 : assembler().Goto(header_block);
1100 :
1101 0 : assembler().Bind(header_block);
1102 :
1103 0 : BreakContinueActivator activator(exit_block, increment_block);
1104 :
1105 : {
1106 : StackScope comparison_scope(this);
1107 0 : VisitResult result = GenerateCall("<", {{index, end}, {}});
1108 0 : if (result.type() != TypeOracle::GetBoolType()) {
1109 : ReportError("operator < with arguments(", *index.type(), ", ",
1110 : *end.type(),
1111 : ") used in for-of loop has to return type bool, but "
1112 : "returned type ",
1113 0 : *result.type());
1114 : }
1115 0 : comparison_scope.Yield(result);
1116 : }
1117 0 : assembler().Branch(body_block, exit_block);
1118 :
1119 0 : assembler().Bind(body_block);
1120 : {
1121 0 : VisitResult element_result;
1122 : {
1123 : StackScope element_scope(this);
1124 0 : VisitResult result = GenerateCall("[]", {{expression_result, index}, {}});
1125 0 : if (stmt->var_declaration->type) {
1126 : const Type* declared_type =
1127 0 : Declarations::GetType(*stmt->var_declaration->type);
1128 0 : result = GenerateImplicitConvert(declared_type, result);
1129 : }
1130 0 : element_result = element_scope.Yield(result);
1131 : }
1132 : Binding<LocalValue> element_var_binding{&ValueBindingsManager::Get(),
1133 0 : stmt->var_declaration->name->value,
1134 0 : LocalValue{true, element_result}};
1135 0 : Visit(stmt->body);
1136 : }
1137 0 : assembler().Goto(increment_block);
1138 :
1139 0 : assembler().Bind(increment_block);
1140 : {
1141 0 : Arguments increment_args;
1142 0 : increment_args.parameters = {index, {TypeOracle::GetConstInt31Type(), "1"}};
1143 0 : VisitResult increment_result = GenerateCall("+", increment_args);
1144 :
1145 0 : GenerateAssignToLocation(LocationReference::VariableAccess(index),
1146 0 : increment_result);
1147 : }
1148 :
1149 0 : assembler().Goto(header_block);
1150 :
1151 0 : assembler().Bind(exit_block);
1152 0 : return TypeOracle::GetVoidType();
1153 : }
1154 :
1155 25 : VisitResult ImplementationVisitor::TemporaryUninitializedStruct(
1156 : const StructType* struct_type, const std::string& reason) {
1157 : StackRange range = assembler().TopRange(0);
1158 91 : for (const Field& f : struct_type->fields()) {
1159 66 : if (const StructType* struct_type =
1160 66 : StructType::DynamicCast(f.name_and_type.type)) {
1161 : range.Extend(
1162 8 : TemporaryUninitializedStruct(struct_type, reason).stack_range());
1163 : } else {
1164 186 : std::string descriptor = "uninitialized field '" + f.name_and_type.name +
1165 310 : "' declared at " + PositionAsString(f.pos) +
1166 124 : " (" + reason + ")";
1167 62 : TypeVector lowered_types = LowerType(f.name_and_type.type);
1168 124 : for (const Type* type : lowered_types) {
1169 186 : assembler().Emit(PushUninitializedInstruction{
1170 186 : TypeOracle::GetTopType(descriptor, type)});
1171 : }
1172 : range.Extend(assembler().TopRange(lowered_types.size()));
1173 : }
1174 : }
1175 25 : return VisitResult(struct_type, range);
1176 : }
1177 :
1178 356 : VisitResult ImplementationVisitor::Visit(TryLabelExpression* expr) {
1179 356 : size_t parameter_count = expr->label_block->parameters.names.size();
1180 356 : std::vector<VisitResult> parameters;
1181 :
1182 : Block* label_block = nullptr;
1183 712 : Block* done_block = assembler().NewBlock();
1184 356 : VisitResult try_result;
1185 :
1186 : {
1187 356 : CurrentSourcePosition::Scope source_position(expr->label_block->pos);
1188 356 : if (expr->label_block->parameters.has_varargs) {
1189 0 : ReportError("cannot use ... for label parameters");
1190 : }
1191 : Stack<const Type*> label_input_stack = assembler().CurrentStack();
1192 : TypeVector parameter_types;
1193 424 : for (size_t i = 0; i < parameter_count; ++i) {
1194 : const Type* type =
1195 68 : Declarations::GetType(expr->label_block->parameters.types[i]);
1196 34 : parameter_types.push_back(type);
1197 34 : if (type->IsConstexpr()) {
1198 0 : ReportError("no constexpr type allowed for label arguments");
1199 : }
1200 68 : StackRange range = label_input_stack.PushMany(LowerType(type));
1201 68 : parameters.push_back(VisitResult(type, range));
1202 : }
1203 712 : label_block = assembler().NewBlock(label_input_stack,
1204 712 : IsDeferred(expr->label_block->body));
1205 :
1206 : Binding<LocalLabel> label_binding{&LabelBindingsManager::Get(),
1207 356 : expr->label_block->label,
1208 1780 : LocalLabel{label_block, parameter_types}};
1209 :
1210 : // Visit try
1211 : StackScope stack_scope(this);
1212 712 : try_result = Visit(expr->try_expression);
1213 356 : if (try_result.type() != TypeOracle::GetNeverType()) {
1214 672 : try_result = stack_scope.Yield(try_result);
1215 224 : assembler().Goto(done_block);
1216 : }
1217 : }
1218 :
1219 : // Visit and output the code for the label block. If the label block falls
1220 : // through, then the try must not return a value. Also, if the try doesn't
1221 : // fall through, but the label does, then overall the try-label block
1222 : // returns type void.
1223 356 : assembler().Bind(label_block);
1224 : const Type* label_result;
1225 : {
1226 : BlockBindings<LocalValue> parameter_bindings(&ValueBindingsManager::Get());
1227 424 : for (size_t i = 0; i < parameter_count; ++i) {
1228 136 : parameter_bindings.Add(expr->label_block->parameters.names[i],
1229 34 : LocalValue{true, parameters[i]});
1230 : }
1231 :
1232 356 : label_result = Visit(expr->label_block->body);
1233 : }
1234 356 : if (!try_result.type()->IsVoidOrNever() && label_result->IsVoid()) {
1235 : ReportError(
1236 0 : "otherwise clauses cannot fall through in a non-void expression");
1237 : }
1238 356 : if (label_result != TypeOracle::GetNeverType()) {
1239 58 : assembler().Goto(done_block);
1240 : }
1241 356 : if (label_result->IsVoid() && try_result.type()->IsNever()) {
1242 26 : try_result =
1243 13 : VisitResult(TypeOracle::GetVoidType(), try_result.stack_range());
1244 : }
1245 :
1246 356 : if (!try_result.type()->IsNever()) {
1247 237 : assembler().Bind(done_block);
1248 : }
1249 356 : return try_result;
1250 : }
1251 :
1252 189 : VisitResult ImplementationVisitor::Visit(StatementExpression* expr) {
1253 378 : return VisitResult{Visit(expr->statement), assembler().TopRange(0)};
1254 : }
1255 :
1256 33 : InitializerResults ImplementationVisitor::VisitInitializerResults(
1257 : const AggregateType* current_aggregate,
1258 : const std::vector<NameAndExpression>& initializers) {
1259 : InitializerResults result;
1260 139 : for (const NameAndExpression& initializer : initializers) {
1261 106 : result.names.push_back(initializer.name);
1262 106 : Expression* e = initializer.expression;
1263 : const Field& field =
1264 106 : current_aggregate->LookupField(initializer.name->value);
1265 106 : auto field_index = field.index;
1266 106 : if (SpreadExpression* s = SpreadExpression::DynamicCast(e)) {
1267 2 : if (!field_index) {
1268 0 : ReportError(
1269 : "spread expressions can only be used to initialize indexed class "
1270 : "fields ('",
1271 0 : initializer.name->value, "' is not)");
1272 : }
1273 2 : e = s->spreadee;
1274 104 : } else if (field_index) {
1275 0 : ReportError("the indexed class field '", initializer.name->value,
1276 0 : "' must be initialized with a spread operator");
1277 : }
1278 212 : result.field_value_map[field.name_and_type.name] = Visit(e);
1279 : }
1280 33 : return result;
1281 : }
1282 :
1283 55 : size_t ImplementationVisitor::InitializeAggregateHelper(
1284 : const AggregateType* aggregate_type, VisitResult allocate_result,
1285 : const InitializerResults& initializer_results) {
1286 : const ClassType* current_class = ClassType::DynamicCast(aggregate_type);
1287 : size_t current = 0;
1288 55 : if (current_class) {
1289 : const ClassType* super = current_class->GetSuperClass();
1290 34 : if (super) {
1291 22 : current = InitializeAggregateHelper(super, allocate_result,
1292 22 : initializer_results);
1293 : }
1294 : }
1295 :
1296 161 : for (Field f : aggregate_type->fields()) {
1297 106 : if (current == initializer_results.field_value_map.size()) {
1298 : ReportError("insufficient number of initializers for ",
1299 0 : aggregate_type->name());
1300 : }
1301 : VisitResult current_value =
1302 106 : initializer_results.field_value_map.at(f.name_and_type.name);
1303 106 : Identifier* fieldname = initializer_results.names[current];
1304 212 : if (fieldname->value != f.name_and_type.name) {
1305 0 : CurrentSourcePosition::Scope scope(fieldname->pos);
1306 : ReportError("Expected fieldname \"", f.name_and_type.name,
1307 0 : "\" instead of \"", fieldname->value, "\"");
1308 : }
1309 106 : if (aggregate_type->IsClassType()) {
1310 51 : if (f.index) {
1311 4 : InitializeFieldFromSpread(allocate_result, f, initializer_results);
1312 : } else {
1313 : allocate_result.SetType(aggregate_type);
1314 98 : GenerateCopy(allocate_result);
1315 196 : assembler().Emit(CreateFieldReferenceInstruction{
1316 49 : ClassType::cast(aggregate_type), f.name_and_type.name});
1317 : VisitResult heap_reference(
1318 49 : TypeOracle::GetReferenceType(f.name_and_type.type),
1319 : assembler().TopRange(2));
1320 : GenerateAssignToLocation(
1321 98 : LocationReference::HeapReference(heap_reference), current_value);
1322 : }
1323 : } else {
1324 : LocationReference struct_field_ref = LocationReference::VariableAccess(
1325 220 : ProjectStructField(allocate_result, f.name_and_type.name));
1326 55 : GenerateAssignToLocation(struct_field_ref, current_value);
1327 : }
1328 106 : ++current;
1329 : }
1330 55 : return current;
1331 : }
1332 :
1333 2 : void ImplementationVisitor::InitializeFieldFromSpread(
1334 : VisitResult object, const Field& field,
1335 : const InitializerResults& initializer_results) {
1336 : StackScope stack_scope(this);
1337 :
1338 4 : VisitResult zero(TypeOracle::GetConstInt31Type(), "0");
1339 2 : const Type* index_type = (*field.index)->name_and_type.type;
1340 4 : VisitResult index = GenerateImplicitConvert(index_type, zero);
1341 4 : Block* post_exit_block = assembler().NewBlock(assembler().CurrentStack());
1342 4 : Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
1343 4 : Block* body_block = assembler().NewBlock(assembler().CurrentStack());
1344 4 : Block* fail_block = assembler().NewBlock(assembler().CurrentStack(), true);
1345 4 : Block* header_block = assembler().NewBlock(assembler().CurrentStack());
1346 :
1347 2 : assembler().Goto(header_block);
1348 :
1349 2 : assembler().Bind(header_block);
1350 2 : Arguments compare_arguments;
1351 2 : compare_arguments.parameters.push_back(index);
1352 : compare_arguments.parameters.push_back(initializer_results.field_value_map.at(
1353 2 : (*field.index)->name_and_type.name));
1354 2 : GenerateExpressionBranch(
1355 8 : [&]() { return GenerateCall("<", compare_arguments); }, body_block,
1356 2 : exit_block);
1357 :
1358 2 : assembler().Bind(body_block);
1359 : {
1360 : VisitResult spreadee =
1361 2 : initializer_results.field_value_map.at(field.name_and_type.name);
1362 4 : LocationReference target = LocationReference::VariableAccess(spreadee);
1363 : Binding<LocalLabel> no_more{&LabelBindingsManager::Get(), "_Done",
1364 10 : LocalLabel{fail_block}};
1365 :
1366 : // Call the Next() method of the iterator
1367 2 : Arguments next_arguments;
1368 4 : next_arguments.labels.push_back(&no_more);
1369 6 : Callable* callable = LookupMethod("Next", target, next_arguments, {});
1370 : VisitResult next_result =
1371 8 : GenerateCall(callable, target, next_arguments, {}, false);
1372 2 : Arguments assign_arguments;
1373 2 : assign_arguments.parameters.push_back(object);
1374 2 : assign_arguments.parameters.push_back(index);
1375 2 : assign_arguments.parameters.push_back(next_result);
1376 8 : GenerateCall("[]=", assign_arguments);
1377 :
1378 : // Increment the indexed field index.
1379 4 : LocationReference index_ref = LocationReference::VariableAccess(index);
1380 2 : Arguments increment_arguments;
1381 4 : VisitResult one = {TypeOracle::GetConstInt31Type(), "1"};
1382 4 : increment_arguments.parameters = {index, one};
1383 6 : VisitResult assignment_value = GenerateCall("+", increment_arguments);
1384 2 : GenerateAssignToLocation(index_ref, assignment_value);
1385 : }
1386 2 : assembler().Goto(header_block);
1387 :
1388 2 : assembler().Bind(fail_block);
1389 8 : assembler().Emit(AbortInstruction(AbortInstruction::Kind::kUnreachable));
1390 :
1391 2 : assembler().Bind(exit_block);
1392 2 : assembler().Goto(post_exit_block);
1393 :
1394 2 : assembler().Bind(post_exit_block);
1395 2 : }
1396 :
1397 33 : void ImplementationVisitor::InitializeAggregate(
1398 : const AggregateType* aggregate_type, VisitResult allocate_result,
1399 : const InitializerResults& initializer_results) {
1400 33 : size_t consumed_initializers = InitializeAggregateHelper(
1401 33 : aggregate_type, allocate_result, initializer_results);
1402 33 : if (consumed_initializers != initializer_results.field_value_map.size()) {
1403 : ReportError("more initializers than fields present in ",
1404 0 : aggregate_type->name());
1405 : }
1406 33 : }
1407 :
1408 9 : VisitResult ImplementationVisitor::AddVariableObjectSize(
1409 : VisitResult object_size, const ClassType* current_class,
1410 : const InitializerResults& initializer_results) {
1411 71 : while (current_class != nullptr) {
1412 : auto current_field = current_class->fields().begin();
1413 64 : while (current_field != current_class->fields().end()) {
1414 33 : if (current_field->index) {
1415 4 : if (!current_field->name_and_type.type->IsSubtypeOf(
1416 2 : TypeOracle::GetObjectType())) {
1417 : ReportError(
1418 : "allocating objects containing indexed fields of non-object "
1419 0 : "types is not yet supported");
1420 : }
1421 : VisitResult index_field_size =
1422 4 : VisitResult(TypeOracle::GetConstInt31Type(), "kTaggedSize");
1423 : VisitResult initializer_value = initializer_results.field_value_map.at(
1424 2 : (*current_field->index)->name_and_type.name);
1425 : VisitResult index_intptr_size =
1426 : GenerateCall("Convert", {{initializer_value}, {}},
1427 10 : {TypeOracle::GetIntPtrType()}, false);
1428 : VisitResult variable_size = GenerateCall(
1429 8 : "*", {{index_intptr_size, index_field_size}, {}}, {}, false);
1430 : object_size =
1431 10 : GenerateCall("+", {{object_size, variable_size}, {}}, {}, false);
1432 : }
1433 : ++current_field;
1434 : }
1435 : current_class = current_class->GetSuperClass();
1436 : }
1437 9 : return object_size;
1438 : }
1439 :
1440 12 : VisitResult ImplementationVisitor::Visit(NewExpression* expr) {
1441 : StackScope stack_scope(this);
1442 12 : const Type* type = Declarations::GetType(expr->type);
1443 : const ClassType* class_type = ClassType::DynamicCast(type);
1444 12 : if (class_type == nullptr) {
1445 : ReportError("type for new expression must be a class, \"", *type,
1446 0 : "\" is not");
1447 : }
1448 :
1449 12 : if (!class_type->AllowInstantiation()) {
1450 : // Classes that are only used for testing should never be instantiated.
1451 : ReportError(*class_type,
1452 0 : " cannot be allocated with new (it's used for testing)");
1453 : }
1454 :
1455 : InitializerResults initializer_results =
1456 24 : VisitInitializerResults(class_type, expr->initializers);
1457 :
1458 : // Output the code to generate an uninitialized object of the class size in
1459 : // the GC heap.
1460 12 : VisitResult allocate_result;
1461 12 : if (class_type->IsExtern()) {
1462 18 : const Field& map_field = class_type->LookupField("map");
1463 9 : if (map_field.offset != 0) {
1464 : ReportError(
1465 0 : "external classes initializers must have a map as first parameter");
1466 : }
1467 : VisitResult object_map =
1468 9 : initializer_results.field_value_map[map_field.name_and_type.name];
1469 9 : Arguments size_arguments;
1470 9 : size_arguments.parameters.push_back(object_map);
1471 : VisitResult object_size = GenerateCall("%GetAllocationBaseSize",
1472 27 : size_arguments, {class_type}, false);
1473 :
1474 : object_size =
1475 27 : AddVariableObjectSize(object_size, class_type, initializer_results);
1476 :
1477 9 : Arguments allocate_arguments;
1478 9 : allocate_arguments.parameters.push_back(object_size);
1479 : allocate_result =
1480 36 : GenerateCall("%Allocate", allocate_arguments, {class_type}, false);
1481 : DCHECK(allocate_result.IsOnStack());
1482 : } else {
1483 3 : Arguments allocate_arguments;
1484 6 : allocate_arguments.parameters.push_back(
1485 : VisitResult(TypeOracle::GetConstexprIntPtrType(),
1486 6 : std::to_string(class_type->size() / kTaggedSize)));
1487 12 : allocate_result = GenerateCall("%AllocateInternalClass", allocate_arguments,
1488 3 : {class_type}, false);
1489 : }
1490 :
1491 24 : InitializeAggregate(class_type, allocate_result, initializer_results);
1492 :
1493 36 : return stack_scope.Yield(allocate_result);
1494 : }
1495 :
1496 27 : const Type* ImplementationVisitor::Visit(BreakStatement* stmt) {
1497 54 : base::Optional<Binding<LocalLabel>*> break_label = TryLookupLabel("_break");
1498 27 : if (!break_label) {
1499 0 : ReportError("break used outside of loop");
1500 : }
1501 54 : assembler().Goto((*break_label)->block);
1502 27 : return TypeOracle::GetNeverType();
1503 : }
1504 :
1505 17 : const Type* ImplementationVisitor::Visit(ContinueStatement* stmt) {
1506 : base::Optional<Binding<LocalLabel>*> continue_label =
1507 34 : TryLookupLabel("_continue");
1508 17 : if (!continue_label) {
1509 0 : ReportError("continue used outside of loop");
1510 : }
1511 34 : assembler().Goto((*continue_label)->block);
1512 17 : return TypeOracle::GetNeverType();
1513 : }
1514 :
1515 61 : const Type* ImplementationVisitor::Visit(ForLoopStatement* stmt) {
1516 : BlockBindings<LocalValue> loop_bindings(&ValueBindingsManager::Get());
1517 :
1518 61 : if (stmt->var_declaration) Visit(*stmt->var_declaration, &loop_bindings);
1519 :
1520 122 : Block* body_block = assembler().NewBlock(assembler().CurrentStack());
1521 122 : Block* exit_block = assembler().NewBlock(assembler().CurrentStack());
1522 :
1523 122 : Block* header_block = assembler().NewBlock();
1524 61 : assembler().Goto(header_block);
1525 61 : assembler().Bind(header_block);
1526 :
1527 : // The continue label is where "continue" statements jump to. If no action
1528 : // expression is provided, we jump directly to the header.
1529 : Block* continue_block = header_block;
1530 :
1531 : // The action label is only needed when an action expression was provided.
1532 : Block* action_block = nullptr;
1533 61 : if (stmt->action) {
1534 112 : action_block = assembler().NewBlock();
1535 :
1536 : // The action expression needs to be executed on a continue.
1537 : continue_block = action_block;
1538 : }
1539 :
1540 61 : if (stmt->test) {
1541 56 : GenerateExpressionBranch(*stmt->test, body_block, exit_block);
1542 : } else {
1543 5 : assembler().Goto(body_block);
1544 : }
1545 :
1546 61 : assembler().Bind(body_block);
1547 : {
1548 61 : BreakContinueActivator activator(exit_block, continue_block);
1549 61 : const Type* body_result = Visit(stmt->body);
1550 61 : if (body_result != TypeOracle::GetNeverType()) {
1551 61 : assembler().Goto(continue_block);
1552 : }
1553 : }
1554 :
1555 61 : if (stmt->action) {
1556 56 : assembler().Bind(action_block);
1557 56 : const Type* action_result = Visit(*stmt->action);
1558 56 : if (action_result != TypeOracle::GetNeverType()) {
1559 56 : assembler().Goto(header_block);
1560 : }
1561 : }
1562 :
1563 61 : assembler().Bind(exit_block);
1564 122 : return TypeOracle::GetVoidType();
1565 : }
1566 :
1567 0 : VisitResult ImplementationVisitor::Visit(SpreadExpression* expr) {
1568 : ReportError(
1569 : "spread operators are only currently supported in indexed class field "
1570 0 : "initialization expressions");
1571 : }
1572 :
1573 42 : void ImplementationVisitor::GenerateImplementation(const std::string& dir,
1574 : Namespace* nspace) {
1575 : std::string new_source(nspace->source());
1576 : std::string base_file_name =
1577 126 : "builtins-" + DashifyString(nspace->name()) + "-from-dsl-gen";
1578 :
1579 126 : std::string source_file_name = dir + "/" + base_file_name + ".cc";
1580 42 : ReplaceFileContentsIfDifferent(source_file_name, new_source);
1581 : std::string new_header(nspace->header());
1582 126 : std::string header_file_name = dir + "/" + base_file_name + ".h";
1583 42 : ReplaceFileContentsIfDifferent(header_file_name, new_header);
1584 42 : }
1585 :
1586 0 : void ImplementationVisitor::GenerateMacroFunctionDeclaration(
1587 : std::ostream& o, const std::string& macro_prefix, Macro* macro) {
1588 : GenerateFunctionDeclaration(o, macro_prefix, macro->ExternalName(),
1589 2240 : macro->signature(), macro->parameter_names());
1590 0 : }
1591 :
1592 2306 : void ImplementationVisitor::GenerateFunctionDeclaration(
1593 : std::ostream& o, const std::string& macro_prefix, const std::string& name,
1594 : const Signature& signature, const NameVector& parameter_names) {
1595 2306 : if (GlobalContext::verbose()) {
1596 0 : std::cout << "generating source for declaration " << name << "\n";
1597 : }
1598 :
1599 2306 : if (signature.return_type->IsVoidOrNever()) {
1600 900 : o << "void";
1601 : } else {
1602 2812 : o << signature.return_type->GetGeneratedTypeName();
1603 : }
1604 2306 : o << " " << macro_prefix << name << "(";
1605 :
1606 : DCHECK_EQ(signature.types().size(), parameter_names.size());
1607 : auto type_iterator = signature.types().begin();
1608 : bool first = true;
1609 6328 : for (const Identifier* name : parameter_names) {
1610 4022 : if (!first) {
1611 1856 : o << ", ";
1612 : }
1613 4022 : const Type* parameter_type = *type_iterator;
1614 : const std::string& generated_type_name =
1615 4022 : parameter_type->GetGeneratedTypeName();
1616 8044 : o << generated_type_name << " " << ExternalParameterName(name->value);
1617 : type_iterator++;
1618 : first = false;
1619 : }
1620 :
1621 2578 : for (const LabelDeclaration& label_info : signature.labels) {
1622 272 : if (!first) {
1623 266 : o << ", ";
1624 : }
1625 544 : o << "compiler::CodeAssemblerLabel* " << ExternalLabelName(label_info.name);
1626 : size_t i = 0;
1627 324 : for (const Type* type : label_info.types) {
1628 : std::string generated_type_name;
1629 52 : if (type->IsStructType()) {
1630 : generated_type_name = "\n#error no structs allowed in labels\n";
1631 : } else {
1632 : generated_type_name = "compiler::TypedCodeAssemblerVariable<";
1633 100 : generated_type_name += type->GetGeneratedTNodeTypeName();
1634 : generated_type_name += ">*";
1635 : }
1636 52 : o << ", ";
1637 : o << generated_type_name << " "
1638 104 : << ExternalLabelParameterName(label_info.name, i);
1639 52 : ++i;
1640 : }
1641 : }
1642 :
1643 2306 : o << ")";
1644 2306 : }
1645 :
1646 : namespace {
1647 :
1648 0 : void FailCallableLookup(const std::string& reason, const QualifiedName& name,
1649 : const TypeVector& parameter_types,
1650 : const std::vector<Binding<LocalLabel>*>& labels,
1651 : const std::vector<Signature>& candidates) {
1652 0 : std::stringstream stream;
1653 0 : stream << "\n" << reason << ": \n " << name << "(" << parameter_types << ")";
1654 0 : if (labels.size() != 0) {
1655 0 : stream << " labels ";
1656 0 : for (size_t i = 0; i < labels.size(); ++i) {
1657 0 : stream << labels[i]->name() << "(" << labels[i]->parameter_types << ")";
1658 : }
1659 : }
1660 0 : stream << "\ncandidates are:";
1661 0 : for (const Signature& signature : candidates) {
1662 0 : stream << "\n " << name;
1663 0 : PrintSignature(stream, signature, false);
1664 : }
1665 0 : ReportError(stream.str());
1666 : }
1667 :
1668 2293 : Callable* GetOrCreateSpecialization(const SpecializationKey& key) {
1669 2293 : if (base::Optional<Callable*> specialization =
1670 2293 : key.generic->GetSpecialization(key.specialized_types)) {
1671 : return *specialization;
1672 : }
1673 187 : return DeclarationVisitor().SpecializeImplicit(key);
1674 : }
1675 :
1676 : } // namespace
1677 :
1678 11740 : base::Optional<Binding<LocalValue>*> ImplementationVisitor::TryLookupLocalValue(
1679 : const std::string& name) {
1680 11740 : return ValueBindingsManager::Get().TryLookup(name);
1681 : }
1682 :
1683 7109 : base::Optional<Binding<LocalLabel>*> ImplementationVisitor::TryLookupLabel(
1684 : const std::string& name) {
1685 7109 : return LabelBindingsManager::Get().TryLookup(name);
1686 : }
1687 :
1688 1700 : Binding<LocalLabel>* ImplementationVisitor::LookupLabel(
1689 : const std::string& name) {
1690 1700 : base::Optional<Binding<LocalLabel>*> label = TryLookupLabel(name);
1691 1700 : if (!label) ReportError("cannot find label ", name);
1692 1700 : return *label;
1693 : }
1694 :
1695 117 : Block* ImplementationVisitor::LookupSimpleLabel(const std::string& name) {
1696 117 : LocalLabel* label = LookupLabel(name);
1697 117 : if (!label->parameter_types.empty()) {
1698 0 : ReportError("label ", name,
1699 : "was expected to have no parameters, but has parameters (",
1700 0 : label->parameter_types, ")");
1701 : }
1702 117 : return label->block;
1703 : }
1704 :
1705 : // Try to lookup a callable with the provided argument types. Do not report
1706 : // an error if no matching callable was found, but return false instead.
1707 : // This is used to test the presence of overloaded field accessors.
1708 1135 : bool ImplementationVisitor::TestLookupCallable(
1709 : const QualifiedName& name, const TypeVector& parameter_types) {
1710 4540 : return LookupCallable(name, Declarations::TryLookup(name), parameter_types,
1711 2270 : {}, {}, true) != nullptr;
1712 : }
1713 :
1714 : template <class Container>
1715 6662 : Callable* ImplementationVisitor::LookupCallable(
1716 : const QualifiedName& name, const Container& declaration_container,
1717 : const TypeVector& parameter_types,
1718 : const std::vector<Binding<LocalLabel>*>& labels,
1719 : const TypeVector& specialization_types, bool silence_errors) {
1720 : Callable* result = nullptr;
1721 :
1722 : std::vector<Declarable*> overloads;
1723 6662 : std::vector<Signature> overload_signatures;
1724 27582 : for (auto* declarable : declaration_container) {
1725 20920 : if (Generic* generic = Generic::DynamicCast(declarable)) {
1726 : base::Optional<TypeVector> inferred_specialization_types =
1727 : generic->InferSpecializationTypes(specialization_types,
1728 2753 : parameter_types);
1729 2753 : if (!inferred_specialization_types) continue;
1730 5506 : overloads.push_back(generic);
1731 8259 : overload_signatures.push_back(
1732 : DeclarationVisitor().MakeSpecializedSignature(
1733 : SpecializationKey{generic, *inferred_specialization_types}));
1734 18167 : } else if (Callable* callable = Callable::DynamicCast(declarable)) {
1735 36334 : overloads.push_back(callable);
1736 18167 : overload_signatures.push_back(callable->signature());
1737 : }
1738 : }
1739 : // Indices of candidates in overloads/overload_signatures.
1740 : std::vector<size_t> candidates;
1741 55164 : for (size_t i = 0; i < overloads.size(); ++i) {
1742 : const Signature& signature = overload_signatures[i];
1743 : bool try_bool_context = labels.size() == 0 &&
1744 20920 : signature.return_type == TypeOracle::GetNeverType();
1745 21450 : if (IsCompatibleSignature(signature, parameter_types, labels.size()) ||
1746 : (try_bool_context &&
1747 530 : IsCompatibleSignature(signature, parameter_types, 2))) {
1748 6475 : candidates.push_back(i);
1749 : }
1750 : }
1751 :
1752 6662 : if (overloads.empty()) {
1753 970 : if (silence_errors) return nullptr;
1754 0 : std::stringstream stream;
1755 0 : stream << "no matching declaration found for " << name;
1756 0 : ReportError(stream.str());
1757 5692 : } else if (candidates.empty()) {
1758 71 : if (silence_errors) return nullptr;
1759 0 : FailCallableLookup("cannot find suitable callable with name", name,
1760 : parameter_types, labels, overload_signatures);
1761 : }
1762 :
1763 1708 : auto is_better_candidate = [&](size_t a, size_t b) {
1764 3416 : return ParameterDifference(overload_signatures[a].GetExplicitTypes(),
1765 3416 : parameter_types)
1766 10248 : .StrictlyBetterThan(ParameterDifference(
1767 : overload_signatures[b].GetExplicitTypes(), parameter_types));
1768 9037 : };
1769 :
1770 : size_t best = *std::min_element(candidates.begin(), candidates.end(),
1771 5621 : is_better_candidate);
1772 : // This check is contained in libstdc++'s std::min_element.
1773 : DCHECK(!is_better_candidate(best, best));
1774 12096 : for (size_t candidate : candidates) {
1775 6475 : if (candidate != best && !is_better_candidate(best, candidate)) {
1776 : std::vector<Signature> candidate_signatures;
1777 0 : for (size_t i : candidates) {
1778 0 : candidate_signatures.push_back(overload_signatures[i]);
1779 : }
1780 0 : FailCallableLookup("ambiguous callable ", name, parameter_types, labels,
1781 : candidate_signatures);
1782 : }
1783 : }
1784 :
1785 11242 : if (Generic* generic = Generic::DynamicCast(overloads[best])) {
1786 8892 : result = GetOrCreateSpecialization(
1787 : SpecializationKey{generic, *generic->InferSpecializationTypes(
1788 : specialization_types, parameter_types)});
1789 : } else {
1790 : result = Callable::cast(overloads[best]);
1791 : }
1792 :
1793 : size_t caller_size = parameter_types.size();
1794 : size_t callee_size =
1795 5621 : result->signature().types().size() - result->signature().implicit_count;
1796 5621 : if (caller_size != callee_size &&
1797 : !result->signature().parameter_types.var_args) {
1798 0 : std::stringstream stream;
1799 0 : stream << "parameter count mismatch calling " << *result << " - expected "
1800 0 : << std::to_string(callee_size) << ", found "
1801 0 : << std::to_string(caller_size);
1802 0 : ReportError(stream.str());
1803 : }
1804 :
1805 : return result;
1806 : }
1807 :
1808 : template <class Container>
1809 5396 : Callable* ImplementationVisitor::LookupCallable(
1810 : const QualifiedName& name, const Container& declaration_container,
1811 : const Arguments& arguments, const TypeVector& specialization_types) {
1812 : return LookupCallable(name, declaration_container,
1813 : arguments.parameters.GetTypeVector(), arguments.labels,
1814 10792 : specialization_types);
1815 : }
1816 :
1817 131 : Method* ImplementationVisitor::LookupMethod(
1818 : const std::string& name, LocationReference this_reference,
1819 : const Arguments& arguments, const TypeVector& specialization_types) {
1820 131 : TypeVector types(arguments.parameters.GetTypeVector());
1821 262 : types.insert(types.begin(), this_reference.ReferencedType());
1822 393 : return Method::cast(LookupCallable(
1823 : {{}, name},
1824 262 : AggregateType::cast(this_reference.ReferencedType())->Methods(name),
1825 131 : types, arguments.labels, specialization_types));
1826 : }
1827 :
1828 102 : const Type* ImplementationVisitor::GetCommonType(const Type* left,
1829 : const Type* right) {
1830 : const Type* common_type;
1831 102 : if (IsAssignableFrom(left, right)) {
1832 : common_type = left;
1833 6 : } else if (IsAssignableFrom(right, left)) {
1834 : common_type = right;
1835 : } else {
1836 0 : common_type = TypeOracle::GetUnionType(left, right);
1837 : }
1838 102 : common_type = common_type->NonConstexprVersion();
1839 102 : return common_type;
1840 : }
1841 :
1842 21654 : VisitResult ImplementationVisitor::GenerateCopy(const VisitResult& to_copy) {
1843 21654 : if (to_copy.IsOnStack()) {
1844 : return VisitResult(to_copy.type(),
1845 37580 : assembler().Peek(to_copy.stack_range(), to_copy.type()));
1846 : }
1847 : return to_copy;
1848 : }
1849 :
1850 21 : VisitResult ImplementationVisitor::Visit(StructExpression* expr) {
1851 : StackScope stack_scope(this);
1852 21 : const Type* raw_type = Declarations::GetType(expr->type);
1853 21 : if (!raw_type->IsStructType()) {
1854 0 : ReportError(*raw_type, " is not a struct but used like one");
1855 : }
1856 :
1857 : const StructType* struct_type = StructType::cast(raw_type);
1858 :
1859 : InitializerResults initialization_results =
1860 : ImplementationVisitor::VisitInitializerResults(struct_type,
1861 42 : expr->initializers);
1862 :
1863 : // Push uninitialized 'this'
1864 : VisitResult result = TemporaryUninitializedStruct(
1865 42 : struct_type, "it's not initialized in the struct " + struct_type->name());
1866 :
1867 42 : InitializeAggregate(struct_type, result, initialization_results);
1868 :
1869 63 : return stack_scope.Yield(result);
1870 : }
1871 :
1872 10184 : LocationReference ImplementationVisitor::GetLocationReference(
1873 : Expression* location) {
1874 10184 : switch (location->kind) {
1875 : case AstNode::Kind::kIdentifierExpression:
1876 8271 : return GetLocationReference(static_cast<IdentifierExpression*>(location));
1877 : case AstNode::Kind::kFieldAccessExpression:
1878 : return GetLocationReference(
1879 1599 : static_cast<FieldAccessExpression*>(location));
1880 : case AstNode::Kind::kElementAccessExpression:
1881 : return GetLocationReference(
1882 283 : static_cast<ElementAccessExpression*>(location));
1883 : case AstNode::Kind::kDereferenceExpression:
1884 : return GetLocationReference(
1885 7 : static_cast<DereferenceExpression*>(location));
1886 : default:
1887 72 : return LocationReference::Temporary(Visit(location), "expression");
1888 : }
1889 : }
1890 :
1891 1599 : LocationReference ImplementationVisitor::GetLocationReference(
1892 : FieldAccessExpression* expr) {
1893 1599 : const std::string& fieldname = expr->field->value;
1894 3198 : LocationReference reference = GetLocationReference(expr->object);
1895 1599 : if (reference.IsVariableAccess() &&
1896 : reference.variable().type()->IsStructType()) {
1897 : const StructType* type = StructType::cast(reference.variable().type());
1898 344 : const Field& field = type->LookupField(fieldname);
1899 344 : if (GlobalContext::collect_language_server_data()) {
1900 0 : LanguageServerData::AddDefinition(expr->field->pos, field.pos);
1901 : }
1902 344 : if (field.const_qualified) {
1903 116 : VisitResult t_value = ProjectStructField(reference.variable(), fieldname);
1904 : return LocationReference::Temporary(
1905 290 : t_value, "for constant field '" + field.name_and_type.name + "'");
1906 : } else {
1907 : return LocationReference::VariableAccess(
1908 858 : ProjectStructField(reference.variable(), fieldname));
1909 : }
1910 : }
1911 1255 : if (reference.IsTemporary() && reference.temporary().type()->IsStructType()) {
1912 114 : if (GlobalContext::collect_language_server_data()) {
1913 : const StructType* type = StructType::cast(reference.temporary().type());
1914 0 : const Field& field = type->LookupField(fieldname);
1915 0 : LanguageServerData::AddDefinition(expr->field->pos, field.pos);
1916 : }
1917 : return LocationReference::Temporary(
1918 342 : ProjectStructField(reference.temporary(), fieldname),
1919 228 : reference.temporary_description());
1920 : }
1921 1141 : VisitResult object_result = GenerateFetchFromLocation(reference);
1922 1141 : if (base::Optional<const ClassType*> class_type =
1923 1141 : object_result.type()->ClassSupertype()) {
1924 : // This is a hack to distinguish the situation where we want to use
1925 : // overloaded field accessors from when we want to create a reference.
1926 4540 : bool has_explicit_overloads = TestLookupCallable(
1927 3405 : QualifiedName{"." + fieldname}, {object_result.type()});
1928 1135 : if ((*class_type)->HasField(fieldname) && !has_explicit_overloads) {
1929 1041 : const Field& field = (*class_type)->LookupField(fieldname);
1930 1041 : if (GlobalContext::collect_language_server_data()) {
1931 0 : LanguageServerData::AddDefinition(expr->field->pos, field.pos);
1932 : }
1933 1041 : if (field.index) {
1934 384 : return LocationReference::IndexedFieldAccess(object_result, fieldname);
1935 : } else {
1936 3652 : assembler().Emit(
1937 913 : CreateFieldReferenceInstruction{*class_type, fieldname});
1938 : const Type* reference_type =
1939 913 : TypeOracle::GetReferenceType(field.name_and_type.type);
1940 : return LocationReference::HeapReference(
1941 913 : VisitResult(reference_type, assembler().TopRange(2)));
1942 : }
1943 : }
1944 : }
1945 300 : return LocationReference::FieldAccess(object_result, fieldname);
1946 : }
1947 :
1948 283 : LocationReference ImplementationVisitor::GetLocationReference(
1949 : ElementAccessExpression* expr) {
1950 566 : LocationReference reference = GetLocationReference(expr->array);
1951 283 : VisitResult index = Visit(expr->index);
1952 283 : if (reference.IsIndexedFieldAccess()) {
1953 256 : return LocationReference::IndexedFieldIndexedAccess(reference, index);
1954 : } else {
1955 310 : return LocationReference::ArrayAccess(GenerateFetchFromLocation(reference),
1956 310 : index);
1957 : }
1958 : }
1959 :
1960 8271 : LocationReference ImplementationVisitor::GetLocationReference(
1961 : IdentifierExpression* expr) {
1962 8271 : if (expr->namespace_qualification.empty()) {
1963 8271 : if (base::Optional<Binding<LocalValue>*> value =
1964 8271 : TryLookupLocalValue(expr->name->value)) {
1965 7168 : if (GlobalContext::collect_language_server_data()) {
1966 1 : LanguageServerData::AddDefinition(expr->name->pos,
1967 1 : (*value)->declaration_position());
1968 : }
1969 7168 : if (expr->generic_arguments.size() != 0) {
1970 0 : ReportError("cannot have generic parameters on local name ",
1971 0 : expr->name);
1972 : }
1973 7168 : if ((*value)->is_const) {
1974 : return LocationReference::Temporary(
1975 20312 : (*value)->value, "constant value " + expr->name->value);
1976 : }
1977 2090 : return LocationReference::VariableAccess((*value)->value);
1978 : }
1979 : }
1980 :
1981 1103 : if (expr->IsThis()) {
1982 0 : ReportError("\"this\" cannot be qualified");
1983 : }
1984 : QualifiedName name =
1985 5515 : QualifiedName(expr->namespace_qualification, expr->name->value);
1986 1103 : if (base::Optional<Builtin*> builtin = Declarations::TryLookupBuiltin(name)) {
1987 4 : if (GlobalContext::collect_language_server_data()) {
1988 0 : LanguageServerData::AddDefinition(expr->name->pos, (*builtin)->pos());
1989 : }
1990 8 : return LocationReference::Temporary(GetBuiltinCode(*builtin),
1991 12 : "builtin " + expr->name->value);
1992 : }
1993 1099 : if (expr->generic_arguments.size() != 0) {
1994 70 : Generic* generic = Declarations::LookupUniqueGeneric(name);
1995 140 : Callable* specialization = GetOrCreateSpecialization(
1996 70 : SpecializationKey{generic, GetTypeVector(expr->generic_arguments)});
1997 70 : if (Builtin* builtin = Builtin::DynamicCast(specialization)) {
1998 : DCHECK(!builtin->IsExternal());
1999 140 : return LocationReference::Temporary(GetBuiltinCode(builtin),
2000 210 : "builtin " + expr->name->value);
2001 : } else {
2002 : ReportError("cannot create function pointer for non-builtin ",
2003 0 : generic->name());
2004 : }
2005 : }
2006 1029 : Value* value = Declarations::LookupValue(name);
2007 1029 : if (GlobalContext::collect_language_server_data()) {
2008 0 : LanguageServerData::AddDefinition(expr->name->pos, value->name()->pos);
2009 : }
2010 1029 : if (auto* constant = NamespaceConstant::DynamicCast(value)) {
2011 400 : if (constant->type()->IsConstexpr()) {
2012 : return LocationReference::Temporary(
2013 111 : VisitResult(constant->type(), constant->ExternalAssemblerName() +
2014 111 : "(state_)." +
2015 74 : constant->name()->value + "()"),
2016 148 : "namespace constant " + expr->name->value);
2017 : }
2018 1452 : assembler().Emit(NamespaceConstantInstruction{constant});
2019 : StackRange stack_range =
2020 363 : assembler().TopRange(LoweredSlotCount(constant->type()));
2021 : return LocationReference::Temporary(
2022 : VisitResult(constant->type(), stack_range),
2023 1452 : "namespace constant " + expr->name->value);
2024 : }
2025 : ExternConstant* constant = ExternConstant::cast(value);
2026 629 : return LocationReference::Temporary(constant->value(),
2027 1887 : "extern value " + expr->name->value);
2028 : }
2029 :
2030 7 : LocationReference ImplementationVisitor::GetLocationReference(
2031 : DereferenceExpression* expr) {
2032 7 : VisitResult ref = Visit(expr->reference);
2033 : const ReferenceType* type = ReferenceType::DynamicCast(ref.type());
2034 7 : if (!type) {
2035 : ReportError("Operator * expects a reference but found a value of type ",
2036 0 : *ref.type());
2037 : }
2038 14 : return LocationReference::HeapReference(ref);
2039 : }
2040 :
2041 8701 : VisitResult ImplementationVisitor::GenerateFetchFromLocation(
2042 : const LocationReference& reference) {
2043 8701 : if (reference.IsTemporary()) {
2044 6263 : return GenerateCopy(reference.temporary());
2045 2438 : } else if (reference.IsVariableAccess()) {
2046 1575 : return GenerateCopy(reference.variable());
2047 863 : } else if (reference.IsHeapReference()) {
2048 1094 : GenerateCopy(reference.heap_reference());
2049 2188 : assembler().Emit(LoadReferenceInstruction{reference.ReferencedType()});
2050 : DCHECK_EQ(1, LoweredSlotCount(reference.ReferencedType()));
2051 : return VisitResult(reference.ReferencedType(), assembler().TopRange(1));
2052 : } else {
2053 316 : if (reference.IsIndexedFieldAccess()) {
2054 : ReportError(
2055 0 : "fetching a value directly from an indexed field isn't allowed");
2056 : }
2057 : DCHECK(reference.IsCallAccess());
2058 : return GenerateCall(reference.eval_function(),
2059 948 : Arguments{reference.call_arguments(), {}});
2060 : }
2061 : }
2062 :
2063 1073 : void ImplementationVisitor::GenerateAssignToLocation(
2064 : const LocationReference& reference, const VisitResult& assignment_value) {
2065 1073 : if (reference.IsCallAccess()) {
2066 67 : Arguments arguments{reference.call_arguments(), {}};
2067 67 : arguments.parameters.push_back(assignment_value);
2068 335 : GenerateCall(reference.assign_function(), arguments);
2069 1006 : } else if (reference.IsVariableAccess()) {
2070 : VisitResult variable = reference.variable();
2071 : VisitResult converted_value =
2072 1172 : GenerateImplicitConvert(variable.type(), assignment_value);
2073 586 : assembler().Poke(variable.stack_range(), converted_value.stack_range(),
2074 586 : variable.type());
2075 420 : } else if (reference.IsIndexedFieldAccess()) {
2076 0 : ReportError("assigning a value directly to an indexed field isn't allowed");
2077 420 : } else if (reference.IsHeapReference()) {
2078 : const Type* referenced_type = reference.ReferencedType();
2079 840 : GenerateCopy(reference.heap_reference());
2080 1260 : GenerateImplicitConvert(referenced_type, assignment_value);
2081 1680 : assembler().Emit(StoreReferenceInstruction{referenced_type});
2082 : } else {
2083 : DCHECK(reference.IsTemporary());
2084 : ReportError("cannot assign to temporary ",
2085 0 : reference.temporary_description());
2086 : }
2087 1073 : }
2088 :
2089 23 : VisitResult ImplementationVisitor::GeneratePointerCall(
2090 : Expression* callee, const Arguments& arguments, bool is_tailcall) {
2091 : StackScope scope(this);
2092 23 : TypeVector parameter_types(arguments.parameters.GetTypeVector());
2093 23 : VisitResult callee_result = Visit(callee);
2094 23 : if (!callee_result.type()->IsBuiltinPointerType()) {
2095 0 : std::stringstream stream;
2096 : stream << "Expected a function pointer type but found "
2097 0 : << *callee_result.type();
2098 0 : ReportError(stream.str());
2099 : }
2100 : const BuiltinPointerType* type =
2101 : BuiltinPointerType::cast(callee_result.type());
2102 :
2103 23 : if (type->parameter_types().size() != parameter_types.size()) {
2104 0 : std::stringstream stream;
2105 : stream << "parameter count mismatch calling function pointer with Type: "
2106 0 : << *type << " - expected "
2107 0 : << std::to_string(type->parameter_types().size()) << ", found "
2108 0 : << std::to_string(parameter_types.size());
2109 0 : ReportError(stream.str());
2110 : }
2111 :
2112 46 : ParameterTypes types{type->parameter_types(), false};
2113 23 : Signature sig;
2114 : sig.parameter_types = types;
2115 23 : if (!IsCompatibleSignature(sig, parameter_types, 0)) {
2116 0 : std::stringstream stream;
2117 : stream << "parameters do not match function pointer signature. Expected: ("
2118 0 : << type->parameter_types() << ") but got: (" << parameter_types
2119 0 : << ")";
2120 0 : ReportError(stream.str());
2121 : }
2122 :
2123 46 : callee_result = GenerateCopy(callee_result);
2124 : StackRange arg_range = assembler().TopRange(0);
2125 157 : for (size_t current = 0; current < arguments.parameters.size(); ++current) {
2126 67 : const Type* to_type = type->parameter_types()[current];
2127 : arg_range.Extend(
2128 201 : GenerateImplicitConvert(to_type, arguments.parameters[current])
2129 : .stack_range());
2130 : }
2131 :
2132 69 : assembler().Emit(
2133 23 : CallBuiltinPointerInstruction{is_tailcall, type, arg_range.Size()});
2134 :
2135 23 : if (is_tailcall) {
2136 0 : return VisitResult::NeverResult();
2137 : }
2138 : DCHECK_EQ(1, LoweredSlotCount(type->return_type()));
2139 46 : return scope.Yield(VisitResult(type->return_type(), assembler().TopRange(1)));
2140 : }
2141 :
2142 9986 : void ImplementationVisitor::AddCallParameter(
2143 : Callable* callable, VisitResult parameter, const Type* parameter_type,
2144 : std::vector<VisitResult>* converted_arguments, StackRange* argument_range,
2145 : std::vector<std::string>* constexpr_arguments) {
2146 19972 : VisitResult converted = GenerateImplicitConvert(parameter_type, parameter);
2147 9986 : converted_arguments->push_back(converted);
2148 9986 : if (!callable->ShouldBeInlined()) {
2149 9883 : if (converted.IsOnStack()) {
2150 : argument_range->Extend(converted.stack_range());
2151 : } else {
2152 2023 : constexpr_arguments->push_back(converted.constexpr_value());
2153 : }
2154 : }
2155 9986 : }
2156 :
2157 5527 : VisitResult ImplementationVisitor::GenerateCall(
2158 : Callable* callable, base::Optional<LocationReference> this_reference,
2159 : Arguments arguments, const TypeVector& specialization_types,
2160 : bool is_tailcall) {
2161 : // Operators used in a branching context can also be function calls that never
2162 : // return but have a True and False label
2163 10587 : if (arguments.labels.size() == 0 &&
2164 : callable->signature().labels.size() == 2) {
2165 : base::Optional<Binding<LocalLabel>*> true_label =
2166 146 : TryLookupLabel(kTrueLabelName);
2167 : base::Optional<Binding<LocalLabel>*> false_label =
2168 146 : TryLookupLabel(kFalseLabelName);
2169 73 : if (!true_label || !false_label) {
2170 : ReportError(
2171 : callable->ReadableName(),
2172 : " does not return a value, but has to be called in a branching "
2173 : "context (e.g., conditional or if-condition). You can fix this by "
2174 0 : "adding \"? true : false\".");
2175 : }
2176 73 : arguments.labels.push_back(*true_label);
2177 73 : arguments.labels.push_back(*false_label);
2178 : }
2179 :
2180 5527 : const Type* return_type = callable->signature().return_type;
2181 :
2182 5527 : std::vector<VisitResult> converted_arguments;
2183 5527 : StackRange argument_range = assembler().TopRange(0);
2184 5527 : std::vector<std::string> constexpr_arguments;
2185 :
2186 : size_t current = 0;
2187 7331 : for (; current < callable->signature().implicit_count; ++current) {
2188 : std::string implicit_name =
2189 902 : callable->signature().parameter_names[current]->value;
2190 : base::Optional<Binding<LocalValue>*> val =
2191 902 : TryLookupLocalValue(implicit_name);
2192 902 : if (!val) {
2193 : ReportError("implicit parameter '", implicit_name,
2194 : "' required for call to '", callable->ReadableName(),
2195 0 : "' is not defined");
2196 : }
2197 1804 : AddCallParameter(callable, (*val)->value,
2198 : callable->signature().parameter_types.types[current],
2199 : &converted_arguments, &argument_range,
2200 902 : &constexpr_arguments);
2201 : }
2202 :
2203 5527 : if (this_reference) {
2204 : DCHECK(callable->IsMethod());
2205 : Method* method = Method::cast(callable);
2206 : // By now, the this reference should either be a variable or
2207 : // a temporary, in both cases the fetch of the VisitResult should succeed.
2208 : VisitResult this_value = this_reference->GetVisitResult();
2209 131 : if (method->ShouldBeInlined()) {
2210 108 : if (!this_value.type()->IsSubtypeOf(method->aggregate_type())) {
2211 0 : ReportError("this parameter must be a subtype of ",
2212 : *method->aggregate_type(), " but it is of type ",
2213 0 : this_value.type());
2214 : }
2215 : } else {
2216 23 : AddCallParameter(callable, this_value, method->aggregate_type(),
2217 : &converted_arguments, &argument_range,
2218 23 : &constexpr_arguments);
2219 : }
2220 131 : ++current;
2221 : }
2222 :
2223 14588 : for (auto arg : arguments.parameters) {
2224 : const Type* to_type = (current >= callable->signature().types().size())
2225 : ? TypeOracle::GetObjectType()
2226 18122 : : callable->signature().types()[current++];
2227 9061 : AddCallParameter(callable, arg, to_type, &converted_arguments,
2228 9061 : &argument_range, &constexpr_arguments);
2229 : }
2230 :
2231 5527 : if (GlobalContext::verbose()) {
2232 : std::cout << "generating code for call to " << callable->ReadableName()
2233 0 : << "\n";
2234 : }
2235 :
2236 : size_t label_count = callable->signature().labels.size();
2237 5527 : if (label_count != arguments.labels.size()) {
2238 0 : std::stringstream s;
2239 : s << "unexpected number of otherwise labels for "
2240 : << callable->ReadableName() << " (expected "
2241 0 : << std::to_string(label_count) << " found "
2242 0 : << std::to_string(arguments.labels.size()) << ")";
2243 0 : ReportError(s.str());
2244 : }
2245 :
2246 5527 : if (callable->IsTransitioning()) {
2247 319 : if (!CurrentCallable::Get()->IsTransitioning()) {
2248 0 : std::stringstream s;
2249 0 : s << *CurrentCallable::Get()
2250 : << " isn't marked transitioning but calls the transitioning "
2251 0 : << *callable;
2252 0 : ReportError(s.str());
2253 : }
2254 : }
2255 :
2256 5527 : if (auto* builtin = Builtin::DynamicCast(callable)) {
2257 143 : base::Optional<Block*> catch_block = GetCatchBlock();
2258 429 : assembler().Emit(CallBuiltinInstruction{
2259 143 : is_tailcall, builtin, argument_range.Size(), catch_block});
2260 143 : GenerateCatchBlock(catch_block);
2261 143 : if (is_tailcall) {
2262 2 : return VisitResult::NeverResult();
2263 : } else {
2264 141 : size_t slot_count = LoweredSlotCount(return_type);
2265 : DCHECK_LE(slot_count, 1);
2266 : // TODO(tebbi): Actually, builtins have to return a value, so we should
2267 : // assert slot_count == 1 here.
2268 : return VisitResult(return_type, assembler().TopRange(slot_count));
2269 : }
2270 5384 : } else if (auto* macro = Macro::DynamicCast(callable)) {
2271 5252 : if (is_tailcall) {
2272 0 : ReportError("can't tail call a macro");
2273 : }
2274 5252 : if (return_type->IsConstexpr()) {
2275 : DCHECK_EQ(0, arguments.labels.size());
2276 214 : std::stringstream result;
2277 : result << "(" << macro->external_assembler_name() << "(state_)."
2278 107 : << macro->ExternalName() << "(";
2279 : bool first = true;
2280 238 : for (VisitResult arg : arguments.parameters) {
2281 : DCHECK(!arg.IsOnStack());
2282 131 : if (!first) {
2283 59 : result << ", ";
2284 : }
2285 : first = false;
2286 : result << arg.constexpr_value();
2287 : }
2288 107 : result << "))";
2289 107 : return VisitResult(return_type, result.str());
2290 5145 : } else if (macro->ShouldBeInlined()) {
2291 : std::vector<Block*> label_blocks;
2292 150 : for (Binding<LocalLabel>* label : arguments.labels) {
2293 41 : label_blocks.push_back(label->block);
2294 : }
2295 : return InlineMacro(macro, this_reference, converted_arguments,
2296 436 : label_blocks);
2297 9573 : } else if (arguments.labels.empty() &&
2298 4537 : return_type != TypeOracle::GetNeverType()) {
2299 4438 : base::Optional<Block*> catch_block = GetCatchBlock();
2300 13314 : assembler().Emit(
2301 4438 : CallCsaMacroInstruction{macro, constexpr_arguments, catch_block});
2302 4438 : GenerateCatchBlock(catch_block);
2303 4438 : size_t return_slot_count = LoweredSlotCount(return_type);
2304 : return VisitResult(return_type, assembler().TopRange(return_slot_count));
2305 : } else {
2306 598 : base::Optional<Block*> return_continuation;
2307 598 : if (return_type != TypeOracle::GetNeverType()) {
2308 828 : return_continuation = assembler().NewBlock();
2309 : }
2310 :
2311 : std::vector<Block*> label_blocks;
2312 :
2313 1758 : for (size_t i = 0; i < label_count; ++i) {
2314 1740 : label_blocks.push_back(assembler().NewBlock());
2315 : }
2316 598 : base::Optional<Block*> catch_block = GetCatchBlock();
2317 1794 : assembler().Emit(CallCsaMacroAndBranchInstruction{
2318 : macro, constexpr_arguments, return_continuation, label_blocks,
2319 598 : catch_block});
2320 598 : GenerateCatchBlock(catch_block);
2321 :
2322 1758 : for (size_t i = 0; i < label_count; ++i) {
2323 580 : Binding<LocalLabel>* label = arguments.labels[i];
2324 : size_t callee_label_parameters =
2325 : callable->signature().labels[i].types.size();
2326 580 : if (label->parameter_types.size() != callee_label_parameters) {
2327 0 : std::stringstream s;
2328 : s << "label " << label->name()
2329 : << " doesn't have the right number of parameters (found "
2330 0 : << std::to_string(label->parameter_types.size()) << " expected "
2331 0 : << std::to_string(callee_label_parameters) << ")";
2332 0 : ReportError(s.str());
2333 : }
2334 580 : assembler().Bind(label_blocks[i]);
2335 : assembler().Goto(
2336 : label->block,
2337 1740 : LowerParameterTypes(callable->signature().labels[i].types).size());
2338 :
2339 : size_t j = 0;
2340 605 : for (auto t : callable->signature().labels[i].types) {
2341 25 : const Type* parameter_type = label->parameter_types[j];
2342 25 : if (parameter_type != t) {
2343 0 : ReportError("mismatch of label parameters (expected ", *t, " got ",
2344 0 : parameter_type, " for parameter ", i + 1, ")");
2345 : }
2346 25 : j++;
2347 : }
2348 : }
2349 :
2350 598 : if (return_continuation) {
2351 414 : assembler().Bind(*return_continuation);
2352 414 : size_t return_slot_count = LoweredSlotCount(return_type);
2353 : return VisitResult(return_type,
2354 : assembler().TopRange(return_slot_count));
2355 : } else {
2356 184 : return VisitResult::NeverResult();
2357 : }
2358 : }
2359 132 : } else if (auto* runtime_function = RuntimeFunction::DynamicCast(callable)) {
2360 27 : base::Optional<Block*> catch_block = GetCatchBlock();
2361 81 : assembler().Emit(CallRuntimeInstruction{
2362 27 : is_tailcall, runtime_function, argument_range.Size(), catch_block});
2363 27 : GenerateCatchBlock(catch_block);
2364 27 : if (is_tailcall || return_type == TypeOracle::GetNeverType()) {
2365 12 : return VisitResult::NeverResult();
2366 : } else {
2367 15 : size_t slot_count = LoweredSlotCount(return_type);
2368 : DCHECK_LE(slot_count, 1);
2369 : // TODO(tebbi): Actually, runtime functions have to return a value, so
2370 : // we should assert slot_count == 1 here.
2371 : return VisitResult(return_type, assembler().TopRange(slot_count));
2372 : }
2373 105 : } else if (auto* intrinsic = Intrinsic::DynamicCast(callable)) {
2374 105 : if (intrinsic->ExternalName() == "%RawConstexprCast") {
2375 2 : if (intrinsic->signature().parameter_types.types.size() != 1 ||
2376 : constexpr_arguments.size() != 1) {
2377 : ReportError(
2378 : "%RawConstexprCast must take a single parameter with constexpr "
2379 0 : "type");
2380 : }
2381 1 : if (!return_type->IsConstexpr()) {
2382 0 : std::stringstream s;
2383 0 : s << *return_type
2384 0 : << " return type for %RawConstexprCast is not constexpr";
2385 0 : ReportError(s.str());
2386 : }
2387 2 : std::stringstream result;
2388 3 : result << "static_cast<" << return_type->GetGeneratedTypeName() << ">(";
2389 : result << constexpr_arguments[0];
2390 1 : result << ")";
2391 1 : return VisitResult(return_type, result.str());
2392 : } else {
2393 312 : assembler().Emit(CallIntrinsicInstruction{intrinsic, specialization_types,
2394 104 : constexpr_arguments});
2395 : size_t return_slot_count =
2396 104 : LoweredSlotCount(intrinsic->signature().return_type);
2397 : return VisitResult(return_type, assembler().TopRange(return_slot_count));
2398 : }
2399 : } else {
2400 0 : UNREACHABLE();
2401 : }
2402 : }
2403 :
2404 5396 : VisitResult ImplementationVisitor::GenerateCall(
2405 : const QualifiedName& callable_name, Arguments arguments,
2406 : const TypeVector& specialization_types, bool is_tailcall) {
2407 : Callable* callable =
2408 10792 : LookupCallable(callable_name, Declarations::Lookup(callable_name),
2409 5396 : arguments, specialization_types);
2410 : return GenerateCall(callable, base::nullopt, arguments, specialization_types,
2411 16188 : is_tailcall);
2412 : }
2413 :
2414 3289 : VisitResult ImplementationVisitor::Visit(CallExpression* expr,
2415 : bool is_tailcall) {
2416 : StackScope scope(this);
2417 :
2418 6603 : if (expr->callee->name->value == "&" && expr->arguments.size() == 1) {
2419 6 : if (auto* loc_expr = LocationExpression::DynamicCast(expr->arguments[0])) {
2420 3 : LocationReference ref = GetLocationReference(loc_expr);
2421 9 : if (ref.IsHeapReference()) return scope.Yield(ref.heap_reference());
2422 : }
2423 0 : ReportError("Unable to create a heap reference.");
2424 : }
2425 :
2426 3286 : Arguments arguments;
2427 3286 : QualifiedName name = QualifiedName(expr->callee->namespace_qualification,
2428 16430 : expr->callee->name->value);
2429 : TypeVector specialization_types =
2430 3286 : GetTypeVector(expr->callee->generic_arguments);
2431 : bool has_template_arguments = !specialization_types.empty();
2432 9647 : for (Expression* arg : expr->arguments)
2433 12722 : arguments.parameters.push_back(Visit(arg));
2434 6572 : arguments.labels = LabelsFromIdentifiers(expr->labels);
2435 5853 : if (!has_template_arguments && name.namespace_qualification.empty() &&
2436 2567 : TryLookupLocalValue(name.name)) {
2437 : return scope.Yield(
2438 46 : GeneratePointerCall(expr->callee, arguments, is_tailcall));
2439 : } else {
2440 3263 : if (GlobalContext::collect_language_server_data()) {
2441 0 : Callable* callable = LookupCallable(name, Declarations::Lookup(name),
2442 0 : arguments, specialization_types);
2443 0 : LanguageServerData::AddDefinition(expr->callee->name->pos,
2444 0 : callable->pos());
2445 : }
2446 : return scope.Yield(
2447 6526 : GenerateCall(name, arguments, specialization_types, is_tailcall));
2448 : }
2449 : }
2450 :
2451 129 : VisitResult ImplementationVisitor::Visit(CallMethodExpression* expr) {
2452 : StackScope scope(this);
2453 129 : Arguments arguments;
2454 129 : std::string method_name = expr->method->name->value;
2455 : TypeVector specialization_types =
2456 129 : GetTypeVector(expr->method->generic_arguments);
2457 258 : LocationReference target = GetLocationReference(expr->target);
2458 129 : if (!target.IsVariableAccess()) {
2459 31 : VisitResult result = GenerateFetchFromLocation(target);
2460 124 : target = LocationReference::Temporary(result, "method target result");
2461 : }
2462 : const AggregateType* target_type =
2463 : AggregateType::DynamicCast(target.ReferencedType());
2464 129 : if (!target_type) {
2465 0 : ReportError("target of method call not a struct or class type");
2466 : }
2467 230 : for (Expression* arg : expr->arguments) {
2468 202 : arguments.parameters.push_back(Visit(arg));
2469 : }
2470 258 : arguments.labels = LabelsFromIdentifiers(expr->labels);
2471 129 : TypeVector argument_types = arguments.parameters.GetTypeVector();
2472 : DCHECK_EQ(expr->method->namespace_qualification.size(), 0);
2473 387 : QualifiedName qualified_name = QualifiedName(method_name);
2474 : Callable* callable = nullptr;
2475 258 : callable = LookupMethod(method_name, target, arguments, {});
2476 774 : return scope.Yield(GenerateCall(callable, target, arguments, {}, false));
2477 : }
2478 :
2479 84 : VisitResult ImplementationVisitor::Visit(IntrinsicCallExpression* expr) {
2480 : StackScope scope(this);
2481 84 : Arguments arguments;
2482 84 : TypeVector specialization_types = GetTypeVector(expr->generic_arguments);
2483 168 : for (Expression* arg : expr->arguments)
2484 168 : arguments.parameters.push_back(Visit(arg));
2485 : return scope.Yield(
2486 420 : GenerateCall(expr->name, arguments, specialization_types, false));
2487 : }
2488 :
2489 0 : void ImplementationVisitor::GenerateBranch(const VisitResult& condition,
2490 : Block* true_block,
2491 : Block* false_block) {
2492 : DCHECK_EQ(condition,
2493 : VisitResult(TypeOracle::GetBoolType(), assembler().TopRange(1)));
2494 759 : assembler().Branch(true_block, false_block);
2495 0 : }
2496 :
2497 859 : void ImplementationVisitor::GenerateExpressionBranch(
2498 : VisitResultGenerator generator, Block* true_block, Block* false_block) {
2499 : // Conditional expressions can either explicitly return a bit
2500 : // type, or they can be backed by macros that don't return but
2501 : // take a true and false label. By declaring the labels before
2502 : // visiting the conditional expression, those label-based
2503 : // macro conditionals will be able to find them through normal
2504 : // label lookups.
2505 : Binding<LocalLabel> true_binding{&LabelBindingsManager::Get(), kTrueLabelName,
2506 4295 : LocalLabel{true_block}};
2507 : Binding<LocalLabel> false_binding{&LabelBindingsManager::Get(),
2508 4295 : kFalseLabelName, LocalLabel{false_block}};
2509 : StackScope stack_scope(this);
2510 : VisitResult expression_result = generator();
2511 859 : if (!expression_result.type()->IsNever()) {
2512 1518 : expression_result = stack_scope.Yield(
2513 3036 : GenerateImplicitConvert(TypeOracle::GetBoolType(), expression_result));
2514 : GenerateBranch(expression_result, true_block, false_block);
2515 : }
2516 859 : }
2517 :
2518 857 : void ImplementationVisitor::GenerateExpressionBranch(Expression* expression,
2519 : Block* true_block,
2520 : Block* false_block) {
2521 1714 : GenerateExpressionBranch([&]() { return this->Visit(expression); },
2522 857 : true_block, false_block);
2523 857 : }
2524 :
2525 14239 : VisitResult ImplementationVisitor::GenerateImplicitConvert(
2526 : const Type* destination_type, VisitResult source) {
2527 : StackScope scope(this);
2528 14239 : if (source.type() == TypeOracle::GetNeverType()) {
2529 0 : ReportError("it is not allowed to use a value of type never");
2530 : }
2531 :
2532 14239 : if (destination_type == source.type()) {
2533 23278 : return scope.Yield(GenerateCopy(source));
2534 : }
2535 :
2536 2600 : if (TypeOracle::IsImplicitlyConvertableFrom(destination_type,
2537 : source.type())) {
2538 8772 : return scope.Yield(GenerateCall(kFromConstexprMacroName, {{source}, {}},
2539 1462 : {destination_type, source.type()}, false));
2540 1138 : } else if (IsAssignableFrom(destination_type, source.type())) {
2541 : source.SetType(destination_type);
2542 2276 : return scope.Yield(GenerateCopy(source));
2543 : } else {
2544 0 : std::stringstream s;
2545 0 : s << "cannot use expression of type " << *source.type()
2546 0 : << " as a value of type " << *destination_type;
2547 0 : ReportError(s.str());
2548 : }
2549 : }
2550 :
2551 0 : StackRange ImplementationVisitor::GenerateLabelGoto(
2552 : LocalLabel* label, base::Optional<StackRange> arguments) {
2553 1746 : return assembler().Goto(label->block, arguments ? arguments->Size() : 0);
2554 : }
2555 :
2556 3415 : std::vector<Binding<LocalLabel>*> ImplementationVisitor::LabelsFromIdentifiers(
2557 : const std::vector<std::string>& names) {
2558 : std::vector<Binding<LocalLabel>*> result;
2559 3415 : result.reserve(names.size());
2560 3888 : for (const auto& name : names) {
2561 946 : result.push_back(LookupLabel(name));
2562 : }
2563 3415 : return result;
2564 : }
2565 :
2566 2110 : StackRange ImplementationVisitor::LowerParameter(
2567 : const Type* type, const std::string& parameter_name,
2568 : Stack<std::string>* lowered_parameters) {
2569 2110 : if (const StructType* struct_type = StructType::DynamicCast(type)) {
2570 : StackRange range = lowered_parameters->TopRange(0);
2571 209 : for (auto& field : struct_type->fields()) {
2572 : StackRange parameter_range = LowerParameter(
2573 162 : field.name_and_type.type,
2574 648 : parameter_name + "." + field.name_and_type.name, lowered_parameters);
2575 : range.Extend(parameter_range);
2576 : }
2577 47 : return range;
2578 2063 : } else if (type->IsReferenceType()) {
2579 4 : lowered_parameters->Push(parameter_name + ".object");
2580 4 : lowered_parameters->Push(parameter_name + ".offset");
2581 : return lowered_parameters->TopRange(2);
2582 : } else {
2583 2061 : lowered_parameters->Push(parameter_name);
2584 : return lowered_parameters->TopRange(1);
2585 : }
2586 : }
2587 :
2588 29 : void ImplementationVisitor::LowerLabelParameter(
2589 : const Type* type, const std::string& parameter_name,
2590 : std::vector<std::string>* lowered_parameters) {
2591 29 : if (const StructType* struct_type = StructType::DynamicCast(type)) {
2592 4 : for (auto& field : struct_type->fields()) {
2593 : LowerLabelParameter(
2594 3 : field.name_and_type.type,
2595 15 : "&((*" + parameter_name + ")." + field.name_and_type.name + ")",
2596 3 : lowered_parameters);
2597 : }
2598 : } else {
2599 28 : lowered_parameters->push_back(parameter_name);
2600 : }
2601 29 : }
2602 :
2603 0 : std::string ImplementationVisitor::ExternalLabelName(
2604 : const std::string& label_name) {
2605 408 : return "label_" + label_name;
2606 : }
2607 :
2608 78 : std::string ImplementationVisitor::ExternalLabelParameterName(
2609 : const std::string& label_name, size_t i) {
2610 312 : return "label_" + label_name + "_parameter_" + std::to_string(i);
2611 : }
2612 :
2613 6033 : std::string ImplementationVisitor::ExternalParameterName(
2614 : const std::string& name) {
2615 12066 : return std::string("p_") + name;
2616 : }
2617 :
2618 0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::ValueBindingsManager)
2619 0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::LabelBindingsManager)
2620 0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentCallable)
2621 0 : DEFINE_CONTEXTUAL_VARIABLE(ImplementationVisitor::CurrentReturnValue)
2622 :
2623 21473 : bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
2624 : size_t label_count) {
2625 21473 : auto i = sig.parameter_types.types.begin() + sig.implicit_count;
2626 42946 : if ((sig.parameter_types.types.size() - sig.implicit_count) > types.size())
2627 : return false;
2628 21089 : if (sig.labels.size() != label_count) return false;
2629 32972 : for (auto current : types) {
2630 26474 : if (i == sig.parameter_types.types.end()) {
2631 196 : if (!sig.parameter_types.var_args) return false;
2632 0 : if (!IsAssignableFrom(TypeOracle::GetObjectType(), current)) return false;
2633 : } else {
2634 26278 : if (!IsAssignableFrom(*i++, current)) return false;
2635 : }
2636 : }
2637 : return true;
2638 : }
2639 :
2640 5206 : base::Optional<Block*> ImplementationVisitor::GetCatchBlock() {
2641 5206 : base::Optional<Block*> catch_block;
2642 5206 : if (base::Optional<Binding<LocalLabel>*> catch_handler =
2643 10412 : TryLookupLabel("_catch")) {
2644 26 : catch_block = assembler().NewBlock(base::nullopt, true);
2645 : }
2646 5206 : return catch_block;
2647 : }
2648 :
2649 5206 : void ImplementationVisitor::GenerateCatchBlock(
2650 : base::Optional<Block*> catch_block) {
2651 5206 : if (catch_block) {
2652 : base::Optional<Binding<LocalLabel>*> catch_handler =
2653 26 : TryLookupLabel("_catch");
2654 13 : if (assembler().CurrentBlockIsComplete()) {
2655 4 : assembler().Bind(*catch_block);
2656 4 : assembler().Goto((*catch_handler)->block, 1);
2657 : } else {
2658 18 : CfgAssemblerScopedTemporaryBlock temp(&assembler(), *catch_block);
2659 9 : assembler().Goto((*catch_handler)->block, 1);
2660 : }
2661 : }
2662 5206 : }
2663 :
2664 3 : void ImplementationVisitor::VisitAllDeclarables() {
2665 : CurrentCallable::Scope current_callable(nullptr);
2666 : const std::vector<std::unique_ptr<Declarable>>& all_declarables =
2667 : GlobalContext::AllDeclarables();
2668 : // This has to be an index-based loop because all_declarables can be extended
2669 : // during the loop.
2670 15179 : for (size_t i = 0; i < all_declarables.size(); ++i) {
2671 7588 : Visit(all_declarables[i].get());
2672 : }
2673 3 : }
2674 :
2675 7588 : void ImplementationVisitor::Visit(Declarable* declarable) {
2676 7588 : CurrentScope::Scope current_scope(declarable->ParentScope());
2677 7588 : CurrentSourcePosition::Scope current_source_position(declarable->pos());
2678 7588 : switch (declarable->kind()) {
2679 : case Declarable::kMacro:
2680 : return Visit(Macro::cast(declarable));
2681 : case Declarable::kMethod:
2682 : return Visit(Method::cast(declarable));
2683 : case Declarable::kBuiltin:
2684 203 : return Visit(Builtin::cast(declarable));
2685 : case Declarable::kTypeAlias:
2686 5526 : return Visit(TypeAlias::cast(declarable));
2687 : case Declarable::kNamespaceConstant:
2688 33 : return Visit(NamespaceConstant::cast(declarable));
2689 : case Declarable::kRuntimeFunction:
2690 : case Declarable::kIntrinsic:
2691 : case Declarable::kExternConstant:
2692 : case Declarable::kNamespace:
2693 : case Declarable::kGeneric:
2694 : return;
2695 : }
2696 : }
2697 :
2698 1 : void ImplementationVisitor::GenerateBuiltinDefinitions(std::string& file_name) {
2699 2 : std::stringstream new_contents_stream;
2700 : new_contents_stream
2701 : << "#ifndef V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
2702 : "#define V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
2703 : "\n"
2704 : "#define BUILTIN_LIST_FROM_DSL(CPP, API, TFJ, TFC, TFS, TFH, ASM) "
2705 1 : "\\\n";
2706 7578 : for (auto& declarable : GlobalContext::AllDeclarables()) {
2707 : Builtin* builtin = Builtin::DynamicCast(declarable.get());
2708 7780 : if (!builtin || builtin->IsExternal()) continue;
2709 : int firstParameterIndex = 1;
2710 : bool declareParameters = true;
2711 184 : if (builtin->IsStub()) {
2712 : new_contents_stream << "TFS(" << builtin->ExternalName();
2713 : } else {
2714 : new_contents_stream << "TFJ(" << builtin->ExternalName();
2715 103 : if (builtin->IsVarArgsJavaScript()) {
2716 : new_contents_stream
2717 77 : << ", SharedFunctionInfo::kDontAdaptArgumentsSentinel";
2718 : declareParameters = false;
2719 : } else {
2720 : assert(builtin->IsFixedArgsJavaScript());
2721 : // FixedArg javascript builtins need to offer the parameter
2722 : // count.
2723 : assert(builtin->parameter_names().size() >= 2);
2724 26 : new_contents_stream << ", " << (builtin->parameter_names().size() - 2);
2725 : // And the receiver is explicitly declared.
2726 26 : new_contents_stream << ", kReceiver";
2727 : firstParameterIndex = 2;
2728 : }
2729 : }
2730 184 : if (declareParameters) {
2731 : int index = 0;
2732 597 : for (const auto& parameter : builtin->parameter_names()) {
2733 490 : if (index >= firstParameterIndex) {
2734 714 : new_contents_stream << ", k" << CamelifyString(parameter->value);
2735 : }
2736 490 : index++;
2737 : }
2738 : }
2739 184 : new_contents_stream << ") \\\n";
2740 : }
2741 1 : new_contents_stream << "\n";
2742 :
2743 : new_contents_stream
2744 1 : << "#define TORQUE_FUNCTION_POINTER_TYPE_TO_BUILTIN_MAP(V) \\\n";
2745 11 : for (const BuiltinPointerType* type : TypeOracle::AllBuiltinPointerTypes()) {
2746 : Builtin* example_builtin =
2747 10 : Declarations::FindSomeInternalBuiltinWithType(type);
2748 10 : if (!example_builtin) {
2749 : CurrentSourcePosition::Scope current_source_position(
2750 0 : SourcePosition{CurrentSourceFile::Get(), {-1, -1}, {-1, -1}});
2751 0 : ReportError("unable to find any builtin with type \"", *type, "\"");
2752 : }
2753 : new_contents_stream << " V(" << type->function_pointer_type_id() << ","
2754 10 : << example_builtin->ExternalName() << ")\\\n";
2755 : }
2756 1 : new_contents_stream << "\n";
2757 :
2758 : new_contents_stream
2759 1 : << "#endif // V8_BUILTINS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n";
2760 :
2761 : std::string new_contents(new_contents_stream.str());
2762 1 : ReplaceFileContentsIfDifferent(file_name, new_contents);
2763 1 : }
2764 :
2765 : namespace {
2766 :
2767 : enum class FieldSectionType {
2768 : kNoSection = 0,
2769 : kWeakSection,
2770 : kStrongSection,
2771 : kScalarSection
2772 : };
2773 :
2774 236 : void PossiblyStartTagged(FieldSectionType* section,
2775 : std::set<FieldSectionType>* completed_sections,
2776 : std::stringstream* o) {
2777 437 : if (completed_sections->count(FieldSectionType::kWeakSection) == 0 &&
2778 118 : completed_sections->count(FieldSectionType::kStrongSection) == 0 &&
2779 472 : *section != FieldSectionType::kWeakSection &&
2780 : *section != FieldSectionType::kStrongSection) {
2781 118 : *o << "V(kStartOfPointerFieldsOffset, 0) \\\n";
2782 : }
2783 236 : }
2784 :
2785 236 : void PossiblyEndTagged(FieldSectionType* section,
2786 : std::set<FieldSectionType>* completed_sections,
2787 : std::stringstream* o) {
2788 389 : if (completed_sections->count(FieldSectionType::kWeakSection) != 0 &&
2789 : completed_sections->count(FieldSectionType::kStrongSection) != 0) {
2790 118 : *o << "V(kEndOfTaggedFieldsOffset, 0) \\\n";
2791 : }
2792 236 : }
2793 :
2794 717 : void ProcessFieldInSection(FieldSectionType* section,
2795 : std::set<FieldSectionType>* completed_sections,
2796 : FieldSectionType field_section,
2797 : std::stringstream* o) {
2798 717 : if (*section != FieldSectionType::kNoSection) {
2799 450 : if (*section != field_section) {
2800 251 : if (completed_sections->count(field_section) != 0) {
2801 0 : ReportError("reopening of weak, strong or scalar field section");
2802 : }
2803 : completed_sections->insert(*section);
2804 251 : if (*section == FieldSectionType::kWeakSection) {
2805 118 : *o << "V(kEndOfWeakFieldsOffset, 0) \\\n";
2806 118 : PossiblyEndTagged(section, completed_sections, o);
2807 133 : } else if (*section == FieldSectionType::kStrongSection) {
2808 118 : *o << "V(kEndOfStrongFieldsOffset, 0) \\\n";
2809 118 : PossiblyEndTagged(section, completed_sections, o);
2810 : }
2811 : }
2812 : }
2813 717 : if (*section != field_section) {
2814 494 : if (field_section == FieldSectionType::kWeakSection) {
2815 118 : PossiblyStartTagged(section, completed_sections, o);
2816 118 : *o << "V(kStartOfWeakFieldsOffset, 0) \\\n";
2817 376 : } else if (field_section == FieldSectionType::kStrongSection) {
2818 118 : PossiblyStartTagged(section, completed_sections, o);
2819 118 : *o << "V(kStartOfStrongFieldsOffset, 0) \\\n";
2820 : }
2821 : }
2822 717 : *section = field_section;
2823 717 : }
2824 :
2825 236 : void CompleteFieldSection(FieldSectionType* section,
2826 : std::set<FieldSectionType>* completed_sections,
2827 : FieldSectionType field_section,
2828 : std::stringstream* o) {
2829 236 : if (completed_sections->count(field_section) == 0) {
2830 149 : ProcessFieldInSection(section, completed_sections, field_section, o);
2831 : ProcessFieldInSection(section, completed_sections,
2832 149 : FieldSectionType::kNoSection, o);
2833 : }
2834 236 : }
2835 :
2836 : } // namespace
2837 :
2838 1 : void ImplementationVisitor::GenerateClassDefinitions(std::string& file_name) {
2839 2 : std::stringstream new_contents_stream;
2840 : new_contents_stream << "#ifndef V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
2841 : "#define V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n"
2842 1 : "\n\n";
2843 :
2844 122 : for (auto i : GlobalContext::GetClasses()) {
2845 : ClassType* type = i.second;
2846 121 : if (!type->IsExtern()) continue;
2847 :
2848 : // TODO(danno): Ideally (and we've got several core V8 dev's feedback
2849 : // supporting this), Torque should generate the constants for the offsets
2850 : // directly and not go through the existing layer of macros, which actually
2851 : // currently just serves to additionally obfuscate where these values come
2852 : // from.
2853 118 : new_contents_stream << "#define ";
2854 : new_contents_stream << "TORQUE_GENERATED_"
2855 236 : << CapifyStringWithUnderscores(i.first)
2856 118 : << "_FIELDS(V) \\\n";
2857 236 : std::vector<Field> fields = type->fields();
2858 118 : FieldSectionType section = FieldSectionType::kNoSection;
2859 : std::set<FieldSectionType> completed_sections;
2860 419 : for (auto f : fields) {
2861 301 : CurrentSourcePosition::Scope scope(f.pos);
2862 301 : if (f.name_and_type.type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
2863 268 : if (f.is_weak) {
2864 : ProcessFieldInSection(§ion, &completed_sections,
2865 : FieldSectionType::kWeakSection,
2866 6 : &new_contents_stream);
2867 : } else {
2868 : ProcessFieldInSection(§ion, &completed_sections,
2869 : FieldSectionType::kStrongSection,
2870 262 : &new_contents_stream);
2871 : }
2872 : } else {
2873 : ProcessFieldInSection(§ion, &completed_sections,
2874 : FieldSectionType::kScalarSection,
2875 33 : &new_contents_stream);
2876 : }
2877 : size_t field_size;
2878 : std::string size_string;
2879 : std::string machine_type;
2880 301 : std::tie(field_size, size_string, machine_type) =
2881 602 : f.GetFieldSizeInformation();
2882 602 : new_contents_stream << "V(k" << CamelifyString(f.name_and_type.name)
2883 301 : << "Offset, " << size_string << ") \\\n";
2884 : }
2885 :
2886 : ProcessFieldInSection(§ion, &completed_sections,
2887 118 : FieldSectionType::kNoSection, &new_contents_stream);
2888 : CompleteFieldSection(§ion, &completed_sections,
2889 118 : FieldSectionType::kWeakSection, &new_contents_stream);
2890 : CompleteFieldSection(§ion, &completed_sections,
2891 : FieldSectionType::kStrongSection,
2892 118 : &new_contents_stream);
2893 :
2894 118 : new_contents_stream << "V(kSize, 0) \\\n";
2895 118 : new_contents_stream << "\n";
2896 : }
2897 :
2898 : new_contents_stream
2899 1 : << "\n#endif // V8_CLASS_BUILTIN_DEFINITIONS_FROM_DSL_H_\n";
2900 :
2901 : std::string new_contents(new_contents_stream.str());
2902 1 : ReplaceFileContentsIfDifferent(file_name, new_contents);
2903 1 : }
2904 :
2905 1 : void ImplementationVisitor::GeneratePrintDefinitions(std::string& file_name) {
2906 2 : std::stringstream new_contents_stream;
2907 :
2908 1 : new_contents_stream << "#ifdef OBJECT_PRINT\n\n";
2909 :
2910 1 : new_contents_stream << "#include \"src/objects.h\"\n\n";
2911 1 : new_contents_stream << "#include <iosfwd>\n\n";
2912 1 : new_contents_stream << "#include \"src/objects/struct-inl.h\"\n\n";
2913 :
2914 1 : new_contents_stream << "namespace v8 {\n";
2915 1 : new_contents_stream << "namespace internal {\n\n";
2916 :
2917 122 : for (auto i : GlobalContext::GetClasses()) {
2918 : ClassType* type = i.second;
2919 121 : if (!type->ShouldGeneratePrint()) continue;
2920 :
2921 : new_contents_stream << "void " << type->name() << "::" << type->name()
2922 3 : << "Print(std::ostream& os) {\n";
2923 3 : new_contents_stream << " PrintHeader(os, \"" << type->name() << "\");\n";
2924 3 : auto hierarchy = type->GetHierarchy();
2925 : std::map<std::string, const AggregateType*> field_names;
2926 13 : for (const AggregateType* aggregate_type : hierarchy) {
2927 20 : for (const Field& f : aggregate_type->fields()) {
2928 20 : if (f.name_and_type.name == "map") continue;
2929 : new_contents_stream << " os << \"\\n - " << f.name_and_type.name
2930 : << ": \" << "
2931 7 : << "Brief(" << f.name_and_type.name << "());\n";
2932 : }
2933 : }
2934 3 : new_contents_stream << " os << \"\\n\";\n";
2935 3 : new_contents_stream << "}\n\n";
2936 : }
2937 :
2938 1 : new_contents_stream << "} // namespace internal\"\n";
2939 1 : new_contents_stream << "} // namespace v8\"\n";
2940 :
2941 1 : new_contents_stream << "\n#endif // OBJECT_PRINT\n\n";
2942 :
2943 : std::string new_contents(new_contents_stream.str());
2944 1 : ReplaceFileContentsIfDifferent(file_name, new_contents);
2945 1 : }
2946 :
2947 : } // namespace torque
2948 : } // namespace internal
2949 59456 : } // namespace v8
|