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
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 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
108FOR_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
128FOR_EACH_CALLBACK(CREATE_INDEXED_CALLBACK)
129
130#undef FOR_EACH_CALLBACK
131#undef CREATE_INDEXED_CALLBACK
132
133Handle<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
151Handle<JSObject> PropertyCallbackArguments::CallNamedEnumerator(
152    Handle<InterceptorInfo> interceptor) {
153  DCHECK(interceptor->is_named());
154  RCS_SCOPE(isolate(), RuntimeCallCounterId::kNamedEnumeratorCallback);
155  return CallPropertyEnumerator(interceptor);
156}
157
158Handle<JSObject> PropertyCallbackArguments::CallIndexedEnumerator(
159    Handle<InterceptorInfo> interceptor) {
160  DCHECK(!interceptor->is_named());
161  RCS_SCOPE(isolate(), RuntimeCallCounterId::kIndexedEnumeratorCallback);
162  return CallPropertyEnumerator(interceptor);
163}
164
165Handle<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
174Handle<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
184Handle<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
195Handle<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
209Handle<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
223Handle<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
236Handle<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
250Handle<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
259Handle<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
268Handle<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
278Handle<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
295Handle<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
305Handle<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