• 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/init/v8.h"
10 #include "src/utils/utils.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 * x,AsmType * y)41 bool AsmType::IsExactly(AsmType* x, AsmType* y) {
42   // TODO(jpp): maybe this can become x == y.
43   if (x == nullptr) return y == nullptr;
44   AsmValueType* avt = x->AsValueType();
45   if (avt != nullptr) {
46     AsmValueType* tavt = y->AsValueType();
47     if (tavt == nullptr) {
48       return false;
49     }
50     return avt->Bitset() == tavt->Bitset();
51   }
52 
53   // TODO(jpp): is it useful to allow non-value types to be tested with
54   // IsExactly?
55   return x == y;
56 }
57 
IsA(AsmType * that)58 bool AsmType::IsA(AsmType* that) {
59   // IsA is used for querying inheritance relationships. Therefore it is only
60   // meaningful for basic types.
61   if (auto* avt = this->AsValueType()) {
62     if (auto* tavt = that->AsValueType()) {
63       return (avt->Bitset() & tavt->Bitset()) == tavt->Bitset();
64     }
65     return false;
66   }
67 
68   if (auto* as_callable = this->AsCallableType()) {
69     return as_callable->IsA(that);
70   }
71 
72   UNREACHABLE();
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 = zone->New<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   friend Zone;
199 
AsmMinMaxType(AsmType * dest,AsmType * src)200   AsmMinMaxType(AsmType* dest, AsmType* src)
201       : AsmCallableType(), return_type_(dest), arg_(src) {}
202 
CanBeInvokedWith(AsmType * return_type,const ZoneVector<AsmType * > & args)203   bool CanBeInvokedWith(AsmType* return_type,
204                         const ZoneVector<AsmType*>& args) override {
205     if (!AsmType::IsExactly(return_type_, return_type)) {
206       return false;
207     }
208 
209     if (args.size() < 2) {
210       return false;
211     }
212 
213     for (size_t ii = 0; ii < args.size(); ++ii) {
214       if (!args[ii]->IsA(arg_)) {
215         return false;
216       }
217     }
218 
219     return true;
220   }
221 
Name()222   std::string Name() override {
223     return "(" + arg_->Name() + ", " + arg_->Name() + "...) -> " +
224            return_type_->Name();
225   }
226 
227   AsmType* return_type_;
228   AsmType* arg_;
229 };
230 }  // namespace
231 
MinMaxType(Zone * zone,AsmType * dest,AsmType * src)232 AsmType* AsmType::MinMaxType(Zone* zone, AsmType* dest, AsmType* src) {
233   DCHECK_NOT_NULL(dest->AsValueType());
234   DCHECK_NOT_NULL(src->AsValueType());
235   auto* MinMax = zone->New<AsmMinMaxType>(dest, src);
236   return reinterpret_cast<AsmType*>(MinMax);
237 }
238 
IsA(AsmType * other)239 bool AsmFunctionType::IsA(AsmType* other) {
240   auto* that = other->AsFunctionType();
241   if (that == nullptr) {
242     return false;
243   }
244   if (!AsmType::IsExactly(return_type_, that->return_type_)) {
245     return false;
246   }
247 
248   if (args_.size() != that->args_.size()) {
249     return false;
250   }
251 
252   for (size_t ii = 0; ii < args_.size(); ++ii) {
253     if (!AsmType::IsExactly(args_[ii], that->args_[ii])) {
254       return false;
255     }
256   }
257 
258   return true;
259 }
260 
CanBeInvokedWith(AsmType * return_type,const ZoneVector<AsmType * > & args)261 bool AsmFunctionType::CanBeInvokedWith(AsmType* return_type,
262                                        const ZoneVector<AsmType*>& args) {
263   if (!AsmType::IsExactly(return_type_, return_type)) {
264     return false;
265   }
266 
267   if (args_.size() != args.size()) {
268     return false;
269   }
270 
271   for (size_t ii = 0; ii < args_.size(); ++ii) {
272     if (!args[ii]->IsA(args_[ii])) {
273       return false;
274     }
275   }
276 
277   return true;
278 }
279 
Name()280 std::string AsmOverloadedFunctionType::Name() {
281   std::string ret;
282 
283   for (size_t ii = 0; ii < overloads_.size(); ++ii) {
284     if (ii != 0) {
285       ret += " /\\ ";
286     }
287     ret += overloads_[ii]->Name();
288   }
289 
290   return ret;
291 }
292 
CanBeInvokedWith(AsmType * return_type,const ZoneVector<AsmType * > & args)293 bool AsmOverloadedFunctionType::CanBeInvokedWith(
294     AsmType* return_type, const ZoneVector<AsmType*>& args) {
295   for (size_t ii = 0; ii < overloads_.size(); ++ii) {
296     if (overloads_[ii]->AsCallableType()->CanBeInvokedWith(return_type, args)) {
297       return true;
298     }
299   }
300 
301   return false;
302 }
303 
AddOverload(AsmType * overload)304 void AsmOverloadedFunctionType::AddOverload(AsmType* overload) {
305   DCHECK_NOT_NULL(overload->AsCallableType());
306   overloads_.push_back(overload);
307 }
308 
309 }  // namespace wasm
310 }  // namespace internal
311 }  // namespace v8
312