forked from nodejs/node
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapi-arguments.h
More file actions
363 lines (310 loc) · 15.4 KB
/
Copy pathapi-arguments.h
File metadata and controls
363 lines (310 loc) · 15.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_API_API_ARGUMENTS_H_
#define V8_API_API_ARGUMENTS_H_
#include "include/v8-template.h"
#include "src/base/small-vector.h"
#include "src/builtins/builtins-utils.h"
#include "src/execution/isolate.h"
#include "src/objects/slots.h"
#include "src/objects/visitors.h"
namespace v8 {
namespace internal {
// This class also serves as a side effects detection scope (JavaScript code
// execution). It is used for ensuring correctness of the interceptor callback
// implementations. The idea is that the interceptor callback that does not
// intercept an operation must not produce side effects. If the callback
// signals that it has handled the operation (by either returning a respective
// result or by throwing an exception) then the AcceptSideEffects() method
// must be called to "accept" the side effects that have happened during the
// lifetime of the PropertyCallbackArguments object.
class PropertyCallbackArguments final : public Relocatable {
public:
using T = PropertyCallbackInfo<Value>;
using Super = CustomArguments<T>;
static constexpr int kMandatoryArgsLength = T::kMandatoryArgsLength;
static constexpr int kFullArgsLength = T::kFullArgsLength;
static constexpr int kMandatoryApiArgsLength = T::kMandatoryApiArgsLength;
static constexpr int kFullApiArgsLength = T::kFullApiArgsLength;
static constexpr int kGetterApiArgsLength = T::kMandatoryApiArgsLength;
static constexpr int kSetterApiArgsLength = T::kFullApiArgsLength;
static constexpr int kFrameTypeIndex = T::kFrameTypeIndex;
static constexpr int kCallbackInfoIndex = T::kCallbackInfoIndex;
static constexpr int kHolderIndex = T::kHolderIndex;
static constexpr int kIsolateIndex = T::kIsolateIndex;
static constexpr int kReturnValueIndex = T::kReturnValueIndex;
static constexpr int kShouldThrowOnErrorIndex = T::kShouldThrowOnErrorIndex;
static constexpr int kPropertyKeyIndex = T::kPropertyKeyIndex;
static constexpr int kValueIndex = T::kValueIndex;
// Helper for converting Api arguments indices to [0..kFullApiArgsLength)
// value.
static constexpr uint32_t ApiArgIndex(uint32_t index) {
DCHECK_GE(index, T::kFirstApiArgumentIndex);
return index - T::kFirstApiArgumentIndex;
}
// This constructor leaves kPropertyKeyIndex, kReturnValueIndex and
// kCallbackInfoIndex slots uninitialized in order to let them be
// initialized by the subsequent CallXXX(..) and avoid double initialization.
// As a consequence, there must be no GC call between this constructor and
// CallXXX(..). In debug mode these slots are zapped, so GC should be able
// to detect misuse of this object.
inline PropertyCallbackArguments(Isolate* isolate, Tagged<JSObject> holder);
inline PropertyCallbackArguments(Isolate* isolate, Tagged<JSObject> holder,
Maybe<ShouldThrow> should_throw);
inline ~PropertyCallbackArguments();
// Don't copy PropertyCallbackArguments, because they would both have the
// same prev_ pointer.
PropertyCallbackArguments(const PropertyCallbackArguments&) = delete;
PropertyCallbackArguments& operator=(const PropertyCallbackArguments&) =
delete;
// -------------------------------------------------------------------------
// Accessor Callbacks
// Returns the result of [[Get]] operation or throws an exception.
// In case of exception empty handle is returned.
// TODO(ishell, 328490288): stop returning empty handles.
inline DirectHandle<JSAny> CallAccessorGetter(Isolate* isolate,
DirectHandle<AccessorInfo> info,
DirectHandle<Name> name);
// Returns the result of [[Set]] operation or throws an exception.
V8_WARN_UNUSED_RESULT
inline bool CallAccessorSetter(Isolate* isolate,
DirectHandle<AccessorInfo> info,
DirectHandle<Name> name,
DirectHandle<Object> value);
// -------------------------------------------------------------------------
// Named Interceptor Callbacks
// Empty handle means that the request was not intercepted.
// Pending exception handling should be done by the caller.
inline DirectHandle<Object> CallNamedQuery(
Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
DirectHandle<Name> name);
inline DirectHandle<JSAny> CallNamedGetter(
Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
DirectHandle<Name> name);
// Calls Setter/Definer/Deleter callback and returns whether the request
// was intercepted.
// Pending exception handling and interpretation of the result should be
// done by the caller using GetBooleanReturnValue(..).
inline v8::Intercepted CallNamedSetter(
Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
DirectHandle<Name> name, DirectHandle<Object> value);
inline v8::Intercepted CallNamedDefiner(
Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
DirectHandle<Name> name, const v8::PropertyDescriptor& desc);
inline v8::Intercepted CallNamedDeleter(
Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
DirectHandle<Name> name);
// Empty handle means that the request was not intercepted.
// Pending exception handling should be done by the caller.
inline Handle<JSAny> CallNamedDescriptor(
Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
DirectHandle<Name> name);
// Returns JSArray-like object with property names or undefined.
inline DirectHandle<JSObjectOrUndefined> CallNamedEnumerator(
Isolate* isolate, DirectHandle<InterceptorInfo> interceptor);
// -------------------------------------------------------------------------
// Indexed Interceptor Callbacks
// Empty handle means that the request was not intercepted.
// Pending exception handling should be done by the caller.
inline DirectHandle<Object> CallIndexedQuery(
Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
uint32_t index);
inline DirectHandle<JSAny> CallIndexedGetter(
Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
uint32_t index);
// Calls Setter/Definer/Deleter callback and returns whether the request
// was intercepted.
// Pending exception handling and interpretation of the result should be
// done by the caller using GetBooleanReturnValue(..).
inline v8::Intercepted CallIndexedSetter(
Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
uint32_t index, DirectHandle<Object> value);
inline v8::Intercepted CallIndexedDefiner(
Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
uint32_t index, const v8::PropertyDescriptor& desc);
inline v8::Intercepted CallIndexedDeleter(
Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
uint32_t index);
// Empty handle means that the request was not intercepted.
// Pending exception handling should be done by the caller.
inline Handle<JSAny> CallIndexedDescriptor(
Isolate* isolate, DirectHandle<InterceptorInfo> interceptor,
uint32_t index);
// Returns JSArray-like object with property names or undefined.
inline DirectHandle<JSObjectOrUndefined> CallIndexedEnumerator(
Isolate* isolate, DirectHandle<InterceptorInfo> interceptor);
// Accept potential JavaScript side effects that might occur during life
// time of this object.
inline void AcceptSideEffects() {
#ifdef DEBUG
javascript_execution_counter_ = 0;
#endif // DEBUG
}
// Converts the result of Setter/Definer/Deleter interceptor callback to
// Maybe<InterceptorResult>.
// Currently, in certain scenarios the actual boolean result returned by
// the Setter/Definer operation is ignored and thus we don't need to process
// the actual return value.
inline Maybe<InterceptorResult> GetBooleanReturnValue(
Isolate* isolate, v8::Intercepted intercepted,
const char* callback_kind_for_error_message,
bool ignore_return_value = false);
// TODO(ishell): cleanup this hack by embedding the PropertyCallbackInfo
// into PropertyCallbackArguments object.
template <typename T>
const v8::PropertyCallbackInfo<T>& GetPropertyCallbackInfo() {
return *(reinterpret_cast<PropertyCallbackInfo<T>*>(&values_[0]));
}
// Forwards ShouldThrowOnError() request to the underlying
// v8::PropertyCallbackInfo<> object.
bool ShouldThrowOnError() {
return GetPropertyCallbackInfo<Value>().ShouldThrowOnError();
}
// Returns AccessorInfo stored in v8::PropertyCallbackInfo<T>.
template <typename T>
static DirectHandle<AccessorInfo> GetAccessorInfo(
const PropertyCallbackInfo<T>& info) {
return Cast<AccessorInfo>(
DirectHandle<Object>::FromSlot(&info.args_[kCallbackInfoIndex]));
}
// Returns InterceptorInfo stored in v8::PropertyCallbackInfo<T>.
template <typename T>
static DirectHandle<InterceptorInfo> GetInterceptorInfo(
const PropertyCallbackInfo<T>& info) {
return Cast<InterceptorInfo>(
DirectHandle<Object>::FromSlot(&info.args_[kCallbackInfoIndex]));
}
// Returns whether given v8::PropertyCallbackInfo<T> object is named/indexed.
template <typename T>
static bool IsNamed(const PropertyCallbackInfo<T>& info) {
return info.IsNamed();
}
// Returns property name stored in v8::PropertyCallbackInfo<T> (for named
// accessors/interceptors).
template <typename T>
static DirectHandle<Name> GetPropertyName(
const PropertyCallbackInfo<T>& info) {
DCHECK(info.IsNamed());
return Cast<Name>(
DirectHandle<Object>::FromSlot(&info.args_[kPropertyKeyIndex]));
}
// Returns property index stored in v8::PropertyCallbackInfo<T> (for indexed
// interceptors).
template <typename T>
static uint32_t GetPropertyIndex(const PropertyCallbackInfo<T>& info) {
DCHECK(!info.IsNamed());
return static_cast<uint32_t>(info.args_[kPropertyKeyIndex]);
}
// Returns true if it's an arguments object for named callback, otherwise
// it's one for an indexed callback.
inline bool is_named() const;
// Set property key and a respective frame type (named vs. indexed).
inline void set_property_key(Tagged<Name> name);
inline void set_property_key(uint32_t index);
inline DirectHandle<JSObject> holder() const;
private:
inline void Initialize(Isolate* isolate, Tagged<JSObject> holder);
// Returns JSArray-like object with property names or undefined.
inline DirectHandle<JSObjectOrUndefined> CallPropertyEnumerator(
Isolate* isolate, DirectHandle<InterceptorInfo> interceptor);
void IterateInstance(RootVisitor* v) override;
template <typename V>
Handle<V> GetReturnValue() const;
inline FullObjectSlot slot_at(int index) const {
// This allows index == kFullArgsLength so "one past the end" slots
// can be retrieved for iterating purposes.
DCHECK_LE(static_cast<unsigned>(index),
static_cast<unsigned>(kFullArgsLength));
return FullObjectSlot(values_ + index);
}
#ifdef DEBUG
// Used for checking that the way this object was constructed matches the
// following CallXxx(..).
const bool is_setter_definer_deleter_;
// This stores current value of Isolate::javascript_execution_counter().
// It's used for detecting whether JavaScript code was executed between
// PropertyCallbackArguments's constructor and destructor.
uint32_t javascript_execution_counter_ = 0;
#endif // DEBUG
Address values_[kFullArgsLength];
};
class FunctionCallbackArguments : public Relocatable {
public:
using T = FunctionCallbackInfo<Value>;
using Super = CustomArguments<T>;
static constexpr int kArgsLength = T::kArgsLength;
// Frame arguments block, the values are located on stack in the frame.
static constexpr int kArgcIndex = T::kArgcIndex;
static constexpr int kNewTargetIndex = T::kNewTargetIndex;
static constexpr int kFrameSPIndex = T::kFrameSPIndex;
static constexpr int kFrameTypeIndex = T::kFrameTypeIndex;
// Api arguments block, the values are located on stack right above PC.
static constexpr int kIsolateIndex = T::kIsolateIndex;
static constexpr int kReturnValueIndex = T::kReturnValueIndex;
static constexpr int kContextIndex = T::kContextIndex;
static constexpr int kTargetIndex = T::kTargetIndex;
static constexpr int kApiArgsLength = T::kApiArgsLength;
// JS arguments block, follows Api arguments.
static constexpr int kReceiverIndex = T::kReceiverIndex;
static constexpr int kFirstJSArgumentIndex = T::kFirstJSArgumentIndex;
// Helper for converting Api arguments indices to [0..kApiArgsLength) value.
static constexpr uint32_t ApiArgIndex(uint32_t index) {
DCHECK_GE(index, T::kFirstApiArgumentIndex);
return index - T::kFirstApiArgumentIndex;
}
// Arguments for [[Call]] operation.
template <typename ArgT>
inline FunctionCallbackArguments(Isolate* isolate,
Tagged<FunctionTemplateInfo> target,
Tagged<Object> receiver,
const base::Vector<const ArgT> args);
// Arguments for [[Construct]] operation.
template <typename ArgT>
inline FunctionCallbackArguments(Isolate* isolate,
Tagged<FunctionTemplateInfo> target,
Tagged<HeapObject> new_target,
Tagged<Object> receiver,
const base::Vector<const ArgT> args);
inline ~FunctionCallbackArguments();
// Performs [[Call]] of [[Construct]] operation for a given function
// and new_target.
// Exception is supposed to be checked by the caller.
// It explicitly returns raw value in order to enforce the caller to create
// a handle if necessary.
inline Tagged<JSAny> CallOrConstruct(Isolate* isolate,
Tagged<FunctionTemplateInfo> function,
bool is_construct);
// Unofficial way of getting target FunctionTemplateInfo from
// v8::FunctionCallbackInfo<T>.
template <typename T>
static Tagged<Object> GetTarget(const FunctionCallbackInfo<T>& info) {
return Tagged<Object>(info.values_[kTargetIndex]);
}
private:
template <bool is_construct, typename ArgT>
requires(std::is_same_v<ArgT, DirectHandle<Object>> ||
std::is_same_v<ArgT, Address>)
inline void Initialize(Isolate* isolate, Tagged<FunctionTemplateInfo> target,
Tagged<Object> new_target, Tagged<Object> receiver,
const base::Vector<const ArgT> args);
inline FullObjectSlot slot_at(uint32_t index) const {
// Shift index to accommodate for unconditionally allocated "optional" part.
index += T::kOptionalArgsLength;
// This allows index == values_.size() so "one past the end" slots
// can be retrieved for iterating purposes.
DCHECK_LE(index, values_.size());
// Don't use operator[] because it doesn't allow one past end index.
return FullObjectSlot(&values_.data()[index]);
}
void IterateInstance(RootVisitor* v) override;
// This default size is enough for passing up to 4 JS arguments.
base::SmallVector<Address, 16> values_;
};
static_assert(BuiltinArguments::kNumExtraArgs ==
BuiltinExitFrameConstants::kNumExtraArgs);
static_assert(BuiltinArguments::kNumExtraArgsWithReceiver ==
BuiltinExitFrameConstants::kNumExtraArgsWithReceiver);
} // namespace internal
} // namespace v8
#endif // V8_API_API_ARGUMENTS_H_