1 // Copyright 2016 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_API_ARGUMENTS_INL_H_ 6 #define V8_API_ARGUMENTS_INL_H_ 7 8 #include "src/api-arguments.h" 9 10 #include "src/api-inl.h" 11 #include "src/objects/api-callbacks.h" 12 #include "src/tracing/trace-event.h" 13 #include "src/vm-state-inl.h" 14 15 namespace v8 { 16 namespace internal { 17 18 CustomArgumentsBase::CustomArgumentsBase(Isolate* isolate) 19 : Relocatable(isolate) {} 20 21 template <typename T> 22 template <typename V> 23 Handle<V> CustomArguments<T>::GetReturnValue(Isolate* isolate) { 24 // Check the ReturnValue. 25 Object** handle = &this->begin()[kReturnValueOffset]; 26 // Nothing was set, return empty handle as per previous behaviour. 27 if ((*handle)->IsTheHole(isolate)) return Handle<V>(); 28 Handle<V> result = Handle<V>::cast(Handle<Object>(handle)); 29 result->VerifyApiCallResultType(); 30 return result; 31 } 32 33 inline JSObject* PropertyCallbackArguments::holder() { 34 return JSObject::cast(this->begin()[T::kHolderIndex]); 35 } 36 37 inline JSObject* FunctionCallbackArguments::holder() { 38 return JSObject::cast(this->begin()[T::kHolderIndex]); 39 } 40 41 #define FOR_EACH_CALLBACK(F) \ 42 F(Query, query, Object, v8::Integer, interceptor) \ 43 F(Deleter, deleter, Object, v8::Boolean, Handle<Object>()) 44 45 #define DCHECK_NAME_COMPATIBLE(interceptor, name) \ 46 DCHECK(interceptor->is_named()); \ 47 DCHECK(!name->IsPrivate()); \ 48 DCHECK_IMPLIES(name->IsSymbol(), interceptor->can_intercept_symbols()); 49 50 #define PREPARE_CALLBACK_INFO(ISOLATE, F, RETURN_VALUE, API_RETURN_TYPE, \ 51 CALLBACK_INFO) \ 52 if (ISOLATE->debug_execution_mode() == DebugInfo::kSideEffects && \ 53 !ISOLATE->debug()->PerformSideEffectCheckForCallback(CALLBACK_INFO)) { \ 54 return RETURN_VALUE(); \ 55 } \ 56 VMState<EXTERNAL> state(ISOLATE); \ 57 ExternalCallbackScope call_scope(ISOLATE, FUNCTION_ADDR(F)); \ 58 PropertyCallbackInfo<API_RETURN_TYPE> callback_info(begin()); 59 60 #define CREATE_NAMED_CALLBACK(FUNCTION, TYPE, RETURN_TYPE, API_RETURN_TYPE, \ 61 INFO_FOR_SIDE_EFFECT) \ 62 Handle<RETURN_TYPE> PropertyCallbackArguments::CallNamed##FUNCTION( \ 63 Handle<InterceptorInfo> interceptor, Handle<Name> name) { \ 64 DCHECK_NAME_COMPATIBLE(interceptor, name); \ 65 Isolate* isolate = this->isolate(); \ 66 RuntimeCallTimerScope timer( \ 67 isolate, RuntimeCallCounterId::kNamed##FUNCTION##Callback); \ 68 GenericNamedProperty##FUNCTION##Callback f = \ 69 ToCData<GenericNamedProperty##FUNCTION##Callback>( \ 70 interceptor->TYPE()); \ 71 PREPARE_CALLBACK_INFO(isolate, f, Handle<RETURN_TYPE>, API_RETURN_TYPE, \ 72 INFO_FOR_SIDE_EFFECT); \ 73 LOG(isolate, \ 74 ApiNamedPropertyAccess("interceptor-named-" #TYPE, holder(), *name)); \ 75 f(v8::Utils::ToLocal(name), callback_info); \ 76 return GetReturnValue<RETURN_TYPE>(isolate); \ 77 } 78 79 FOR_EACH_CALLBACK(CREATE_NAMED_CALLBACK) 80 #undef CREATE_NAMED_CALLBACK 81 82 #define CREATE_INDEXED_CALLBACK(FUNCTION, TYPE, RETURN_TYPE, API_RETURN_TYPE, \ 83 INFO_FOR_SIDE_EFFECT) \ 84 Handle<RETURN_TYPE> PropertyCallbackArguments::CallIndexed##FUNCTION( \ 85 Handle<InterceptorInfo> interceptor, uint32_t index) { \ 86 DCHECK(!interceptor->is_named()); \ 87 Isolate* isolate = this->isolate(); \ 88 RuntimeCallTimerScope timer( \ 89 isolate, RuntimeCallCounterId::kIndexed##FUNCTION##Callback); \ 90 IndexedProperty##FUNCTION##Callback f = \ 91 ToCData<IndexedProperty##FUNCTION##Callback>(interceptor->TYPE()); \ 92 PREPARE_CALLBACK_INFO(isolate, f, Handle<RETURN_TYPE>, API_RETURN_TYPE, \ 93 INFO_FOR_SIDE_EFFECT); \ 94 LOG(isolate, ApiIndexedPropertyAccess("interceptor-indexed-" #TYPE, \ 95 holder(), index)); \ 96 f(index, callback_info); \ 97 return GetReturnValue<RETURN_TYPE>(isolate); \ 98 } 99 100 FOR_EACH_CALLBACK(CREATE_INDEXED_CALLBACK) 101 102 #undef FOR_EACH_CALLBACK 103 #undef CREATE_INDEXED_CALLBACK 104 105 Handle<Object> FunctionCallbackArguments::Call(CallHandlerInfo* handler) { 106 Isolate* isolate = this->isolate(); 107 LOG(isolate, ApiObjectAccess("call", holder())); 108 RuntimeCallTimerScope timer(isolate, RuntimeCallCounterId::kFunctionCallback); 109 v8::FunctionCallback f = 110 v8::ToCData<v8::FunctionCallback>(handler->callback()); 111 if (isolate->debug_execution_mode() == DebugInfo::kSideEffects && 112 !isolate->debug()->PerformSideEffectCheckForCallback( 113 handle(handler, isolate))) { 114 return Handle<Object>(); 115 } 116 VMState<EXTERNAL> state(isolate); 117 ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f)); 118 FunctionCallbackInfo<v8::Value> info(begin(), argv_, argc_); 119 f(info); 120 return GetReturnValue<Object>(isolate); 121 } 122 123 Handle<JSObject> PropertyCallbackArguments::CallNamedEnumerator( 124 Handle<InterceptorInfo> interceptor) { 125 DCHECK(interceptor->is_named()); 126 LOG(isolate(), ApiObjectAccess("interceptor-named-enumerator", holder())); 127 RuntimeCallTimerScope timer(isolate(), 128 RuntimeCallCounterId::kNamedEnumeratorCallback); 129 return CallPropertyEnumerator(interceptor); 130 } 131 132 Handle<JSObject> PropertyCallbackArguments::CallIndexedEnumerator( 133 Handle<InterceptorInfo> interceptor) { 134 DCHECK(!interceptor->is_named()); 135 LOG(isolate(), ApiObjectAccess("interceptor-indexed-enumerator", holder())); 136 RuntimeCallTimerScope timer(isolate(), 137 RuntimeCallCounterId::kIndexedEnumeratorCallback); 138 return CallPropertyEnumerator(interceptor); 139 } 140 141 Handle<Object> PropertyCallbackArguments::CallNamedGetter( 142 Handle<InterceptorInfo> interceptor, Handle<Name> name) { 143 DCHECK_NAME_COMPATIBLE(interceptor, name); 144 Isolate* isolate = this->isolate(); 145 RuntimeCallTimerScope timer(isolate, 146 RuntimeCallCounterId::kNamedGetterCallback); 147 LOG(isolate, 148 ApiNamedPropertyAccess("interceptor-named-getter", holder(), *name)); 149 GenericNamedPropertyGetterCallback f = 150 ToCData<GenericNamedPropertyGetterCallback>(interceptor->getter()); 151 return BasicCallNamedGetterCallback(f, name, interceptor); 152 } 153 154 Handle<Object> PropertyCallbackArguments::CallNamedDescriptor( 155 Handle<InterceptorInfo> interceptor, Handle<Name> name) { 156 DCHECK_NAME_COMPATIBLE(interceptor, name); 157 Isolate* isolate = this->isolate(); 158 RuntimeCallTimerScope timer(isolate, 159 RuntimeCallCounterId::kNamedDescriptorCallback); 160 LOG(isolate, 161 ApiNamedPropertyAccess("interceptor-named-descriptor", holder(), *name)); 162 GenericNamedPropertyDescriptorCallback f = 163 ToCData<GenericNamedPropertyDescriptorCallback>( 164 interceptor->descriptor()); 165 return BasicCallNamedGetterCallback(f, name, interceptor); 166 } 167 168 Handle<Object> PropertyCallbackArguments::BasicCallNamedGetterCallback( 169 GenericNamedPropertyGetterCallback f, Handle<Name> name, 170 Handle<Object> info) { 171 DCHECK(!name->IsPrivate()); 172 Isolate* isolate = this->isolate(); 173 PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, v8::Value, info); 174 f(v8::Utils::ToLocal(name), callback_info); 175 return GetReturnValue<Object>(isolate); 176 } 177 178 Handle<Object> PropertyCallbackArguments::CallNamedSetter( 179 Handle<InterceptorInfo> interceptor, Handle<Name> name, 180 Handle<Object> value) { 181 DCHECK_NAME_COMPATIBLE(interceptor, name); 182 GenericNamedPropertySetterCallback f = 183 ToCData<GenericNamedPropertySetterCallback>(interceptor->setter()); 184 Isolate* isolate = this->isolate(); 185 RuntimeCallTimerScope timer(isolate, 186 RuntimeCallCounterId::kNamedSetterCallback); 187 Handle<Object> side_effect_check_not_supported; 188 PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, v8::Value, 189 side_effect_check_not_supported); 190 LOG(isolate, 191 ApiNamedPropertyAccess("interceptor-named-set", holder(), *name)); 192 f(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), callback_info); 193 return GetReturnValue<Object>(isolate); 194 } 195 196 Handle<Object> PropertyCallbackArguments::CallNamedDefiner( 197 Handle<InterceptorInfo> interceptor, Handle<Name> name, 198 const v8::PropertyDescriptor& desc) { 199 DCHECK_NAME_COMPATIBLE(interceptor, name); 200 Isolate* isolate = this->isolate(); 201 RuntimeCallTimerScope timer(isolate, 202 RuntimeCallCounterId::kNamedDefinerCallback); 203 GenericNamedPropertyDefinerCallback f = 204 ToCData<GenericNamedPropertyDefinerCallback>(interceptor->definer()); 205 Handle<Object> side_effect_check_not_supported; 206 PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, v8::Value, 207 side_effect_check_not_supported); 208 LOG(isolate, 209 ApiNamedPropertyAccess("interceptor-named-define", holder(), *name)); 210 f(v8::Utils::ToLocal(name), desc, callback_info); 211 return GetReturnValue<Object>(isolate); 212 } 213 214 Handle<Object> PropertyCallbackArguments::CallIndexedSetter( 215 Handle<InterceptorInfo> interceptor, uint32_t index, Handle<Object> value) { 216 DCHECK(!interceptor->is_named()); 217 Isolate* isolate = this->isolate(); 218 RuntimeCallTimerScope timer(isolate, 219 RuntimeCallCounterId::kIndexedSetterCallback); 220 IndexedPropertySetterCallback f = 221 ToCData<IndexedPropertySetterCallback>(interceptor->setter()); 222 Handle<Object> side_effect_check_not_supported; 223 PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, v8::Value, 224 side_effect_check_not_supported); 225 LOG(isolate, 226 ApiIndexedPropertyAccess("interceptor-indexed-set", holder(), index)); 227 f(index, v8::Utils::ToLocal(value), callback_info); 228 return GetReturnValue<Object>(isolate); 229 } 230 231 Handle<Object> PropertyCallbackArguments::CallIndexedDefiner( 232 Handle<InterceptorInfo> interceptor, uint32_t index, 233 const v8::PropertyDescriptor& desc) { 234 DCHECK(!interceptor->is_named()); 235 Isolate* isolate = this->isolate(); 236 RuntimeCallTimerScope timer(isolate, 237 RuntimeCallCounterId::kIndexedDefinerCallback); 238 IndexedPropertyDefinerCallback f = 239 ToCData<IndexedPropertyDefinerCallback>(interceptor->definer()); 240 Handle<Object> side_effect_check_not_supported; 241 PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, v8::Value, 242 side_effect_check_not_supported); 243 LOG(isolate, 244 ApiIndexedPropertyAccess("interceptor-indexed-define", holder(), index)); 245 f(index, desc, callback_info); 246 return GetReturnValue<Object>(isolate); 247 } 248 249 Handle<Object> PropertyCallbackArguments::CallIndexedGetter( 250 Handle<InterceptorInfo> interceptor, uint32_t index) { 251 DCHECK(!interceptor->is_named()); 252 Isolate* isolate = this->isolate(); 253 RuntimeCallTimerScope timer(isolate, 254 RuntimeCallCounterId::kNamedGetterCallback); 255 LOG(isolate, 256 ApiIndexedPropertyAccess("interceptor-indexed-getter", holder(), index)); 257 IndexedPropertyGetterCallback f = 258 ToCData<IndexedPropertyGetterCallback>(interceptor->getter()); 259 return BasicCallIndexedGetterCallback(f, index, interceptor); 260 } 261 262 Handle<Object> PropertyCallbackArguments::CallIndexedDescriptor( 263 Handle<InterceptorInfo> interceptor, uint32_t index) { 264 DCHECK(!interceptor->is_named()); 265 Isolate* isolate = this->isolate(); 266 RuntimeCallTimerScope timer(isolate, 267 RuntimeCallCounterId::kIndexedDescriptorCallback); 268 LOG(isolate, ApiIndexedPropertyAccess("interceptor-indexed-descriptor", 269 holder(), index)); 270 IndexedPropertyDescriptorCallback f = 271 ToCData<IndexedPropertyDescriptorCallback>(interceptor->descriptor()); 272 return BasicCallIndexedGetterCallback(f, index, interceptor); 273 } 274 275 Handle<Object> PropertyCallbackArguments::BasicCallIndexedGetterCallback( 276 IndexedPropertyGetterCallback f, uint32_t index, Handle<Object> info) { 277 Isolate* isolate = this->isolate(); 278 PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, v8::Value, info); 279 f(index, callback_info); 280 return GetReturnValue<Object>(isolate); 281 } 282 283 Handle<JSObject> PropertyCallbackArguments::CallPropertyEnumerator( 284 Handle<InterceptorInfo> interceptor) { 285 // For now there is a single enumerator for indexed and named properties. 286 IndexedPropertyEnumeratorCallback f = 287 v8::ToCData<IndexedPropertyEnumeratorCallback>(interceptor->enumerator()); 288 // TODO(cbruni): assert same type for indexed and named callback. 289 Isolate* isolate = this->isolate(); 290 PREPARE_CALLBACK_INFO(isolate, f, Handle<JSObject>, v8::Array, interceptor); 291 f(callback_info); 292 return GetReturnValue<JSObject>(isolate); 293 } 294 295 // ------------------------------------------------------------------------- 296 // Accessors 297 298 Handle<Object> PropertyCallbackArguments::CallAccessorGetter( 299 Handle<AccessorInfo> info, Handle<Name> name) { 300 Isolate* isolate = this->isolate(); 301 RuntimeCallTimerScope timer(isolate, 302 RuntimeCallCounterId::kAccessorGetterCallback); 303 LOG(isolate, ApiNamedPropertyAccess("accessor-getter", holder(), *name)); 304 AccessorNameGetterCallback f = 305 ToCData<AccessorNameGetterCallback>(info->getter()); 306 return BasicCallNamedGetterCallback(f, name, info); 307 } 308 309 Handle<Object> PropertyCallbackArguments::CallAccessorSetter( 310 Handle<AccessorInfo> accessor_info, Handle<Name> name, 311 Handle<Object> value) { 312 Isolate* isolate = this->isolate(); 313 RuntimeCallTimerScope timer(isolate, 314 RuntimeCallCounterId::kAccessorSetterCallback); 315 AccessorNameSetterCallback f = 316 ToCData<AccessorNameSetterCallback>(accessor_info->setter()); 317 Handle<Object> side_effect_check_not_supported; 318 PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, void, 319 side_effect_check_not_supported); 320 LOG(isolate, ApiNamedPropertyAccess("accessor-setter", holder(), *name)); 321 f(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), callback_info); 322 return GetReturnValue<Object>(isolate); 323 } 324 325 #undef PREPARE_CALLBACK_INFO 326 327 } // namespace internal 328 } // namespace v8 329 330 #endif // V8_API_ARGUMENTS_INL_H_ 331