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 | |
17 | namespace v8 { |
18 | namespace internal { |
19 | |
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 | |
31 | CustomArgumentsBase::CustomArgumentsBase(Isolate* isolate) |
32 | : Relocatable(isolate) {} |
33 | |
34 | template <typename T> |
35 | CustomArguments<T>::~CustomArguments() { |
36 | slot_at(kReturnValueOffset).store(Object(kHandleZapValue)); |
37 | } |
38 | |
39 | template <typename T> |
40 | template <typename V> |
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 | |
51 | inline JSObject PropertyCallbackArguments::holder() { |
52 | return JSObject::cast(*slot_at(T::kHolderIndex)); |
53 | } |
54 | |
55 | inline Object PropertyCallbackArguments::receiver() { |
56 | return *slot_at(T::kThisIndex); |
57 | } |
58 | |
59 | inline 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 | |
113 | FOR_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 | |
136 | FOR_EACH_CALLBACK(CREATE_INDEXED_CALLBACK) |
137 | |
138 | #undef FOR_EACH_CALLBACK |
139 | #undef CREATE_INDEXED_CALLBACK |
140 | |
141 | Handle<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 | |
161 | Handle<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 | |
170 | Handle<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 | |
179 | Handle<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 | |
192 | Handle<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 | |
206 | Handle<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 | |
217 | Handle<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 | |
234 | Handle<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 | |
251 | Handle<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 | |
267 | Handle<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 | |
284 | Handle<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 | |
297 | Handle<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 | |
310 | Handle<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 | |
320 | Handle<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 | |
337 | Handle<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 | |
349 | Handle<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 | |