• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "src/asmjs/asm-types.h"
6 
7 #include <cinttypes>
8 
9 #include "src/utils.h"
10 #include "src/v8.h"
11 
12 namespace v8 {
13 namespace internal {
14 namespace wasm {
15 
AsCallableType()16 AsmCallableType* AsmType::AsCallableType() {
17   if (AsValueType() != nullptr) {
18     return nullptr;
19   }
20 
21   return reinterpret_cast<AsmCallableType*>(this);
22 }
23 
Name()24 std::string AsmType::Name() {
25   AsmValueType* avt = this->AsValueType();
26   if (avt != nullptr) {
27     switch (avt->Bitset()) {
28 #define RETURN_TYPE_NAME(CamelName, string_name, number, parent_types) \
29   case AsmValueType::kAsm##CamelName:                                  \
30     return string_name;
31       FOR_EACH_ASM_VALUE_TYPE_LIST(RETURN_TYPE_NAME)
32 #undef RETURN_TYPE_NAME
33       default:
34         UNREACHABLE();
35     }
36   }
37 
38   return this->AsCallableType()->Name();
39 }
40 
IsExactly(AsmType * that)41 bool AsmType::IsExactly(AsmType* that) {
42   // TODO(jpp): maybe this can become this == that.
43   AsmValueType* avt = this->AsValueType();
44   if (avt != nullptr) {
45     AsmValueType* tavt = that->AsValueType();
46     if (tavt == nullptr) {
47       return false;
48     }
49     return avt->Bitset() == tavt->Bitset();
50   }
51 
52   // TODO(jpp): is it useful to allow non-value types to be tested with
53   // IsExactly?
54   return that == this;
55 }
56 
IsA(AsmType * that)57 bool AsmType::IsA(AsmType* that) {
58   // IsA is used for querying inheritance relationships. Therefore it is only
59   // meaningful for basic types.
60   if (auto* avt = this->AsValueType()) {
61     if (auto* tavt = that->AsValueType()) {
62       return (avt->Bitset() & tavt->Bitset()) == tavt->Bitset();
63     }
64     return false;
65   }
66 
67   if (auto* as_callable = this->AsCallableType()) {
68     return as_callable->IsA(that);
69   }
70 
71   UNREACHABLE();
72   return that == this;
73 }
74 
ElementSizeInBytes()75 int32_t AsmType::ElementSizeInBytes() {
76   auto* value = AsValueType();
77   if (value == nullptr) {
78     return AsmType::kNotHeapType;
79   }
80   switch (value->Bitset()) {
81     case AsmValueType::kAsmInt8Array:
82     case AsmValueType::kAsmUint8Array:
83       return 1;
84     case AsmValueType::kAsmInt16Array:
85     case AsmValueType::kAsmUint16Array:
86       return 2;
87     case AsmValueType::kAsmInt32Array:
88     case AsmValueType::kAsmUint32Array:
89     case AsmValueType::kAsmFloat32Array:
90       return 4;
91     case AsmValueType::kAsmFloat64Array:
92       return 8;
93     default:
94       return AsmType::kNotHeapType;
95   }
96 }
97 
LoadType()98 AsmType* AsmType::LoadType() {
99   auto* value = AsValueType();
100   if (value == nullptr) {
101     return AsmType::None();
102   }
103   switch (value->Bitset()) {
104     case AsmValueType::kAsmInt8Array:
105     case AsmValueType::kAsmUint8Array:
106     case AsmValueType::kAsmInt16Array:
107     case AsmValueType::kAsmUint16Array:
108     case AsmValueType::kAsmInt32Array:
109     case AsmValueType::kAsmUint32Array:
110       return AsmType::Intish();
111     case AsmValueType::kAsmFloat32Array:
112       return AsmType::FloatQ();
113     case AsmValueType::kAsmFloat64Array:
114       return AsmType::DoubleQ();
115     default:
116       return AsmType::None();
117   }
118 }
119 
StoreType()120 AsmType* AsmType::StoreType() {
121   auto* value = AsValueType();
122   if (value == nullptr) {
123     return AsmType::None();
124   }
125   switch (value->Bitset()) {
126     case AsmValueType::kAsmInt8Array:
127     case AsmValueType::kAsmUint8Array:
128     case AsmValueType::kAsmInt16Array:
129     case AsmValueType::kAsmUint16Array:
130     case AsmValueType::kAsmInt32Array:
131     case AsmValueType::kAsmUint32Array:
132       return AsmType::Intish();
133     case AsmValueType::kAsmFloat32Array:
134       return AsmType::FloatishDoubleQ();
135     case AsmValueType::kAsmFloat64Array:
136       return AsmType::FloatQDoubleQ();
137     default:
138       return AsmType::None();
139   }
140 }
141 
IsA(AsmType * other)142 bool AsmCallableType::IsA(AsmType* other) {
143   return other->AsCallableType() == this;
144 }
145 
Name()146 std::string AsmFunctionType::Name() {
147   std::string ret;
148   ret += "(";
149   for (size_t ii = 0; ii < args_.size(); ++ii) {
150     ret += args_[ii]->Name();
151     if (ii != args_.size() - 1) {
152       ret += ", ";
153     }
154   }
155   ret += ") -> ";
156   ret += return_type_->Name();
157   return ret;
158 }
159 
160 namespace {
161 class AsmFroundType final : public AsmCallableType {
162  public:
163   friend AsmType;
164 
AsmFroundType()165   AsmFroundType() : AsmCallableType() {}
166 
167   bool CanBeInvokedWith(AsmType* return_type,
168                         const ZoneVector<AsmType*>& args) override;
169 
Name()170   std::string Name() override { return "fround"; }
171 };
172 }  // namespace
173 
FroundType(Zone * zone)174 AsmType* AsmType::FroundType(Zone* zone) {
175   auto* Fround = new (zone) AsmFroundType();
176   return reinterpret_cast<AsmType*>(Fround);
177 }
178 
CanBeInvokedWith(AsmType * return_type,const ZoneVector<AsmType * > & args)179 bool AsmFroundType::CanBeInvokedWith(AsmType* return_type,
180                                      const ZoneVector<AsmType*>& args) {
181   if (args.size() != 1) {
182     return false;
183   }
184 
185   auto* arg = args[0];
186   if (!arg->IsA(AsmType::Floatish()) && !arg->IsA(AsmType::DoubleQ()) &&
187       !arg->IsA(AsmType::Signed()) && !arg->IsA(AsmType::Unsigned())) {
188     return false;
189   }
190 
191   return true;
192 }
193 
194 namespace {
195 class AsmMinMaxType final : public AsmCallableType {
196  private:
197   friend AsmType;
198 
AsmMinMaxType(AsmType * dest,AsmType * src)199   AsmMinMaxType(AsmType* dest, AsmType* src)
200       : AsmCallableType(), return_type_(dest), arg_(src) {}
201 
CanBeInvokedWith(AsmType * return_type,const ZoneVector<AsmType * > & args)202   bool CanBeInvokedWith(AsmType* return_type,
203                         const ZoneVector<AsmType*>& args) override {
204     if (!return_type_->IsExactly(return_type)) {
205       return false;
206     }
207 
208     if (args.size() < 2) {
209       return false;
210     }
211 
212     for (size_t ii = 0; ii < args.size(); ++ii) {
213       if (!args[ii]->IsA(arg_)) {
214         return false;
215       }
216     }
217 
218     return true;
219   }
220 
Name()221   std::string Name() override {
222     return "(" + arg_->Name() + ", " + arg_->Name() + "...) -> " +
223            return_type_->Name();
224   }
225 
226   AsmType* return_type_;
227   AsmType* arg_;
228 };
229 }  // namespace
230 
MinMaxType(Zone * zone,AsmType * dest,AsmType * src)231 AsmType* AsmType::MinMaxType(Zone* zone, AsmType* dest, AsmType* src) {
232   DCHECK(dest->AsValueType() != nullptr);
233   DCHECK(src->AsValueType() != nullptr);
234   auto* MinMax = new (zone) AsmMinMaxType(dest, src);
235   return reinterpret_cast<AsmType*>(MinMax);
236 }
237 
CanBeInvokedWith(AsmType * return_type,const ZoneVector<AsmType * > & args)238 bool AsmFFIType::CanBeInvokedWith(AsmType* return_type,
239                                   const ZoneVector<AsmType*>& args) {
240   if (return_type->IsExactly(AsmType::Float())) {
241     return false;
242   }
243 
244   for (size_t ii = 0; ii < args.size(); ++ii) {
245     if (!args[ii]->IsA(AsmType::Extern())) {
246       return false;
247     }
248   }
249 
250   return true;
251 }
252 
IsA(AsmType * other)253 bool AsmFunctionType::IsA(AsmType* other) {
254   auto* that = other->AsFunctionType();
255   if (that == nullptr) {
256     return false;
257   }
258   if (!return_type_->IsExactly(that->return_type_)) {
259     return false;
260   }
261 
262   if (args_.size() != that->args_.size()) {
263     return false;
264   }
265 
266   for (size_t ii = 0; ii < args_.size(); ++ii) {
267     if (!args_[ii]->IsExactly(that->args_[ii])) {
268       return false;
269     }
270   }
271 
272   return true;
273 }
274 
CanBeInvokedWith(AsmType * return_type,const ZoneVector<AsmType * > & args)275 bool AsmFunctionType::CanBeInvokedWith(AsmType* return_type,
276                                        const ZoneVector<AsmType*>& args) {
277   if (!return_type_->IsExactly(return_type)) {
278     return false;
279   }
280 
281   if (args_.size() != args.size()) {
282     return false;
283   }
284 
285   for (size_t ii = 0; ii < args_.size(); ++ii) {
286     if (!args[ii]->IsA(args_[ii])) {
287       return false;
288     }
289   }
290 
291   return true;
292 }
293 
Name()294 std::string AsmOverloadedFunctionType::Name() {
295   std::string ret;
296 
297   for (size_t ii = 0; ii < overloads_.size(); ++ii) {
298     if (ii != 0) {
299       ret += " /\\ ";
300     }
301     ret += overloads_[ii]->Name();
302   }
303 
304   return ret;
305 }
306 
CanBeInvokedWith(AsmType * return_type,const ZoneVector<AsmType * > & args)307 bool AsmOverloadedFunctionType::CanBeInvokedWith(
308     AsmType* return_type, const ZoneVector<AsmType*>& args) {
309   for (size_t ii = 0; ii < overloads_.size(); ++ii) {
310     if (overloads_[ii]->AsCallableType()->CanBeInvokedWith(return_type, args)) {
311       return true;
312     }
313   }
314 
315   return false;
316 }
317 
AddOverload(AsmType * overload)318 void AsmOverloadedFunctionType::AddOverload(AsmType* overload) {
319   DCHECK(overload->AsCallableType() != nullptr);
320   overloads_.push_back(overload);
321 }
322 
AsmFunctionTableType(size_t length,AsmType * signature)323 AsmFunctionTableType::AsmFunctionTableType(size_t length, AsmType* signature)
324     : length_(length), signature_(signature) {
325   DCHECK(signature_ != nullptr);
326   DCHECK(signature_->AsFunctionType() != nullptr);
327 }
328 
329 namespace {
330 // ToString is used for reporting function tables' names. It converts its
331 // argument to uint32_t because asm.js integers are 32-bits, thus effectively
332 // limiting the max function table's length.
ToString(size_t s)333 std::string ToString(size_t s) {
334   auto u32 = static_cast<uint32_t>(s);
335   // 16 bytes is more than enough to represent a 32-bit integer as a base 10
336   // string.
337   char digits[16];
338   int length = base::OS::SNPrintF(digits, arraysize(digits), "%" PRIu32, u32);
339   DCHECK_NE(length, -1);
340   return std::string(digits, length);
341 }
342 }  // namespace
343 
Name()344 std::string AsmFunctionTableType::Name() {
345   return "(" + signature_->Name() + ")[" + ToString(length_) + "]";
346 }
347 
CanBeInvokedWith(AsmType * return_type,const ZoneVector<AsmType * > & args)348 bool AsmFunctionTableType::CanBeInvokedWith(AsmType* return_type,
349                                             const ZoneVector<AsmType*>& args) {
350   return signature_->AsCallableType()->CanBeInvokedWith(return_type, args);
351 }
352 
353 }  // namespace wasm
354 }  // namespace internal
355 }  // namespace v8
356