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/v8.h"
6
7 #include "src/wasm/asm-types.h"
8
9 namespace v8 {
10 namespace internal {
11 namespace wasm {
12
AsCallableType()13 AsmCallableType* AsmType::AsCallableType() {
14 if (AsValueType() != nullptr) {
15 return nullptr;
16 }
17
18 DCHECK(this->AsFunctionType() != nullptr ||
19 this->AsOverloadedFunctionType() != nullptr ||
20 this->AsFFIType() != nullptr ||
21 this->AsFunctionTableType() != nullptr);
22 return reinterpret_cast<AsmCallableType*>(this);
23 }
24
Name()25 std::string AsmType::Name() {
26 AsmValueType* avt = this->AsValueType();
27 if (avt != nullptr) {
28 switch (avt->Bitset()) {
29 #define RETURN_TYPE_NAME(CamelName, string_name, number, parent_types) \
30 case AsmValueType::kAsm##CamelName: \
31 return string_name;
32 FOR_EACH_ASM_VALUE_TYPE_LIST(RETURN_TYPE_NAME)
33 #undef RETURN_TYPE_NAME
34 default:
35 UNREACHABLE();
36 }
37 }
38
39 return this->AsCallableType()->Name();
40 }
41
IsExactly(AsmType * that)42 bool AsmType::IsExactly(AsmType* that) {
43 // TODO(jpp): maybe this can become this == that.
44 AsmValueType* avt = this->AsValueType();
45 if (avt != nullptr) {
46 AsmValueType* tavt = that->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 that == this;
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 AsmValueType* tavt = that->AsValueType();
62 if (tavt != nullptr) {
63 AsmValueType* avt = this->AsValueType();
64 if (avt == nullptr) {
65 return false;
66 }
67 return (avt->Bitset() & tavt->Bitset()) == tavt->Bitset();
68 }
69
70 // TODO(jpp): is it useful to allow non-value types to be tested with IsA?
71 return that == this;
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
Name()141 std::string AsmFunctionType::Name() {
142 if (IsFroundType()) {
143 return "fround";
144 }
145
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 if (IsMinMaxType()) {
155 DCHECK_EQ(args_.size(), 2);
156 ret += "...";
157 }
158 ret += ") -> ";
159 ret += return_type_->Name();
160 return ret;
161 }
162
163 namespace {
164 class AsmFroundType final : public AsmFunctionType {
165 public:
IsFroundType() const166 bool IsFroundType() const override { return true; }
167
168 private:
169 friend AsmType;
170
AsmFroundType(Zone * zone)171 explicit AsmFroundType(Zone* zone)
172 : AsmFunctionType(zone, AsmType::Float()) {}
173
174 AsmType* ValidateCall(AsmType* return_type,
175 const ZoneVector<AsmType*>& args) override;
176 };
177 } // namespace
178
FroundType(Zone * zone)179 AsmType* AsmType::FroundType(Zone* zone) {
180 auto* Fround = new (zone) AsmFroundType(zone);
181 return reinterpret_cast<AsmType*>(Fround);
182 }
183
ValidateCall(AsmType * return_type,const ZoneVector<AsmType * > & args)184 AsmType* AsmFroundType::ValidateCall(AsmType* return_type,
185 const ZoneVector<AsmType*>& args) {
186 if (args.size() != 1) {
187 return AsmType::None();
188 }
189
190 auto* arg = args[0];
191 if (!arg->IsA(AsmType::Floatish()) && !arg->IsA(AsmType::DoubleQ()) &&
192 !arg->IsA(AsmType::Signed()) && !arg->IsA(AsmType::Unsigned())) {
193 return AsmType::None();
194 }
195
196 return AsmType::Float();
197 }
198
199 namespace {
200 class AsmMinMaxType final : public AsmFunctionType {
201 public:
IsMinMaxType() const202 bool IsMinMaxType() const override { return true; }
203
204 private:
205 friend AsmType;
206
AsmMinMaxType(Zone * zone,AsmType * dest,AsmType * src)207 AsmMinMaxType(Zone* zone, AsmType* dest, AsmType* src)
208 : AsmFunctionType(zone, dest) {
209 AddArgument(src);
210 AddArgument(src);
211 }
212
ValidateCall(AsmType * return_type,const ZoneVector<AsmType * > & args)213 AsmType* ValidateCall(AsmType* return_type,
214 const ZoneVector<AsmType*>& args) override {
215 if (!ReturnType()->IsExactly(return_type)) {
216 return AsmType::None();
217 }
218
219 if (args.size() < 2) {
220 return AsmType::None();
221 }
222
223 for (size_t ii = 0; ii < Arguments().size(); ++ii) {
224 if (!Arguments()[0]->IsExactly(args[ii])) {
225 return AsmType::None();
226 }
227 }
228
229 return ReturnType();
230 }
231 };
232 } // namespace
233
MinMaxType(Zone * zone,AsmType * dest,AsmType * src)234 AsmType* AsmType::MinMaxType(Zone* zone, AsmType* dest, AsmType* src) {
235 DCHECK(dest->AsValueType() != nullptr);
236 DCHECK(src->AsValueType() != nullptr);
237 auto* MinMax = new (zone) AsmMinMaxType(zone, dest, src);
238 return reinterpret_cast<AsmType*>(MinMax);
239 }
240
ValidateCall(AsmType * return_type,const ZoneVector<AsmType * > & args)241 AsmType* AsmFFIType::ValidateCall(AsmType* return_type,
242 const ZoneVector<AsmType*>& args) {
243 for (size_t ii = 0; ii < args.size(); ++ii) {
244 if (!args[ii]->IsA(AsmType::Extern())) {
245 return AsmType::None();
246 }
247 }
248
249 return return_type;
250 }
251
ValidateCall(AsmType * return_type,const ZoneVector<AsmType * > & args)252 AsmType* AsmFunctionType::ValidateCall(AsmType* return_type,
253 const ZoneVector<AsmType*>& args) {
254 if (!return_type_->IsExactly(return_type)) {
255 return AsmType::None();
256 }
257
258 if (args_.size() != args.size()) {
259 return AsmType::None();
260 }
261
262 for (size_t ii = 0; ii < args_.size(); ++ii) {
263 if (!args_[ii]->IsExactly(args[ii])) {
264 return AsmType::None();
265 }
266 }
267
268 return return_type_;
269 }
270
Name()271 std::string AsmOverloadedFunctionType::Name() {
272 std::string ret;
273
274 for (size_t ii = 0; ii < overloads_.size(); ++ii) {
275 if (ii != 0) {
276 ret += " /\\ ";
277 }
278 ret += overloads_[ii]->Name();
279 }
280
281 return ret;
282 }
283
ValidateCall(AsmType * return_type,const ZoneVector<AsmType * > & args)284 AsmType* AsmOverloadedFunctionType::ValidateCall(
285 AsmType* return_type, const ZoneVector<AsmType*>& args) {
286 for (size_t ii = 0; ii < overloads_.size(); ++ii) {
287 auto* validated_type =
288 overloads_[ii]->AsCallableType()->ValidateCall(return_type, args);
289 if (validated_type != AsmType::None()) {
290 return validated_type;
291 }
292 }
293
294 return AsmType::None();
295 }
296
AddOverload(AsmType * overload)297 void AsmOverloadedFunctionType::AddOverload(AsmType* overload) {
298 DCHECK(overload->AsFunctionType() != nullptr);
299 overloads_.push_back(overload);
300 }
301
AsmFunctionTableType(size_t length,AsmType * signature)302 AsmFunctionTableType::AsmFunctionTableType(size_t length, AsmType* signature)
303 : length_(length), signature_(signature) {
304 DCHECK(signature_ != nullptr);
305 DCHECK(signature_->AsFunctionType() != nullptr);
306 }
307
Name()308 std::string AsmFunctionTableType::Name() {
309 return signature_->Name() + "[" + std::to_string(length_) + "]";
310 }
311
ValidateCall(AsmType * return_type,const ZoneVector<AsmType * > & args)312 AsmType* AsmFunctionTableType::ValidateCall(AsmType* return_type,
313 const ZoneVector<AsmType*>& args) {
314 return signature_->AsCallableType()->ValidateCall(return_type, args);
315 }
316
317 } // namespace wasm
318 } // namespace internal
319 } // namespace v8
320