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