|
|
|||
File indexing completed on 2026-09-18 09:18:31
0001 // Copyright 2013 the V8 project authors. All rights reserved. 0002 // Use of this source code is governed by a BSD-style license that can be 0003 // found in the LICENSE file. 0004 0005 #ifndef V8_V8_PLATFORM_H_ 0006 #define V8_V8_PLATFORM_H_ 0007 0008 #include <math.h> 0009 #include <stddef.h> 0010 #include <stdint.h> 0011 #include <stdlib.h> // For abort. 0012 0013 #include <memory> 0014 #include <optional> 0015 #include <string> 0016 0017 #include "v8-source-location.h" // NOLINT(build/include_directory) 0018 #include "v8config.h" // NOLINT(build/include_directory) 0019 0020 namespace v8 { 0021 0022 class Isolate; 0023 0024 // Valid priorities supported by the task scheduling infrastructure. 0025 enum class TaskPriority : uint8_t { 0026 /** 0027 * Best effort tasks are not critical for performance of the application. The 0028 * platform implementation should preempt such tasks if higher priority tasks 0029 * arrive. 0030 */ 0031 kBestEffort, 0032 /** 0033 * User visible tasks are long running background tasks that will 0034 * improve performance and memory usage of the application upon completion. 0035 * Example: background compilation and garbage collection. 0036 */ 0037 kUserVisible, 0038 /** 0039 * User blocking tasks are highest priority tasks that block the execution 0040 * thread (e.g. major garbage collection). They must be finished as soon as 0041 * possible. 0042 */ 0043 kUserBlocking, 0044 kMaxPriority = kUserBlocking 0045 }; 0046 0047 /** 0048 * A Task represents a unit of work. 0049 */ 0050 class Task { 0051 public: 0052 virtual ~Task() = default; 0053 0054 virtual void Run() = 0; 0055 }; 0056 0057 /** 0058 * An IdleTask represents a unit of work to be performed in idle time. 0059 * The Run method is invoked with an argument that specifies the deadline in 0060 * seconds returned by MonotonicallyIncreasingTime(). 0061 * The idle task is expected to complete by this deadline. 0062 */ 0063 class IdleTask { 0064 public: 0065 virtual ~IdleTask() = default; 0066 virtual void Run(double deadline_in_seconds) = 0; 0067 }; 0068 0069 /** 0070 * A TaskRunner allows scheduling of tasks. The TaskRunner may still be used to 0071 * post tasks after the isolate gets destructed, but these tasks may not get 0072 * executed anymore. All tasks posted to a given TaskRunner will be invoked in 0073 * sequence. Tasks can be posted from any thread. 0074 */ 0075 class TaskRunner { 0076 public: 0077 /** 0078 * Schedules a task to be invoked by this TaskRunner. The TaskRunner 0079 * implementation takes ownership of |task|. 0080 * 0081 * Embedders should override PostTaskImpl instead of this. 0082 */ 0083 void PostTask(std::unique_ptr<Task> task, 0084 SourceLocation location = SourceLocation::Current()) { 0085 PostTaskImpl(std::move(task), location); 0086 } 0087 0088 /** 0089 * Schedules a task to be invoked by this TaskRunner. The TaskRunner 0090 * implementation takes ownership of |task|. The |task| cannot be nested 0091 * within other task executions. 0092 * 0093 * Tasks which shouldn't be interleaved with JS execution must be posted with 0094 * |PostNonNestableTask| or |PostNonNestableDelayedTask|. This is because the 0095 * embedder may process tasks in a callback which is called during JS 0096 * execution. 0097 * 0098 * In particular, tasks which execute JS must be non-nestable, since JS 0099 * execution is not allowed to nest. 0100 * 0101 * Requires that |TaskRunner::NonNestableTasksEnabled()| is true. 0102 * 0103 * Embedders should override PostNonNestableTaskImpl instead of this. 0104 */ 0105 void PostNonNestableTask( 0106 std::unique_ptr<Task> task, 0107 SourceLocation location = SourceLocation::Current()) { 0108 PostNonNestableTaskImpl(std::move(task), location); 0109 } 0110 0111 /** 0112 * Schedules a task to be invoked by this TaskRunner. The task is scheduled 0113 * after the given number of seconds |delay_in_seconds|. The TaskRunner 0114 * implementation takes ownership of |task|. 0115 * 0116 * Embedders should override PostDelayedTaskImpl instead of this. 0117 */ 0118 void PostDelayedTask(std::unique_ptr<Task> task, double delay_in_seconds, 0119 SourceLocation location = SourceLocation::Current()) { 0120 PostDelayedTaskImpl(std::move(task), delay_in_seconds, location); 0121 } 0122 0123 /** 0124 * Schedules a task to be invoked by this TaskRunner. The task is scheduled 0125 * after the given number of seconds |delay_in_seconds|. The TaskRunner 0126 * implementation takes ownership of |task|. The |task| cannot be nested 0127 * within other task executions. 0128 * 0129 * Tasks which shouldn't be interleaved with JS execution must be posted with 0130 * |PostNonNestableTask| or |PostNonNestableDelayedTask|. This is because the 0131 * embedder may process tasks in a callback which is called during JS 0132 * execution. 0133 * 0134 * In particular, tasks which execute JS must be non-nestable, since JS 0135 * execution is not allowed to nest. 0136 * 0137 * Requires that |TaskRunner::NonNestableDelayedTasksEnabled()| is true. 0138 * 0139 * Embedders should override PostNonNestableDelayedTaskImpl instead of this. 0140 */ 0141 void PostNonNestableDelayedTask( 0142 std::unique_ptr<Task> task, double delay_in_seconds, 0143 SourceLocation location = SourceLocation::Current()) { 0144 PostNonNestableDelayedTaskImpl(std::move(task), delay_in_seconds, location); 0145 } 0146 0147 /** 0148 * Schedules an idle task to be invoked by this TaskRunner. The task is 0149 * scheduled when the embedder is idle. Requires that 0150 * |TaskRunner::IdleTasksEnabled()| is true. Idle tasks may be reordered 0151 * relative to other task types and may be starved for an arbitrarily long 0152 * time if no idle time is available. The TaskRunner implementation takes 0153 * ownership of |task|. 0154 * 0155 * Embedders should override PostIdleTaskImpl instead of this. 0156 */ 0157 void PostIdleTask(std::unique_ptr<IdleTask> task, 0158 SourceLocation location = SourceLocation::Current()) { 0159 PostIdleTaskImpl(std::move(task), location); 0160 } 0161 0162 /** 0163 * Returns true if idle tasks are enabled for this TaskRunner. 0164 */ 0165 virtual bool IdleTasksEnabled() = 0; 0166 0167 /** 0168 * Returns true if non-nestable tasks are enabled for this TaskRunner. 0169 */ 0170 virtual bool NonNestableTasksEnabled() const { return false; } 0171 0172 /** 0173 * Returns true if non-nestable delayed tasks are enabled for this TaskRunner. 0174 */ 0175 virtual bool NonNestableDelayedTasksEnabled() const { return false; } 0176 0177 TaskRunner() = default; 0178 virtual ~TaskRunner() = default; 0179 0180 TaskRunner(const TaskRunner&) = delete; 0181 TaskRunner& operator=(const TaskRunner&) = delete; 0182 0183 protected: 0184 /** 0185 * Implementation of above methods with an additional `location` argument. 0186 */ 0187 virtual void PostTaskImpl(std::unique_ptr<Task> task, 0188 const SourceLocation& location) {} 0189 virtual void PostNonNestableTaskImpl(std::unique_ptr<Task> task, 0190 const SourceLocation& location) {} 0191 virtual void PostDelayedTaskImpl(std::unique_ptr<Task> task, 0192 double delay_in_seconds, 0193 const SourceLocation& location) {} 0194 virtual void PostNonNestableDelayedTaskImpl(std::unique_ptr<Task> task, 0195 double delay_in_seconds, 0196 const SourceLocation& location) {} 0197 virtual void PostIdleTaskImpl(std::unique_ptr<IdleTask> task, 0198 const SourceLocation& location) {} 0199 }; 0200 0201 /** 0202 * Delegate that's passed to Job's worker task, providing an entry point to 0203 * communicate with the scheduler. 0204 */ 0205 class JobDelegate { 0206 public: 0207 /** 0208 * Returns true if this thread *must* return from the worker task on the 0209 * current thread ASAP. Workers should periodically invoke ShouldYield (or 0210 * YieldIfNeeded()) as often as is reasonable. 0211 * After this method returned true, ShouldYield must not be called again. 0212 */ 0213 virtual bool ShouldYield() = 0; 0214 0215 /** 0216 * Notifies the scheduler that max concurrency was increased, and the number 0217 * of worker should be adjusted accordingly. See Platform::PostJob() for more 0218 * details. 0219 */ 0220 virtual void NotifyConcurrencyIncrease() = 0; 0221 0222 /** 0223 * Returns a task_id unique among threads currently running this job, such 0224 * that GetTaskId() < worker count. To achieve this, the same task_id may be 0225 * reused by a different thread after a worker_task returns. 0226 */ 0227 virtual uint8_t GetTaskId() = 0; 0228 0229 /** 0230 * Returns true if the current task is called from the thread currently 0231 * running JobHandle::Join(). 0232 */ 0233 virtual bool IsJoiningThread() const = 0; 0234 }; 0235 0236 /** 0237 * Handle returned when posting a Job. Provides methods to control execution of 0238 * the posted Job. 0239 */ 0240 class JobHandle { 0241 public: 0242 virtual ~JobHandle() = default; 0243 0244 /** 0245 * Notifies the scheduler that max concurrency was increased, and the number 0246 * of worker should be adjusted accordingly. See Platform::PostJob() for more 0247 * details. 0248 */ 0249 virtual void NotifyConcurrencyIncrease() = 0; 0250 0251 /** 0252 * Contributes to the job on this thread. Doesn't return until all tasks have 0253 * completed and max concurrency becomes 0. When Join() is called and max 0254 * concurrency reaches 0, it should not increase again. This also promotes 0255 * this Job's priority to be at least as high as the calling thread's 0256 * priority. 0257 */ 0258 virtual void Join() = 0; 0259 0260 /** 0261 * Forces all existing workers to yield ASAP. Waits until they have all 0262 * returned from the Job's callback before returning. 0263 */ 0264 virtual void Cancel() = 0; 0265 0266 /* 0267 * Forces all existing workers to yield ASAP but doesn’t wait for them. 0268 * Warning, this is dangerous if the Job's callback is bound to or has access 0269 * to state which may be deleted after this call. 0270 */ 0271 virtual void CancelAndDetach() = 0; 0272 0273 /** 0274 * Returns true if there's any work pending or any worker running. 0275 */ 0276 virtual bool IsActive() = 0; 0277 0278 /** 0279 * Returns true if associated with a Job and other methods may be called. 0280 * Returns false after Join() or Cancel() was called. This may return true 0281 * even if no workers are running and IsCompleted() returns true 0282 */ 0283 virtual bool IsValid() = 0; 0284 0285 /** 0286 * Returns true if job priority can be changed. 0287 */ 0288 virtual bool UpdatePriorityEnabled() const { return false; } 0289 0290 /** 0291 * Update this Job's priority. 0292 */ 0293 virtual void UpdatePriority(TaskPriority new_priority) {} 0294 }; 0295 0296 /** 0297 * A JobTask represents work to run in parallel from Platform::PostJob(). 0298 */ 0299 class JobTask { 0300 public: 0301 virtual ~JobTask() = default; 0302 0303 virtual void Run(JobDelegate* delegate) = 0; 0304 0305 /** 0306 * Controls the maximum number of threads calling Run() concurrently, given 0307 * the number of threads currently assigned to this job and executing Run(). 0308 * Run() is only invoked if the number of threads previously running Run() was 0309 * less than the value returned. In general, this should return the latest 0310 * number of incomplete work items (smallest unit of work) left to process, 0311 * including items that are currently in progress. |worker_count| is the 0312 * number of threads currently assigned to this job which some callers may 0313 * need to determine their return value. Since GetMaxConcurrency() is a leaf 0314 * function, it must not call back any JobHandle methods. 0315 */ 0316 virtual size_t GetMaxConcurrency(size_t worker_count) const = 0; 0317 }; 0318 0319 // Allows a thread to temporarily boost another thread's priority to match its 0320 // own priority. The priority is reset when the object is destroyed, which must 0321 // happens on the boosted thread. 0322 class ScopedBoostablePriority { 0323 public: 0324 ScopedBoostablePriority() = default; 0325 virtual ~ScopedBoostablePriority() = default; 0326 ScopedBoostablePriority(const ScopedBoostablePriority&) = delete; 0327 ScopedBoostablePriority& operator=(const ScopedBoostablePriority& other) = 0328 delete; 0329 0330 // Boosts the priority of the thread where this ScopedBoostablePriority was 0331 // created. Can be called from any thread, but requires proper external 0332 // synchronization with the constructor, destructor and any other call to 0333 // BoostPriority/Reset(). If called multiple times, only the first call takes 0334 // effect. 0335 virtual bool BoostPriority() = 0; 0336 0337 // Resets the priority of the thread where this ScopedBoostablePriority was 0338 // created to its original priority. 0339 virtual void Reset() = 0; 0340 }; 0341 0342 /** 0343 * A "blocking call" refers to any call that causes the calling thread to wait 0344 * off-CPU. It includes but is not limited to calls that wait on synchronous 0345 * file I/O operations: read or write a file from disk, interact with a pipe or 0346 * a socket, rename or delete a file, enumerate files in a directory, etc. 0347 * Acquiring a low contention lock is not considered a blocking call. 0348 */ 0349 0350 /** 0351 * BlockingType indicates the likelihood that a blocking call will actually 0352 * block. 0353 */ 0354 enum class BlockingType { 0355 // The call might block (e.g. file I/O that might hit in memory cache). 0356 kMayBlock, 0357 // The call will definitely block (e.g. cache already checked and now pinging 0358 // server synchronously). 0359 kWillBlock 0360 }; 0361 0362 /** 0363 * This class is instantiated with CreateBlockingScope() in every scope where a 0364 * blocking call is made and serves as a precise annotation of the scope that 0365 * may/will block. May be implemented by an embedder to adjust the thread count. 0366 * CPU usage should be minimal within that scope. ScopedBlockingCalls can be 0367 * nested. 0368 */ 0369 class ScopedBlockingCall { 0370 public: 0371 virtual ~ScopedBlockingCall() = default; 0372 }; 0373 0374 /** 0375 * The interface represents complex arguments to trace events. 0376 */ 0377 class ConvertableToTraceFormat { 0378 public: 0379 virtual ~ConvertableToTraceFormat() = default; 0380 0381 /** 0382 * Append the class info to the provided |out| string. The appended 0383 * data must be a valid JSON object. Strings must be properly quoted, and 0384 * escaped. There is no processing applied to the content after it is 0385 * appended. 0386 */ 0387 virtual void AppendAsTraceFormat(std::string* out) const = 0; 0388 }; 0389 0390 /** 0391 * V8 Tracing controller. 0392 * 0393 * Can be implemented by an embedder to record trace events from V8. 0394 * 0395 * Will become obsolete in Perfetto build (v8_use_perfetto = true). 0396 */ 0397 class TracingController { 0398 public: 0399 virtual ~TracingController() = default; 0400 0401 // In Perfetto mode, trace events are written using Perfetto's Track Event 0402 // API directly without going through the embedder. However, it is still 0403 // possible to observe tracing being enabled and disabled. 0404 #if !defined(V8_USE_PERFETTO) 0405 /** 0406 * Called by TRACE_EVENT* macros, don't call this directly. 0407 * The name parameter is a category group for example: 0408 * TRACE_EVENT0("v8,parse", "V8.Parse") 0409 * The pointer returned points to a value with zero or more of the bits 0410 * defined in CategoryGroupEnabledFlags. 0411 **/ 0412 virtual const uint8_t* GetCategoryGroupEnabled(const char* name) { 0413 static uint8_t no = 0; 0414 return &no; 0415 } 0416 0417 /** 0418 * Adds a trace event to the platform tracing system. These function calls are 0419 * usually the result of a TRACE_* macro from trace-event-no-perfetto.h when 0420 * tracing and the category of the particular trace are enabled. It is not 0421 * advisable to call these functions on their own; they are really only meant 0422 * to be used by the trace macros. The returned handle can be used by 0423 * UpdateTraceEventDuration to update the duration of COMPLETE events. 0424 */ 0425 virtual uint64_t AddTraceEvent( 0426 char phase, const uint8_t* category_enabled_flag, const char* name, 0427 const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, 0428 const char** arg_names, const uint8_t* arg_types, 0429 const uint64_t* arg_values, 0430 std::unique_ptr<ConvertableToTraceFormat>* arg_convertables, 0431 unsigned int flags) { 0432 return 0; 0433 } 0434 virtual uint64_t AddTraceEventWithTimestamp( 0435 char phase, const uint8_t* category_enabled_flag, const char* name, 0436 const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, 0437 const char** arg_names, const uint8_t* arg_types, 0438 const uint64_t* arg_values, 0439 std::unique_ptr<ConvertableToTraceFormat>* arg_convertables, 0440 unsigned int flags, int64_t timestamp) { 0441 return 0; 0442 } 0443 0444 /** 0445 * Sets the duration field of a COMPLETE trace event. It must be called with 0446 * the handle returned from AddTraceEvent(). 0447 **/ 0448 virtual void UpdateTraceEventDuration(const uint8_t* category_enabled_flag, 0449 const char* name, uint64_t handle) {} 0450 #endif // !defined(V8_USE_PERFETTO) 0451 0452 class TraceStateObserver { 0453 public: 0454 virtual ~TraceStateObserver() = default; 0455 virtual void OnTraceEnabled() = 0; 0456 virtual void OnTraceDisabled() = 0; 0457 }; 0458 0459 /** 0460 * Adds tracing state change observer. 0461 * Does nothing in Perfetto SDK build (v8_use_perfetto = true). 0462 */ 0463 virtual void AddTraceStateObserver(TraceStateObserver*) {} 0464 0465 /** 0466 * Removes tracing state change observer. 0467 * Does nothing in Perfetto SDK build (v8_use_perfetto = true). 0468 */ 0469 virtual void RemoveTraceStateObserver(TraceStateObserver*) {} 0470 }; 0471 0472 // Opaque type representing a handle to a shared memory region. 0473 class SharedMemoryHandle { 0474 public: 0475 // For the handle itself, we use the underlying type (e.g. unsigned int) 0476 // instead of e.g. mach_port_t to avoid pulling in large OS header files into 0477 // this header file. Instead, the users of these routines are expected to 0478 // include the respective OS headers in addition to this one. 0479 0480 #if V8_OS_DARWIN 0481 // A mach_port_t referencing a memory entry object. 0482 using PlatformHandle = unsigned int; 0483 #elif V8_OS_FUCHSIA 0484 // A zx_handle_t to a VMO. 0485 using PlatformHandle = uint32_t; 0486 #elif V8_OS_WIN 0487 // A Windows HANDLE to a file mapping object. 0488 using PlatformHandle = void*; 0489 #else 0490 // A file descriptor. 0491 using PlatformHandle = int; 0492 #endif 0493 0494 static constexpr SharedMemoryHandle FromPlatformHandle( 0495 PlatformHandle handle) { 0496 return SharedMemoryHandle(handle); 0497 } 0498 0499 PlatformHandle GetPlatformHandle() const { return handle_; } 0500 0501 private: 0502 SharedMemoryHandle() = delete; 0503 explicit constexpr SharedMemoryHandle(PlatformHandle handle) 0504 : handle_(handle) {} 0505 0506 PlatformHandle handle_; 0507 }; 0508 0509 #define DEFINE_SHARED_MEMORY_HANDLE_WRAPPERS(Wrap, Unwrap) \ 0510 V8_DEPRECATE_SOON("Use SharedMemoryHandle::FromPlatformHandle instead") \ 0511 inline SharedMemoryHandle Wrap(SharedMemoryHandle::PlatformHandle handle) { \ 0512 return SharedMemoryHandle::FromPlatformHandle(handle); \ 0513 } \ 0514 V8_DEPRECATE_SOON("Use SharedMemoryHandle::GetPlatformHandle instead") \ 0515 inline SharedMemoryHandle::PlatformHandle Unwrap( \ 0516 SharedMemoryHandle handle) { \ 0517 return handle.GetPlatformHandle(); \ 0518 } 0519 0520 #if V8_OS_DARWIN 0521 DEFINE_SHARED_MEMORY_HANDLE_WRAPPERS(SharedMemoryHandleFromMachMemoryEntry, 0522 MachMemoryEntryFromSharedMemoryHandle) 0523 #elif V8_OS_FUCHSIA 0524 DEFINE_SHARED_MEMORY_HANDLE_WRAPPERS(SharedMemoryHandleFromVMO, 0525 VMOFromSharedMemoryHandle) 0526 #elif V8_OS_WIN 0527 DEFINE_SHARED_MEMORY_HANDLE_WRAPPERS(SharedMemoryHandleFromFileMapping, 0528 FileMappingFromSharedMemoryHandle) 0529 #else 0530 DEFINE_SHARED_MEMORY_HANDLE_WRAPPERS(SharedMemoryHandleFromFileDescriptor, 0531 FileDescriptorFromSharedMemoryHandle) 0532 #endif 0533 0534 #undef DEFINE_SHARED_MEMORY_HANDLE_WRAPPERS 0535 0536 // TODO(https://crbug.com/463925491): Remove this type alias once Chromium's 0537 // "gin" V8 binding migrates off it. 0538 using PlatformSharedMemoryHandle = std::optional<SharedMemoryHandle>; 0539 V8_DEPRECATE_SOON("Use std::nullopt instead") 0540 static constexpr PlatformSharedMemoryHandle kInvalidSharedMemoryHandle = 0541 std::nullopt; 0542 0543 /** 0544 * A V8 memory page allocator. 0545 * 0546 * Can be implemented by an embedder to manage large host OS allocations. 0547 */ 0548 class PageAllocator { 0549 public: 0550 virtual ~PageAllocator() = default; 0551 0552 /** 0553 * Gets the page granularity for AllocatePages and FreePages. Addresses and 0554 * lengths for those calls should be multiples of AllocatePageSize(). 0555 */ 0556 virtual size_t AllocatePageSize() = 0; 0557 0558 /** 0559 * Gets the page granularity for SetPermissions and ReleasePages. Addresses 0560 * and lengths for those calls should be multiples of CommitPageSize(). 0561 */ 0562 virtual size_t CommitPageSize() = 0; 0563 0564 /** 0565 * Sets the random seed so that GetRandomMmapAddr() will generate repeatable 0566 * sequences of random mmap addresses. 0567 */ 0568 virtual void SetRandomMmapSeed(int64_t seed) = 0; 0569 0570 /** 0571 * Returns a randomized address, suitable for memory allocation under ASLR. 0572 * The address will be aligned to AllocatePageSize. 0573 */ 0574 virtual void* GetRandomMmapAddr() = 0; 0575 0576 /** 0577 * Memory permissions. 0578 */ 0579 enum Permission { 0580 kNoAccess, 0581 kRead, 0582 kReadWrite, 0583 kReadWriteExecute, 0584 kReadExecute, 0585 // Set this when reserving memory that will later require kReadWriteExecute 0586 // permissions. The resulting behavior is platform-specific, currently 0587 // this is used to set the MAP_JIT flag on Apple Silicon. 0588 // TODO(jkummerow): Remove this when Wasm has a platform-independent 0589 // w^x implementation. 0590 // TODO(saelo): Remove this once all JIT pages are allocated through the 0591 // VirtualAddressSpace API. 0592 kNoAccessWillJitLater 0593 }; 0594 0595 /** 0596 * Optional hints for AllocatePages(). 0597 */ 0598 class AllocationHint final { 0599 public: 0600 AllocationHint() = default; 0601 0602 V8_WARN_UNUSED_RESULT constexpr AllocationHint WithAddress( 0603 void* address) const { 0604 return AllocationHint(address, may_grow_); 0605 } 0606 0607 V8_WARN_UNUSED_RESULT constexpr AllocationHint WithMayGrow() const { 0608 return AllocationHint(address_, true); 0609 } 0610 0611 bool MayGrow() const { return may_grow_; } 0612 void* Address() const { return address_; } 0613 0614 private: 0615 constexpr AllocationHint(void* address, bool may_grow) 0616 : address_(address), may_grow_(may_grow) {} 0617 0618 void* address_ = nullptr; 0619 bool may_grow_ = false; 0620 }; 0621 0622 /** 0623 * Allocates memory in range with the given alignment and permission. 0624 */ 0625 virtual void* AllocatePages(void* address, size_t length, size_t alignment, 0626 Permission permissions) = 0; 0627 0628 /** 0629 * Allocates memory in range with the given alignment and permission. In 0630 * addition to AllocatePages it allows to pass in allocation hints. The 0631 * underlying implementation may not make use of hints. 0632 */ 0633 virtual void* AllocatePages(size_t length, size_t alignment, 0634 Permission permissions, AllocationHint hint) { 0635 return AllocatePages(hint.Address(), length, alignment, permissions); 0636 } 0637 0638 /** 0639 * Resizes the previously allocated memory at the given address. Returns true 0640 * if the allocation could be resized. Returns false if this operation is 0641 * either not supported or the object could not be resized in-place. 0642 */ 0643 virtual bool ResizeAllocationAt(void* address, size_t old_length, 0644 size_t new_length, Permission permissions) { 0645 return false; 0646 } 0647 0648 /** 0649 * Frees memory in a range that was allocated by a call to AllocatePages. 0650 */ 0651 virtual bool FreePages(void* address, size_t length) = 0; 0652 0653 /** 0654 * Releases memory in a range that was allocated by a call to AllocatePages. 0655 */ 0656 virtual bool ReleasePages(void* address, size_t length, 0657 size_t new_length) = 0; 0658 0659 /** 0660 * Sets permissions on pages in an allocated range. 0661 */ 0662 virtual bool SetPermissions(void* address, size_t length, 0663 Permission permissions) = 0; 0664 0665 /** 0666 * Recommits discarded pages in the given range with given permissions. 0667 * Discarded pages must be recommitted with their original permissions 0668 * before they are used again. 0669 */ 0670 virtual bool RecommitPages(void* address, size_t length, 0671 Permission permissions) { 0672 // TODO(v8:12797): make it pure once it's implemented on Chromium side. 0673 return false; 0674 } 0675 0676 /** 0677 * Frees memory in the given [address, address + size) range. address and size 0678 * should be operating system page-aligned. The next write to this 0679 * memory area brings the memory transparently back. This should be treated as 0680 * a hint to the OS that the pages are no longer needed. It does not guarantee 0681 * that the pages will be discarded immediately or at all. 0682 */ 0683 virtual bool DiscardSystemPages(void* address, size_t size) { return true; } 0684 0685 /** 0686 * Decommits any wired memory pages in the given range, allowing the OS to 0687 * reclaim them, and marks the region as inacessible (kNoAccess). The address 0688 * range stays reserved and can be accessed again later by changing its 0689 * permissions. However, in that case the memory content is guaranteed to be 0690 * zero-initialized again. The memory must have been previously allocated by a 0691 * call to AllocatePages. Returns true on success, false otherwise. 0692 */ 0693 virtual bool DecommitPages(void* address, size_t size) = 0; 0694 0695 /** 0696 * Block any modifications to the given mapping such as changing permissions 0697 * or unmapping the pages on supported platforms. 0698 * The address space reservation will exist until the process ends, but it's 0699 * possible to release the memory using DiscardSystemPages. Note that this 0700 * might require write permissions to the page as e.g. on Linux, mseal will 0701 * block discarding sealed anonymous memory. 0702 */ 0703 virtual bool SealPages(void* address, size_t length) { 0704 // TODO(360048056): make it pure once it's implemented on Chromium side. 0705 return false; 0706 } 0707 0708 /** 0709 * INTERNAL ONLY: This interface has not been stabilised and may change 0710 * without notice from one release to another without being deprecated first. 0711 */ 0712 class SharedMemoryMapping { 0713 public: 0714 // Implementations are expected to free the shared memory mapping in the 0715 // destructor. 0716 virtual ~SharedMemoryMapping() = default; 0717 virtual void* GetMemory() const = 0; 0718 }; 0719 0720 /** 0721 * INTERNAL ONLY: This interface has not been stabilised and may change 0722 * without notice from one release to another without being deprecated first. 0723 */ 0724 class SharedMemory { 0725 public: 0726 // Implementations are expected to free the shared memory in the destructor. 0727 virtual ~SharedMemory() = default; 0728 virtual std::unique_ptr<SharedMemoryMapping> RemapTo( 0729 void* new_address) const = 0; 0730 virtual void* GetMemory() const = 0; 0731 virtual size_t GetSize() const = 0; 0732 }; 0733 0734 /** 0735 * INTERNAL ONLY: This interface has not been stabilised and may change 0736 * without notice from one release to another without being deprecated first. 0737 * 0738 * Reserve pages at a fixed address returning whether the reservation is 0739 * possible. The reserved memory is detached from the PageAllocator and so 0740 * should not be freed by it. It's intended for use with 0741 * SharedMemory::RemapTo, where ~SharedMemoryMapping would free the memory. 0742 */ 0743 virtual bool ReserveForSharedMemoryMapping(void* address, size_t size) { 0744 return false; 0745 } 0746 0747 /** 0748 * INTERNAL ONLY: This interface has not been stabilised and may change 0749 * without notice from one release to another without being deprecated first. 0750 * 0751 * Allocates shared memory pages. Not all PageAllocators need support this and 0752 * so this method need not be overridden. 0753 * Allocates a new read-only shared memory region of size |length| and copies 0754 * the memory at |original_address| into it. 0755 */ 0756 virtual std::unique_ptr<SharedMemory> AllocateSharedPages( 0757 size_t length, const void* original_address) { 0758 return {}; 0759 } 0760 0761 /** 0762 * INTERNAL ONLY: This interface has not been stabilised and may change 0763 * without notice from one release to another without being deprecated first. 0764 * 0765 * If not overridden and changed to return true, V8 will not attempt to call 0766 * AllocateSharedPages or RemapSharedPages. If overridden, AllocateSharedPages 0767 * and RemapSharedPages must also be overridden. 0768 */ 0769 virtual bool CanAllocateSharedPages() { return false; } 0770 }; 0771 0772 /** 0773 * An allocator that uses per-thread permissions to protect the memory. 0774 * 0775 * The implementation is platform/hardware specific, e.g. using pkeys on x64. 0776 * 0777 * INTERNAL ONLY: This interface has not been stabilised and may change 0778 * without notice from one release to another without being deprecated first. 0779 */ 0780 class ThreadIsolatedAllocator { 0781 public: 0782 virtual ~ThreadIsolatedAllocator() = default; 0783 0784 virtual void* Allocate(size_t size) = 0; 0785 0786 virtual void Free(void* object) = 0; 0787 0788 enum class Type { 0789 kPkey, 0790 }; 0791 0792 virtual Type Type() const = 0; 0793 0794 /** 0795 * Return the pkey used to implement the thread isolation if Type == kPkey. 0796 */ 0797 virtual int Pkey() const { return -1; } 0798 }; 0799 0800 /** 0801 * Possible permissions for memory pages. 0802 */ 0803 enum class PagePermissions { 0804 kNoAccess = 0, 0805 kRead = 1, 0806 kWrite = 2, 0807 kExecute = 4, 0808 kReadWrite = kRead | kWrite, 0809 kReadExecute = kRead | kExecute, 0810 kWriteExecute = kWrite | kExecute, 0811 kReadWriteExecute = kRead | kWrite | kExecute, 0812 }; 0813 0814 inline constexpr PagePermissions operator|(PagePermissions lhs, 0815 PagePermissions rhs) { 0816 return static_cast<PagePermissions>(static_cast<int>(lhs) | 0817 static_cast<int>(rhs)); 0818 } 0819 0820 inline constexpr PagePermissions operator&(PagePermissions lhs, 0821 PagePermissions rhs) { 0822 return static_cast<PagePermissions>(static_cast<int>(lhs) & 0823 static_cast<int>(rhs)); 0824 } 0825 0826 inline PagePermissions& operator|=(PagePermissions& lhs, PagePermissions rhs) { 0827 lhs = lhs | rhs; 0828 return lhs; 0829 } 0830 0831 /** 0832 * Helper routine to determine whether one set of page permissions (the lhs) is 0833 * a subset of another one (the rhs). 0834 */ 0835 inline constexpr bool IsSubset(PagePermissions lhs, PagePermissions rhs) { 0836 return (lhs & rhs) == lhs; 0837 } 0838 0839 /** 0840 * Class to manage a virtual memory address space. 0841 * 0842 * This class represents a contiguous region of virtual address space in which 0843 * sub-spaces and (private or shared) memory pages can be allocated, freed, and 0844 * modified. This interface is meant to eventually replace the PageAllocator 0845 * interface, and can be used as an alternative in the meantime. 0846 * 0847 * This API is not yet stable and may change without notice! 0848 */ 0849 class VirtualAddressSpace { 0850 public: 0851 using Address = uintptr_t; 0852 0853 VirtualAddressSpace(size_t page_size, size_t allocation_granularity, 0854 Address base, size_t size, 0855 PagePermissions max_page_permissions) 0856 : page_size_(page_size), 0857 allocation_granularity_(allocation_granularity), 0858 base_(base), 0859 size_(size), 0860 max_page_permissions_(max_page_permissions) {} 0861 0862 virtual ~VirtualAddressSpace() = default; 0863 0864 /** 0865 * The page size used inside this space. Guaranteed to be a power of two. 0866 * Used as granularity for all page-related operations except for allocation, 0867 * which use the allocation_granularity(), see below. 0868 * 0869 * \returns the page size in bytes. 0870 */ 0871 size_t page_size() const { return page_size_; } 0872 0873 /** 0874 * The granularity of page allocations and, by extension, of subspace 0875 * allocations. This is guaranteed to be a power of two and a multiple of the 0876 * page_size(). In practice, this is equal to the page size on most OSes, but 0877 * on Windows it is usually 64KB, while the page size is 4KB. 0878 * 0879 * \returns the allocation granularity in bytes. 0880 */ 0881 size_t allocation_granularity() const { return allocation_granularity_; } 0882 0883 /** 0884 * The base address of the address space managed by this instance. 0885 * 0886 * \returns the base address of this address space. 0887 */ 0888 Address base() const { return base_; } 0889 0890 /** 0891 * The size of the address space managed by this instance. 0892 * 0893 * \returns the size of this address space in bytes. 0894 */ 0895 size_t size() const { return size_; } 0896 0897 /** 0898 * The maximum page permissions that pages allocated inside this space can 0899 * obtain. 0900 * 0901 * \returns the maximum page permissions. 0902 */ 0903 PagePermissions max_page_permissions() const { return max_page_permissions_; } 0904 0905 /** 0906 * Whether the |address| is inside the address space managed by this instance. 0907 * 0908 * \returns true if it is inside the address space, false if not. 0909 */ 0910 bool Contains(Address address) const { 0911 return (address >= base()) && (address < base() + size()); 0912 } 0913 0914 /** 0915 * Sets the random seed so that GetRandomPageAddress() will generate 0916 * repeatable sequences of random addresses. 0917 * 0918 * \param The seed for the PRNG. 0919 */ 0920 virtual void SetRandomSeed(int64_t seed) = 0; 0921 0922 /** 0923 * Returns a random address inside this address space, suitable for page 0924 * allocations hints. 0925 * 0926 * \returns a random address aligned to allocation_granularity(). 0927 */ 0928 virtual Address RandomPageAddress() = 0; 0929 0930 /** 0931 * Allocates private memory pages with the given alignment and permissions. 0932 * 0933 * \param hint If nonzero, the allocation is attempted to be placed at the 0934 * given address first. If that fails, the allocation is attempted to be 0935 * placed elsewhere, possibly nearby, but that is not guaranteed. Specifying 0936 * zero for the hint always causes this function to choose a random address. 0937 * The hint, if specified, must be aligned to the specified alignment. 0938 * 0939 * \param size The size of the allocation in bytes. Must be a multiple of the 0940 * allocation_granularity(). 0941 * 0942 * \param alignment The alignment of the allocation in bytes. Must be a 0943 * multiple of the allocation_granularity() and should be a power of two. 0944 * 0945 * \param permissions The page permissions of the newly allocated pages. 0946 * 0947 * \returns the start address of the allocated pages on success, zero on 0948 * failure. 0949 */ 0950 static constexpr Address kNoHint = 0; 0951 virtual V8_WARN_UNUSED_RESULT Address 0952 AllocatePages(Address hint, size_t size, size_t alignment, 0953 PagePermissions permissions) = 0; 0954 0955 /** 0956 * Frees previously allocated pages. 0957 * 0958 * This function will terminate the process on failure as this implies a bug 0959 * in the client. As such, there is no return value. 0960 * 0961 * \param address The start address of the pages to free. This address must 0962 * have been obtained through a call to AllocatePages. 0963 * 0964 * \param size The size in bytes of the region to free. This must match the 0965 * size passed to AllocatePages when the pages were allocated. 0966 */ 0967 virtual void FreePages(Address address, size_t size) = 0; 0968 0969 /** 0970 * Sets permissions of all allocated pages in the given range. 0971 * 0972 * This operation can fail due to OOM, in which case false is returned. If 0973 * the operation fails for a reason other than OOM, this function will 0974 * terminate the process as this implies a bug in the client. 0975 * 0976 * \param address The start address of the range. Must be aligned to 0977 * page_size(). 0978 * 0979 * \param size The size in bytes of the range. Must be a multiple 0980 * of page_size(). 0981 * 0982 * \param permissions The new permissions for the range. 0983 * 0984 * \returns true on success, false on OOM. 0985 */ 0986 virtual V8_WARN_UNUSED_RESULT bool SetPagePermissions( 0987 Address address, size_t size, PagePermissions permissions) = 0; 0988 0989 /** 0990 * Creates a guard region at the specified address. 0991 * 0992 * Guard regions are guaranteed to cause a fault when accessed and generally 0993 * do not count towards any memory consumption limits. Further, allocating 0994 * guard regions can usually not fail in subspaces if the region does not 0995 * overlap with another region, subspace, or page allocation. 0996 * 0997 * \param address The start address of the guard region. Must be aligned to 0998 * the allocation_granularity(). 0999 * 1000 * \param size The size of the guard region in bytes. Must be a multiple of 1001 * the allocation_granularity(). 1002 * 1003 * \returns true on success, false otherwise. 1004 */ 1005 virtual V8_WARN_UNUSED_RESULT bool AllocateGuardRegion(Address address, 1006 size_t size) = 0; 1007 1008 /** 1009 * Frees an existing guard region. 1010 * 1011 * This function will terminate the process on failure as this implies a bug 1012 * in the client. As such, there is no return value. 1013 * 1014 * \param address The start address of the guard region to free. This address 1015 * must have previously been used as address parameter in a successful 1016 * invocation of AllocateGuardRegion. 1017 * 1018 * \param size The size in bytes of the guard region to free. This must match 1019 * the size passed to AllocateGuardRegion when the region was created. 1020 */ 1021 virtual void FreeGuardRegion(Address address, size_t size) = 0; 1022 1023 /** 1024 * Allocates shared memory pages with the given permissions. 1025 * 1026 * \param hint Placement hint. See AllocatePages. 1027 * 1028 * \param size The size of the allocation in bytes. Must be a multiple of the 1029 * allocation_granularity(). 1030 * 1031 * \param permissions The page permissions of the newly allocated pages. 1032 * 1033 * \param handle A platform-specific handle to a shared memory object. See 1034 * the SharedMemoryHandleFromX routines above for ways to obtain these. 1035 * 1036 * \param offset The offset in the shared memory object at which the mapping 1037 * should start. Must be a multiple of the allocation_granularity(). 1038 * 1039 * \returns the start address of the allocated pages on success, zero on 1040 * failure. 1041 */ 1042 virtual V8_WARN_UNUSED_RESULT Address 1043 AllocateSharedPages(Address hint, size_t size, PagePermissions permissions, 1044 SharedMemoryHandle handle, uint64_t offset) = 0; 1045 1046 // TODO(https://crbug.com/463925491): Remove me once API users change from 1047 // PlatformSharedMemoryHandle to SharedMemoryHandle. 1048 V8_DEPRECATE_SOON("Use AllocateSharedPages() with SharedMemoryHandle") 1049 V8_WARN_UNUSED_RESULT Address AllocateSharedPages( 1050 Address hint, size_t size, PagePermissions permissions, 1051 std::optional<SharedMemoryHandle> handle, uint64_t offset) { 1052 return AllocateSharedPages(hint, size, permissions, *handle, offset); 1053 } 1054 1055 /** 1056 * Frees previously allocated shared pages. 1057 * 1058 * This function will terminate the process on failure as this implies a bug 1059 * in the client. As such, there is no return value. 1060 * 1061 * \param address The start address of the pages to free. This address must 1062 * have been obtained through a call to AllocateSharedPages. 1063 * 1064 * \param size The size in bytes of the region to free. This must match the 1065 * size passed to AllocateSharedPages when the pages were allocated. 1066 */ 1067 virtual void FreeSharedPages(Address address, size_t size) = 0; 1068 1069 /** 1070 * Memory protection key support. 1071 * 1072 * If supported by the hardware and operating system, virtual address spaces 1073 * can use memory protection keys in addition to the regular page 1074 * permissions. The MemoryProtectionKeyId type identifies a memory protection 1075 * key and is used by the related APIs in this class. 1076 * 1077 * TODO(saelo): consider renaming to just MemoryProtectionKey, but currently 1078 * there's a naming conflict with base::MemoryProtectionKey. 1079 */ 1080 using MemoryProtectionKeyId = int; 1081 1082 /** 1083 * The memory protection key used by this space, if any. 1084 * 1085 * If this space uses a memory protection key, then all memory pages in it 1086 * will have this key set. In that case, this API will return that key. 1087 * 1088 * \returns the memory protection key used by this space or std::nullopt. 1089 */ 1090 virtual std::optional<MemoryProtectionKeyId> ActiveMemoryProtectionKey() = 0; 1091 1092 /** 1093 * Whether this instance can allocate subspaces or not. 1094 * 1095 * \returns true if subspaces can be allocated, false if not. 1096 */ 1097 virtual bool CanAllocateSubspaces() = 0; 1098 1099 /* 1100 * Allocate a subspace. 1101 * 1102 * The address space of a subspace stays reserved in the parent space for the 1103 * lifetime of the subspace. As such, it is guaranteed that page allocations 1104 * on the parent space cannot end up inside a subspace. 1105 * 1106 * \param hint Hints where the subspace should be allocated. See 1107 * AllocatePages() for more details. 1108 * 1109 * \param size The size in bytes of the subspace. Must be a multiple of the 1110 * allocation_granularity(). 1111 * 1112 * \param alignment The alignment of the subspace in bytes. Must be a multiple 1113 * of the allocation_granularity() and should be a power of two. 1114 * 1115 * \param max_page_permissions The maximum permissions that pages allocated in 1116 * the subspace can obtain. 1117 * 1118 * \param key Optional memory protection key for the subspace. If used, the 1119 * returned subspace will use this key for all its memory pages. 1120 * 1121 * \param handle Optional file descriptor for the subspace. If used, the 1122 * returned subspace will use this file descriptor with 0 offset as the 1123 * space's underlying file. 1124 * 1125 * \returns a new subspace or nullptr on failure. 1126 */ 1127 virtual std::unique_ptr<VirtualAddressSpace> AllocateSubspace( 1128 Address hint, size_t size, size_t alignment, 1129 PagePermissions max_page_permissions, 1130 std::optional<MemoryProtectionKeyId> key = std::nullopt, 1131 std::optional<SharedMemoryHandle> handle = std::nullopt) = 0; 1132 1133 // 1134 // TODO(v8) maybe refactor the methods below before stabilizing the API. For 1135 // example by combining them into some form of page operation method that 1136 // takes a command enum as parameter. 1137 // 1138 1139 /** 1140 * Recommits discarded pages in the given range with given permissions. 1141 * Discarded pages must be recommitted with their original permissions 1142 * before they are used again. 1143 * 1144 * \param address The start address of the range. Must be aligned to 1145 * page_size(). 1146 * 1147 * \param size The size in bytes of the range. Must be a multiple 1148 * of page_size(). 1149 * 1150 * \param permissions The permissions for the range that the pages must have. 1151 * 1152 * \returns true on success, false otherwise. 1153 */ 1154 virtual V8_WARN_UNUSED_RESULT bool RecommitPages( 1155 Address address, size_t size, PagePermissions permissions) = 0; 1156 1157 /** 1158 * Frees memory in the given [address, address + size) range. address and 1159 * size should be aligned to the page_size(). The next write to this memory 1160 * area brings the memory transparently back. This should be treated as a 1161 * hint to the OS that the pages are no longer needed. It does not guarantee 1162 * that the pages will be discarded immediately or at all. 1163 * 1164 * \returns true on success, false otherwise. Since this method is only a 1165 * hint, a successful invocation does not imply that pages have been removed. 1166 */ 1167 virtual V8_WARN_UNUSED_RESULT bool DiscardSystemPages(Address address, 1168 size_t size) { 1169 return true; 1170 } 1171 /** 1172 * Decommits any wired memory pages in the given range, allowing the OS to 1173 * reclaim them, and marks the region as inacessible (kNoAccess). The address 1174 * range stays reserved and can be accessed again later by changing its 1175 * permissions. However, in that case the memory content is guaranteed to be 1176 * zero-initialized again. The memory must have been previously allocated by a 1177 * call to AllocatePages. 1178 * 1179 * \returns true on success, false otherwise. 1180 */ 1181 virtual V8_WARN_UNUSED_RESULT bool DecommitPages(Address address, 1182 size_t size) = 0; 1183 1184 /** 1185 * Sets a name for the address space. 1186 * 1187 * This is mostly useful for debugging tools. If supported by the system, the 1188 * name will for example show up in /proc/$pid/maps next to the virtual 1189 * address reservation: 1190 * 1191 * 2ae700000000-2ae700010000 r--p 00000000 00:00 0 [anon:foo-bar] 1192 * 1193 * \param name The name of the address space. The name must only contain 1194 * alphanumeric characters or dashes. 1195 * 1196 * \returns true on success, false otherwise. 1197 */ 1198 virtual bool SetName(const std::string& name) { return false; } 1199 1200 private: 1201 const size_t page_size_; 1202 const size_t allocation_granularity_; 1203 const Address base_; 1204 const size_t size_; 1205 const PagePermissions max_page_permissions_; 1206 }; 1207 1208 /** 1209 * Observer used by V8 to notify the embedder about entering/leaving sections 1210 * with high throughput of malloc/free operations. 1211 */ 1212 class HighAllocationThroughputObserver { 1213 public: 1214 virtual void EnterSection() {} 1215 virtual void LeaveSection() {} 1216 }; 1217 1218 /** 1219 * V8 Platform abstraction layer. 1220 * 1221 * The embedder has to provide an implementation of this interface before 1222 * initializing the rest of V8. 1223 */ 1224 class Platform { 1225 public: 1226 virtual ~Platform() = default; 1227 1228 /** 1229 * Allows the embedder to manage memory page allocations. 1230 * Returning nullptr will cause V8 to use the default page allocator. 1231 */ 1232 virtual PageAllocator* GetPageAllocator() { return nullptr; } 1233 1234 /** 1235 * Allows the embedder to provide an allocator that uses per-thread memory 1236 * permissions to protect allocations. 1237 * Returning nullptr will cause V8 to disable protections that rely on this 1238 * feature. 1239 */ 1240 virtual ThreadIsolatedAllocator* GetThreadIsolatedAllocator() { 1241 return nullptr; 1242 } 1243 1244 /** 1245 * Enables the embedder to respond in cases where V8 can't allocate large 1246 * blocks of memory. V8 retries the failed allocation once after calling this 1247 * method. On success, execution continues; otherwise V8 exits with a fatal 1248 * error. 1249 * Embedder overrides of this function must NOT call back into V8. 1250 */ 1251 virtual void OnCriticalMemoryPressure() {} 1252 1253 /** 1254 * Gets the max number of worker threads that may be used to execute 1255 * concurrent work scheduled for any single TaskPriority by 1256 * Call(BlockingTask)OnWorkerThread() or PostJob(). This can be used to 1257 * estimate the number of tasks a work package should be split into. A return 1258 * value of 0 means that there are no worker threads available. Note that a 1259 * value of 0 won't prohibit V8 from posting tasks using |CallOnWorkerThread|. 1260 */ 1261 virtual int NumberOfWorkerThreads() = 0; 1262 1263 /** 1264 * Returns a TaskRunner which can be used to post a task on the foreground. 1265 * The TaskRunner's NonNestableTasksEnabled() must be true. This function 1266 * should only be called from a foreground thread. 1267 */ 1268 std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner(Isolate* isolate) { 1269 return GetForegroundTaskRunner(isolate, TaskPriority::kUserBlocking); 1270 } 1271 1272 /** 1273 * Returns a TaskRunner with a specific |priority| which can be used to post a 1274 * task on the foreground thread. The TaskRunner's NonNestableTasksEnabled() 1275 * must be true. This function should only be called from a foreground thread. 1276 */ 1277 virtual std::shared_ptr<v8::TaskRunner> GetForegroundTaskRunner( 1278 Isolate* isolate, TaskPriority priority) = 0; 1279 1280 /** 1281 * Schedules a task to be invoked on a worker thread. 1282 * Embedders should override PostTaskOnWorkerThreadImpl() instead of 1283 * CallOnWorkerThread(). 1284 */ 1285 V8_DEPRECATE_SOON("Use PostTaskOnWorkerThread instead.") 1286 void CallOnWorkerThread(std::unique_ptr<Task> task, 1287 SourceLocation location = SourceLocation::Current()) { 1288 PostTaskOnWorkerThreadImpl(TaskPriority::kUserVisible, std::move(task), 1289 location); 1290 } 1291 1292 /** 1293 * Schedules a task that blocks the main thread to be invoked with 1294 * high-priority on a worker thread. 1295 * Embedders should override PostTaskOnWorkerThreadImpl() instead of 1296 * CallBlockingTaskOnWorkerThread(). 1297 */ 1298 V8_DEPRECATE_SOON("Use PostTaskOnWorkerThread instead.") 1299 void CallBlockingTaskOnWorkerThread( 1300 std::unique_ptr<Task> task, 1301 SourceLocation location = SourceLocation::Current()) { 1302 // Embedders may optionally override this to process these tasks in a high 1303 // priority pool. 1304 PostTaskOnWorkerThreadImpl(TaskPriority::kUserBlocking, std::move(task), 1305 location); 1306 } 1307 1308 /** 1309 * Schedules a task to be invoked with low-priority on a worker thread. 1310 * Embedders should override PostTaskOnWorkerThreadImpl() instead of 1311 * CallLowPriorityTaskOnWorkerThread(). 1312 */ 1313 V8_DEPRECATE_SOON("Use PostTaskOnWorkerThread instead.") 1314 void CallLowPriorityTaskOnWorkerThread( 1315 std::unique_ptr<Task> task, 1316 SourceLocation location = SourceLocation::Current()) { 1317 // Embedders may optionally override this to process these tasks in a low 1318 // priority pool. 1319 PostTaskOnWorkerThreadImpl(TaskPriority::kBestEffort, std::move(task), 1320 location); 1321 } 1322 1323 /** 1324 * Schedules a task to be invoked on a worker thread after |delay_in_seconds| 1325 * expires. 1326 * Embedders should override PostDelayedTaskOnWorkerThreadImpl() instead of 1327 * CallDelayedOnWorkerThread(). 1328 */ 1329 V8_DEPRECATE_SOON("Use PostDelayedTaskOnWorkerThread instead.") 1330 void CallDelayedOnWorkerThread( 1331 std::unique_ptr<Task> task, double delay_in_seconds, 1332 SourceLocation location = SourceLocation::Current()) { 1333 PostDelayedTaskOnWorkerThreadImpl(TaskPriority::kUserVisible, 1334 std::move(task), delay_in_seconds, 1335 location); 1336 } 1337 1338 /** 1339 * Schedules a task to be invoked on a worker thread. 1340 * Embedders should override PostTaskOnWorkerThreadImpl() instead of 1341 * PostTaskOnWorkerThread(). 1342 */ 1343 void PostTaskOnWorkerThread( 1344 TaskPriority priority, std::unique_ptr<Task> task, 1345 SourceLocation location = SourceLocation::Current()) { 1346 PostTaskOnWorkerThreadImpl(priority, std::move(task), location); 1347 } 1348 1349 /** 1350 * Schedules a task to be invoked on a worker thread after |delay_in_seconds| 1351 * expires. 1352 * Embedders should override PostDelayedTaskOnWorkerThreadImpl() instead of 1353 * PostDelayedTaskOnWorkerThread(). 1354 */ 1355 void PostDelayedTaskOnWorkerThread( 1356 TaskPriority priority, std::unique_ptr<Task> task, 1357 double delay_in_seconds, 1358 SourceLocation location = SourceLocation::Current()) { 1359 PostDelayedTaskOnWorkerThreadImpl(priority, std::move(task), 1360 delay_in_seconds, location); 1361 } 1362 1363 /** 1364 * Returns true if idle tasks are enabled for the given |isolate|. 1365 */ 1366 virtual bool IdleTasksEnabled(Isolate* isolate) { return false; } 1367 1368 /** 1369 * Posts |job_task| to run in parallel. Returns a JobHandle associated with 1370 * the Job, which can be joined or canceled. 1371 * This avoids degenerate cases: 1372 * - Calling CallOnWorkerThread() for each work item, causing significant 1373 * overhead. 1374 * - Fixed number of CallOnWorkerThread() calls that split the work and might 1375 * run for a long time. This is problematic when many components post 1376 * "num cores" tasks and all expect to use all the cores. In these cases, 1377 * the scheduler lacks context to be fair to multiple same-priority requests 1378 * and/or ability to request lower priority work to yield when high priority 1379 * work comes in. 1380 * A canonical implementation of |job_task| looks like: 1381 * class MyJobTask : public JobTask { 1382 * public: 1383 * MyJobTask(...) : worker_queue_(...) {} 1384 * // JobTask: 1385 * void Run(JobDelegate* delegate) override { 1386 * while (!delegate->ShouldYield()) { 1387 * // Smallest unit of work. 1388 * auto work_item = worker_queue_.TakeWorkItem(); // Thread safe. 1389 * if (!work_item) return; 1390 * ProcessWork(work_item); 1391 * } 1392 * } 1393 * 1394 * size_t GetMaxConcurrency() const override { 1395 * return worker_queue_.GetSize(); // Thread safe. 1396 * } 1397 * }; 1398 * auto handle = PostJob(TaskPriority::kUserVisible, 1399 * std::make_unique<MyJobTask>(...)); 1400 * handle->Join(); 1401 * 1402 * PostJob() and methods of the returned JobHandle/JobDelegate, must never be 1403 * called while holding a lock that could be acquired by JobTask::Run or 1404 * JobTask::GetMaxConcurrency -- that could result in a deadlock. This is 1405 * because [1] JobTask::GetMaxConcurrency may be invoked while holding 1406 * internal lock (A), hence JobTask::GetMaxConcurrency can only use a lock (B) 1407 * if that lock is *never* held while calling back into JobHandle from any 1408 * thread (A=>B/B=>A deadlock) and [2] JobTask::Run or 1409 * JobTask::GetMaxConcurrency may be invoked synchronously from JobHandle 1410 * (B=>JobHandle::foo=>B deadlock). 1411 * Embedders should override CreateJobImpl() instead of PostJob(). 1412 */ 1413 std::unique_ptr<JobHandle> PostJob( 1414 TaskPriority priority, std::unique_ptr<JobTask> job_task, 1415 SourceLocation location = SourceLocation::Current()) { 1416 auto handle = CreateJob(priority, std::move(job_task), location); 1417 handle->NotifyConcurrencyIncrease(); 1418 return handle; 1419 } 1420 1421 /** 1422 * Creates and returns a JobHandle associated with a Job. Unlike PostJob(), 1423 * this doesn't immediately schedules |worker_task| to run; the Job is then 1424 * scheduled by calling either NotifyConcurrencyIncrease() or Join(). 1425 * 1426 * A sufficient CreateJob() implementation that uses the default Job provided 1427 * in libplatform looks like: 1428 * std::unique_ptr<JobHandle> CreateJob( 1429 * TaskPriority priority, std::unique_ptr<JobTask> job_task) override { 1430 * return v8::platform::NewDefaultJobHandle( 1431 * this, priority, std::move(job_task), NumberOfWorkerThreads()); 1432 * } 1433 * 1434 * Embedders should override CreateJobImpl() instead of CreateJob(). 1435 */ 1436 std::unique_ptr<JobHandle> CreateJob( 1437 TaskPriority priority, std::unique_ptr<JobTask> job_task, 1438 SourceLocation location = SourceLocation::Current()) { 1439 return CreateJobImpl(priority, std::move(job_task), location); 1440 } 1441 1442 /** 1443 * Instantiates a ScopedBoostablePriority to boost a thread's priority. 1444 */ 1445 virtual std::unique_ptr<ScopedBoostablePriority> 1446 CreateBoostablePriorityScope() { 1447 return nullptr; 1448 } 1449 1450 /** 1451 * Instantiates a ScopedBlockingCall to annotate a scope that may/will block. 1452 */ 1453 virtual std::unique_ptr<ScopedBlockingCall> CreateBlockingScope( 1454 BlockingType blocking_type) { 1455 return nullptr; 1456 } 1457 1458 /** 1459 * Monotonically increasing time in seconds from an arbitrary fixed point in 1460 * the past. This function is expected to return at least 1461 * millisecond-precision values. For this reason, 1462 * it is recommended that the fixed point be no further in the past than 1463 * the epoch. 1464 **/ 1465 virtual double MonotonicallyIncreasingTime() = 0; 1466 1467 /** 1468 * Current wall-clock time in milliseconds since epoch. Use 1469 * CurrentClockTimeMillisHighResolution() when higher precision is 1470 * required. 1471 */ 1472 virtual int64_t CurrentClockTimeMilliseconds() { 1473 return static_cast<int64_t>(floor(CurrentClockTimeMillis())); 1474 } 1475 1476 /** 1477 * This function is deprecated and will be deleted. Use either 1478 * CurrentClockTimeMilliseconds() or 1479 * CurrentClockTimeMillisecondsHighResolution(). 1480 */ 1481 virtual double CurrentClockTimeMillis() = 0; 1482 1483 /** 1484 * Same as CurrentClockTimeMilliseconds(), but with more precision. 1485 */ 1486 virtual double CurrentClockTimeMillisecondsHighResolution() { 1487 return CurrentClockTimeMillis(); 1488 } 1489 1490 typedef void (*StackTracePrinter)(); 1491 1492 /** 1493 * Returns a function pointer that print a stack trace of the current stack 1494 * on invocation. Disables printing of the stack trace if nullptr. 1495 */ 1496 virtual StackTracePrinter GetStackTracePrinter() { return nullptr; } 1497 1498 /** 1499 * Returns an instance of a v8::TracingController. This must be non-nullptr. 1500 */ 1501 virtual TracingController* GetTracingController() = 0; 1502 1503 /** 1504 * Tells the embedder to generate and upload a crashdump during an unexpected 1505 * but non-critical scenario. 1506 */ 1507 virtual void DumpWithoutCrashing() {} 1508 1509 /** 1510 * Allows the embedder to observe sections with high throughput allocation 1511 * operations. 1512 */ 1513 virtual HighAllocationThroughputObserver* 1514 GetHighAllocationThroughputObserver() { 1515 static HighAllocationThroughputObserver default_observer; 1516 return &default_observer; 1517 } 1518 1519 protected: 1520 /** 1521 * Default implementation of current wall-clock time in milliseconds 1522 * since epoch. Useful for implementing |CurrentClockTimeMillis| if 1523 * nothing special needed. 1524 */ 1525 V8_EXPORT static double SystemClockTimeMillis(); 1526 1527 /** 1528 * Creates and returns a JobHandle associated with a Job. 1529 */ 1530 virtual std::unique_ptr<JobHandle> CreateJobImpl( 1531 TaskPriority priority, std::unique_ptr<JobTask> job_task, 1532 const SourceLocation& location) = 0; 1533 1534 /** 1535 * Schedules a task with |priority| to be invoked on a worker thread. 1536 */ 1537 virtual void PostTaskOnWorkerThreadImpl(TaskPriority priority, 1538 std::unique_ptr<Task> task, 1539 const SourceLocation& location) = 0; 1540 1541 /** 1542 * Schedules a task with |priority| to be invoked on a worker thread after 1543 * |delay_in_seconds| expires. 1544 */ 1545 virtual void PostDelayedTaskOnWorkerThreadImpl( 1546 TaskPriority priority, std::unique_ptr<Task> task, 1547 double delay_in_seconds, const SourceLocation& location) = 0; 1548 }; 1549 1550 } // namespace v8 1551 1552 #endif // V8_V8_PLATFORM_H_
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|