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/objects/api-callbacks.h"
11 #include "src/tracing/trace-event.h"
12 #include "src/vm-state-inl.h"
13
14 namespace v8 {
15 namespace internal {
16
17 #define FOR_EACH_CALLBACK(F) \
18 F(Query, query, Object, v8::Integer, interceptor) \
19 F(Deleter, deleter, Object, v8::Boolean, Handle<Object>())
20
21 #define DCHECK_NAME_COMPATIBLE(interceptor, name) \
22 DCHECK(interceptor->is_named()); \
23 DCHECK(!name->IsPrivate()); \
24 DCHECK_IMPLIES(name->IsSymbol(), interceptor->can_intercept_symbols());
25
26 #define PREPARE_CALLBACK_INFO(ISOLATE, F, RETURN_VALUE, API_RETURN_TYPE, \
27 CALLBACK_INFO) \
28 if (ISOLATE->debug_execution_mode() == DebugInfo::kSideEffects && \
29 !ISOLATE->debug()->PerformSideEffectCheckForCallback(CALLBACK_INFO)) { \
30 return RETURN_VALUE(); \
31 } \
32 VMState<EXTERNAL> state(ISOLATE); \
33 ExternalCallbackScope call_scope(ISOLATE, FUNCTION_ADDR(F)); \
34 PropertyCallbackInfo<API_RETURN_TYPE> callback_info(begin());
35
36 #define CREATE_NAMED_CALLBACK(FUNCTION, TYPE, RETURN_TYPE, API_RETURN_TYPE, \
37 INFO_FOR_SIDE_EFFECT) \
38 Handle<RETURN_TYPE> PropertyCallbackArguments::CallNamed##FUNCTION( \
39 Handle<InterceptorInfo> interceptor, Handle<Name> name) { \
40 DCHECK_NAME_COMPATIBLE(interceptor, name); \
41 Isolate* isolate = this->isolate(); \
42 RuntimeCallTimerScope timer( \
43 isolate, RuntimeCallCounterId::kNamed##FUNCTION##Callback); \
44 GenericNamedProperty##FUNCTION##Callback f = \
45 ToCData<GenericNamedProperty##FUNCTION##Callback>( \
46 interceptor->TYPE()); \
47 PREPARE_CALLBACK_INFO(isolate, f, Handle<RETURN_TYPE>, API_RETURN_TYPE, \
48 INFO_FOR_SIDE_EFFECT); \
49 LOG(isolate, \
50 ApiNamedPropertyAccess("interceptor-named-" #TYPE, holder(), *name)); \
51 f(v8::Utils::ToLocal(name), callback_info); \
52 return GetReturnValue<RETURN_TYPE>(isolate); \
53 }
54
55 FOR_EACH_CALLBACK(CREATE_NAMED_CALLBACK)
56 #undef CREATE_NAMED_CALLBACK
57
58 #define CREATE_INDEXED_CALLBACK(FUNCTION, TYPE, RETURN_TYPE, API_RETURN_TYPE, \
59 INFO_FOR_SIDE_EFFECT) \
60 Handle<RETURN_TYPE> PropertyCallbackArguments::CallIndexed##FUNCTION( \
61 Handle<InterceptorInfo> interceptor, uint32_t index) { \
62 DCHECK(!interceptor->is_named()); \
63 Isolate* isolate = this->isolate(); \
64 RuntimeCallTimerScope timer( \
65 isolate, RuntimeCallCounterId::kIndexed##FUNCTION##Callback); \
66 IndexedProperty##FUNCTION##Callback f = \
67 ToCData<IndexedProperty##FUNCTION##Callback>(interceptor->TYPE()); \
68 PREPARE_CALLBACK_INFO(isolate, f, Handle<RETURN_TYPE>, API_RETURN_TYPE, \
69 INFO_FOR_SIDE_EFFECT); \
70 LOG(isolate, ApiIndexedPropertyAccess("interceptor-indexed-" #TYPE, \
71 holder(), index)); \
72 f(index, callback_info); \
73 return GetReturnValue<RETURN_TYPE>(isolate); \
74 }
75
FOR_EACH_CALLBACK(CREATE_INDEXED_CALLBACK)76 FOR_EACH_CALLBACK(CREATE_INDEXED_CALLBACK)
77
78 #undef FOR_EACH_CALLBACK
79 #undef CREATE_INDEXED_CALLBACK
80
81 Handle<Object> FunctionCallbackArguments::Call(CallHandlerInfo* handler) {
82 Isolate* isolate = this->isolate();
83 LOG(isolate, ApiObjectAccess("call", holder()));
84 RuntimeCallTimerScope timer(isolate, RuntimeCallCounterId::kFunctionCallback);
85 v8::FunctionCallback f =
86 v8::ToCData<v8::FunctionCallback>(handler->callback());
87 if (isolate->debug_execution_mode() == DebugInfo::kSideEffects &&
88 !isolate->debug()->PerformSideEffectCheckForCallback(handle(handler))) {
89 return Handle<Object>();
90 }
91 VMState<EXTERNAL> state(isolate);
92 ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f));
93 FunctionCallbackInfo<v8::Value> info(begin(), argv_, argc_);
94 f(info);
95 return GetReturnValue<Object>(isolate);
96 }
97
CallNamedEnumerator(Handle<InterceptorInfo> interceptor)98 Handle<JSObject> PropertyCallbackArguments::CallNamedEnumerator(
99 Handle<InterceptorInfo> interceptor) {
100 DCHECK(interceptor->is_named());
101 LOG(isolate(), ApiObjectAccess("interceptor-named-enumerator", holder()));
102 RuntimeCallTimerScope timer(isolate(),
103 RuntimeCallCounterId::kNamedEnumeratorCallback);
104 return CallPropertyEnumerator(interceptor);
105 }
106
CallIndexedEnumerator(Handle<InterceptorInfo> interceptor)107 Handle<JSObject> PropertyCallbackArguments::CallIndexedEnumerator(
108 Handle<InterceptorInfo> interceptor) {
109 DCHECK(!interceptor->is_named());
110 LOG(isolate(), ApiObjectAccess("interceptor-indexed-enumerator", holder()));
111 RuntimeCallTimerScope timer(isolate(),
112 RuntimeCallCounterId::kIndexedEnumeratorCallback);
113 return CallPropertyEnumerator(interceptor);
114 }
115
CallNamedGetter(Handle<InterceptorInfo> interceptor,Handle<Name> name)116 Handle<Object> PropertyCallbackArguments::CallNamedGetter(
117 Handle<InterceptorInfo> interceptor, Handle<Name> name) {
118 DCHECK_NAME_COMPATIBLE(interceptor, name);
119 Isolate* isolate = this->isolate();
120 RuntimeCallTimerScope timer(isolate,
121 RuntimeCallCounterId::kNamedGetterCallback);
122 LOG(isolate,
123 ApiNamedPropertyAccess("interceptor-named-getter", holder(), *name));
124 GenericNamedPropertyGetterCallback f =
125 ToCData<GenericNamedPropertyGetterCallback>(interceptor->getter());
126 return BasicCallNamedGetterCallback(f, name, interceptor);
127 }
128
CallNamedDescriptor(Handle<InterceptorInfo> interceptor,Handle<Name> name)129 Handle<Object> PropertyCallbackArguments::CallNamedDescriptor(
130 Handle<InterceptorInfo> interceptor, Handle<Name> name) {
131 DCHECK_NAME_COMPATIBLE(interceptor, name);
132 Isolate* isolate = this->isolate();
133 RuntimeCallTimerScope timer(isolate,
134 RuntimeCallCounterId::kNamedDescriptorCallback);
135 LOG(isolate,
136 ApiNamedPropertyAccess("interceptor-named-descriptor", holder(), *name));
137 GenericNamedPropertyDescriptorCallback f =
138 ToCData<GenericNamedPropertyDescriptorCallback>(
139 interceptor->descriptor());
140 return BasicCallNamedGetterCallback(f, name, interceptor);
141 }
142
BasicCallNamedGetterCallback(GenericNamedPropertyGetterCallback f,Handle<Name> name,Handle<Object> info)143 Handle<Object> PropertyCallbackArguments::BasicCallNamedGetterCallback(
144 GenericNamedPropertyGetterCallback f, Handle<Name> name,
145 Handle<Object> info) {
146 DCHECK(!name->IsPrivate());
147 Isolate* isolate = this->isolate();
148 PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, v8::Value, info);
149 f(v8::Utils::ToLocal(name), callback_info);
150 return GetReturnValue<Object>(isolate);
151 }
152
CallNamedSetter(Handle<InterceptorInfo> interceptor,Handle<Name> name,Handle<Object> value)153 Handle<Object> PropertyCallbackArguments::CallNamedSetter(
154 Handle<InterceptorInfo> interceptor, Handle<Name> name,
155 Handle<Object> value) {
156 DCHECK_NAME_COMPATIBLE(interceptor, name);
157 GenericNamedPropertySetterCallback f =
158 ToCData<GenericNamedPropertySetterCallback>(interceptor->setter());
159 Isolate* isolate = this->isolate();
160 RuntimeCallTimerScope timer(isolate,
161 RuntimeCallCounterId::kNamedSetterCallback);
162 Handle<Object> side_effect_check_not_supported;
163 PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, v8::Value,
164 side_effect_check_not_supported);
165 LOG(isolate,
166 ApiNamedPropertyAccess("interceptor-named-set", holder(), *name));
167 f(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), callback_info);
168 return GetReturnValue<Object>(isolate);
169 }
170
CallNamedDefiner(Handle<InterceptorInfo> interceptor,Handle<Name> name,const v8::PropertyDescriptor & desc)171 Handle<Object> PropertyCallbackArguments::CallNamedDefiner(
172 Handle<InterceptorInfo> interceptor, Handle<Name> name,
173 const v8::PropertyDescriptor& desc) {
174 DCHECK_NAME_COMPATIBLE(interceptor, name);
175 Isolate* isolate = this->isolate();
176 RuntimeCallTimerScope timer(isolate,
177 RuntimeCallCounterId::kNamedDefinerCallback);
178 GenericNamedPropertyDefinerCallback f =
179 ToCData<GenericNamedPropertyDefinerCallback>(interceptor->definer());
180 Handle<Object> side_effect_check_not_supported;
181 PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, v8::Value,
182 side_effect_check_not_supported);
183 LOG(isolate,
184 ApiNamedPropertyAccess("interceptor-named-define", holder(), *name));
185 f(v8::Utils::ToLocal(name), desc, callback_info);
186 return GetReturnValue<Object>(isolate);
187 }
188
CallIndexedSetter(Handle<InterceptorInfo> interceptor,uint32_t index,Handle<Object> value)189 Handle<Object> PropertyCallbackArguments::CallIndexedSetter(
190 Handle<InterceptorInfo> interceptor, uint32_t index, Handle<Object> value) {
191 DCHECK(!interceptor->is_named());
192 Isolate* isolate = this->isolate();
193 RuntimeCallTimerScope timer(isolate,
194 RuntimeCallCounterId::kIndexedSetterCallback);
195 IndexedPropertySetterCallback f =
196 ToCData<IndexedPropertySetterCallback>(interceptor->setter());
197 Handle<Object> side_effect_check_not_supported;
198 PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, v8::Value,
199 side_effect_check_not_supported);
200 LOG(isolate,
201 ApiIndexedPropertyAccess("interceptor-indexed-set", holder(), index));
202 f(index, v8::Utils::ToLocal(value), callback_info);
203 return GetReturnValue<Object>(isolate);
204 }
205
CallIndexedDefiner(Handle<InterceptorInfo> interceptor,uint32_t index,const v8::PropertyDescriptor & desc)206 Handle<Object> PropertyCallbackArguments::CallIndexedDefiner(
207 Handle<InterceptorInfo> interceptor, uint32_t index,
208 const v8::PropertyDescriptor& desc) {
209 DCHECK(!interceptor->is_named());
210 Isolate* isolate = this->isolate();
211 RuntimeCallTimerScope timer(isolate,
212 RuntimeCallCounterId::kIndexedDefinerCallback);
213 IndexedPropertyDefinerCallback f =
214 ToCData<IndexedPropertyDefinerCallback>(interceptor->definer());
215 Handle<Object> side_effect_check_not_supported;
216 PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, v8::Value,
217 side_effect_check_not_supported);
218 LOG(isolate,
219 ApiIndexedPropertyAccess("interceptor-indexed-define", holder(), index));
220 f(index, desc, callback_info);
221 return GetReturnValue<Object>(isolate);
222 }
223
CallIndexedGetter(Handle<InterceptorInfo> interceptor,uint32_t index)224 Handle<Object> PropertyCallbackArguments::CallIndexedGetter(
225 Handle<InterceptorInfo> interceptor, uint32_t index) {
226 DCHECK(!interceptor->is_named());
227 Isolate* isolate = this->isolate();
228 RuntimeCallTimerScope timer(isolate,
229 RuntimeCallCounterId::kNamedGetterCallback);
230 LOG(isolate,
231 ApiIndexedPropertyAccess("interceptor-indexed-getter", holder(), index));
232 IndexedPropertyGetterCallback f =
233 ToCData<IndexedPropertyGetterCallback>(interceptor->getter());
234 return BasicCallIndexedGetterCallback(f, index, interceptor);
235 }
236
CallIndexedDescriptor(Handle<InterceptorInfo> interceptor,uint32_t index)237 Handle<Object> PropertyCallbackArguments::CallIndexedDescriptor(
238 Handle<InterceptorInfo> interceptor, uint32_t index) {
239 DCHECK(!interceptor->is_named());
240 Isolate* isolate = this->isolate();
241 RuntimeCallTimerScope timer(isolate,
242 RuntimeCallCounterId::kIndexedDescriptorCallback);
243 LOG(isolate, ApiIndexedPropertyAccess("interceptor-indexed-descriptor",
244 holder(), index));
245 IndexedPropertyDescriptorCallback f =
246 ToCData<IndexedPropertyDescriptorCallback>(interceptor->descriptor());
247 return BasicCallIndexedGetterCallback(f, index, interceptor);
248 }
249
BasicCallIndexedGetterCallback(IndexedPropertyGetterCallback f,uint32_t index,Handle<Object> info)250 Handle<Object> PropertyCallbackArguments::BasicCallIndexedGetterCallback(
251 IndexedPropertyGetterCallback f, uint32_t index, Handle<Object> info) {
252 Isolate* isolate = this->isolate();
253 PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, v8::Value, info);
254 f(index, callback_info);
255 return GetReturnValue<Object>(isolate);
256 }
257
CallPropertyEnumerator(Handle<InterceptorInfo> interceptor)258 Handle<JSObject> PropertyCallbackArguments::CallPropertyEnumerator(
259 Handle<InterceptorInfo> interceptor) {
260 // For now there is a single enumerator for indexed and named properties.
261 IndexedPropertyEnumeratorCallback f =
262 v8::ToCData<IndexedPropertyEnumeratorCallback>(interceptor->enumerator());
263 // TODO(cbruni): assert same type for indexed and named callback.
264 Isolate* isolate = this->isolate();
265 PREPARE_CALLBACK_INFO(isolate, f, Handle<JSObject>, v8::Array, interceptor);
266 f(callback_info);
267 return GetReturnValue<JSObject>(isolate);
268 }
269
270 // -------------------------------------------------------------------------
271 // Accessors
272
CallAccessorGetter(Handle<AccessorInfo> info,Handle<Name> name)273 Handle<Object> PropertyCallbackArguments::CallAccessorGetter(
274 Handle<AccessorInfo> info, Handle<Name> name) {
275 Isolate* isolate = this->isolate();
276 RuntimeCallTimerScope timer(isolate,
277 RuntimeCallCounterId::kAccessorGetterCallback);
278 LOG(isolate, ApiNamedPropertyAccess("accessor-getter", holder(), *name));
279 AccessorNameGetterCallback f =
280 ToCData<AccessorNameGetterCallback>(info->getter());
281 return BasicCallNamedGetterCallback(f, name, info);
282 }
283
CallAccessorSetter(Handle<AccessorInfo> accessor_info,Handle<Name> name,Handle<Object> value)284 Handle<Object> PropertyCallbackArguments::CallAccessorSetter(
285 Handle<AccessorInfo> accessor_info, Handle<Name> name,
286 Handle<Object> value) {
287 Isolate* isolate = this->isolate();
288 RuntimeCallTimerScope timer(isolate,
289 RuntimeCallCounterId::kAccessorSetterCallback);
290 AccessorNameSetterCallback f =
291 ToCData<AccessorNameSetterCallback>(accessor_info->setter());
292 Handle<Object> side_effect_check_not_supported;
293 PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, void,
294 side_effect_check_not_supported);
295 LOG(isolate, ApiNamedPropertyAccess("accessor-setter", holder(), *name));
296 f(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), callback_info);
297 return GetReturnValue<Object>(isolate);
298 }
299
300 #undef PREPARE_CALLBACK_INFO
301
302 } // namespace internal
303 } // namespace v8
304
305 #endif // V8_API_ARGUMENTS_INL_H_
306