• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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