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