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
CustomArgumentsBase(Isolate * isolate)18 CustomArgumentsBase::CustomArgumentsBase(Isolate* isolate)
19 : Relocatable(isolate) {}
20
21 template <typename T>
22 template <typename V>
GetReturnValue(Isolate * isolate)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
holder()33 inline JSObject* PropertyCallbackArguments::holder() {
34 return JSObject::cast(this->begin()[T::kHolderIndex]);
35 }
36
holder()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
FOR_EACH_CALLBACK(CREATE_INDEXED_CALLBACK)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
CallNamedEnumerator(Handle<InterceptorInfo> interceptor)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
CallIndexedEnumerator(Handle<InterceptorInfo> interceptor)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
CallNamedGetter(Handle<InterceptorInfo> interceptor,Handle<Name> name)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
CallNamedDescriptor(Handle<InterceptorInfo> interceptor,Handle<Name> name)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
BasicCallNamedGetterCallback(GenericNamedPropertyGetterCallback f,Handle<Name> name,Handle<Object> info)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
CallNamedSetter(Handle<InterceptorInfo> interceptor,Handle<Name> name,Handle<Object> value)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
CallNamedDefiner(Handle<InterceptorInfo> interceptor,Handle<Name> name,const v8::PropertyDescriptor & desc)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
CallIndexedSetter(Handle<InterceptorInfo> interceptor,uint32_t index,Handle<Object> value)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
CallIndexedDefiner(Handle<InterceptorInfo> interceptor,uint32_t index,const v8::PropertyDescriptor & desc)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
CallIndexedGetter(Handle<InterceptorInfo> interceptor,uint32_t index)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
CallIndexedDescriptor(Handle<InterceptorInfo> interceptor,uint32_t index)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
BasicCallIndexedGetterCallback(IndexedPropertyGetterCallback f,uint32_t index,Handle<Object> info)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
CallPropertyEnumerator(Handle<InterceptorInfo> interceptor)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
CallAccessorGetter(Handle<AccessorInfo> info,Handle<Name> name)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
CallAccessorSetter(Handle<AccessorInfo> accessor_info,Handle<Name> name,Handle<Object> value)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