Line data Source code
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 :
16 405664 : AsmCallableType* AsmType::AsCallableType() {
17 456554 : if (AsValueType() != nullptr) {
18 : return nullptr;
19 : }
20 :
21 32605 : return reinterpret_cast<AsmCallableType*>(this);
22 : }
23 :
24 54 : std::string AsmType::Name() {
25 : AsmValueType* avt = this->AsValueType();
26 54 : if (avt != nullptr) {
27 43 : switch (avt->Bitset()) {
28 : #define RETURN_TYPE_NAME(CamelName, string_name, number, parent_types) \
29 : case AsmValueType::kAsm##CamelName: \
30 : return string_name;
31 1 : FOR_EACH_ASM_VALUE_TYPE_LIST(RETURN_TYPE_NAME)
32 : #undef RETURN_TYPE_NAME
33 : default:
34 0 : UNREACHABLE();
35 : }
36 : }
37 :
38 11 : return this->AsCallableType()->Name();
39 : }
40 :
41 51343 : bool AsmType::IsExactly(AsmType* that) {
42 : // TODO(jpp): maybe this can become this == that.
43 : AsmValueType* avt = this->AsValueType();
44 103282 : if (avt != nullptr) {
45 : AsmValueType* tavt = that->AsValueType();
46 68144 : if (tavt == nullptr) {
47 : return false;
48 : }
49 74927 : 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 28139 : return that == this;
55 : }
56 :
57 5713611 : bool AsmType::IsA(AsmType* that) {
58 : // IsA is used for querying inheritance relationships. Therefore it is only
59 : // meaningful for basic types.
60 5713611 : if (auto* avt = this->AsValueType()) {
61 5674340 : if (auto* tavt = that->AsValueType()) {
62 5649932 : return (avt->Bitset() & tavt->Bitset()) == tavt->Bitset();
63 : }
64 : return false;
65 : }
66 :
67 39271 : if (auto* as_callable = this->AsCallableType()) {
68 39271 : return as_callable->IsA(that);
69 : }
70 :
71 0 : UNREACHABLE();
72 : return that == this;
73 : }
74 :
75 273714 : int32_t AsmType::ElementSizeInBytes() {
76 : auto* value = AsValueType();
77 273714 : if (value == nullptr) {
78 : return AsmType::kNotHeapType;
79 : }
80 273705 : switch (value->Bitset()) {
81 : case AsmValueType::kAsmInt8Array:
82 : case AsmValueType::kAsmUint8Array:
83 : return 1;
84 : case AsmValueType::kAsmInt16Array:
85 : case AsmValueType::kAsmUint16Array:
86 7690 : return 2;
87 : case AsmValueType::kAsmInt32Array:
88 : case AsmValueType::kAsmUint32Array:
89 : case AsmValueType::kAsmFloat32Array:
90 235280 : return 4;
91 : case AsmValueType::kAsmFloat64Array:
92 1995 : return 8;
93 : default:
94 16 : return AsmType::kNotHeapType;
95 : }
96 : }
97 :
98 87540 : AsmType* AsmType::LoadType() {
99 : auto* value = AsValueType();
100 87540 : if (value == nullptr) {
101 : return AsmType::None();
102 : }
103 87531 : 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 8273 : return AsmType::FloatQ();
113 : case AsmValueType::kAsmFloat64Array:
114 550 : return AsmType::DoubleQ();
115 : default:
116 16 : return AsmType::None();
117 : }
118 : }
119 :
120 60221 : AsmType* AsmType::StoreType() {
121 : auto* value = AsValueType();
122 60221 : if (value == nullptr) {
123 : return AsmType::None();
124 : }
125 60212 : 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 4919 : return AsmType::FloatishDoubleQ();
135 : case AsmValueType::kAsmFloat64Array:
136 558 : return AsmType::FloatQDoubleQ();
137 : default:
138 16 : return AsmType::None();
139 : }
140 : }
141 :
142 10802 : bool AsmCallableType::IsA(AsmType* other) {
143 10802 : return other->AsCallableType() == this;
144 : }
145 :
146 4 : std::string AsmFunctionType::Name() {
147 : std::string ret;
148 : ret += "(";
149 20 : for (size_t ii = 0; ii < args_.size(); ++ii) {
150 22 : ret += args_[ii]->Name();
151 6 : if (ii != args_.size() - 1) {
152 : ret += ", ";
153 : }
154 : }
155 : ret += ") -> ";
156 8 : ret += return_type_->Name();
157 4 : return ret;
158 : }
159 :
160 : namespace {
161 0 : class AsmFroundType final : public AsmCallableType {
162 : public:
163 : friend AsmType;
164 :
165 709993 : AsmFroundType() : AsmCallableType() {}
166 :
167 : bool CanBeInvokedWith(AsmType* return_type,
168 : const ZoneVector<AsmType*>& args) override;
169 :
170 1 : std::string Name() override { return "fround"; }
171 : };
172 : } // namespace
173 :
174 709994 : AsmType* AsmType::FroundType(Zone* zone) {
175 : auto* Fround = new (zone) AsmFroundType();
176 709993 : return reinterpret_cast<AsmType*>(Fround);
177 : }
178 :
179 8 : bool AsmFroundType::CanBeInvokedWith(AsmType* return_type,
180 : const ZoneVector<AsmType*>& args) {
181 16 : if (args.size() != 1) {
182 : return false;
183 : }
184 :
185 8 : auto* arg = args[0];
186 24 : if (!arg->IsA(AsmType::Floatish()) && !arg->IsA(AsmType::DoubleQ()) &&
187 12 : !arg->IsA(AsmType::Signed()) && !arg->IsA(AsmType::Unsigned())) {
188 : return false;
189 : }
190 :
191 8 : return true;
192 : }
193 :
194 : namespace {
195 0 : class AsmMinMaxType final : public AsmCallableType {
196 : private:
197 : friend AsmType;
198 :
199 : AsmMinMaxType(AsmType* dest, AsmType* src)
200 2129962 : : AsmCallableType(), return_type_(dest), arg_(src) {}
201 :
202 229 : bool CanBeInvokedWith(AsmType* return_type,
203 : const ZoneVector<AsmType*>& args) override {
204 458 : if (!return_type_->IsExactly(return_type)) {
205 : return false;
206 : }
207 :
208 544 : if (args.size() < 2) {
209 : return false;
210 : }
211 :
212 532 : for (size_t ii = 0; ii < args.size(); ++ii) {
213 440 : if (!args[ii]->IsA(arg_)) {
214 : return false;
215 : }
216 : }
217 :
218 : return true;
219 : }
220 :
221 3 : std::string Name() override {
222 24 : return "(" + arg_->Name() + ", " + arg_->Name() + "...) -> " +
223 9 : return_type_->Name();
224 : }
225 :
226 : AsmType* return_type_;
227 : AsmType* arg_;
228 : };
229 : } // namespace
230 :
231 2129957 : 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 2129962 : return reinterpret_cast<AsmType*>(MinMax);
236 : }
237 :
238 6999 : bool AsmFFIType::CanBeInvokedWith(AsmType* return_type,
239 : const ZoneVector<AsmType*>& args) {
240 6999 : if (return_type->IsExactly(AsmType::Float())) {
241 : return false;
242 : }
243 :
244 21991 : for (size_t ii = 0; ii < args.size(); ++ii) {
245 22014 : if (!args[ii]->IsA(AsmType::Extern())) {
246 : return false;
247 : }
248 : }
249 :
250 : return true;
251 : }
252 :
253 28469 : bool AsmFunctionType::IsA(AsmType* other) {
254 : auto* that = other->AsFunctionType();
255 28469 : if (that == nullptr) {
256 : return false;
257 : }
258 12052 : if (!return_type_->IsExactly(that->return_type_)) {
259 : return false;
260 : }
261 :
262 18012 : if (args_.size() != that->args_.size()) {
263 : return false;
264 : }
265 :
266 29702 : for (size_t ii = 0; ii < args_.size(); ++ii) {
267 35643 : if (!args_[ii]->IsExactly(that->args_[ii])) {
268 : return false;
269 : }
270 : }
271 :
272 : return true;
273 : }
274 :
275 26804 : bool AsmFunctionType::CanBeInvokedWith(AsmType* return_type,
276 : const ZoneVector<AsmType*>& args) {
277 53608 : if (!return_type_->IsExactly(return_type)) {
278 : return false;
279 : }
280 :
281 231212 : if (args_.size() != args.size()) {
282 : return false;
283 : }
284 :
285 151795 : for (size_t ii = 0; ii < args_.size(); ++ii) {
286 125392 : if (!args[ii]->IsA(args_[ii])) {
287 : return false;
288 : }
289 : }
290 :
291 : return true;
292 : }
293 :
294 1 : std::string AsmOverloadedFunctionType::Name() {
295 : std::string ret;
296 :
297 6 : for (size_t ii = 0; ii < overloads_.size(); ++ii) {
298 2 : if (ii != 0) {
299 : ret += " /\\ ";
300 : }
301 9 : ret += overloads_[ii]->Name();
302 : }
303 :
304 1 : return ret;
305 : }
306 :
307 534 : bool AsmOverloadedFunctionType::CanBeInvokedWith(
308 : AsmType* return_type, const ZoneVector<AsmType*>& args) {
309 1662 : for (size_t ii = 0; ii < overloads_.size(); ++ii) {
310 2439 : if (overloads_[ii]->AsCallableType()->CanBeInvokedWith(return_type, args)) {
311 : return true;
312 : }
313 : }
314 :
315 : return false;
316 : }
317 :
318 5679875 : void AsmOverloadedFunctionType::AddOverload(AsmType* overload) {
319 : DCHECK(overload->AsCallableType() != nullptr);
320 5679875 : overloads_.push_back(overload);
321 5679877 : }
322 :
323 1529 : AsmFunctionTableType::AsmFunctionTableType(size_t length, AsmType* signature)
324 1529 : : length_(length), signature_(signature) {
325 : DCHECK(signature_ != nullptr);
326 : DCHECK(signature_->AsFunctionType() != nullptr);
327 1529 : }
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.
333 1 : std::string ToString(size_t s) {
334 1 : 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 1 : int length = base::OS::SNPrintF(digits, arraysize(digits), "%" PRIu32, u32);
339 : DCHECK_NE(length, -1);
340 1 : return std::string(digits, length);
341 : }
342 : } // namespace
343 :
344 1 : std::string AsmFunctionTableType::Name() {
345 7 : return "(" + signature_->Name() + ")[" + ToString(length_) + "]";
346 : }
347 :
348 2 : bool AsmFunctionTableType::CanBeInvokedWith(AsmType* return_type,
349 : const ZoneVector<AsmType*>& args) {
350 4 : return signature_->AsCallableType()->CanBeInvokedWith(return_type, args);
351 : }
352 :
353 : } // namespace wasm
354 : } // namespace internal
355 : } // namespace v8
|