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 // mappings from old property callbacks to new ones 87 // F(old name, new name, return value, parameters...) 88 // 89 // These aren't included in the list as they have duplicate signatures 90 // F(NamedPropertyEnumerator, NamedPropertyEnumeratorCallback, ...) 91 // F(NamedPropertyGetter, NamedPropertyGetterCallback, ...) 92 93 #define FOR_EACH_CALLBACK_TABLE_MAPPING_0(F) \ 94 F(IndexedPropertyEnumerator, IndexedPropertyEnumeratorCallback, v8::Array) \ 95 96 #define FOR_EACH_CALLBACK_TABLE_MAPPING_1(F) \ 97 F(AccessorGetter, AccessorGetterCallback, v8::Value, v8::Local<v8::String>) \ 98 F(NamedPropertyQuery, \ 99 NamedPropertyQueryCallback, \ 100 v8::Integer, \ 101 v8::Local<v8::String>) \ 102 F(NamedPropertyDeleter, \ 103 NamedPropertyDeleterCallback, \ 104 v8::Boolean, \ 105 v8::Local<v8::String>) \ 106 F(IndexedPropertyGetter, \ 107 IndexedPropertyGetterCallback, \ 108 v8::Value, \ 109 uint32_t) \ 110 F(IndexedPropertyQuery, \ 111 IndexedPropertyQueryCallback, \ 112 v8::Integer, \ 113 uint32_t) \ 114 F(IndexedPropertyDeleter, \ 115 IndexedPropertyDeleterCallback, \ 116 v8::Boolean, \ 117 uint32_t) \ 118 119 #define FOR_EACH_CALLBACK_TABLE_MAPPING_2(F) \ 120 F(NamedPropertySetter, \ 121 NamedPropertySetterCallback, \ 122 v8::Value, \ 123 v8::Local<v8::String>, \ 124 v8::Local<v8::Value>) \ 125 F(IndexedPropertySetter, \ 126 IndexedPropertySetterCallback, \ 127 v8::Value, \ 128 uint32_t, \ 129 v8::Local<v8::Value>) \ 130 131 #define FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(F) \ 132 F(AccessorSetter, \ 133 AccessorSetterCallback, \ 134 void, \ 135 v8::Local<v8::String>, \ 136 v8::Local<v8::Value>) \ 137 138 // All property callbacks as well as invocation callbacks 139 #define FOR_EACH_CALLBACK_TABLE_MAPPING(F) \ 140 F(InvocationCallback, FunctionCallback) \ 141 F(AccessorGetter, AccessorGetterCallback) \ 142 F(AccessorSetter, AccessorSetterCallback) \ 143 F(NamedPropertySetter, NamedPropertySetterCallback) \ 144 F(NamedPropertyQuery, NamedPropertyQueryCallback) \ 145 F(NamedPropertyDeleter, NamedPropertyDeleterCallback) \ 146 F(IndexedPropertyGetter, IndexedPropertyGetterCallback) \ 147 F(IndexedPropertySetter, IndexedPropertySetterCallback) \ 148 F(IndexedPropertyQuery, IndexedPropertyQueryCallback) \ 149 F(IndexedPropertyDeleter, IndexedPropertyDeleterCallback) \ 150 F(IndexedPropertyEnumerator, IndexedPropertyEnumeratorCallback) \ 151 152 153 // TODO(dcarney): Remove this class when old callbacks are gone. 154 class CallbackTable { 155 public: 156 static const bool kStoreVoidFunctions = false; 157 static inline bool ReturnsVoid(Isolate* isolate, void* function) { 158 CallbackTable* table = isolate->callback_table(); 159 bool contains = 160 table != NULL && 161 table->map_.occupancy() != 0 && 162 table->Contains(function); 163 return contains == kStoreVoidFunctions; 164 } 165 166 STATIC_ASSERT(sizeof(intptr_t) == sizeof(AccessorGetterCallback)); 167 168 template<typename F> 169 static inline void* FunctionToVoidPtr(F function) { 170 return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(function)); 171 } 172 173 #define WRITE_REGISTER(OldFunction, NewFunction) \ 174 static NewFunction Register(Isolate* isolate, OldFunction f) { \ 175 InsertCallback(isolate, FunctionToVoidPtr(f), false); \ 176 return reinterpret_cast<NewFunction>(f); \ 177 } \ 178 \ 179 static NewFunction Register(Isolate* isolate, NewFunction f) { \ 180 InsertCallback(isolate, FunctionToVoidPtr(f), true); \ 181 return f; \ 182 } 183 FOR_EACH_CALLBACK_TABLE_MAPPING(WRITE_REGISTER) 184 #undef WRITE_REGISTER 185 186 private: 187 CallbackTable(); 188 bool Contains(void* function); 189 static void InsertCallback(Isolate* isolate, 190 void* function, 191 bool returns_void); 192 HashMap map_; 193 DISALLOW_COPY_AND_ASSIGN(CallbackTable); 194 }; 195 196 197 // Custom arguments replicate a small segment of stack that can be 198 // accessed through an Arguments object the same way the actual stack 199 // can. 200 template<int kArrayLength> 201 class CustomArgumentsBase : public Relocatable { 202 public: 203 virtual inline void IterateInstance(ObjectVisitor* v) { 204 v->VisitPointers(values_, values_ + kArrayLength); 205 } 206 protected: 207 inline Object** end() { return values_ + kArrayLength - 1; } 208 explicit inline CustomArgumentsBase(Isolate* isolate) 209 : Relocatable(isolate) {} 210 Object* values_[kArrayLength]; 211 }; 212 213 214 template<typename T> 215 class CustomArguments : public CustomArgumentsBase<T::kArgsLength> { 216 public: 217 static const int kReturnValueOffset = T::kReturnValueIndex; 218 219 typedef CustomArgumentsBase<T::kArgsLength> Super; 220 ~CustomArguments() { 221 // TODO(dcarney): create a new zap value for this. 222 this->end()[kReturnValueOffset] = 223 reinterpret_cast<Object*>(kHandleZapValue); 224 } 225 226 protected: 227 explicit inline CustomArguments(Isolate* isolate) : Super(isolate) {} 228 229 template<typename V> 230 v8::Handle<V> GetReturnValue(Isolate* isolate); 231 232 inline Isolate* isolate() { 233 return reinterpret_cast<Isolate*>(this->end()[T::kIsolateIndex]); 234 } 235 }; 236 237 238 class PropertyCallbackArguments 239 : public CustomArguments<PropertyCallbackInfo<Value> > { 240 public: 241 typedef PropertyCallbackInfo<Value> T; 242 typedef CustomArguments<T> Super; 243 static const int kArgsLength = T::kArgsLength; 244 static const int kThisIndex = T::kThisIndex; 245 static const int kHolderIndex = T::kHolderIndex; 246 247 PropertyCallbackArguments(Isolate* isolate, 248 Object* data, 249 Object* self, 250 JSObject* holder) 251 : Super(isolate) { 252 Object** values = this->end(); 253 values[T::kThisIndex] = self; 254 values[T::kHolderIndex] = holder; 255 values[T::kDataIndex] = data; 256 values[T::kIsolateIndex] = reinterpret_cast<Object*>(isolate); 257 // Here the hole is set as default value. 258 // It cannot escape into js as it's remove in Call below. 259 values[T::kReturnValueDefaultValueIndex] = 260 isolate->heap()->the_hole_value(); 261 values[T::kReturnValueIndex] = isolate->heap()->the_hole_value(); 262 ASSERT(values[T::kHolderIndex]->IsHeapObject()); 263 ASSERT(values[T::kIsolateIndex]->IsSmi()); 264 } 265 266 /* 267 * The following Call functions wrap the calling of all callbacks to handle 268 * calling either the old or the new style callbacks depending on which one 269 * has been registered. 270 * For old callbacks which return an empty handle, the ReturnValue is checked 271 * and used if it's been set to anything inside the callback. 272 * New style callbacks always use the return value. 273 */ 274 #define WRITE_CALL_0(OldFunction, NewFunction, ReturnValue) \ 275 v8::Handle<ReturnValue> Call(OldFunction f); \ 276 277 #define WRITE_CALL_1(OldFunction, NewFunction, ReturnValue, Arg1) \ 278 v8::Handle<ReturnValue> Call(OldFunction f, Arg1 arg1); \ 279 280 #define WRITE_CALL_2(OldFunction, NewFunction, ReturnValue, Arg1, Arg2) \ 281 v8::Handle<ReturnValue> Call(OldFunction f, Arg1 arg1, Arg2 arg2); \ 282 283 #define WRITE_CALL_2_VOID(OldFunction, NewFunction, ReturnValue, Arg1, Arg2) \ 284 void Call(OldFunction f, Arg1 arg1, Arg2 arg2); \ 285 286 FOR_EACH_CALLBACK_TABLE_MAPPING_0(WRITE_CALL_0) 287 FOR_EACH_CALLBACK_TABLE_MAPPING_1(WRITE_CALL_1) 288 FOR_EACH_CALLBACK_TABLE_MAPPING_2(WRITE_CALL_2) 289 FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(WRITE_CALL_2_VOID) 290 291 #undef WRITE_CALL_0 292 #undef WRITE_CALL_1 293 #undef WRITE_CALL_2 294 #undef WRITE_CALL_2_VOID 295 }; 296 297 298 class FunctionCallbackArguments 299 : public CustomArguments<FunctionCallbackInfo<Value> > { 300 public: 301 typedef FunctionCallbackInfo<Value> T; 302 typedef CustomArguments<T> Super; 303 static const int kArgsLength = T::kArgsLength; 304 305 FunctionCallbackArguments(internal::Isolate* isolate, 306 internal::Object* data, 307 internal::JSFunction* callee, 308 internal::Object* holder, 309 internal::Object** argv, 310 int argc, 311 bool is_construct_call) 312 : Super(isolate), 313 argv_(argv), 314 argc_(argc), 315 is_construct_call_(is_construct_call) { 316 Object** values = end(); 317 values[T::kDataIndex] = data; 318 values[T::kCalleeIndex] = callee; 319 values[T::kHolderIndex] = holder; 320 values[T::kIsolateIndex] = reinterpret_cast<internal::Object*>(isolate); 321 // Here the hole is set as default value. 322 // It cannot escape into js as it's remove in Call below. 323 values[T::kReturnValueDefaultValueIndex] = 324 isolate->heap()->the_hole_value(); 325 values[T::kReturnValueIndex] = isolate->heap()->the_hole_value(); 326 ASSERT(values[T::kCalleeIndex]->IsJSFunction()); 327 ASSERT(values[T::kHolderIndex]->IsHeapObject()); 328 ASSERT(values[T::kIsolateIndex]->IsSmi()); 329 } 330 331 /* 332 * The following Call function wraps the calling of all callbacks to handle 333 * calling either the old or the new style callbacks depending on which one 334 * has been registered. 335 * For old callbacks which return an empty handle, the ReturnValue is checked 336 * and used if it's been set to anything inside the callback. 337 * New style callbacks always use the return value. 338 */ 339 v8::Handle<v8::Value> Call(InvocationCallback f); 340 341 private: 342 internal::Object** argv_; 343 int argc_; 344 bool is_construct_call_; 345 }; 346 347 348 #define DECLARE_RUNTIME_FUNCTION(Type, Name) \ 349 Type Name(int args_length, Object** args_object, Isolate* isolate) 350 351 #define RUNTIME_FUNCTION(Type, Name) \ 352 static Type __RT_impl_##Name(Arguments args, Isolate* isolate); \ 353 Type Name(int args_length, Object** args_object, Isolate* isolate) { \ 354 Arguments args(args_length, args_object); \ 355 return __RT_impl_##Name(args, isolate); \ 356 } \ 357 static Type __RT_impl_##Name(Arguments args, Isolate* isolate) 358 359 #define RUNTIME_ARGUMENTS(isolate, args) \ 360 args.length(), args.arguments(), isolate 361 362 } } // namespace v8::internal 363 364 #endif // V8_ARGUMENTS_H_ 365