OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 #include "src/asmjs/asm-types.h" |
| 6 |
| 7 #include <cinttypes> |
| 8 |
5 #include "src/v8.h" | 9 #include "src/v8.h" |
6 | 10 |
7 #include "src/asmjs/asm-types.h" | |
8 | |
9 namespace v8 { | 11 namespace v8 { |
10 namespace internal { | 12 namespace internal { |
11 namespace wasm { | 13 namespace wasm { |
12 | 14 |
13 AsmCallableType* AsmType::AsCallableType() { | 15 AsmCallableType* AsmType::AsCallableType() { |
14 if (AsValueType() != nullptr) { | 16 if (AsValueType() != nullptr) { |
15 return nullptr; | 17 return nullptr; |
16 } | 18 } |
17 | 19 |
18 DCHECK(this->AsFunctionType() != nullptr || | |
19 this->AsOverloadedFunctionType() != nullptr || | |
20 this->AsFFIType() != nullptr || | |
21 this->AsFunctionTableType() != nullptr); | |
22 return reinterpret_cast<AsmCallableType*>(this); | 20 return reinterpret_cast<AsmCallableType*>(this); |
23 } | 21 } |
24 | 22 |
25 std::string AsmType::Name() { | 23 std::string AsmType::Name() { |
26 AsmValueType* avt = this->AsValueType(); | 24 AsmValueType* avt = this->AsValueType(); |
27 if (avt != nullptr) { | 25 if (avt != nullptr) { |
28 switch (avt->Bitset()) { | 26 switch (avt->Bitset()) { |
29 #define RETURN_TYPE_NAME(CamelName, string_name, number, parent_types) \ | 27 #define RETURN_TYPE_NAME(CamelName, string_name, number, parent_types) \ |
30 case AsmValueType::kAsm##CamelName: \ | 28 case AsmValueType::kAsm##CamelName: \ |
31 return string_name; | 29 return string_name; |
(...skipping 19 matching lines...) Expand all Loading... |
51 } | 49 } |
52 | 50 |
53 // TODO(jpp): is it useful to allow non-value types to be tested with | 51 // TODO(jpp): is it useful to allow non-value types to be tested with |
54 // IsExactly? | 52 // IsExactly? |
55 return that == this; | 53 return that == this; |
56 } | 54 } |
57 | 55 |
58 bool AsmType::IsA(AsmType* that) { | 56 bool AsmType::IsA(AsmType* that) { |
59 // IsA is used for querying inheritance relationships. Therefore it is only | 57 // IsA is used for querying inheritance relationships. Therefore it is only |
60 // meaningful for basic types. | 58 // meaningful for basic types. |
61 AsmValueType* tavt = that->AsValueType(); | 59 if (auto* avt = this->AsValueType()) { |
62 if (tavt != nullptr) { | 60 if (auto* tavt = that->AsValueType()) { |
63 AsmValueType* avt = this->AsValueType(); | 61 return (avt->Bitset() & tavt->Bitset()) == tavt->Bitset(); |
64 if (avt == nullptr) { | |
65 return false; | |
66 } | 62 } |
67 return (avt->Bitset() & tavt->Bitset()) == tavt->Bitset(); | 63 return false; |
68 } | 64 } |
69 | 65 |
70 // TODO(jpp): is it useful to allow non-value types to be tested with IsA? | 66 if (auto* as_callable = this->AsCallableType()) { |
| 67 return as_callable->IsA(that); |
| 68 } |
| 69 |
| 70 UNREACHABLE(); |
71 return that == this; | 71 return that == this; |
72 } | 72 } |
73 | 73 |
74 int32_t AsmType::ElementSizeInBytes() { | 74 int32_t AsmType::ElementSizeInBytes() { |
75 auto* value = AsValueType(); | 75 auto* value = AsValueType(); |
76 if (value == nullptr) { | 76 if (value == nullptr) { |
77 return AsmType::kNotHeapType; | 77 return AsmType::kNotHeapType; |
78 } | 78 } |
79 switch (value->Bitset()) { | 79 switch (value->Bitset()) { |
80 case AsmValueType::kAsmInt8Array: | 80 case AsmValueType::kAsmInt8Array: |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 return AsmType::Intish(); | 131 return AsmType::Intish(); |
132 case AsmValueType::kAsmFloat32Array: | 132 case AsmValueType::kAsmFloat32Array: |
133 return AsmType::FloatishDoubleQ(); | 133 return AsmType::FloatishDoubleQ(); |
134 case AsmValueType::kAsmFloat64Array: | 134 case AsmValueType::kAsmFloat64Array: |
135 return AsmType::FloatQDoubleQ(); | 135 return AsmType::FloatQDoubleQ(); |
136 default: | 136 default: |
137 return AsmType::None(); | 137 return AsmType::None(); |
138 } | 138 } |
139 } | 139 } |
140 | 140 |
| 141 bool AsmCallableType::IsA(AsmType* other) { |
| 142 return other->AsCallableType() == this; |
| 143 } |
| 144 |
141 std::string AsmFunctionType::Name() { | 145 std::string AsmFunctionType::Name() { |
142 if (IsFroundType()) { | |
143 return "fround"; | |
144 } | |
145 | |
146 std::string ret; | 146 std::string ret; |
147 ret += "("; | 147 ret += "("; |
148 for (size_t ii = 0; ii < args_.size(); ++ii) { | 148 for (size_t ii = 0; ii < args_.size(); ++ii) { |
149 ret += args_[ii]->Name(); | 149 ret += args_[ii]->Name(); |
150 if (ii != args_.size() - 1) { | 150 if (ii != args_.size() - 1) { |
151 ret += ", "; | 151 ret += ", "; |
152 } | 152 } |
153 } | 153 } |
154 if (IsMinMaxType()) { | |
155 DCHECK_EQ(args_.size(), 2); | |
156 ret += "..."; | |
157 } | |
158 ret += ") -> "; | 154 ret += ") -> "; |
159 ret += return_type_->Name(); | 155 ret += return_type_->Name(); |
160 return ret; | 156 return ret; |
161 } | 157 } |
162 | 158 |
163 namespace { | 159 namespace { |
164 class AsmFroundType final : public AsmFunctionType { | 160 class AsmFroundType final : public AsmCallableType { |
165 public: | 161 public: |
166 bool IsFroundType() const override { return true; } | |
167 | |
168 private: | |
169 friend AsmType; | 162 friend AsmType; |
170 | 163 |
171 explicit AsmFroundType(Zone* zone) | 164 AsmFroundType() : AsmCallableType() {} |
172 : AsmFunctionType(zone, AsmType::Float()) {} | |
173 | 165 |
174 AsmType* ValidateCall(AsmType* return_type, | |
175 const ZoneVector<AsmType*>& args) override; | |
176 bool CanBeInvokedWith(AsmType* return_type, | 166 bool CanBeInvokedWith(AsmType* return_type, |
177 const ZoneVector<AsmType*>& args) override; | 167 const ZoneVector<AsmType*>& args) override; |
| 168 |
| 169 std::string Name() override { return "fround"; } |
178 }; | 170 }; |
179 } // namespace | 171 } // namespace |
180 | 172 |
181 AsmType* AsmType::FroundType(Zone* zone) { | 173 AsmType* AsmType::FroundType(Zone* zone) { |
182 auto* Fround = new (zone) AsmFroundType(zone); | 174 auto* Fround = new (zone) AsmFroundType(); |
183 return reinterpret_cast<AsmType*>(Fround); | 175 return reinterpret_cast<AsmType*>(Fround); |
184 } | 176 } |
185 | 177 |
186 // TODO(jpp): Remove this method. | |
187 AsmType* AsmFroundType::ValidateCall(AsmType* return_type, | |
188 const ZoneVector<AsmType*>& args) { | |
189 if (args.size() != 1) { | |
190 return AsmType::None(); | |
191 } | |
192 | |
193 auto* arg = args[0]; | |
194 if (!arg->IsA(AsmType::Floatish()) && !arg->IsA(AsmType::DoubleQ()) && | |
195 !arg->IsA(AsmType::Signed()) && !arg->IsA(AsmType::Unsigned())) { | |
196 return AsmType::None(); | |
197 } | |
198 | |
199 return AsmType::Float(); | |
200 } | |
201 | |
202 bool AsmFroundType::CanBeInvokedWith(AsmType* return_type, | 178 bool AsmFroundType::CanBeInvokedWith(AsmType* return_type, |
203 const ZoneVector<AsmType*>& args) { | 179 const ZoneVector<AsmType*>& args) { |
204 if (args.size() != 1) { | 180 if (args.size() != 1) { |
205 return false; | 181 return false; |
206 } | 182 } |
207 | 183 |
208 auto* arg = args[0]; | 184 auto* arg = args[0]; |
209 if (!arg->IsA(AsmType::Floatish()) && !arg->IsA(AsmType::DoubleQ()) && | 185 if (!arg->IsA(AsmType::Floatish()) && !arg->IsA(AsmType::DoubleQ()) && |
210 !arg->IsA(AsmType::Signed()) && !arg->IsA(AsmType::Unsigned())) { | 186 !arg->IsA(AsmType::Signed()) && !arg->IsA(AsmType::Unsigned())) { |
211 return false; | 187 return false; |
212 } | 188 } |
213 | 189 |
214 return true; | 190 return true; |
215 } | 191 } |
216 | 192 |
217 namespace { | 193 namespace { |
218 class AsmMinMaxType final : public AsmFunctionType { | 194 class AsmMinMaxType final : public AsmCallableType { |
219 public: | |
220 bool IsMinMaxType() const override { return true; } | |
221 | |
222 private: | 195 private: |
223 friend AsmType; | 196 friend AsmType; |
224 | 197 |
225 AsmMinMaxType(Zone* zone, AsmType* dest, AsmType* src) | 198 AsmMinMaxType(AsmType* dest, AsmType* src) |
226 : AsmFunctionType(zone, dest) { | 199 : AsmCallableType(), return_type_(dest), arg_(src) {} |
227 AddArgument(src); | |
228 AddArgument(src); | |
229 } | |
230 | |
231 AsmType* ValidateCall(AsmType* return_type, | |
232 const ZoneVector<AsmType*>& args) override { | |
233 if (!ReturnType()->IsExactly(return_type)) { | |
234 return AsmType::None(); | |
235 } | |
236 | |
237 if (args.size() < 2) { | |
238 return AsmType::None(); | |
239 } | |
240 | |
241 for (size_t ii = 0; ii < Arguments().size(); ++ii) { | |
242 if (!Arguments()[0]->IsExactly(args[ii])) { | |
243 return AsmType::None(); | |
244 } | |
245 } | |
246 | |
247 return ReturnType(); | |
248 } | |
249 | 200 |
250 bool CanBeInvokedWith(AsmType* return_type, | 201 bool CanBeInvokedWith(AsmType* return_type, |
251 const ZoneVector<AsmType*>& args) override { | 202 const ZoneVector<AsmType*>& args) override { |
252 if (!ReturnType()->IsExactly(return_type)) { | 203 if (!return_type_->IsExactly(return_type)) { |
253 return false; | 204 return false; |
254 } | 205 } |
255 | 206 |
256 if (args.size() < 2) { | 207 if (args.size() < 2) { |
257 return false; | 208 return false; |
258 } | 209 } |
259 | 210 |
260 auto* arg_type = Arguments()[0]; | 211 for (size_t ii = 0; ii < args.size(); ++ii) { |
261 for (size_t ii = 0; ii < Arguments().size(); ++ii) { | 212 if (!args[ii]->IsA(arg_)) { |
262 if (!args[ii]->IsA(arg_type)) { | |
263 return false; | 213 return false; |
264 } | 214 } |
265 } | 215 } |
266 | 216 |
267 return true; | 217 return true; |
268 } | 218 } |
| 219 |
| 220 std::string Name() override { |
| 221 return "(" + arg_->Name() + ", " + arg_->Name() + "...) -> " + |
| 222 return_type_->Name(); |
| 223 } |
| 224 |
| 225 AsmType* return_type_; |
| 226 AsmType* arg_; |
269 }; | 227 }; |
270 } // namespace | 228 } // namespace |
271 | 229 |
272 AsmType* AsmType::MinMaxType(Zone* zone, AsmType* dest, AsmType* src) { | 230 AsmType* AsmType::MinMaxType(Zone* zone, AsmType* dest, AsmType* src) { |
273 DCHECK(dest->AsValueType() != nullptr); | 231 DCHECK(dest->AsValueType() != nullptr); |
274 DCHECK(src->AsValueType() != nullptr); | 232 DCHECK(src->AsValueType() != nullptr); |
275 auto* MinMax = new (zone) AsmMinMaxType(zone, dest, src); | 233 auto* MinMax = new (zone) AsmMinMaxType(dest, src); |
276 return reinterpret_cast<AsmType*>(MinMax); | 234 return reinterpret_cast<AsmType*>(MinMax); |
277 } | 235 } |
278 | 236 |
279 AsmType* AsmFFIType::ValidateCall(AsmType* return_type, | |
280 const ZoneVector<AsmType*>& args) { | |
281 for (size_t ii = 0; ii < args.size(); ++ii) { | |
282 if (!args[ii]->IsA(AsmType::Extern())) { | |
283 return AsmType::None(); | |
284 } | |
285 } | |
286 | |
287 return return_type; | |
288 } | |
289 | |
290 bool AsmFFIType::CanBeInvokedWith(AsmType* return_type, | 237 bool AsmFFIType::CanBeInvokedWith(AsmType* return_type, |
291 const ZoneVector<AsmType*>& args) { | 238 const ZoneVector<AsmType*>& args) { |
292 if (return_type->IsExactly(AsmType::Float())) { | 239 if (return_type->IsExactly(AsmType::Float())) { |
293 return false; | 240 return false; |
294 } | 241 } |
295 | 242 |
296 for (size_t ii = 0; ii < args.size(); ++ii) { | 243 for (size_t ii = 0; ii < args.size(); ++ii) { |
297 if (!args[ii]->IsA(AsmType::Extern())) { | 244 if (!args[ii]->IsA(AsmType::Extern())) { |
298 return false; | 245 return false; |
299 } | 246 } |
300 } | 247 } |
301 | 248 |
302 return true; | 249 return true; |
303 } | 250 } |
304 | 251 |
305 AsmType* AsmFunctionType::ValidateCall(AsmType* return_type, | 252 bool AsmFunctionType::IsA(AsmType* other) { |
306 const ZoneVector<AsmType*>& args) { | 253 auto* that = other->AsFunctionType(); |
307 if (!return_type_->IsExactly(return_type)) { | 254 if (that == nullptr) { |
308 return AsmType::None(); | 255 return false; |
| 256 } |
| 257 if (!return_type_->IsExactly(that->return_type_)) { |
| 258 return false; |
309 } | 259 } |
310 | 260 |
311 if (args_.size() != args.size()) { | 261 if (args_.size() != that->args_.size()) { |
312 return AsmType::None(); | 262 return false; |
313 } | 263 } |
314 | 264 |
315 for (size_t ii = 0; ii < args_.size(); ++ii) { | 265 for (size_t ii = 0; ii < args_.size(); ++ii) { |
316 if (!args_[ii]->IsExactly(args[ii])) { | 266 if (!args_[ii]->IsExactly(that->args_[ii])) { |
317 return AsmType::None(); | 267 return false; |
318 } | 268 } |
319 } | 269 } |
320 | 270 |
321 return return_type_; | 271 return true; |
322 } | 272 } |
323 | 273 |
324 bool AsmFunctionType::CanBeInvokedWith(AsmType* return_type, | 274 bool AsmFunctionType::CanBeInvokedWith(AsmType* return_type, |
325 const ZoneVector<AsmType*>& args) { | 275 const ZoneVector<AsmType*>& args) { |
326 if (!return_type_->IsExactly(return_type)) { | 276 if (!return_type_->IsExactly(return_type)) { |
327 return false; | 277 return false; |
328 } | 278 } |
329 | 279 |
330 if (args_.size() != args.size()) { | 280 if (args_.size() != args.size()) { |
331 return false; | 281 return false; |
(...skipping 14 matching lines...) Expand all Loading... |
346 for (size_t ii = 0; ii < overloads_.size(); ++ii) { | 296 for (size_t ii = 0; ii < overloads_.size(); ++ii) { |
347 if (ii != 0) { | 297 if (ii != 0) { |
348 ret += " /\\ "; | 298 ret += " /\\ "; |
349 } | 299 } |
350 ret += overloads_[ii]->Name(); | 300 ret += overloads_[ii]->Name(); |
351 } | 301 } |
352 | 302 |
353 return ret; | 303 return ret; |
354 } | 304 } |
355 | 305 |
356 AsmType* AsmOverloadedFunctionType::ValidateCall( | |
357 AsmType* return_type, const ZoneVector<AsmType*>& args) { | |
358 for (size_t ii = 0; ii < overloads_.size(); ++ii) { | |
359 auto* validated_type = | |
360 overloads_[ii]->AsCallableType()->ValidateCall(return_type, args); | |
361 if (validated_type != AsmType::None()) { | |
362 return validated_type; | |
363 } | |
364 } | |
365 | |
366 return AsmType::None(); | |
367 } | |
368 | |
369 bool AsmOverloadedFunctionType::CanBeInvokedWith( | 306 bool AsmOverloadedFunctionType::CanBeInvokedWith( |
370 AsmType* return_type, const ZoneVector<AsmType*>& args) { | 307 AsmType* return_type, const ZoneVector<AsmType*>& args) { |
371 for (size_t ii = 0; ii < overloads_.size(); ++ii) { | 308 for (size_t ii = 0; ii < overloads_.size(); ++ii) { |
372 if (overloads_[ii]->AsCallableType()->CanBeInvokedWith(return_type, args)) { | 309 if (overloads_[ii]->AsCallableType()->CanBeInvokedWith(return_type, args)) { |
373 return true; | 310 return true; |
374 } | 311 } |
375 } | 312 } |
376 | 313 |
377 return false; | 314 return false; |
378 } | 315 } |
379 | 316 |
380 void AsmOverloadedFunctionType::AddOverload(AsmType* overload) { | 317 void AsmOverloadedFunctionType::AddOverload(AsmType* overload) { |
381 DCHECK(overload->AsFunctionType() != nullptr); | 318 DCHECK(overload->AsCallableType() != nullptr); |
382 overloads_.push_back(overload); | 319 overloads_.push_back(overload); |
383 } | 320 } |
384 | 321 |
385 AsmFunctionTableType::AsmFunctionTableType(size_t length, AsmType* signature) | 322 AsmFunctionTableType::AsmFunctionTableType(size_t length, AsmType* signature) |
386 : length_(length), signature_(signature) { | 323 : length_(length), signature_(signature) { |
387 DCHECK(signature_ != nullptr); | 324 DCHECK(signature_ != nullptr); |
388 DCHECK(signature_->AsFunctionType() != nullptr); | 325 DCHECK(signature_->AsFunctionType() != nullptr); |
389 } | 326 } |
390 | 327 |
| 328 namespace { |
| 329 // ToString is used for reporting function tables' names. It converts its |
| 330 // argument to uint32_t because asm.js integers are 32-bits, thus effectively |
| 331 // limiting the max function table's length. |
| 332 std::string ToString(size_t s) { |
| 333 auto u32 = static_cast<uint32_t>(s); |
| 334 // 16 bytes is more than enough to represent a 32-bit integer as a base 10 |
| 335 // string. |
| 336 char digits[16]; |
| 337 int length = base::OS::SNPrintF(digits, arraysize(digits), "%" PRIu32, u32); |
| 338 DCHECK_NE(length, -1); |
| 339 return std::string(digits, length); |
| 340 } |
| 341 } // namespace |
| 342 |
391 std::string AsmFunctionTableType::Name() { | 343 std::string AsmFunctionTableType::Name() { |
392 return signature_->Name() + "[" + std::to_string(length_) + "]"; | 344 return "(" + signature_->Name() + ")[" + ToString(length_) + "]"; |
393 } | |
394 | |
395 AsmType* AsmFunctionTableType::ValidateCall(AsmType* return_type, | |
396 const ZoneVector<AsmType*>& args) { | |
397 return signature_->AsCallableType()->ValidateCall(return_type, args); | |
398 } | 345 } |
399 | 346 |
400 bool AsmFunctionTableType::CanBeInvokedWith(AsmType* return_type, | 347 bool AsmFunctionTableType::CanBeInvokedWith(AsmType* return_type, |
401 const ZoneVector<AsmType*>& args) { | 348 const ZoneVector<AsmType*>& args) { |
402 return signature_->AsCallableType()->CanBeInvokedWith(return_type, args); | 349 return signature_->AsCallableType()->CanBeInvokedWith(return_type, args); |
403 } | 350 } |
404 | 351 |
405 } // namespace wasm | 352 } // namespace wasm |
406 } // namespace internal | 353 } // namespace internal |
407 } // namespace v8 | 354 } // namespace v8 |
OLD | NEW |