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