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