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