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 <iostream>
6
7 #include "src/torque/declarable.h"
8 #include "src/torque/type-oracle.h"
9 #include "src/torque/types.h"
10
11 namespace v8 {
12 namespace internal {
13 namespace torque {
14
ToString() const15 std::string Type::ToString() const {
16 if (aliases_.size() == 0) return ToExplicitString();
17 if (aliases_.size() == 1) return *aliases_.begin();
18 std::stringstream result;
19 int i = 0;
20 for (const std::string& alias : aliases_) {
21 if (i == 0) {
22 result << alias << " (aka. ";
23 } else if (i == 1) {
24 result << alias;
25 } else {
26 result << ", " << alias;
27 }
28 ++i;
29 }
30 result << ")";
31 return result.str();
32 }
33
IsSubtypeOf(const Type * supertype) const34 bool Type::IsSubtypeOf(const Type* supertype) const {
35 if (IsNever()) return true;
36 if (const UnionType* union_type = UnionType::DynamicCast(supertype)) {
37 return union_type->IsSupertypeOf(this);
38 }
39 const Type* subtype = this;
40 while (subtype != nullptr) {
41 if (subtype == supertype) return true;
42 subtype = subtype->parent();
43 }
44 return false;
45 }
46
47 // static
CommonSupertype(const Type * a,const Type * b)48 const Type* Type::CommonSupertype(const Type* a, const Type* b) {
49 int diff = a->Depth() - b->Depth();
50 const Type* a_supertype = a;
51 const Type* b_supertype = b;
52 for (; diff > 0; --diff) a_supertype = a_supertype->parent();
53 for (; diff < 0; ++diff) b_supertype = b_supertype->parent();
54 while (a_supertype && b_supertype) {
55 if (a_supertype == b_supertype) return a_supertype;
56 a_supertype = a_supertype->parent();
57 b_supertype = b_supertype->parent();
58 }
59 ReportError("types " + a->ToString() + " and " + b->ToString() +
60 " have no common supertype");
61 }
62
Depth() const63 int Type::Depth() const {
64 int result = 0;
65 for (const Type* current = parent_; current; current = current->parent_) {
66 ++result;
67 }
68 return result;
69 }
70
IsAbstractName(const std::string & name) const71 bool Type::IsAbstractName(const std::string& name) const {
72 if (!IsAbstractType()) return false;
73 return AbstractType::cast(this)->name() == name;
74 }
75
GetGeneratedTNodeTypeName() const76 std::string AbstractType::GetGeneratedTNodeTypeName() const {
77 std::string result = GetGeneratedTypeName();
78 DCHECK_EQ(result.substr(0, 6), "TNode<");
79 result = result.substr(6, result.length() - 7);
80 return result;
81 }
82
ToExplicitString() const83 std::string FunctionPointerType::ToExplicitString() const {
84 std::stringstream result;
85 result << "builtin (";
86 PrintCommaSeparatedList(result, parameter_types_);
87 result << ") => " << *return_type_;
88 return result.str();
89 }
90
MangledName() const91 std::string FunctionPointerType::MangledName() const {
92 std::stringstream result;
93 result << "FT";
94 for (const Type* t : parameter_types_) {
95 std::string arg_type_string = t->MangledName();
96 result << arg_type_string.size() << arg_type_string;
97 }
98 std::string return_type_string = return_type_->MangledName();
99 result << return_type_string.size() << return_type_string;
100 return result.str();
101 }
102
ToExplicitString() const103 std::string UnionType::ToExplicitString() const {
104 std::stringstream result;
105 result << "(";
106 bool first = true;
107 for (const Type* t : types_) {
108 if (!first) {
109 result << " | ";
110 }
111 first = false;
112 result << *t;
113 }
114 result << ")";
115 return result.str();
116 }
117
MangledName() const118 std::string UnionType::MangledName() const {
119 std::stringstream result;
120 result << "UT";
121 for (const Type* t : types_) {
122 std::string arg_type_string = t->MangledName();
123 result << arg_type_string.size() << arg_type_string;
124 }
125 return result.str();
126 }
127
GetGeneratedTNodeTypeName() const128 std::string UnionType::GetGeneratedTNodeTypeName() const {
129 if (types_.size() <= 3) {
130 std::set<std::string> members;
131 for (const Type* t : types_) {
132 members.insert(t->GetGeneratedTNodeTypeName());
133 }
134 if (members == std::set<std::string>{"Smi", "HeapNumber"}) {
135 return "Number";
136 }
137 if (members == std::set<std::string>{"Smi", "HeapNumber", "BigInt"}) {
138 return "Numeric";
139 }
140 }
141 return parent()->GetGeneratedTNodeTypeName();
142 }
143
NonConstexprVersion() const144 const Type* UnionType::NonConstexprVersion() const {
145 if (IsConstexpr()) {
146 auto it = types_.begin();
147 UnionType result((*it)->NonConstexprVersion());
148 ++it;
149 for (; it != types_.end(); ++it) {
150 result.Extend((*it)->NonConstexprVersion());
151 }
152 return TypeOracle::GetUnionType(std::move(result));
153 }
154 return this;
155 }
156
RecomputeParent()157 void UnionType::RecomputeParent() {
158 const Type* parent = nullptr;
159 for (const Type* t : types_) {
160 if (parent == nullptr) {
161 parent = t;
162 } else {
163 parent = CommonSupertype(parent, t);
164 }
165 }
166 set_parent(parent);
167 }
168
Subtract(const Type * t)169 void UnionType::Subtract(const Type* t) {
170 for (auto it = types_.begin(); it != types_.end();) {
171 if ((*it)->IsSubtypeOf(t)) {
172 it = types_.erase(it);
173 } else {
174 ++it;
175 }
176 }
177 if (types_.size() == 0) types_.insert(TypeOracle::GetNeverType());
178 RecomputeParent();
179 }
180
SubtractType(const Type * a,const Type * b)181 const Type* SubtractType(const Type* a, const Type* b) {
182 UnionType result = UnionType::FromType(a);
183 result.Subtract(b);
184 return TypeOracle::GetUnionType(result);
185 }
186
ToExplicitString() const187 std::string StructType::ToExplicitString() const {
188 std::stringstream result;
189 result << "{";
190 PrintCommaSeparatedList(result, fields_);
191 result << "}";
192 return result.str();
193 }
194
PrintSignature(std::ostream & os,const Signature & sig,bool with_names)195 void PrintSignature(std::ostream& os, const Signature& sig, bool with_names) {
196 os << "(";
197 for (size_t i = 0; i < sig.parameter_types.types.size(); ++i) {
198 if (i > 0) os << ", ";
199 if (with_names && !sig.parameter_names.empty()) {
200 os << sig.parameter_names[i] << ": ";
201 }
202 os << *sig.parameter_types.types[i];
203 }
204 if (sig.parameter_types.var_args) {
205 if (sig.parameter_names.size()) os << ", ";
206 os << "...";
207 }
208 os << ")";
209 os << ": " << *sig.return_type;
210
211 if (sig.labels.empty()) return;
212
213 os << " labels ";
214 for (size_t i = 0; i < sig.labels.size(); ++i) {
215 if (i > 0) os << ", ";
216 if (with_names) os << sig.labels[i].name;
217
218 if (sig.labels[i].types.size() > 0) os << "(" << sig.labels[i].types << ")";
219 }
220 }
221
operator <<(std::ostream & os,const NameAndType & name_and_type)222 std::ostream& operator<<(std::ostream& os, const NameAndType& name_and_type) {
223 os << name_and_type.name;
224 os << ": ";
225 os << *name_and_type.type;
226 return os;
227 }
228
operator <<(std::ostream & os,const Signature & sig)229 std::ostream& operator<<(std::ostream& os, const Signature& sig) {
230 PrintSignature(os, sig, true);
231 return os;
232 }
233
operator <<(std::ostream & os,const TypeVector & types)234 std::ostream& operator<<(std::ostream& os, const TypeVector& types) {
235 PrintCommaSeparatedList(os, types);
236 return os;
237 }
238
operator <<(std::ostream & os,const ParameterTypes & p)239 std::ostream& operator<<(std::ostream& os, const ParameterTypes& p) {
240 PrintCommaSeparatedList(os, p.types);
241 if (p.var_args) {
242 if (p.types.size() > 0) os << ", ";
243 os << "...";
244 }
245 return os;
246 }
247
HasSameTypesAs(const Signature & other) const248 bool Signature::HasSameTypesAs(const Signature& other) const {
249 if (!(parameter_types.types == other.parameter_types.types &&
250 parameter_types.var_args == other.parameter_types.var_args &&
251 return_type == other.return_type)) {
252 return false;
253 }
254 if (labels.size() != other.labels.size()) {
255 return false;
256 }
257 size_t i = 0;
258 for (auto l : labels) {
259 if (l.types != other.labels[i++].types) {
260 return false;
261 }
262 }
263 return true;
264 }
265
IsAssignableFrom(const Type * to,const Type * from)266 bool IsAssignableFrom(const Type* to, const Type* from) {
267 if (to == from) return true;
268 if (from->IsSubtypeOf(to)) return true;
269 return TypeOracle::IsImplicitlyConvertableFrom(to, from);
270 }
271
IsCompatibleSignature(const Signature & sig,const TypeVector & types,const std::vector<Label * > & labels)272 bool IsCompatibleSignature(const Signature& sig, const TypeVector& types,
273 const std::vector<Label*>& labels) {
274 auto i = sig.parameter_types.types.begin();
275 if (sig.parameter_types.types.size() > types.size()) return false;
276 // TODO(danno): The test below is actually insufficient. The labels'
277 // parameters must be checked too. ideally, the named part of
278 // LabelDeclarationVector would be factored out so that the label count and
279 // parameter types could be passed separately.
280 if (sig.labels.size() != labels.size()) return false;
281 for (auto current : types) {
282 if (i == sig.parameter_types.types.end()) {
283 if (!sig.parameter_types.var_args) return false;
284 if (!IsAssignableFrom(TypeOracle::GetObjectType(), current)) return false;
285 } else {
286 if (!IsAssignableFrom(*i++, current)) return false;
287 }
288 }
289 return true;
290 }
291
operator <(const Type & a,const Type & b)292 bool operator<(const Type& a, const Type& b) {
293 return a.MangledName() < b.MangledName();
294 }
295
VisitResult(const Type * type,const Value * declarable)296 VisitResult::VisitResult(const Type* type, const Value* declarable)
297 : type_(type), value_(), declarable_(declarable) {}
298
LValue() const299 std::string VisitResult::LValue() const {
300 return std::string("*") + (declarable_ ? (*declarable_)->value() : value_);
301 }
302
RValue() const303 std::string VisitResult::RValue() const {
304 std::string result;
305 if (declarable()) {
306 auto value = *declarable();
307 if (value->IsVariable() && !Variable::cast(value)->IsDefined()) {
308 std::stringstream s;
309 s << "\"" << value->name() << "\" is used before it is defined";
310 ReportError(s.str());
311 }
312 result = value->RValue();
313 } else {
314 result = value_;
315 }
316 return "implicit_cast<" + type()->GetGeneratedTypeName() + ">(" + result +
317 ")";
318 }
319
320 } // namespace torque
321 } // namespace internal
322 } // namespace v8
323