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