v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
declaration-visitor.cc
Go to the documentation of this file.
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
6
7#include <optional>
8
9#include "src/torque/ast.h"
14
15namespace v8::internal::torque {
16
17Namespace* GetOrCreateNamespace(const std::string& name) {
18 std::vector<Namespace*> existing_namespaces = FilterDeclarables<Namespace>(
20 if (existing_namespaces.empty()) {
22 }
23 DCHECK_EQ(1, existing_namespaces.size());
24 return existing_namespaces.front();
25}
26
28 CurrentSourcePosition::Scope scope(decl->pos);
29 switch (decl->kind) {
30#define ENUM_ITEM(name) \
31 case AstNode::Kind::k##name: \
32 return Predeclare(name::cast(decl));
34#undef ENUM_ITEM
35 case AstNode::Kind::kNamespaceDeclaration:
36 return Predeclare(NamespaceDeclaration::cast(decl));
37 case AstNode::Kind::kGenericCallableDeclaration:
38 return Predeclare(GenericCallableDeclaration::cast(decl));
39 case AstNode::Kind::kGenericTypeDeclaration:
40 return Predeclare(GenericTypeDeclaration::cast(decl));
41
42 default:
43 // Only processes type declaration nodes, namespaces and generics.
44 break;
45 }
46}
47
49 CurrentSourcePosition::Scope scope(decl->pos);
50 switch (decl->kind) {
51#define ENUM_ITEM(name) \
52 case AstNode::Kind::k##name: \
53 return Visit(name::cast(decl));
55#undef ENUM_ITEM
56 default:
58 }
59}
60
62 BuiltinDeclaration* decl, std::string external_name,
63 std::string readable_name, Signature signature,
64 std::optional<std::string> use_counter_name,
65 std::optional<Statement*> body) {
66 const bool javascript = decl->javascript_linkage;
67 const bool varargs = decl->parameters.has_varargs;
68 Builtin::Kind kind = !javascript ? Builtin::kStub
71 bool has_custom_interface_descriptor = false;
72 if (decl->kind == AstNode::Kind::kTorqueBuiltinDeclaration) {
73 has_custom_interface_descriptor =
74 static_cast<TorqueBuiltinDeclaration*>(decl)
75 ->has_custom_interface_descriptor;
76 }
77
78 if (varargs && !javascript) {
79 Error("Rest parameters require ", decl->name,
80 " to be a JavaScript builtin");
81 }
82
83 if (javascript) {
84 if (!signature.return_type->IsSubtypeOf(TypeOracle::GetJSAnyType())) {
85 Error("Return type of JavaScript-linkage builtins has to be JSAny.")
86 .Position(decl->return_type->pos);
87 }
88 // Validate the parameter types. In general, for JS builtins the parameters
89 // must all be tagged values (JSAny). However, we currently allow declaring
90 // "extern javascript" builtins with any parameter types. The reason is
91 // that those are typically used for tailcalls, in which case we typically
92 // need to supply the implicit parameters of the JS calling convention
93 // (target, receiver, argc, etc.). It would probablu be nicer if we could
94 // instead declare these parameters as js-implicit (like we do for
95 // torque-defined javascript builtins) and then allow explicitly supplying
96 // the implicit arguments during tailscalls. It's unclear though if that's
97 // worth the effort. In particular, calls and tailcalls to javascript
98 // builtins will emit CSA::CallJSBuiltin and CSA::TailCallJSBuiltin calls
99 // which will validate the parameter types at C++ compile time.
100 if (decl->kind != AstNode::Kind::kExternalBuiltinDeclaration) {
101 for (size_t i = signature.implicit_count;
102 i < signature.parameter_types.types.size(); ++i) {
103 const Type* parameter_type = signature.parameter_types.types[i];
104 if (!TypeOracle::GetJSAnyType()->IsSubtypeOf(parameter_type)) {
105 Error(
106 "Parameters of JavaScript-linkage builtins have to be a "
107 "supertype "
108 "of JSAny.")
109 .Position(decl->parameters.types[i]->pos);
110 }
111 }
112 }
113 }
114
115 for (size_t i = 0; i < signature.types().size(); ++i) {
116 const Type* parameter_type = signature.types()[i];
117 if (parameter_type->StructSupertype()) {
118 Error("Builtin do not support structs as arguments, but argument ",
119 signature.parameter_names[i], " has type ", *signature.types()[i],
120 ".");
121 }
122 if (parameter_type->IsFloat32() || parameter_type->IsFloat64()) {
123 if (!has_custom_interface_descriptor) {
124 Error("Builtin ", external_name,
125 " needs a custom interface descriptor, "
126 "because it uses type ",
127 *parameter_type, " for argument ", signature.parameter_names[i],
128 ". One reason being "
129 "that the default descriptor defines xmm0 to be the first "
130 "floating point argument register, which is current used as "
131 "scratch on ia32 and cannot be allocated.");
132 }
133 }
134 }
135
136 if (signature.return_type->StructSupertype() && javascript) {
137 Error(
138 "Builtins with JS linkage cannot return structs, but the return type "
139 "is ",
140 *signature.return_type, ".");
141 }
142
143 if (signature.return_type == TypeOracle::GetVoidType()) {
144 Error("Builtins cannot have return type void.");
145 }
146
148 if (has_custom_interface_descriptor)
151 std::move(external_name), std::move(readable_name), kind, flags,
152 std::move(signature), std::move(use_counter_name), body);
153 // TODO(v8:12261): Recheck this.
154 // builtin->SetIdentifierPosition(decl->name->pos);
155 return builtin;
156}
157
159 Builtin* builtin = CreateBuiltin(decl, decl->name->value, decl->name->value,
161 std::nullopt, std::nullopt);
162 builtin->SetIdentifierPosition(decl->name->pos);
163 Declarations::Declare(decl->name->value, builtin);
164}
165
167 Signature signature = TypeVisitor::MakeSignature(decl);
168 if (signature.parameter_types.types.empty()) {
170 "Missing parameters for runtime function, at least the context "
171 "parameter is required.");
172 }
173 if (!(signature.parameter_types.types[0] == TypeOracle::GetContextType() ||
176 "first parameter to runtime functions has to be the context and have "
177 "type Context or NoContext, but found type ",
178 *signature.parameter_types.types[0]);
179 }
180 if (!(signature.return_type->IsSubtypeOf(TypeOracle::GetStrongTaggedType()) ||
181 signature.return_type == TypeOracle::GetVoidType() ||
182 signature.return_type == TypeOracle::GetNeverType())) {
184 "runtime functions can only return strong tagged values, but "
185 "found type ",
186 *signature.return_type);
187 }
188 for (const Type* parameter_type : signature.parameter_types.types) {
189 if (!parameter_type->IsSubtypeOf(TypeOracle::GetStrongTaggedType())) {
191 "runtime functions can only take strong tagged parameters, but "
192 "found type ",
193 *parameter_type);
194 }
195 }
196
197 RuntimeFunction* function =
199 function->SetIdentifierPosition(decl->name->pos);
200 function->SetPosition(decl->pos);
203 }
204}
205
208 decl->name->value, true, decl->external_assembler_name,
209 TypeVisitor::MakeSignature(decl), std::nullopt, decl->op);
210 macro->SetIdentifierPosition(decl->name->pos);
211 macro->SetPosition(decl->pos);
214 }
215}
216
218 Signature signature = TypeVisitor::MakeSignature(decl);
219 if (decl->use_counter_name &&
220 (signature.types().empty() ||
221 (signature.types()[0] != TypeOracle::GetNativeContextType() &&
222 signature.types()[0] != TypeOracle::GetContextType()))) {
224 "@incrementUseCounter requires the builtin's first parameter to be of "
225 "type Context or NativeContext, but found type ",
226 *signature.types()[0]);
227 }
228 auto builtin = CreateBuiltin(decl, decl->name->value, decl->name->value,
229 signature, decl->use_counter_name, decl->body);
230 builtin->SetIdentifierPosition(decl->name->pos);
231 builtin->SetPosition(decl->pos);
232 Declarations::Declare(decl->name->value, builtin);
233}
234
237 decl->name->value, decl->export_to_csa, std::nullopt,
238 TypeVisitor::MakeSignature(decl), decl->body, decl->op);
239 macro->SetIdentifierPosition(decl->name->pos);
240 macro->SetPosition(decl->pos);
243 }
244}
245
250
258
260 std::vector<GenericCallable*> generic_list =
262 // Find the matching generic specialization based on the concrete parameter
263 // list.
264 GenericCallable* matching_generic = nullptr;
265 Signature signature_with_types = TypeVisitor::MakeSignature(decl);
266 for (GenericCallable* generic : generic_list) {
267 // This argument inference is just to trigger constraint checking on the
268 // generic arguments.
269 TypeArgumentInference inference = generic->InferSpecializationTypes(
271 if (inference.HasFailed()) {
272 continue;
273 }
274 Signature generic_signature_with_types =
277 if (signature_with_types.HasSameTypesAs(generic_signature_with_types,
279 if (matching_generic != nullptr) {
280 std::stringstream stream;
281 stream << "specialization of " << decl->name
282 << " is ambigous, it matches more than one generic declaration ("
283 << *matching_generic << " and " << *generic << ")";
284 ReportError(stream.str());
285 }
286 matching_generic = generic;
287 }
288 }
289
290 if (matching_generic == nullptr) {
291 std::stringstream stream;
292 if (generic_list.empty()) {
293 stream << "no generic defined with the name " << decl->name;
294 ReportError(stream.str());
295 }
296 stream << "specialization of " << decl->name
297 << " doesn't match any generic declaration\n";
298 stream << "specialization signature:";
299 stream << "\n " << signature_with_types;
300 stream << "\ncandidates are:";
301 for (GenericCallable* generic : generic_list) {
302 stream << "\n "
304 generic,
306 }
307 ReportError(stream.str());
308 }
309
312 matching_generic->IdentifierPosition());
313 }
314
315 CallableDeclaration* generic_declaration = matching_generic->declaration();
316
319 decl->generic_parameters)},
320 generic_declaration, decl, decl->body, decl->pos);
321}
322
324 const Type* type = TypeVisitor::ComputeType(decl->type);
325 if (!type->IsConstexpr()) {
326 std::stringstream stream;
327 stream << "extern constants must have constexpr type, but found: \""
328 << *type << "\"\n";
329 ReportError(stream.str());
330 }
331
332 ExternConstant* constant =
336 }
337}
338
342
345 size_t i = 0;
346 const std::size_t generic_parameter_count =
347 key.generic->generic_parameters().size();
348 if (generic_parameter_count != key.specialized_types.size()) {
349 std::stringstream stream;
350 stream << "Wrong generic argument count for specialization of \""
351 << key.generic->name() << "\", expected: " << generic_parameter_count
352 << ", actual: " << key.specialized_types.size();
353 ReportError(stream.str());
354 }
355
356 for (auto type : key.specialized_types) {
357 Identifier* generic_type_name = key.generic->generic_parameters()[i++].name;
358 TypeAlias* alias = Declarations::DeclareType(generic_type_name, type);
359 alias->SetIsUserDefined(false);
360 }
361}
362
365 CurrentScope::Scope generic_scope(key.generic->ParentScope());
366 // Create a temporary fake-namespace just to temporarily declare the
367 // specialization aliases for the generic types to create a signature.
368 Namespace tmp_namespace("_tmp");
369 CurrentScope::Scope tmp_namespace_scope(&tmp_namespace);
371 return TypeVisitor::MakeSignature(key.generic->declaration());
372}
373
376 std::optional<Statement*> body = key.generic->CallableBody();
377 if (!body && IntrinsicDeclaration::DynamicCast(key.generic->declaration()) ==
378 nullptr) {
379 ReportError("missing specialization of ", key.generic->name(),
380 " with types <", key.specialized_types, "> declared at ",
381 key.generic->Position());
382 }
383 SpecializationRequester requester{CurrentSourcePosition::Get(),
384 CurrentScope::Get(), ""};
385 CurrentScope::Scope generic_scope(key.generic->ParentScope());
386 Callable* result = Specialize(key, key.generic->declaration(), std::nullopt,
387 body, CurrentSourcePosition::Get());
388 result->SetIsUserDefined(false);
389 requester.name = result->ReadableName();
390 result->SetSpecializationRequester(requester);
391 CurrentScope::Scope callable_scope(result);
393 return result;
394}
395
399 std::optional<const SpecializationDeclaration*> explicit_specialization,
400 std::optional<Statement*> body, SourcePosition position) {
401 CurrentSourcePosition::Scope pos_scope(position);
402 size_t generic_parameter_count = key.generic->generic_parameters().size();
403 if (generic_parameter_count != key.specialized_types.size()) {
404 std::stringstream stream;
405 stream << "number of template parameters ("
406 << std::to_string(key.specialized_types.size())
407 << ") to intantiation of generic " << declaration->name
408 << " doesnt match the generic's declaration ("
409 << std::to_string(generic_parameter_count) << ")";
410 ReportError(stream.str());
411 }
412 if (key.generic->GetSpecialization(key.specialized_types)) {
413 ReportError("cannot redeclare specialization of ", key.generic->name(),
414 " with types <", key.specialized_types, ">");
415 }
416
417 Signature type_signature =
418 explicit_specialization
419 ? TypeVisitor::MakeSignature(*explicit_specialization)
421
422 std::string generated_name = Declarations::GetGeneratedCallableName(
423 declaration->name->value, key.specialized_types);
424 std::stringstream readable_name;
425 readable_name << declaration->name->value << "<";
426 bool first = true;
427 for (const Type* t : key.specialized_types) {
428 if (!first) readable_name << ", ";
429 readable_name << *t;
430 first = false;
431 }
432 readable_name << ">";
433 Callable* callable;
434 if (MacroDeclaration::DynamicCast(declaration) != nullptr) {
435 callable =
436 Declarations::CreateTorqueMacro(generated_name, readable_name.str(),
437 false, type_signature, *body, true);
438 } else if (IntrinsicDeclaration::DynamicCast(declaration) != nullptr) {
439 callable =
440 Declarations::CreateIntrinsic(declaration->name->value, type_signature);
441 } else {
442 BuiltinDeclaration* builtin = BuiltinDeclaration::cast(declaration);
443 std::optional<std::string> use_counter_name;
444 if (TorqueBuiltinDeclaration* torque_builtin =
445 TorqueBuiltinDeclaration::DynamicCast(builtin)) {
446 use_counter_name = torque_builtin->use_counter_name;
447 } else {
448 use_counter_name = std::nullopt;
449 }
450 callable = CreateBuiltin(
451 builtin, GlobalContext::MakeUniqueName(generated_name),
452 readable_name.str(), type_signature, use_counter_name, *body);
453 }
454 key.generic->AddSpecialization(key.specialized_types, callable);
455 return callable;
456}
457
459 const auto& all_declarables = GlobalContext::AllDeclarables();
460 for (size_t i = 0; i < all_declarables.size(); ++i) {
461 Declarable* declarable = all_declarables[i].get();
462 if (const TypeAlias* alias = TypeAlias::DynamicCast(declarable)) {
463 CurrentScope::Scope scope_activator(alias->ParentScope());
464 CurrentSourcePosition::Scope position_activator(alias->Position());
465 alias->Resolve();
466 }
467 }
468}
469
470} // namespace v8::internal::torque
Builtins::Kind kind
Definition builtins.cc:40
SourcePosition IdentifierPosition() const
Definition declarable.h:103
void SetIsUserDefined(bool is_user_defined)
Definition declarable.h:112
static Signature MakeSpecializedSignature(const SpecializationKey< GenericCallable > &key)
static Callable * SpecializeImplicit(const SpecializationKey< GenericCallable > &key)
static Callable * Specialize(const SpecializationKey< GenericCallable > &key, CallableDeclaration *declaration, std::optional< const SpecializationDeclaration * > explicit_specialization, std::optional< Statement * > body, SourcePosition position)
static void DeclareSpecializedTypes(const SpecializationKey< GenericCallable > &key)
static Builtin * CreateBuiltin(BuiltinDeclaration *decl, std::string external_name, std::string readable_name, Signature signature, std::optional< std::string > use_counter_name, std::optional< Statement * > body)
static Intrinsic * CreateIntrinsic(const std::string &name, const Signature &signature)
static TypeAlias * DeclareType(const Identifier *name, const Type *type)
static TorqueMacro * CreateTorqueMacro(std::string external_name, std::string readable_name, bool exported_to_csa, Signature signature, std::optional< Statement * > body, bool is_user_defined)
static T * Declare(const std::string &name, T *d)
static Macro * DeclareMacro(const std::string &name, bool accessible_from_csa, std::optional< std::string > external_assembler_name, const Signature &signature, std::optional< Statement * > body, std::optional< std::string > op={}, bool is_user_defined=true)
static std::vector< Declarable * > TryLookupShallow(const QualifiedName &name)
static ExternConstant * DeclareExternConstant(Identifier *name, const Type *type, std::string value)
static Builtin * CreateBuiltin(std::string external_name, std::string readable_name, Builtin::Kind kind, Builtin::Flags flags, Signature signature, std::optional< std::string > use_counter_name, std::optional< Statement * > body)
static Namespace * DeclareNamespace(const std::string &name)
static std::vector< GenericCallable * > LookupGeneric(const std::string &name)
static RuntimeFunction * DeclareRuntimeFunction(const std::string &name, const Signature &signature)
static Intrinsic * DeclareIntrinsic(const std::string &name, const Signature &signature)
static std::string GetGeneratedCallableName(const std::string &name, const TypeVector &specialized_types)
static NamespaceConstant * DeclareNamespaceConstant(Identifier *name, const Type *type, Expression *body)
static void AddCppInclude(std::string include_path)
static const std::vector< std::unique_ptr< Declarable > > & AllDeclarables()
static std::string MakeUniqueName(const std::string &base)
static V8_EXPORT_PRIVATE kythe_entity_t AddConstantDefinition(const Value *constant)
Definition kythe-data.cc:28
static V8_EXPORT_PRIVATE kythe_entity_t AddFunctionDefinition(Callable *callable)
Definition kythe-data.cc:53
static V8_EXPORT_PRIVATE void AddDefinition(SourcePosition token, SourcePosition definition)
MessageBuilder & Position(SourcePosition position)
Definition utils.h:52
static const Type * GetStrongTaggedType()
static const Type * GetNoContextType()
static const Type * GetNativeContextType()
static const Type * GetVoidType()
static const Type * GetContextType()
static const Type * GetJSAnyType()
static const Type * GetNeverType()
static TypeVector ComputeTypeVector(const std::vector< TypeExpression * > &v)
static const Type * ComputeType(TypeExpression *type_expression)
static Signature MakeSignature(const CallableDeclaration *declaration)
virtual bool IsSubtypeOf(const Type *supertype) const
Definition types.cc:101
std::optional< const StructType * > StructSupertype() const
Definition types.cc:133
bool IsFloat64() const
Definition types.h:133
bool IsFloat32() const
Definition types.h:132
ZoneVector< RpoNumber > & result
Builtin builtin
int position
Definition liveedit.cc:290
void ReportError(Args &&... args)
Definition utils.h:96
Namespace * GetOrCreateNamespace(const std::string &name)
std::vector< T * > FilterDeclarables(const std::vector< Declarable * > list)
MessageBuilder Error(Args &&... args)
Definition utils.h:81
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
SourcePosition pos
Definition ast.h:112
std::optional< std::string > op
Definition ast.h:1003
std::vector< TypeExpression * > types
Definition ast.h:627
ParameterTypes parameter_types
Definition types.h:923
bool HasSameTypesAs(const Signature &other, ParameterMode mode=ParameterMode::kProcessImplicit) const
Definition types.cc:1128
const TypeVector & types() const
Definition types.h:920
std::vector< TypeExpression * > generic_parameters
Definition ast.h:1176
std::optional< std::string > use_counter_name
Definition ast.h:1098
std::optional< Statement * > body
Definition ast.h:1099
std::optional< Statement * > body
Definition ast.h:1044
Symbol declaration
#define AST_DECLARATION_NODE_KIND_LIST(V)
Definition ast.h:75
#define AST_TYPE_DECLARATION_NODE_KIND_LIST(V)
Definition ast.h:68