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