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