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