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 #ifndef SRC_ASMJS_ASM_TYPES_H_
6 #define SRC_ASMJS_ASM_TYPES_H_
7
8 #include <string>
9
10 #include "src/base/compiler-specific.h"
11 #include "src/base/macros.h"
12 #include "src/globals.h"
13 #include "src/zone/zone-containers.h"
14 #include "src/zone/zone.h"
15
16 namespace v8 {
17 namespace internal {
18 namespace wasm {
19
20 class AsmType;
21 class AsmFFIType;
22 class AsmFunctionType;
23 class AsmOverloadedFunctionType;
24 class AsmFunctionTableType;
25
26 // List of V(CamelName, string_name, number, parent_types)
27 #define FOR_EACH_ASM_VALUE_TYPE_LIST(V) \
28 /* These tags are not types that are expressable in the asm source. They */ \
29 /* are used to express semantic information about the types they tag. */ \
30 V(Heap, "[]", 1, 0) \
31 V(FloatishDoubleQ, "floatish|double?", 2, 0) \
32 V(FloatQDoubleQ, "float?|double?", 3, 0) \
33 /* The following are actual types that appear in the asm source. */ \
34 V(Void, "void", 4, 0) \
35 V(Extern, "extern", 5, 0) \
36 V(DoubleQ, "double?", 6, kAsmFloatishDoubleQ | kAsmFloatQDoubleQ) \
37 V(Double, "double", 7, kAsmDoubleQ | kAsmExtern) \
38 V(Intish, "intish", 8, 0) \
39 V(Int, "int", 9, kAsmIntish) \
40 V(Signed, "signed", 10, kAsmInt | kAsmExtern) \
41 V(Unsigned, "unsigned", 11, kAsmInt) \
42 V(FixNum, "fixnum", 12, kAsmSigned | kAsmUnsigned) \
43 V(Floatish, "floatish", 13, kAsmFloatishDoubleQ) \
44 V(FloatQ, "float?", 14, kAsmFloatQDoubleQ | kAsmFloatish) \
45 V(Float, "float", 15, kAsmFloatQ) \
46 /* Types used for expressing the Heap accesses. */ \
47 V(Uint8Array, "Uint8Array", 16, kAsmHeap) \
48 V(Int8Array, "Int8Array", 17, kAsmHeap) \
49 V(Uint16Array, "Uint16Array", 18, kAsmHeap) \
50 V(Int16Array, "Int16Array", 19, kAsmHeap) \
51 V(Uint32Array, "Uint32Array", 20, kAsmHeap) \
52 V(Int32Array, "Int32Array", 21, kAsmHeap) \
53 V(Float32Array, "Float32Array", 22, kAsmHeap) \
54 V(Float64Array, "Float64Array", 23, kAsmHeap) \
55 /* None is used to represent errors in the type checker. */ \
56 V(None, "<none>", 31, 0)
57
58 // List of V(CamelName)
59 #define FOR_EACH_ASM_CALLABLE_TYPE_LIST(V) \
60 V(FunctionType) \
61 V(FFIType) \
62 V(OverloadedFunctionType) \
63 V(FunctionTableType)
64
65 class AsmValueType {
66 public:
67 typedef uint32_t bitset_t;
68
69 enum : uint32_t {
70 #define DEFINE_TAG(CamelName, string_name, number, parent_types) \
71 kAsm##CamelName = ((1u << (number)) | (parent_types)),
72 FOR_EACH_ASM_VALUE_TYPE_LIST(DEFINE_TAG)
73 #undef DEFINE_TAG
74 kAsmUnknown = 0,
75 kAsmValueTypeTag = 1u
76 };
77
78 private:
79 friend class AsmType;
80
AsValueType(AsmType * type)81 static AsmValueType* AsValueType(AsmType* type) {
82 if ((reinterpret_cast<uintptr_t>(type) & kAsmValueTypeTag) ==
83 kAsmValueTypeTag) {
84 return reinterpret_cast<AsmValueType*>(type);
85 }
86 return nullptr;
87 }
88
Bitset()89 bitset_t Bitset() const {
90 DCHECK((reinterpret_cast<uintptr_t>(this) & kAsmValueTypeTag) ==
91 kAsmValueTypeTag);
92 return static_cast<bitset_t>(reinterpret_cast<uintptr_t>(this) &
93 ~kAsmValueTypeTag);
94 }
95
New(bitset_t bits)96 static AsmType* New(bitset_t bits) {
97 DCHECK_EQ((bits & kAsmValueTypeTag), 0u);
98 return reinterpret_cast<AsmType*>(
99 static_cast<uintptr_t>(bits | kAsmValueTypeTag));
100 }
101
102 // AsmValueTypes can't be created except through AsmValueType::New.
103 DISALLOW_IMPLICIT_CONSTRUCTORS(AsmValueType);
104 };
105
NON_EXPORTED_BASE(ZoneObject)106 class V8_EXPORT_PRIVATE AsmCallableType : public NON_EXPORTED_BASE(ZoneObject) {
107 public:
108 virtual std::string Name() = 0;
109
110 virtual bool CanBeInvokedWith(AsmType* return_type,
111 const ZoneVector<AsmType*>& args) = 0;
112
113 #define DECLARE_CAST(CamelName) \
114 virtual Asm##CamelName* As##CamelName() { return nullptr; }
115 FOR_EACH_ASM_CALLABLE_TYPE_LIST(DECLARE_CAST)
116 #undef DECLARE_CAST
117
118 protected:
119 AsmCallableType() = default;
120 virtual ~AsmCallableType() = default;
121 virtual bool IsA(AsmType* other);
122
123 private:
124 friend class AsmType;
125
126 DISALLOW_COPY_AND_ASSIGN(AsmCallableType);
127 };
128
129 class V8_EXPORT_PRIVATE AsmFunctionType final : public AsmCallableType {
130 public:
AsFunctionType()131 AsmFunctionType* AsFunctionType() final { return this; }
132
AddArgument(AsmType * type)133 void AddArgument(AsmType* type) { args_.push_back(type); }
Arguments()134 const ZoneVector<AsmType*> Arguments() const { return args_; }
ReturnType()135 AsmType* ReturnType() const { return return_type_; }
136
137 bool CanBeInvokedWith(AsmType* return_type,
138 const ZoneVector<AsmType*>& args) override;
139
140 protected:
AsmFunctionType(Zone * zone,AsmType * return_type)141 AsmFunctionType(Zone* zone, AsmType* return_type)
142 : return_type_(return_type), args_(zone) {}
143
144 private:
145 friend AsmType;
146
147 std::string Name() override;
148 bool IsA(AsmType* other) override;
149
150 AsmType* return_type_;
151 ZoneVector<AsmType*> args_;
152
153 DISALLOW_COPY_AND_ASSIGN(AsmFunctionType);
154 };
155
156 class V8_EXPORT_PRIVATE AsmOverloadedFunctionType final
157 : public AsmCallableType {
158 public:
AsOverloadedFunctionType()159 AsmOverloadedFunctionType* AsOverloadedFunctionType() override {
160 return this;
161 }
162
163 void AddOverload(AsmType* overload);
164
165 private:
166 friend AsmType;
167
AsmOverloadedFunctionType(Zone * zone)168 explicit AsmOverloadedFunctionType(Zone* zone) : overloads_(zone) {}
169
170 std::string Name() override;
171 bool CanBeInvokedWith(AsmType* return_type,
172 const ZoneVector<AsmType*>& args) override;
173
174 ZoneVector<AsmType*> overloads_;
175
176 DISALLOW_IMPLICIT_CONSTRUCTORS(AsmOverloadedFunctionType);
177 };
178
179 class V8_EXPORT_PRIVATE AsmFFIType final : public AsmCallableType {
180 public:
AsFFIType()181 AsmFFIType* AsFFIType() override { return this; }
182
Name()183 std::string Name() override { return "Function"; }
184 bool CanBeInvokedWith(AsmType* return_type,
185 const ZoneVector<AsmType*>& args) override;
186
187 private:
188 friend AsmType;
189
190 AsmFFIType() = default;
191
192 DISALLOW_COPY_AND_ASSIGN(AsmFFIType);
193 };
194
195 class V8_EXPORT_PRIVATE AsmFunctionTableType : public AsmCallableType {
196 public:
AsFunctionTableType()197 AsmFunctionTableType* AsFunctionTableType() override { return this; }
198
199 std::string Name() override;
200
201 bool CanBeInvokedWith(AsmType* return_type,
202 const ZoneVector<AsmType*>& args) override;
203
length()204 size_t length() const { return length_; }
signature()205 AsmType* signature() { return signature_; }
206
207 private:
208 friend class AsmType;
209
210 AsmFunctionTableType(size_t length, AsmType* signature);
211
212 size_t length_;
213 AsmType* signature_;
214
215 DISALLOW_IMPLICIT_CONSTRUCTORS(AsmFunctionTableType);
216 };
217
218 class V8_EXPORT_PRIVATE AsmType {
219 public:
220 #define DEFINE_CONSTRUCTOR(CamelName, string_name, number, parent_types) \
221 static AsmType* CamelName() { \
222 return AsmValueType::New(AsmValueType::kAsm##CamelName); \
223 }
FOR_EACH_ASM_VALUE_TYPE_LIST(DEFINE_CONSTRUCTOR)224 FOR_EACH_ASM_VALUE_TYPE_LIST(DEFINE_CONSTRUCTOR)
225 #undef DEFINE_CONSTRUCTOR
226
227 #define DEFINE_CAST(CamelCase) \
228 Asm##CamelCase* As##CamelCase() { \
229 if (AsValueType() != nullptr) { \
230 return nullptr; \
231 } \
232 return reinterpret_cast<AsmCallableType*>(this)->As##CamelCase(); \
233 }
234 FOR_EACH_ASM_CALLABLE_TYPE_LIST(DEFINE_CAST)
235 #undef DEFINE_CAST
236 AsmValueType* AsValueType() { return AsmValueType::AsValueType(this); }
237 AsmCallableType* AsCallableType();
238
239 // A function returning ret. Callers still need to invoke AddArgument with the
240 // returned type to fully create this type.
Function(Zone * zone,AsmType * ret)241 static AsmType* Function(Zone* zone, AsmType* ret) {
242 AsmFunctionType* f = new (zone) AsmFunctionType(zone, ret);
243 return reinterpret_cast<AsmType*>(f);
244 }
245
246 // Overloaded function types. Not creatable by asm source, but useful to
247 // represent the overloaded stdlib functions.
OverloadedFunction(Zone * zone)248 static AsmType* OverloadedFunction(Zone* zone) {
249 auto* f = new (zone) AsmOverloadedFunctionType(zone);
250 return reinterpret_cast<AsmType*>(f);
251 }
252
253 // The type for fround(src).
254 static AsmType* FroundType(Zone* zone);
255
256 // The (variadic) type for min and max.
257 static AsmType* MinMaxType(Zone* zone, AsmType* dest, AsmType* src);
258
259 // The type for foreign functions.
FFIType(Zone * zone)260 static AsmType* FFIType(Zone* zone) {
261 auto* f = new (zone) AsmFFIType();
262 return reinterpret_cast<AsmType*>(f);
263 }
264
265 // The type for function tables.
FunctionTableType(Zone * zone,size_t length,AsmType * signature)266 static AsmType* FunctionTableType(Zone* zone, size_t length,
267 AsmType* signature) {
268 auto* f = new (zone) AsmFunctionTableType(length, signature);
269 return reinterpret_cast<AsmType*>(f);
270 }
271
272 std::string Name();
273 // IsExactly returns true if this is the exact same type as that. For
274 // non-value types (e.g., callables), this returns this == that.
275 bool IsExactly(AsmType* that);
276 // IsA is used to query whether this is an instance of that (i.e., if this is
277 // a type derived from that.) For non-value types (e.g., callables), this
278 // returns this == that.
279 bool IsA(AsmType* that);
280
281 // Types allowed in return statements. void is the type for returns without
282 // an expression.
IsReturnType()283 bool IsReturnType() {
284 return this == AsmType::Void() || this == AsmType::Double() ||
285 this == AsmType::Signed() || this == AsmType::Float();
286 }
287
288 // Converts this to the corresponding valid argument type.
ToReturnType()289 AsmType* ToReturnType() {
290 if (this->IsA(AsmType::Signed())) {
291 return AsmType::Signed();
292 }
293 if (this->IsA(AsmType::Double())) {
294 return AsmType::Double();
295 }
296 if (this->IsA(AsmType::Float())) {
297 return AsmType::Float();
298 }
299 if (this->IsA(AsmType::Void())) {
300 return AsmType::Void();
301 }
302 return AsmType::None();
303 }
304
305 // Types allowed to be parameters in asm functions.
IsParameterType()306 bool IsParameterType() {
307 return this == AsmType::Double() || this == AsmType::Int() ||
308 this == AsmType::Float();
309 }
310
311 // Converts this to the corresponding valid argument type.
ToParameterType()312 AsmType* ToParameterType() {
313 if (this->IsA(AsmType::Int())) {
314 return AsmType::Int();
315 }
316 if (this->IsA(AsmType::Double())) {
317 return AsmType::Double();
318 }
319 if (this->IsA(AsmType::Float())) {
320 return AsmType::Float();
321 }
322 return AsmType::None();
323 }
324
325 // Types allowed to be compared using the comparison operators.
IsComparableType()326 bool IsComparableType() {
327 return this == AsmType::Double() || this == AsmType::Signed() ||
328 this == AsmType::Unsigned() || this == AsmType::Float();
329 }
330
331 // The following methods are meant to be used for inspecting the traits of
332 // element types for the heap view types.
333 enum : int32_t { kNotHeapType = -1 };
334
335 // Returns the element size if this is a heap type. Otherwise returns
336 // kNotHeapType.
337 int32_t ElementSizeInBytes();
338 // Returns the load type if this is a heap type. AsmType::None is returned if
339 // this is not a heap type.
340 AsmType* LoadType();
341 // Returns the store type if this is a heap type. AsmType::None is returned if
342 // this is not a heap type.
343 AsmType* StoreType();
344 };
345
346 } // namespace wasm
347 } // namespace internal
348 } // namespace v8
349
350 #endif // SRC_ASMJS_ASM_TYPES_H_
351