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