1 // Copyright 2014 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 V8_RUNTIME_RUNTIME_UTILS_H_ 6 #define V8_RUNTIME_RUNTIME_UTILS_H_ 7 8 #include "src/base/logging.h" 9 #include "src/globals.h" 10 #include "src/runtime/runtime.h" 11 12 namespace v8 { 13 namespace internal { 14 15 // Cast the given object to a value of the specified type and store 16 // it in a variable with the given name. If the object is not of the 17 // expected type we crash safely. 18 #define CONVERT_ARG_CHECKED(Type, name, index) \ 19 CHECK(args[index]->Is##Type()); \ 20 Type* name = Type::cast(args[index]); 21 22 #define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \ 23 CHECK(args[index]->Is##Type()); \ 24 Handle<Type> name = args.at<Type>(index); 25 26 #define CONVERT_NUMBER_ARG_HANDLE_CHECKED(name, index) \ 27 CHECK(args[index]->IsNumber()); \ 28 Handle<Object> name = args.at(index); 29 30 // Cast the given object to a boolean and store it in a variable with 31 // the given name. If the object is not a boolean we crash safely. 32 #define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \ 33 CHECK(args[index]->IsBoolean()); \ 34 bool name = args[index]->IsTrue(isolate); 35 36 // Cast the given argument to a Smi and store its value in an int variable 37 // with the given name. If the argument is not a Smi we crash safely. 38 #define CONVERT_SMI_ARG_CHECKED(name, index) \ 39 CHECK(args[index]->IsSmi()); \ 40 int name = args.smi_at(index); 41 42 // Cast the given argument to a double and store it in a variable with 43 // the given name. If the argument is not a number (as opposed to 44 // the number not-a-number) we crash safely. 45 #define CONVERT_DOUBLE_ARG_CHECKED(name, index) \ 46 CHECK(args[index]->IsNumber()); \ 47 double name = args.number_at(index); 48 49 // Cast the given argument to a size_t and store its value in a variable with 50 // the given name. If the argument is not a size_t we crash safely. 51 #define CONVERT_SIZE_ARG_CHECKED(name, index) \ 52 CHECK(args[index]->IsNumber()); \ 53 Handle<Object> name##_object = args.at(index); \ 54 size_t name = 0; \ 55 CHECK(TryNumberToSize(*name##_object, &name)); 56 57 // Call the specified converter on the object *comand store the result in 58 // a variable of the specified type with the given name. If the 59 // object is not a Number we crash safely. 60 #define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \ 61 CHECK(obj->IsNumber()); \ 62 type name = NumberTo##Type(obj); 63 64 // Cast the given argument to PropertyDetails and store its value in a 65 // variable with the given name. If the argument is not a Smi we crash safely. 66 #define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \ 67 CHECK(args[index]->IsSmi()); \ 68 PropertyDetails name = PropertyDetails(Smi::cast(args[index])); 69 70 // Assert that the given argument has a valid value for a LanguageMode 71 // and store it in a LanguageMode variable with the given name. 72 #define CONVERT_LANGUAGE_MODE_ARG_CHECKED(name, index) \ 73 CHECK(args[index]->IsNumber()); \ 74 int32_t __tmp_##name = 0; \ 75 CHECK(args[index]->ToInt32(&__tmp_##name)); \ 76 CHECK(is_valid_language_mode(__tmp_##name)); \ 77 LanguageMode name = static_cast<LanguageMode>(__tmp_##name); 78 79 // Assert that the given argument is a number within the Int32 range 80 // and convert it to int32_t. If the argument is not an Int32 we crash safely. 81 #define CONVERT_INT32_ARG_CHECKED(name, index) \ 82 CHECK(args[index]->IsNumber()); \ 83 int32_t name = 0; \ 84 CHECK(args[index]->ToInt32(&name)); 85 86 // Assert that the given argument is a number within the Uint32 range 87 // and convert it to uint32_t. If the argument is not an Uint32 call 88 // IllegalOperation and return. 89 #define CONVERT_UINT32_ARG_CHECKED(name, index) \ 90 CHECK(args[index]->IsNumber()); \ 91 uint32_t name = 0; \ 92 CHECK(args[index]->ToUint32(&name)); 93 94 // Cast the given argument to PropertyAttributes and store its value in a 95 // variable with the given name. If the argument is not a Smi or the 96 // enum value is out of range, we crash safely. 97 #define CONVERT_PROPERTY_ATTRIBUTES_CHECKED(name, index) \ 98 CHECK(args[index]->IsSmi()); \ 99 CHECK((args.smi_at(index) & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); \ 100 PropertyAttributes name = static_cast<PropertyAttributes>(args.smi_at(index)); 101 102 // A mechanism to return a pair of Object pointers in registers (if possible). 103 // How this is achieved is calling convention-dependent. 104 // All currently supported x86 compiles uses calling conventions that are cdecl 105 // variants where a 64-bit value is returned in two 32-bit registers 106 // (edx:eax on ia32, r1:r0 on ARM). 107 // In AMD-64 calling convention a struct of two pointers is returned in rdx:rax. 108 // In Win64 calling convention, a struct of two pointers is returned in memory, 109 // allocated by the caller, and passed as a pointer in a hidden first parameter. 110 #ifdef V8_HOST_ARCH_64_BIT 111 struct ObjectPair { 112 Object* x; 113 Object* y; 114 }; 115 116 117 static inline ObjectPair MakePair(Object* x, Object* y) { 118 ObjectPair result = {x, y}; 119 // Pointers x and y returned in rax and rdx, in AMD-x64-abi. 120 // In Win64 they are assigned to a hidden first argument. 121 return result; 122 } 123 #elif V8_TARGET_ARCH_X64 && V8_TARGET_ARCH_32_BIT 124 // For x32 a 128-bit struct return is done as rax and rdx from the ObjectPair 125 // are used in the full codegen and Crankshaft compiler. An alternative is 126 // using uint64_t and modifying full codegen and Crankshaft compiler. 127 struct ObjectPair { 128 Object* x; 129 uint32_t x_upper; 130 Object* y; 131 uint32_t y_upper; 132 }; 133 134 135 static inline ObjectPair MakePair(Object* x, Object* y) { 136 ObjectPair result = {x, 0, y, 0}; 137 // Pointers x and y returned in rax and rdx, in x32-abi. 138 return result; 139 } 140 #else 141 typedef uint64_t ObjectPair; 142 static inline ObjectPair MakePair(Object* x, Object* y) { 143 #if defined(V8_TARGET_LITTLE_ENDIAN) 144 return reinterpret_cast<uint32_t>(x) | 145 (reinterpret_cast<ObjectPair>(y) << 32); 146 #elif defined(V8_TARGET_BIG_ENDIAN) 147 return reinterpret_cast<uint32_t>(y) | 148 (reinterpret_cast<ObjectPair>(x) << 32); 149 #else 150 #error Unknown endianness 151 #endif 152 } 153 #endif 154 155 156 // A mechanism to return a triple of Object pointers. In all calling 157 // conventions, a struct of two pointers is returned in memory, 158 // allocated by the caller, and passed as a pointer in a hidden first parameter. 159 struct ObjectTriple { 160 Object* x; 161 Object* y; 162 Object* z; 163 }; 164 165 static inline ObjectTriple MakeTriple(Object* x, Object* y, Object* z) { 166 ObjectTriple result = {x, y, z}; 167 // ObjectTriple is assigned to a hidden first argument. 168 return result; 169 } 170 171 } // namespace internal 172 } // namespace v8 173 174 #endif // V8_RUNTIME_RUNTIME_UTILS_H_ 175