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