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