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