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