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 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 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 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 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: 131 AsmFunctionType* AsFunctionType() final { return this; } 132 133 void AddArgument(AsmType* type) { args_.push_back(type); } 134 const ZoneVector<AsmType*> Arguments() const { return args_; } 135 AsmType* ReturnType() const { return return_type_; } 136 137 bool CanBeInvokedWith(AsmType* return_type, 138 const ZoneVector<AsmType*>& args) override; 139 140 protected: 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: 159 AsmOverloadedFunctionType* AsOverloadedFunctionType() override { 160 return this; 161 } 162 163 void AddOverload(AsmType* overload); 164 165 private: 166 friend AsmType; 167 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: 181 AsmFFIType* AsFFIType() override { return this; } 182 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: 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 204 size_t length() const { return length_; } 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 } 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. 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. 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. 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. 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. 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. 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. 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. 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. 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