• 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 #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 
17 namespace v8 {
18 namespace internal {
19 
VerifyApiCallResultType()20 void 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 
CustomArgumentsBase(Isolate * isolate)31 CustomArgumentsBase::CustomArgumentsBase(Isolate* isolate)
32     : Relocatable(isolate) {}
33 
34 template <typename T>
~CustomArguments()35 CustomArguments<T>::~CustomArguments() {
36   slot_at(kReturnValueOffset).store(Object(kHandleZapValue));
37 }
38 
39 template <typename T>
40 template <typename V>
GetReturnValue(Isolate * isolate)41 Handle<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 
holder()51 inline JSObject PropertyCallbackArguments::holder() {
52   return JSObject::cast(*slot_at(T::kHolderIndex));
53 }
54 
receiver()55 inline Object PropertyCallbackArguments::receiver() {
56   return *slot_at(T::kThisIndex);
57 }
58 
holder()59 inline 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 
108 FOR_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 
FOR_EACH_CALLBACK(CREATE_INDEXED_CALLBACK)128 FOR_EACH_CALLBACK(CREATE_INDEXED_CALLBACK)
129 
130 #undef FOR_EACH_CALLBACK
131 #undef CREATE_INDEXED_CALLBACK
132 
133 Handle<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 
CallNamedEnumerator(Handle<InterceptorInfo> interceptor)151 Handle<JSObject> PropertyCallbackArguments::CallNamedEnumerator(
152     Handle<InterceptorInfo> interceptor) {
153   DCHECK(interceptor->is_named());
154   RCS_SCOPE(isolate(), RuntimeCallCounterId::kNamedEnumeratorCallback);
155   return CallPropertyEnumerator(interceptor);
156 }
157 
CallIndexedEnumerator(Handle<InterceptorInfo> interceptor)158 Handle<JSObject> PropertyCallbackArguments::CallIndexedEnumerator(
159     Handle<InterceptorInfo> interceptor) {
160   DCHECK(!interceptor->is_named());
161   RCS_SCOPE(isolate(), RuntimeCallCounterId::kIndexedEnumeratorCallback);
162   return CallPropertyEnumerator(interceptor);
163 }
164 
CallNamedGetter(Handle<InterceptorInfo> interceptor,Handle<Name> name)165 Handle<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 
CallNamedDescriptor(Handle<InterceptorInfo> interceptor,Handle<Name> name)174 Handle<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 
BasicCallNamedGetterCallback(GenericNamedPropertyGetterCallback f,Handle<Name> name,Handle<Object> info,Handle<Object> receiver)184 Handle<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 
CallNamedSetter(Handle<InterceptorInfo> interceptor,Handle<Name> name,Handle<Object> value)195 Handle<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 
CallNamedDefiner(Handle<InterceptorInfo> interceptor,Handle<Name> name,const v8::PropertyDescriptor & desc)209 Handle<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 
CallIndexedSetter(Handle<InterceptorInfo> interceptor,uint32_t index,Handle<Object> value)223 Handle<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 
CallIndexedDefiner(Handle<InterceptorInfo> interceptor,uint32_t index,const v8::PropertyDescriptor & desc)236 Handle<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 
CallIndexedGetter(Handle<InterceptorInfo> interceptor,uint32_t index)250 Handle<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 
CallIndexedDescriptor(Handle<InterceptorInfo> interceptor,uint32_t index)259 Handle<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 
BasicCallIndexedGetterCallback(IndexedPropertyGetterCallback f,uint32_t index,Handle<Object> info)268 Handle<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 
CallPropertyEnumerator(Handle<InterceptorInfo> interceptor)278 Handle<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 
CallAccessorGetter(Handle<AccessorInfo> info,Handle<Name> name)295 Handle<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 
CallAccessorSetter(Handle<AccessorInfo> accessor_info,Handle<Name> name,Handle<Object> value)305 Handle<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