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