1 // Copyright 2012 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_ARGUMENTS_H_ 6 #define V8_ARGUMENTS_H_ 7 8 #include "src/allocation.h" 9 10 namespace v8 { 11 namespace internal { 12 13 // Arguments provides access to runtime call parameters. 14 // 15 // It uses the fact that the instance fields of Arguments 16 // (length_, arguments_) are "overlayed" with the parameters 17 // (no. of parameters, and the parameter pointer) passed so 18 // that inside the C++ function, the parameters passed can 19 // be accessed conveniently: 20 // 21 // Object* Runtime_function(Arguments args) { 22 // ... use args[i] here ... 23 // } 24 // 25 // Note that length_ (whose value is in the integer range) is defined 26 // as intptr_t to provide endian-neutrality on 64-bit archs. 27 28 class Arguments BASE_EMBEDDED { 29 public: 30 Arguments(int length, Object** arguments) 31 : length_(length), arguments_(arguments) { } 32 33 Object*& operator[] (int index) { 34 ASSERT(0 <= index && index < length_); 35 return *(reinterpret_cast<Object**>(reinterpret_cast<intptr_t>(arguments_) - 36 index * kPointerSize)); 37 } 38 39 template <class S> Handle<S> at(int index) { 40 Object** value = &((*this)[index]); 41 // This cast checks that the object we're accessing does indeed have the 42 // expected type. 43 S::cast(*value); 44 return Handle<S>(reinterpret_cast<S**>(value)); 45 } 46 47 int smi_at(int index) { 48 return Smi::cast((*this)[index])->value(); 49 } 50 51 double number_at(int index) { 52 return (*this)[index]->Number(); 53 } 54 55 // Get the total number of arguments including the receiver. 56 int length() const { return static_cast<int>(length_); } 57 58 Object** arguments() { return arguments_; } 59 60 private: 61 intptr_t length_; 62 Object** arguments_; 63 }; 64 65 66 // For each type of callback, we have a list of arguments 67 // They are used to generate the Call() functions below 68 // These aren't included in the list as they have duplicate signatures 69 // F(NamedPropertyEnumeratorCallback, ...) 70 // F(NamedPropertyGetterCallback, ...) 71 72 #define FOR_EACH_CALLBACK_TABLE_MAPPING_0(F) \ 73 F(IndexedPropertyEnumeratorCallback, v8::Array) \ 74 75 #define FOR_EACH_CALLBACK_TABLE_MAPPING_1(F) \ 76 F(AccessorGetterCallback, v8::Value, v8::Local<v8::String>) \ 77 F(NamedPropertyQueryCallback, \ 78 v8::Integer, \ 79 v8::Local<v8::String>) \ 80 F(NamedPropertyDeleterCallback, \ 81 v8::Boolean, \ 82 v8::Local<v8::String>) \ 83 F(IndexedPropertyGetterCallback, \ 84 v8::Value, \ 85 uint32_t) \ 86 F(IndexedPropertyQueryCallback, \ 87 v8::Integer, \ 88 uint32_t) \ 89 F(IndexedPropertyDeleterCallback, \ 90 v8::Boolean, \ 91 uint32_t) \ 92 93 #define FOR_EACH_CALLBACK_TABLE_MAPPING_2(F) \ 94 F(NamedPropertySetterCallback, \ 95 v8::Value, \ 96 v8::Local<v8::String>, \ 97 v8::Local<v8::Value>) \ 98 F(IndexedPropertySetterCallback, \ 99 v8::Value, \ 100 uint32_t, \ 101 v8::Local<v8::Value>) \ 102 103 #define FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(F) \ 104 F(AccessorSetterCallback, \ 105 void, \ 106 v8::Local<v8::String>, \ 107 v8::Local<v8::Value>) \ 108 109 110 // Custom arguments replicate a small segment of stack that can be 111 // accessed through an Arguments object the same way the actual stack 112 // can. 113 template<int kArrayLength> 114 class CustomArgumentsBase : public Relocatable { 115 public: 116 virtual inline void IterateInstance(ObjectVisitor* v) { 117 v->VisitPointers(values_, values_ + kArrayLength); 118 } 119 protected: 120 inline Object** begin() { return values_; } 121 explicit inline CustomArgumentsBase(Isolate* isolate) 122 : Relocatable(isolate) {} 123 Object* values_[kArrayLength]; 124 }; 125 126 127 template<typename T> 128 class CustomArguments : public CustomArgumentsBase<T::kArgsLength> { 129 public: 130 static const int kReturnValueOffset = T::kReturnValueIndex; 131 132 typedef CustomArgumentsBase<T::kArgsLength> Super; 133 ~CustomArguments() { 134 this->begin()[kReturnValueOffset] = 135 reinterpret_cast<Object*>(kHandleZapValue); 136 } 137 138 protected: 139 explicit inline CustomArguments(Isolate* isolate) : Super(isolate) {} 140 141 template<typename V> 142 v8::Handle<V> GetReturnValue(Isolate* isolate); 143 144 inline Isolate* isolate() { 145 return reinterpret_cast<Isolate*>(this->begin()[T::kIsolateIndex]); 146 } 147 }; 148 149 150 class PropertyCallbackArguments 151 : public CustomArguments<PropertyCallbackInfo<Value> > { 152 public: 153 typedef PropertyCallbackInfo<Value> T; 154 typedef CustomArguments<T> Super; 155 static const int kArgsLength = T::kArgsLength; 156 static const int kThisIndex = T::kThisIndex; 157 static const int kHolderIndex = T::kHolderIndex; 158 static const int kDataIndex = T::kDataIndex; 159 static const int kReturnValueDefaultValueIndex = 160 T::kReturnValueDefaultValueIndex; 161 static const int kIsolateIndex = T::kIsolateIndex; 162 163 PropertyCallbackArguments(Isolate* isolate, 164 Object* data, 165 Object* self, 166 JSObject* holder) 167 : Super(isolate) { 168 Object** values = this->begin(); 169 values[T::kThisIndex] = self; 170 values[T::kHolderIndex] = holder; 171 values[T::kDataIndex] = data; 172 values[T::kIsolateIndex] = reinterpret_cast<Object*>(isolate); 173 // Here the hole is set as default value. 174 // It cannot escape into js as it's remove in Call below. 175 values[T::kReturnValueDefaultValueIndex] = 176 isolate->heap()->the_hole_value(); 177 values[T::kReturnValueIndex] = isolate->heap()->the_hole_value(); 178 ASSERT(values[T::kHolderIndex]->IsHeapObject()); 179 ASSERT(values[T::kIsolateIndex]->IsSmi()); 180 } 181 182 /* 183 * The following Call functions wrap the calling of all callbacks to handle 184 * calling either the old or the new style callbacks depending on which one 185 * has been registered. 186 * For old callbacks which return an empty handle, the ReturnValue is checked 187 * and used if it's been set to anything inside the callback. 188 * New style callbacks always use the return value. 189 */ 190 #define WRITE_CALL_0(Function, ReturnValue) \ 191 v8::Handle<ReturnValue> Call(Function f); \ 192 193 #define WRITE_CALL_1(Function, ReturnValue, Arg1) \ 194 v8::Handle<ReturnValue> Call(Function f, Arg1 arg1); \ 195 196 #define WRITE_CALL_2(Function, ReturnValue, Arg1, Arg2) \ 197 v8::Handle<ReturnValue> Call(Function f, Arg1 arg1, Arg2 arg2); \ 198 199 #define WRITE_CALL_2_VOID(Function, ReturnValue, Arg1, Arg2) \ 200 void Call(Function f, Arg1 arg1, Arg2 arg2); \ 201 202 FOR_EACH_CALLBACK_TABLE_MAPPING_0(WRITE_CALL_0) 203 FOR_EACH_CALLBACK_TABLE_MAPPING_1(WRITE_CALL_1) 204 FOR_EACH_CALLBACK_TABLE_MAPPING_2(WRITE_CALL_2) 205 FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(WRITE_CALL_2_VOID) 206 207 #undef WRITE_CALL_0 208 #undef WRITE_CALL_1 209 #undef WRITE_CALL_2 210 #undef WRITE_CALL_2_VOID 211 }; 212 213 214 class FunctionCallbackArguments 215 : public CustomArguments<FunctionCallbackInfo<Value> > { 216 public: 217 typedef FunctionCallbackInfo<Value> T; 218 typedef CustomArguments<T> Super; 219 static const int kArgsLength = T::kArgsLength; 220 static const int kHolderIndex = T::kHolderIndex; 221 static const int kDataIndex = T::kDataIndex; 222 static const int kReturnValueDefaultValueIndex = 223 T::kReturnValueDefaultValueIndex; 224 static const int kIsolateIndex = T::kIsolateIndex; 225 static const int kCalleeIndex = T::kCalleeIndex; 226 static const int kContextSaveIndex = T::kContextSaveIndex; 227 228 FunctionCallbackArguments(internal::Isolate* isolate, 229 internal::Object* data, 230 internal::JSFunction* callee, 231 internal::Object* holder, 232 internal::Object** argv, 233 int argc, 234 bool is_construct_call) 235 : Super(isolate), 236 argv_(argv), 237 argc_(argc), 238 is_construct_call_(is_construct_call) { 239 Object** values = begin(); 240 values[T::kDataIndex] = data; 241 values[T::kCalleeIndex] = callee; 242 values[T::kHolderIndex] = holder; 243 values[T::kContextSaveIndex] = isolate->heap()->the_hole_value(); 244 values[T::kIsolateIndex] = reinterpret_cast<internal::Object*>(isolate); 245 // Here the hole is set as default value. 246 // It cannot escape into js as it's remove in Call below. 247 values[T::kReturnValueDefaultValueIndex] = 248 isolate->heap()->the_hole_value(); 249 values[T::kReturnValueIndex] = isolate->heap()->the_hole_value(); 250 ASSERT(values[T::kCalleeIndex]->IsJSFunction()); 251 ASSERT(values[T::kHolderIndex]->IsHeapObject()); 252 ASSERT(values[T::kIsolateIndex]->IsSmi()); 253 } 254 255 /* 256 * The following Call function wraps the calling of all callbacks to handle 257 * calling either the old or the new style callbacks depending on which one 258 * has been registered. 259 * For old callbacks which return an empty handle, the ReturnValue is checked 260 * and used if it's been set to anything inside the callback. 261 * New style callbacks always use the return value. 262 */ 263 v8::Handle<v8::Value> Call(FunctionCallback f); 264 265 private: 266 internal::Object** argv_; 267 int argc_; 268 bool is_construct_call_; 269 }; 270 271 272 double ClobberDoubleRegisters(double x1, double x2, double x3, double x4); 273 274 275 #ifdef DEBUG 276 #define CLOBBER_DOUBLE_REGISTERS() ClobberDoubleRegisters(1, 2, 3, 4); 277 #else 278 #define CLOBBER_DOUBLE_REGISTERS() 279 #endif 280 281 282 #define DECLARE_RUNTIME_FUNCTION(Name) \ 283 Object* Name(int args_length, Object** args_object, Isolate* isolate) 284 285 #define RUNTIME_FUNCTION_RETURNS_TYPE(Type, Name) \ 286 static INLINE(Type __RT_impl_##Name(Arguments args, Isolate* isolate)); \ 287 Type Name(int args_length, Object** args_object, Isolate* isolate) { \ 288 CLOBBER_DOUBLE_REGISTERS(); \ 289 Arguments args(args_length, args_object); \ 290 return __RT_impl_##Name(args, isolate); \ 291 } \ 292 static Type __RT_impl_##Name(Arguments args, Isolate* isolate) 293 294 295 #define RUNTIME_FUNCTION(Name) RUNTIME_FUNCTION_RETURNS_TYPE(Object*, Name) 296 #define RUNTIME_FUNCTION_RETURN_PAIR(Name) \ 297 RUNTIME_FUNCTION_RETURNS_TYPE(ObjectPair, Name) 298 299 #define RUNTIME_ARGUMENTS(isolate, args) \ 300 args.length(), args.arguments(), isolate 301 302 } } // namespace v8::internal 303 304 #endif // V8_ARGUMENTS_H_ 305