1 // Copyright 2012 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_H_
6 #define V8_API_API_H_
7
8 #include <memory>
9
10 #include "src/execution/isolate.h"
11 #include "src/heap/factory.h"
12 #include "src/objects/bigint.h"
13 #include "src/objects/contexts.h"
14 #include "src/objects/js-collection.h"
15 #include "src/objects/js-generator.h"
16 #include "src/objects/js-promise.h"
17 #include "src/objects/js-proxy.h"
18 #include "src/objects/objects.h"
19 #include "src/objects/shared-function-info.h"
20 #include "src/objects/source-text-module.h"
21 #include "src/utils/detachable-vector.h"
22
23 #include "src/objects/templates.h"
24
25 namespace v8 {
26
27 namespace internal {
28 class JSArrayBufferView;
29 class JSFinalizationRegistry;
30 } // namespace internal
31
32 namespace debug {
33 class AccessorPair;
34 class GeneratorObject;
35 class Script;
36 class WasmValue;
37 class WeakMap;
38 } // namespace debug
39
40 // Constants used in the implementation of the API. The most natural thing
41 // would usually be to place these with the classes that use them, but
42 // we want to keep them out of v8.h because it is an externally
43 // visible file.
44 class Consts {
45 public:
46 enum TemplateType { FUNCTION_TEMPLATE = 0, OBJECT_TEMPLATE = 1 };
47 };
48
49 template <typename T>
50 inline T ToCData(v8::internal::Object obj);
51
52 template <>
53 inline v8::internal::Address ToCData(v8::internal::Object obj);
54
55 template <typename T>
56 inline v8::internal::Handle<v8::internal::Object> FromCData(
57 v8::internal::Isolate* isolate, T obj);
58
59 template <>
60 inline v8::internal::Handle<v8::internal::Object> FromCData(
61 v8::internal::Isolate* isolate, v8::internal::Address obj);
62
63 class ApiFunction {
64 public:
ApiFunction(v8::internal::Address addr)65 explicit ApiFunction(v8::internal::Address addr) : addr_(addr) {}
address()66 v8::internal::Address address() { return addr_; }
67
68 private:
69 v8::internal::Address addr_;
70 };
71
72 class RegisteredExtension {
73 public:
74 static void Register(std::unique_ptr<Extension>);
75 static void UnregisterAll();
extension()76 Extension* extension() const { return extension_.get(); }
next()77 RegisteredExtension* next() const { return next_; }
first_extension()78 static RegisteredExtension* first_extension() { return first_extension_; }
79
80 private:
81 explicit RegisteredExtension(Extension*);
82 explicit RegisteredExtension(std::unique_ptr<Extension>);
83 std::unique_ptr<Extension> extension_;
84 RegisteredExtension* next_ = nullptr;
85 static RegisteredExtension* first_extension_;
86 };
87
88 #define OPEN_HANDLE_LIST(V) \
89 V(Template, TemplateInfo) \
90 V(FunctionTemplate, FunctionTemplateInfo) \
91 V(ObjectTemplate, ObjectTemplateInfo) \
92 V(Signature, FunctionTemplateInfo) \
93 V(AccessorSignature, FunctionTemplateInfo) \
94 V(Data, Object) \
95 V(RegExp, JSRegExp) \
96 V(Object, JSReceiver) \
97 V(Array, JSArray) \
98 V(Map, JSMap) \
99 V(Set, JSSet) \
100 V(ArrayBuffer, JSArrayBuffer) \
101 V(ArrayBufferView, JSArrayBufferView) \
102 V(TypedArray, JSTypedArray) \
103 V(Uint8Array, JSTypedArray) \
104 V(Uint8ClampedArray, JSTypedArray) \
105 V(Int8Array, JSTypedArray) \
106 V(Uint16Array, JSTypedArray) \
107 V(Int16Array, JSTypedArray) \
108 V(Uint32Array, JSTypedArray) \
109 V(Int32Array, JSTypedArray) \
110 V(Float32Array, JSTypedArray) \
111 V(Float64Array, JSTypedArray) \
112 V(DataView, JSDataView) \
113 V(SharedArrayBuffer, JSArrayBuffer) \
114 V(Name, Name) \
115 V(String, String) \
116 V(Symbol, Symbol) \
117 V(Script, JSFunction) \
118 V(UnboundModuleScript, SharedFunctionInfo) \
119 V(UnboundScript, SharedFunctionInfo) \
120 V(Module, Module) \
121 V(Function, JSReceiver) \
122 V(Message, JSMessageObject) \
123 V(Context, Context) \
124 V(External, Object) \
125 V(StackTrace, FixedArray) \
126 V(StackFrame, StackTraceFrame) \
127 V(Proxy, JSProxy) \
128 V(debug::GeneratorObject, JSGeneratorObject) \
129 V(debug::Script, Script) \
130 V(debug::WeakMap, JSWeakMap) \
131 V(debug::AccessorPair, AccessorPair) \
132 V(debug::WasmValue, WasmValue) \
133 V(Promise, JSPromise) \
134 V(Primitive, Object) \
135 V(PrimitiveArray, FixedArray) \
136 V(BigInt, BigInt) \
137 V(ScriptOrModule, Script)
138
139 class Utils {
140 public:
ApiCheck(bool condition,const char * location,const char * message)141 static inline bool ApiCheck(bool condition, const char* location,
142 const char* message) {
143 if (!condition) Utils::ReportApiFailure(location, message);
144 return condition;
145 }
146 static void ReportOOMFailure(v8::internal::Isolate* isolate,
147 const char* location, bool is_heap_oom);
148
149 static inline Local<debug::AccessorPair> ToLocal(
150 v8::internal::Handle<v8::internal::AccessorPair> obj);
151 static inline Local<Context> ToLocal(
152 v8::internal::Handle<v8::internal::Context> obj);
153 static inline Local<Value> ToLocal(
154 v8::internal::Handle<v8::internal::Object> obj);
155 static inline Local<Module> ToLocal(
156 v8::internal::Handle<v8::internal::Module> obj);
157 static inline Local<Name> ToLocal(
158 v8::internal::Handle<v8::internal::Name> obj);
159 static inline Local<String> ToLocal(
160 v8::internal::Handle<v8::internal::String> obj);
161 static inline Local<Symbol> ToLocal(
162 v8::internal::Handle<v8::internal::Symbol> obj);
163 static inline Local<RegExp> ToLocal(
164 v8::internal::Handle<v8::internal::JSRegExp> obj);
165 static inline Local<Object> ToLocal(
166 v8::internal::Handle<v8::internal::JSReceiver> obj);
167 static inline Local<Object> ToLocal(
168 v8::internal::Handle<v8::internal::JSObject> obj);
169 static inline Local<Function> ToLocal(
170 v8::internal::Handle<v8::internal::JSFunction> obj);
171 static inline Local<Array> ToLocal(
172 v8::internal::Handle<v8::internal::JSArray> obj);
173 static inline Local<Map> ToLocal(
174 v8::internal::Handle<v8::internal::JSMap> obj);
175 static inline Local<Set> ToLocal(
176 v8::internal::Handle<v8::internal::JSSet> obj);
177 static inline Local<Proxy> ToLocal(
178 v8::internal::Handle<v8::internal::JSProxy> obj);
179 static inline Local<ArrayBuffer> ToLocal(
180 v8::internal::Handle<v8::internal::JSArrayBuffer> obj);
181 static inline Local<ArrayBufferView> ToLocal(
182 v8::internal::Handle<v8::internal::JSArrayBufferView> obj);
183 static inline Local<DataView> ToLocal(
184 v8::internal::Handle<v8::internal::JSDataView> obj);
185 static inline Local<TypedArray> ToLocal(
186 v8::internal::Handle<v8::internal::JSTypedArray> obj);
187 static inline Local<Uint8Array> ToLocalUint8Array(
188 v8::internal::Handle<v8::internal::JSTypedArray> obj);
189 static inline Local<Uint8ClampedArray> ToLocalUint8ClampedArray(
190 v8::internal::Handle<v8::internal::JSTypedArray> obj);
191 static inline Local<Int8Array> ToLocalInt8Array(
192 v8::internal::Handle<v8::internal::JSTypedArray> obj);
193 static inline Local<Uint16Array> ToLocalUint16Array(
194 v8::internal::Handle<v8::internal::JSTypedArray> obj);
195 static inline Local<Int16Array> ToLocalInt16Array(
196 v8::internal::Handle<v8::internal::JSTypedArray> obj);
197 static inline Local<Uint32Array> ToLocalUint32Array(
198 v8::internal::Handle<v8::internal::JSTypedArray> obj);
199 static inline Local<Int32Array> ToLocalInt32Array(
200 v8::internal::Handle<v8::internal::JSTypedArray> obj);
201 static inline Local<Float32Array> ToLocalFloat32Array(
202 v8::internal::Handle<v8::internal::JSTypedArray> obj);
203 static inline Local<Float64Array> ToLocalFloat64Array(
204 v8::internal::Handle<v8::internal::JSTypedArray> obj);
205 static inline Local<BigInt64Array> ToLocalBigInt64Array(
206 v8::internal::Handle<v8::internal::JSTypedArray> obj);
207 static inline Local<BigUint64Array> ToLocalBigUint64Array(
208 v8::internal::Handle<v8::internal::JSTypedArray> obj);
209
210 static inline Local<SharedArrayBuffer> ToLocalShared(
211 v8::internal::Handle<v8::internal::JSArrayBuffer> obj);
212
213 static inline Local<Message> MessageToLocal(
214 v8::internal::Handle<v8::internal::Object> obj);
215 static inline Local<Promise> PromiseToLocal(
216 v8::internal::Handle<v8::internal::JSObject> obj);
217 static inline Local<StackTrace> StackTraceToLocal(
218 v8::internal::Handle<v8::internal::FixedArray> obj);
219 static inline Local<StackFrame> StackFrameToLocal(
220 v8::internal::Handle<v8::internal::StackTraceFrame> obj);
221 static inline Local<Number> NumberToLocal(
222 v8::internal::Handle<v8::internal::Object> obj);
223 static inline Local<Integer> IntegerToLocal(
224 v8::internal::Handle<v8::internal::Object> obj);
225 static inline Local<Uint32> Uint32ToLocal(
226 v8::internal::Handle<v8::internal::Object> obj);
227 static inline Local<BigInt> ToLocal(
228 v8::internal::Handle<v8::internal::BigInt> obj);
229 static inline Local<FunctionTemplate> ToLocal(
230 v8::internal::Handle<v8::internal::FunctionTemplateInfo> obj);
231 static inline Local<ObjectTemplate> ToLocal(
232 v8::internal::Handle<v8::internal::ObjectTemplateInfo> obj);
233 static inline Local<Signature> SignatureToLocal(
234 v8::internal::Handle<v8::internal::FunctionTemplateInfo> obj);
235 static inline Local<AccessorSignature> AccessorSignatureToLocal(
236 v8::internal::Handle<v8::internal::FunctionTemplateInfo> obj);
237 static inline Local<External> ExternalToLocal(
238 v8::internal::Handle<v8::internal::JSObject> obj);
239 static inline Local<Function> CallableToLocal(
240 v8::internal::Handle<v8::internal::JSReceiver> obj);
241 static inline Local<Primitive> ToLocalPrimitive(
242 v8::internal::Handle<v8::internal::Object> obj);
243 static inline Local<PrimitiveArray> ToLocal(
244 v8::internal::Handle<v8::internal::FixedArray> obj);
245 static inline Local<ScriptOrModule> ScriptOrModuleToLocal(
246 v8::internal::Handle<v8::internal::Script> obj);
247
248 #define DECLARE_OPEN_HANDLE(From, To) \
249 static inline v8::internal::Handle<v8::internal::To> OpenHandle( \
250 const From* that, bool allow_empty_handle = false);
251
252 OPEN_HANDLE_LIST(DECLARE_OPEN_HANDLE)
253
254 #undef DECLARE_OPEN_HANDLE
255
256 template <class From, class To>
257 static inline Local<To> Convert(v8::internal::Handle<From> obj);
258
259 template <class T, class M>
OpenPersistent(const v8::Persistent<T,M> & persistent)260 static inline v8::internal::Handle<v8::internal::Object> OpenPersistent(
261 const v8::Persistent<T, M>& persistent) {
262 return v8::internal::Handle<v8::internal::Object>(
263 reinterpret_cast<v8::internal::Address*>(persistent.val_));
264 }
265
266 template <class T>
OpenPersistent(v8::Persistent<T> * persistent)267 static inline v8::internal::Handle<v8::internal::Object> OpenPersistent(
268 v8::Persistent<T>* persistent) {
269 return OpenPersistent(*persistent);
270 }
271
272 template <class From, class To>
OpenHandle(v8::Local<From> handle)273 static inline v8::internal::Handle<To> OpenHandle(v8::Local<From> handle) {
274 return OpenHandle(*handle);
275 }
276
277 private:
278 static void ReportApiFailure(const char* location, const char* message);
279 };
280
281 template <class T>
ToApi(v8::internal::Handle<v8::internal::Object> obj)282 inline T* ToApi(v8::internal::Handle<v8::internal::Object> obj) {
283 return reinterpret_cast<T*>(obj.location());
284 }
285
286 template <class T>
ToApiHandle(v8::internal::Handle<v8::internal::Object> obj)287 inline v8::Local<T> ToApiHandle(
288 v8::internal::Handle<v8::internal::Object> obj) {
289 return Utils::Convert<v8::internal::Object, T>(obj);
290 }
291
292 template <class T>
ToLocal(v8::internal::MaybeHandle<v8::internal::Object> maybe,Local<T> * local)293 inline bool ToLocal(v8::internal::MaybeHandle<v8::internal::Object> maybe,
294 Local<T>* local) {
295 v8::internal::Handle<v8::internal::Object> handle;
296 if (maybe.ToHandle(&handle)) {
297 *local = Utils::Convert<v8::internal::Object, T>(handle);
298 return true;
299 }
300 return false;
301 }
302
303 namespace internal {
304
305 class PersistentHandles;
306
307 // This class is here in order to be able to declare it a friend of
308 // HandleScope. Moving these methods to be members of HandleScope would be
309 // neat in some ways, but it would expose internal implementation details in
310 // our public header file, which is undesirable.
311 //
312 // An isolate has a single instance of this class to hold the current thread's
313 // data. In multithreaded V8 programs this data is copied in and out of storage
314 // so that the currently executing thread always has its own copy of this
315 // data.
316 class HandleScopeImplementer {
317 public:
318 class EnteredContextRewindScope {
319 public:
EnteredContextRewindScope(HandleScopeImplementer * hsi)320 explicit EnteredContextRewindScope(HandleScopeImplementer* hsi)
321 : hsi_(hsi), saved_entered_context_count_(hsi->EnteredContextCount()) {}
322
~EnteredContextRewindScope()323 ~EnteredContextRewindScope() {
324 DCHECK_LE(saved_entered_context_count_, hsi_->EnteredContextCount());
325 while (saved_entered_context_count_ < hsi_->EnteredContextCount())
326 hsi_->LeaveContext();
327 }
328
329 private:
330 HandleScopeImplementer* hsi_;
331 size_t saved_entered_context_count_;
332 };
333
HandleScopeImplementer(Isolate * isolate)334 explicit HandleScopeImplementer(Isolate* isolate)
335 : isolate_(isolate),
336 spare_(nullptr),
337 last_handle_before_deferred_block_(nullptr) {}
338
~HandleScopeImplementer()339 ~HandleScopeImplementer() { DeleteArray(spare_); }
340
341 // Threading support for handle data.
342 static int ArchiveSpacePerThread();
343 char* RestoreThread(char* from);
344 char* ArchiveThread(char* to);
345 void FreeThreadResources();
346
347 // Garbage collection support.
348 V8_EXPORT_PRIVATE void Iterate(v8::internal::RootVisitor* v);
349 V8_EXPORT_PRIVATE static char* Iterate(v8::internal::RootVisitor* v,
350 char* data);
351
352 inline internal::Address* GetSpareOrNewBlock();
353 inline void DeleteExtensions(internal::Address* prev_limit);
354
355 inline void EnterContext(Context context);
356 inline void LeaveContext();
357 inline bool LastEnteredContextWas(Context context);
EnteredContextCount()358 inline size_t EnteredContextCount() const { return entered_contexts_.size(); }
359
360 inline void EnterMicrotaskContext(Context context);
361
362 // Returns the last entered context or an empty handle if no
363 // contexts have been entered.
364 inline Handle<Context> LastEnteredContext();
365 inline Handle<Context> LastEnteredOrMicrotaskContext();
366
367 inline void SaveContext(Context context);
368 inline Context RestoreContext();
369 inline bool HasSavedContexts();
370
blocks()371 inline DetachableVector<Address*>* blocks() { return &blocks_; }
isolate()372 Isolate* isolate() const { return isolate_; }
373
ReturnBlock(Address * block)374 void ReturnBlock(Address* block) {
375 DCHECK_NOT_NULL(block);
376 if (spare_ != nullptr) DeleteArray(spare_);
377 spare_ = block;
378 }
379
380 static const size_t kEnteredContextsOffset;
381 static const size_t kIsMicrotaskContextOffset;
382
383 private:
ResetAfterArchive()384 void ResetAfterArchive() {
385 blocks_.detach();
386 entered_contexts_.detach();
387 is_microtask_context_.detach();
388 saved_contexts_.detach();
389 spare_ = nullptr;
390 last_handle_before_deferred_block_ = nullptr;
391 }
392
Free()393 void Free() {
394 DCHECK(blocks_.empty());
395 DCHECK(entered_contexts_.empty());
396 DCHECK(is_microtask_context_.empty());
397 DCHECK(saved_contexts_.empty());
398
399 blocks_.free();
400 entered_contexts_.free();
401 is_microtask_context_.free();
402 saved_contexts_.free();
403 if (spare_ != nullptr) {
404 DeleteArray(spare_);
405 spare_ = nullptr;
406 }
407 DCHECK(isolate_->thread_local_top()->CallDepthIsZero());
408 }
409
410 void BeginDeferredScope();
411 std::unique_ptr<PersistentHandles> DetachPersistent(Address* prev_limit);
412
413 Isolate* isolate_;
414 DetachableVector<Address*> blocks_;
415
416 // Used as a stack to keep track of entered contexts.
417 // If |i|th item of |entered_contexts_| is added by EnterMicrotaskContext,
418 // `is_microtask_context_[i]` is 1.
419 // TODO(tzik): Remove |is_microtask_context_| after the deprecated
420 // v8::Isolate::GetEnteredContext() is removed.
421 DetachableVector<Context> entered_contexts_;
422 DetachableVector<int8_t> is_microtask_context_;
423
424 // Used as a stack to keep track of saved contexts.
425 DetachableVector<Context> saved_contexts_;
426 Address* spare_;
427 Address* last_handle_before_deferred_block_;
428 // This is only used for threading support.
429 HandleScopeData handle_scope_data_;
430
431 void IterateThis(RootVisitor* v);
432 char* RestoreThreadHelper(char* from);
433 char* ArchiveThreadHelper(char* to);
434
435 friend class HandleScopeImplementerOffsets;
436 friend class PersistentHandlesScope;
437
438 DISALLOW_COPY_AND_ASSIGN(HandleScopeImplementer);
439 };
440
441 const int kHandleBlockSize = v8::internal::KB - 2; // fit in one page
442
SaveContext(Context context)443 void HandleScopeImplementer::SaveContext(Context context) {
444 saved_contexts_.push_back(context);
445 }
446
RestoreContext()447 Context HandleScopeImplementer::RestoreContext() {
448 Context last_context = saved_contexts_.back();
449 saved_contexts_.pop_back();
450 return last_context;
451 }
452
HasSavedContexts()453 bool HandleScopeImplementer::HasSavedContexts() {
454 return !saved_contexts_.empty();
455 }
456
EnterContext(Context context)457 void HandleScopeImplementer::EnterContext(Context context) {
458 DCHECK_EQ(entered_contexts_.size(), is_microtask_context_.size());
459 entered_contexts_.push_back(context);
460 is_microtask_context_.push_back(0);
461 }
462
LeaveContext()463 void HandleScopeImplementer::LeaveContext() {
464 DCHECK(!entered_contexts_.empty());
465 DCHECK_EQ(entered_contexts_.size(), is_microtask_context_.size());
466 entered_contexts_.pop_back();
467 is_microtask_context_.pop_back();
468 }
469
LastEnteredContextWas(Context context)470 bool HandleScopeImplementer::LastEnteredContextWas(Context context) {
471 return !entered_contexts_.empty() && entered_contexts_.back() == context;
472 }
473
EnterMicrotaskContext(Context context)474 void HandleScopeImplementer::EnterMicrotaskContext(Context context) {
475 DCHECK_EQ(entered_contexts_.size(), is_microtask_context_.size());
476 entered_contexts_.push_back(context);
477 is_microtask_context_.push_back(1);
478 }
479
480 // If there's a spare block, use it for growing the current scope.
GetSpareOrNewBlock()481 internal::Address* HandleScopeImplementer::GetSpareOrNewBlock() {
482 internal::Address* block =
483 (spare_ != nullptr) ? spare_
484 : NewArray<internal::Address>(kHandleBlockSize);
485 spare_ = nullptr;
486 return block;
487 }
488
DeleteExtensions(internal::Address * prev_limit)489 void HandleScopeImplementer::DeleteExtensions(internal::Address* prev_limit) {
490 while (!blocks_.empty()) {
491 internal::Address* block_start = blocks_.back();
492 internal::Address* block_limit = block_start + kHandleBlockSize;
493
494 // SealHandleScope may make the prev_limit to point inside the block.
495 // Cast possibly-unrelated pointers to plain Addres before comparing them
496 // to avoid undefined behavior.
497 if (reinterpret_cast<Address>(block_start) <=
498 reinterpret_cast<Address>(prev_limit) &&
499 reinterpret_cast<Address>(prev_limit) <=
500 reinterpret_cast<Address>(block_limit)) {
501 #ifdef ENABLE_HANDLE_ZAPPING
502 internal::HandleScope::ZapRange(prev_limit, block_limit);
503 #endif
504 break;
505 }
506
507 blocks_.pop_back();
508 #ifdef ENABLE_HANDLE_ZAPPING
509 internal::HandleScope::ZapRange(block_start, block_limit);
510 #endif
511 if (spare_ != nullptr) {
512 DeleteArray(spare_);
513 }
514 spare_ = block_start;
515 }
516 DCHECK((blocks_.empty() && prev_limit == nullptr) ||
517 (!blocks_.empty() && prev_limit != nullptr));
518 }
519
520 // Interceptor functions called from generated inline caches to notify
521 // CPU profiler that external callbacks are invoked.
522 void InvokeAccessorGetterCallback(
523 v8::Local<v8::Name> property,
524 const v8::PropertyCallbackInfo<v8::Value>& info,
525 v8::AccessorNameGetterCallback getter);
526
527 void InvokeFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>& info,
528 v8::FunctionCallback callback);
529
530 void InvokeFinalizationRegistryCleanupFromTask(
531 Handle<Context> context,
532 Handle<JSFinalizationRegistry> finalization_registry,
533 Handle<Object> callback);
534
535 } // namespace internal
536 } // namespace v8
537
538 #endif // V8_API_API_H_
539