1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_ARGUMENTS_H_ 29 #define V8_ARGUMENTS_H_ 30 31 #include "allocation.h" 32 33 namespace v8 { 34 namespace internal { 35 36 // Arguments provides access to runtime call parameters. 37 // 38 // It uses the fact that the instance fields of Arguments 39 // (length_, arguments_) are "overlayed" with the parameters 40 // (no. of parameters, and the parameter pointer) passed so 41 // that inside the C++ function, the parameters passed can 42 // be accessed conveniently: 43 // 44 // Object* Runtime_function(Arguments args) { 45 // ... use args[i] here ... 46 // } 47 48 class Arguments BASE_EMBEDDED { 49 public: 50 Arguments(int length, Object** arguments) 51 : length_(length), arguments_(arguments) { } 52 53 Object*& operator[] (int index) { 54 ASSERT(0 <= index && index < length_); 55 return *(reinterpret_cast<Object**>(reinterpret_cast<intptr_t>(arguments_) - 56 index * kPointerSize)); 57 } 58 59 template <class S> Handle<S> at(int index) { 60 Object** value = &((*this)[index]); 61 // This cast checks that the object we're accessing does indeed have the 62 // expected type. 63 S::cast(*value); 64 return Handle<S>(reinterpret_cast<S**>(value)); 65 } 66 67 int smi_at(int index) { 68 return Smi::cast((*this)[index])->value(); 69 } 70 71 double number_at(int index) { 72 return (*this)[index]->Number(); 73 } 74 75 // Get the total number of arguments including the receiver. 76 int length() const { return length_; } 77 78 Object** arguments() { return arguments_; } 79 80 private: 81 int length_; 82 Object** arguments_; 83 }; 84 85 86 // For each type of callback, we have a list of arguments 87 // They are used to generate the Call() functions below 88 // These aren't included in the list as they have duplicate signatures 89 // F(NamedPropertyEnumeratorCallback, ...) 90 // F(NamedPropertyGetterCallback, ...) 91 92 #define FOR_EACH_CALLBACK_TABLE_MAPPING_0(F) \ 93 F(IndexedPropertyEnumeratorCallback, v8::Array) \ 94 95 #define FOR_EACH_CALLBACK_TABLE_MAPPING_1(F) \ 96 F(AccessorGetterCallback, v8::Value, v8::Local<v8::String>) \ 97 F(NamedPropertyQueryCallback, \ 98 v8::Integer, \ 99 v8::Local<v8::String>) \ 100 F(NamedPropertyDeleterCallback, \ 101 v8::Boolean, \ 102 v8::Local<v8::String>) \ 103 F(IndexedPropertyGetterCallback, \ 104 v8::Value, \ 105 uint32_t) \ 106 F(IndexedPropertyQueryCallback, \ 107 v8::Integer, \ 108 uint32_t) \ 109 F(IndexedPropertyDeleterCallback, \ 110 v8::Boolean, \ 111 uint32_t) \ 112 113 #define FOR_EACH_CALLBACK_TABLE_MAPPING_2(F) \ 114 F(NamedPropertySetterCallback, \ 115 v8::Value, \ 116 v8::Local<v8::String>, \ 117 v8::Local<v8::Value>) \ 118 F(IndexedPropertySetterCallback, \ 119 v8::Value, \ 120 uint32_t, \ 121 v8::Local<v8::Value>) \ 122 123 #define FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(F) \ 124 F(AccessorSetterCallback, \ 125 void, \ 126 v8::Local<v8::String>, \ 127 v8::Local<v8::Value>) \ 128 129 130 // Custom arguments replicate a small segment of stack that can be 131 // accessed through an Arguments object the same way the actual stack 132 // can. 133 template<int kArrayLength> 134 class CustomArgumentsBase : public Relocatable { 135 public: 136 virtual inline void IterateInstance(ObjectVisitor* v) { 137 v->VisitPointers(values_, values_ + kArrayLength); 138 } 139 protected: 140 inline Object** begin() { return values_; } 141 explicit inline CustomArgumentsBase(Isolate* isolate) 142 : Relocatable(isolate) {} 143 Object* values_[kArrayLength]; 144 }; 145 146 147 template<typename T> 148 class CustomArguments : public CustomArgumentsBase<T::kArgsLength> { 149 public: 150 static const int kReturnValueOffset = T::kReturnValueIndex; 151 152 typedef CustomArgumentsBase<T::kArgsLength> Super; 153 ~CustomArguments() { 154 this->begin()[kReturnValueOffset] = 155 reinterpret_cast<Object*>(kHandleZapValue); 156 } 157 158 protected: 159 explicit inline CustomArguments(Isolate* isolate) : Super(isolate) {} 160 161 template<typename V> 162 v8::Handle<V> GetReturnValue(Isolate* isolate); 163 164 inline Isolate* isolate() { 165 return reinterpret_cast<Isolate*>(this->begin()[T::kIsolateIndex]); 166 } 167 }; 168 169 170 class PropertyCallbackArguments 171 : public CustomArguments<PropertyCallbackInfo<Value> > { 172 public: 173 typedef PropertyCallbackInfo<Value> T; 174 typedef CustomArguments<T> Super; 175 static const int kArgsLength = T::kArgsLength; 176 static const int kThisIndex = T::kThisIndex; 177 static const int kHolderIndex = T::kHolderIndex; 178 static const int kDataIndex = T::kDataIndex; 179 static const int kReturnValueDefaultValueIndex = 180 T::kReturnValueDefaultValueIndex; 181 static const int kIsolateIndex = T::kIsolateIndex; 182 183 PropertyCallbackArguments(Isolate* isolate, 184 Object* data, 185 Object* self, 186 JSObject* holder) 187 : Super(isolate) { 188 Object** values = this->begin(); 189 values[T::kThisIndex] = self; 190 values[T::kHolderIndex] = holder; 191 values[T::kDataIndex] = data; 192 values[T::kIsolateIndex] = reinterpret_cast<Object*>(isolate); 193 // Here the hole is set as default value. 194 // It cannot escape into js as it's remove in Call below. 195 values[T::kReturnValueDefaultValueIndex] = 196 isolate->heap()->the_hole_value(); 197 values[T::kReturnValueIndex] = isolate->heap()->the_hole_value(); 198 ASSERT(values[T::kHolderIndex]->IsHeapObject()); 199 ASSERT(values[T::kIsolateIndex]->IsSmi()); 200 } 201 202 /* 203 * The following Call functions wrap the calling of all callbacks to handle 204 * calling either the old or the new style callbacks depending on which one 205 * has been registered. 206 * For old callbacks which return an empty handle, the ReturnValue is checked 207 * and used if it's been set to anything inside the callback. 208 * New style callbacks always use the return value. 209 */ 210 #define WRITE_CALL_0(Function, ReturnValue) \ 211 v8::Handle<ReturnValue> Call(Function f); \ 212 213 #define WRITE_CALL_1(Function, ReturnValue, Arg1) \ 214 v8::Handle<ReturnValue> Call(Function f, Arg1 arg1); \ 215 216 #define WRITE_CALL_2(Function, ReturnValue, Arg1, Arg2) \ 217 v8::Handle<ReturnValue> Call(Function f, Arg1 arg1, Arg2 arg2); \ 218 219 #define WRITE_CALL_2_VOID(Function, ReturnValue, Arg1, Arg2) \ 220 void Call(Function f, Arg1 arg1, Arg2 arg2); \ 221 222 FOR_EACH_CALLBACK_TABLE_MAPPING_0(WRITE_CALL_0) 223 FOR_EACH_CALLBACK_TABLE_MAPPING_1(WRITE_CALL_1) 224 FOR_EACH_CALLBACK_TABLE_MAPPING_2(WRITE_CALL_2) 225 FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(WRITE_CALL_2_VOID) 226 227 #undef WRITE_CALL_0 228 #undef WRITE_CALL_1 229 #undef WRITE_CALL_2 230 #undef WRITE_CALL_2_VOID 231 }; 232 233 234 class FunctionCallbackArguments 235 : public CustomArguments<FunctionCallbackInfo<Value> > { 236 public: 237 typedef FunctionCallbackInfo<Value> T; 238 typedef CustomArguments<T> Super; 239 static const int kArgsLength = T::kArgsLength; 240 static const int kHolderIndex = T::kHolderIndex; 241 static const int kDataIndex = T::kDataIndex; 242 static const int kReturnValueDefaultValueIndex = 243 T::kReturnValueDefaultValueIndex; 244 static const int kIsolateIndex = T::kIsolateIndex; 245 static const int kCalleeIndex = T::kCalleeIndex; 246 static const int kContextSaveIndex = T::kContextSaveIndex; 247 248 FunctionCallbackArguments(internal::Isolate* isolate, 249 internal::Object* data, 250 internal::JSFunction* callee, 251 internal::Object* holder, 252 internal::Object** argv, 253 int argc, 254 bool is_construct_call) 255 : Super(isolate), 256 argv_(argv), 257 argc_(argc), 258 is_construct_call_(is_construct_call) { 259 Object** values = begin(); 260 values[T::kDataIndex] = data; 261 values[T::kCalleeIndex] = callee; 262 values[T::kHolderIndex] = holder; 263 values[T::kContextSaveIndex] = isolate->heap()->the_hole_value(); 264 values[T::kIsolateIndex] = reinterpret_cast<internal::Object*>(isolate); 265 // Here the hole is set as default value. 266 // It cannot escape into js as it's remove in Call below. 267 values[T::kReturnValueDefaultValueIndex] = 268 isolate->heap()->the_hole_value(); 269 values[T::kReturnValueIndex] = isolate->heap()->the_hole_value(); 270 ASSERT(values[T::kCalleeIndex]->IsJSFunction()); 271 ASSERT(values[T::kHolderIndex]->IsHeapObject()); 272 ASSERT(values[T::kIsolateIndex]->IsSmi()); 273 } 274 275 /* 276 * The following Call function wraps the calling of all callbacks to handle 277 * calling either the old or the new style callbacks depending on which one 278 * has been registered. 279 * For old callbacks which return an empty handle, the ReturnValue is checked 280 * and used if it's been set to anything inside the callback. 281 * New style callbacks always use the return value. 282 */ 283 v8::Handle<v8::Value> Call(FunctionCallback f); 284 285 private: 286 internal::Object** argv_; 287 int argc_; 288 bool is_construct_call_; 289 }; 290 291 292 double ClobberDoubleRegisters(double x1, double x2, double x3, double x4); 293 294 295 #ifdef DEBUG 296 #define CLOBBER_DOUBLE_REGISTERS() ClobberDoubleRegisters(1, 2, 3, 4); 297 #else 298 #define CLOBBER_DOUBLE_REGISTERS() 299 #endif 300 301 302 #define DECLARE_RUNTIME_FUNCTION(Type, Name) \ 303 Type Name(int args_length, Object** args_object, Isolate* isolate) 304 305 #define RUNTIME_FUNCTION(Type, Name) \ 306 static Type __RT_impl_##Name(Arguments args, Isolate* isolate); \ 307 Type Name(int args_length, Object** args_object, Isolate* isolate) { \ 308 CLOBBER_DOUBLE_REGISTERS(); \ 309 Arguments args(args_length, args_object); \ 310 return __RT_impl_##Name(args, isolate); \ 311 } \ 312 static Type __RT_impl_##Name(Arguments args, Isolate* isolate) 313 314 #define RUNTIME_ARGUMENTS(isolate, args) \ 315 args.length(), args.arguments(), isolate 316 317 } } // namespace v8::internal 318 319 #endif // V8_ARGUMENTS_H_ 320