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