Home | History | Annotate | Download | only in src
      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