• 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 }
73 
ElementSizeInBytes()74 int32_t AsmType::ElementSizeInBytes() {
75   auto* value = AsValueType();
76   if (value == nullptr) {
77     return AsmType::kNotHeapType;
78   }
79   switch (value->Bitset()) {
80     case AsmValueType::kAsmInt8Array:
81     case AsmValueType::kAsmUint8Array:
82       return 1;
83     case AsmValueType::kAsmInt16Array:
84     case AsmValueType::kAsmUint16Array:
85       return 2;
86     case AsmValueType::kAsmInt32Array:
87     case AsmValueType::kAsmUint32Array:
88     case AsmValueType::kAsmFloat32Array:
89       return 4;
90     case AsmValueType::kAsmFloat64Array:
91       return 8;
92     default:
93       return AsmType::kNotHeapType;
94   }
95 }
96 
LoadType()97 AsmType* AsmType::LoadType() {
98   auto* value = AsValueType();
99   if (value == nullptr) {
100     return AsmType::None();
101   }
102   switch (value->Bitset()) {
103     case AsmValueType::kAsmInt8Array:
104     case AsmValueType::kAsmUint8Array:
105     case AsmValueType::kAsmInt16Array:
106     case AsmValueType::kAsmUint16Array:
107     case AsmValueType::kAsmInt32Array:
108     case AsmValueType::kAsmUint32Array:
109       return AsmType::Intish();
110     case AsmValueType::kAsmFloat32Array:
111       return AsmType::FloatQ();
112     case AsmValueType::kAsmFloat64Array:
113       return AsmType::DoubleQ();
114     default:
115       return AsmType::None();
116   }
117 }
118 
StoreType()119 AsmType* AsmType::StoreType() {
120   auto* value = AsValueType();
121   if (value == nullptr) {
122     return AsmType::None();
123   }
124   switch (value->Bitset()) {
125     case AsmValueType::kAsmInt8Array:
126     case AsmValueType::kAsmUint8Array:
127     case AsmValueType::kAsmInt16Array:
128     case AsmValueType::kAsmUint16Array:
129     case AsmValueType::kAsmInt32Array:
130     case AsmValueType::kAsmUint32Array:
131       return AsmType::Intish();
132     case AsmValueType::kAsmFloat32Array:
133       return AsmType::FloatishDoubleQ();
134     case AsmValueType::kAsmFloat64Array:
135       return AsmType::FloatQDoubleQ();
136     default:
137       return AsmType::None();
138   }
139 }
140 
IsA(AsmType * other)141 bool AsmCallableType::IsA(AsmType* other) {
142   return other->AsCallableType() == this;
143 }
144 
Name()145 std::string AsmFunctionType::Name() {
146   std::string ret;
147   ret += "(";
148   for (size_t ii = 0; ii < args_.size(); ++ii) {
149     ret += args_[ii]->Name();
150     if (ii != args_.size() - 1) {
151       ret += ", ";
152     }
153   }
154   ret += ") -> ";
155   ret += return_type_->Name();
156   return ret;
157 }
158 
159 namespace {
160 class AsmFroundType final : public AsmCallableType {
161  public:
162   friend AsmType;
163 
AsmFroundType()164   AsmFroundType() : AsmCallableType() {}
165 
166   bool CanBeInvokedWith(AsmType* return_type,
167                         const ZoneVector<AsmType*>& args) override;
168 
Name()169   std::string Name() override { return "fround"; }
170 };
171 }  // namespace
172 
FroundType(Zone * zone)173 AsmType* AsmType::FroundType(Zone* zone) {
174   auto* Fround = new (zone) AsmFroundType();
175   return reinterpret_cast<AsmType*>(Fround);
176 }
177 
CanBeInvokedWith(AsmType * return_type,const ZoneVector<AsmType * > & args)178 bool AsmFroundType::CanBeInvokedWith(AsmType* return_type,
179                                      const ZoneVector<AsmType*>& args) {
180   if (args.size() != 1) {
181     return false;
182   }
183 
184   auto* arg = args[0];
185   if (!arg->IsA(AsmType::Floatish()) && !arg->IsA(AsmType::DoubleQ()) &&
186       !arg->IsA(AsmType::Signed()) && !arg->IsA(AsmType::Unsigned())) {
187     return false;
188   }
189 
190   return true;
191 }
192 
193 namespace {
194 class AsmMinMaxType final : public AsmCallableType {
195  private:
196   friend AsmType;
197 
AsmMinMaxType(AsmType * dest,AsmType * src)198   AsmMinMaxType(AsmType* dest, AsmType* src)
199       : AsmCallableType(), return_type_(dest), arg_(src) {}
200 
CanBeInvokedWith(AsmType * return_type,const ZoneVector<AsmType * > & args)201   bool CanBeInvokedWith(AsmType* return_type,
202                         const ZoneVector<AsmType*>& args) override {
203     if (!return_type_->IsExactly(return_type)) {
204       return false;
205     }
206 
207     if (args.size() < 2) {
208       return false;
209     }
210 
211     for (size_t ii = 0; ii < args.size(); ++ii) {
212       if (!args[ii]->IsA(arg_)) {
213         return false;
214       }
215     }
216 
217     return true;
218   }
219 
Name()220   std::string Name() override {
221     return "(" + arg_->Name() + ", " + arg_->Name() + "...) -> " +
222            return_type_->Name();
223   }
224 
225   AsmType* return_type_;
226   AsmType* arg_;
227 };
228 }  // namespace
229 
MinMaxType(Zone * zone,AsmType * dest,AsmType * src)230 AsmType* AsmType::MinMaxType(Zone* zone, AsmType* dest, AsmType* src) {
231   DCHECK_NOT_NULL(dest->AsValueType());
232   DCHECK_NOT_NULL(src->AsValueType());
233   auto* MinMax = new (zone) AsmMinMaxType(dest, src);
234   return reinterpret_cast<AsmType*>(MinMax);
235 }
236 
IsA(AsmType * other)237 bool AsmFunctionType::IsA(AsmType* other) {
238   auto* that = other->AsFunctionType();
239   if (that == nullptr) {
240     return false;
241   }
242   if (!return_type_->IsExactly(that->return_type_)) {
243     return false;
244   }
245 
246   if (args_.size() != that->args_.size()) {
247     return false;
248   }
249 
250   for (size_t ii = 0; ii < args_.size(); ++ii) {
251     if (!args_[ii]->IsExactly(that->args_[ii])) {
252       return false;
253     }
254   }
255 
256   return true;
257 }
258 
CanBeInvokedWith(AsmType * return_type,const ZoneVector<AsmType * > & args)259 bool AsmFunctionType::CanBeInvokedWith(AsmType* return_type,
260                                        const ZoneVector<AsmType*>& args) {
261   if (!return_type_->IsExactly(return_type)) {
262     return false;
263   }
264 
265   if (args_.size() != args.size()) {
266     return false;
267   }
268 
269   for (size_t ii = 0; ii < args_.size(); ++ii) {
270     if (!args[ii]->IsA(args_[ii])) {
271       return false;
272     }
273   }
274 
275   return true;
276 }
277 
Name()278 std::string AsmOverloadedFunctionType::Name() {
279   std::string ret;
280 
281   for (size_t ii = 0; ii < overloads_.size(); ++ii) {
282     if (ii != 0) {
283       ret += " /\\ ";
284     }
285     ret += overloads_[ii]->Name();
286   }
287 
288   return ret;
289 }
290 
CanBeInvokedWith(AsmType * return_type,const ZoneVector<AsmType * > & args)291 bool AsmOverloadedFunctionType::CanBeInvokedWith(
292     AsmType* return_type, const ZoneVector<AsmType*>& args) {
293   for (size_t ii = 0; ii < overloads_.size(); ++ii) {
294     if (overloads_[ii]->AsCallableType()->CanBeInvokedWith(return_type, args)) {
295       return true;
296     }
297   }
298 
299   return false;
300 }
301 
AddOverload(AsmType * overload)302 void AsmOverloadedFunctionType::AddOverload(AsmType* overload) {
303   DCHECK_NOT_NULL(overload->AsCallableType());
304   overloads_.push_back(overload);
305 }
306 
307 }  // namespace wasm
308 }  // namespace internal
309 }  // namespace v8
310