diff --git a/win32/include/v8/libplatform/libplatform.h b/win32/include/v8/libplatform/libplatform.h index e9450456..6908aeaa 100644 --- a/win32/include/v8/libplatform/libplatform.h +++ b/win32/include/v8/libplatform/libplatform.h @@ -8,6 +8,7 @@ #include "libplatform/libplatform-export.h" #include "libplatform/v8-tracing.h" #include "v8-platform.h" // NOLINT(build/include) +#include "v8config.h" // NOLINT(build/include) namespace v8 { namespace platform { @@ -30,12 +31,15 @@ enum class MessageLoopBehavior : bool { * If |idle_task_support| is enabled then the platform will accept idle * tasks (IdleTasksEnabled will return true) and will rely on the embedder * calling v8::platform::RunIdleTasks to process the idle tasks. + * If |tracing_controller| is nullptr, the default platform will create a + * v8::platform::TracingController instance and use it. */ -V8_PLATFORM_EXPORT v8::Platform* CreateDefaultPlatform( +V8_PLATFORM_EXPORT std::unique_ptr NewDefaultPlatform( int thread_pool_size = 0, IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled, InProcessStackDumping in_process_stack_dumping = - InProcessStackDumping::kEnabled); + InProcessStackDumping::kDisabled, + std::unique_ptr tracing_controller = {}); /** * Pumps the message loop for the given isolate. @@ -43,21 +47,18 @@ V8_PLATFORM_EXPORT v8::Platform* CreateDefaultPlatform( * The caller has to make sure that this is called from the right thread. * Returns true if a task was executed, and false otherwise. Unless requested * through the |behavior| parameter, this call does not block if no task is - * pending. The |platform| has to be created using |CreateDefaultPlatform|. + * pending. The |platform| has to be created using |NewDefaultPlatform|. */ V8_PLATFORM_EXPORT bool PumpMessageLoop( v8::Platform* platform, v8::Isolate* isolate, MessageLoopBehavior behavior = MessageLoopBehavior::kDoNotWait); -V8_PLATFORM_EXPORT void EnsureEventLoopInitialized(v8::Platform* platform, - v8::Isolate* isolate); - /** * Runs pending idle tasks for at most |idle_time_in_seconds| seconds. * * The caller has to make sure that this is called from the right thread. * This call does not block if no task is pending. The |platform| has to be - * created using |CreateDefaultPlatform|. + * created using |NewDefaultPlatform|. */ V8_PLATFORM_EXPORT void RunIdleTasks(v8::Platform* platform, v8::Isolate* isolate, @@ -66,11 +67,14 @@ V8_PLATFORM_EXPORT void RunIdleTasks(v8::Platform* platform, /** * Attempts to set the tracing controller for the given platform. * - * The |platform| has to be created using |CreateDefaultPlatform|. + * The |platform| has to be created using |NewDefaultPlatform|. + * */ -V8_PLATFORM_EXPORT void SetTracingController( - v8::Platform* platform, - v8::platform::tracing::TracingController* tracing_controller); +V8_PLATFORM_EXPORT V8_DEPRECATE_SOON( + "Access the DefaultPlatform directly", + void SetTracingController( + v8::Platform* platform, + v8::platform::tracing::TracingController* tracing_controller)); } // namespace platform } // namespace v8 diff --git a/win32/include/v8/libplatform/v8-tracing.h b/win32/include/v8/libplatform/v8-tracing.h index 902f8ea9..bc249cb9 100644 --- a/win32/include/v8/libplatform/v8-tracing.h +++ b/win32/include/v8/libplatform/v8-tracing.h @@ -5,6 +5,7 @@ #ifndef V8_LIBPLATFORM_V8_TRACING_H_ #define V8_LIBPLATFORM_V8_TRACING_H_ +#include #include #include #include @@ -35,7 +36,7 @@ class V8_PLATFORM_EXPORT TraceObject { const char* as_string; }; - TraceObject() {} + TraceObject() = default; ~TraceObject(); void Initialize( char phase, const uint8_t* category_enabled_flag, const char* name, @@ -43,8 +44,8 @@ class V8_PLATFORM_EXPORT TraceObject { const char** arg_names, const uint8_t* arg_types, const uint64_t* arg_values, std::unique_ptr* arg_convertables, - unsigned int flags); - void UpdateDuration(); + unsigned int flags, int64_t timestamp, int64_t cpu_timestamp); + void UpdateDuration(int64_t timestamp, int64_t cpu_timestamp); void InitializeForTesting( char phase, const uint8_t* category_enabled_flag, const char* name, const char* scope, uint64_t id, uint64_t bind_id, int num_args, @@ -106,12 +107,14 @@ class V8_PLATFORM_EXPORT TraceObject { class V8_PLATFORM_EXPORT TraceWriter { public: - TraceWriter() {} - virtual ~TraceWriter() {} + TraceWriter() = default; + virtual ~TraceWriter() = default; virtual void AppendTraceEvent(TraceObject* trace_event) = 0; virtual void Flush() = 0; static TraceWriter* CreateJSONTraceWriter(std::ostream& stream); + static TraceWriter* CreateJSONTraceWriter(std::ostream& stream, + const std::string& tag); private: // Disallow copy and assign @@ -145,8 +148,8 @@ class V8_PLATFORM_EXPORT TraceBufferChunk { class V8_PLATFORM_EXPORT TraceBuffer { public: - TraceBuffer() {} - virtual ~TraceBuffer() {} + TraceBuffer() = default; + virtual ~TraceBuffer() = default; virtual TraceObject* AddTraceEvent(uint64_t* handle) = 0; virtual TraceObject* GetEventByHandle(uint64_t handle) = 0; @@ -209,14 +212,20 @@ class V8_PLATFORM_EXPORT TraceConfig { void operator=(const TraceConfig&) = delete; }; -class V8_PLATFORM_EXPORT TracingController { - public: - enum Mode { DISABLED = 0, RECORDING_MODE }; +#if defined(_MSC_VER) +#define V8_PLATFORM_NON_EXPORTED_BASE(code) \ + __pragma(warning(suppress : 4275)) code +#else +#define V8_PLATFORM_NON_EXPORTED_BASE(code) code +#endif // defined(_MSC_VER) - // The pointer returned from GetCategoryGroupEnabledInternal() points to a - // value with zero or more of the following bits. Used in this class only. - // The TRACE_EVENT macros should only use the value as a bool. - // These values must be in sync with macro values in TraceEvent.h in Blink. +class V8_PLATFORM_EXPORT TracingController + : public V8_PLATFORM_NON_EXPORTED_BASE(v8::TracingController) { + public: + // The pointer returned from GetCategoryGroupEnabled() points to a value with + // zero or more of the following bits. Used in this class only. The + // TRACE_EVENT macros should only use the value as a bool. These values must + // be in sync with macro values in TraceEvent.h in Blink. enum CategoryGroupEnabledFlags { // Category group enabled for the recording mode. ENABLED_FOR_RECORDING = 1 << 0, @@ -227,42 +236,58 @@ class V8_PLATFORM_EXPORT TracingController { }; TracingController(); - ~TracingController(); + ~TracingController() override; void Initialize(TraceBuffer* trace_buffer); - const uint8_t* GetCategoryGroupEnabled(const char* category_group); - static const char* GetCategoryGroupName(const uint8_t* category_enabled_flag); + + // v8::TracingController implementation. + const uint8_t* GetCategoryGroupEnabled(const char* category_group) override; uint64_t AddTraceEvent( char phase, const uint8_t* category_enabled_flag, const char* name, const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, const char** arg_names, const uint8_t* arg_types, const uint64_t* arg_values, std::unique_ptr* arg_convertables, - unsigned int flags); + unsigned int flags) override; + uint64_t AddTraceEventWithTimestamp( + char phase, const uint8_t* category_enabled_flag, const char* name, + const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, + const char** arg_names, const uint8_t* arg_types, + const uint64_t* arg_values, + std::unique_ptr* arg_convertables, + unsigned int flags, int64_t timestamp) override; void UpdateTraceEventDuration(const uint8_t* category_enabled_flag, - const char* name, uint64_t handle); + const char* name, uint64_t handle) override; + void AddTraceStateObserver( + v8::TracingController::TraceStateObserver* observer) override; + void RemoveTraceStateObserver( + v8::TracingController::TraceStateObserver* observer) override; void StartTracing(TraceConfig* trace_config); void StopTracing(); - void AddTraceStateObserver(Platform::TraceStateObserver* observer); - void RemoveTraceStateObserver(Platform::TraceStateObserver* observer); + static const char* GetCategoryGroupName(const uint8_t* category_enabled_flag); + + protected: + virtual int64_t CurrentTimestampMicroseconds(); + virtual int64_t CurrentCpuTimestampMicroseconds(); private: - const uint8_t* GetCategoryGroupEnabledInternal(const char* category_group); void UpdateCategoryGroupEnabledFlag(size_t category_index); void UpdateCategoryGroupEnabledFlags(); std::unique_ptr trace_buffer_; std::unique_ptr trace_config_; std::unique_ptr mutex_; - std::unordered_set observers_; - Mode mode_ = DISABLED; + std::unordered_set observers_; + std::atomic_bool recording_{false}; // Disallow copy and assign TracingController(const TracingController&) = delete; void operator=(const TracingController&) = delete; }; +#undef V8_PLATFORM_NON_EXPORTED_BASE + } // namespace tracing } // namespace platform } // namespace v8 diff --git a/win32/include/v8/v8-debug.h b/win32/include/v8/v8-debug.h deleted file mode 100644 index 54c0f216..00000000 --- a/win32/include/v8/v8-debug.h +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2008 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_V8_DEBUG_H_ -#define V8_V8_DEBUG_H_ - -#include "v8.h" // NOLINT(build/include) - -/** - * ATTENTION: The debugger API exposed by this file is deprecated and will be - * removed by the end of 2017. Please use the V8 inspector declared - * in include/v8-inspector.h instead. - */ -namespace v8 { - -// Debug events which can occur in the V8 JavaScript engine. -enum DebugEvent { - Break = 1, - Exception = 2, - AfterCompile = 3, - CompileError = 4, - AsyncTaskEvent = 5, -}; - -class V8_EXPORT Debug { - public: - /** - * A client object passed to the v8 debugger whose ownership will be taken by - * it. v8 is always responsible for deleting the object. - */ - class ClientData { - public: - virtual ~ClientData() {} - }; - - - /** - * A message object passed to the debug message handler. - */ - class Message { - public: - /** - * Check type of message. - */ - virtual bool IsEvent() const = 0; - virtual bool IsResponse() const = 0; - virtual DebugEvent GetEvent() const = 0; - - /** - * Indicate whether this is a response to a continue command which will - * start the VM running after this is processed. - */ - virtual bool WillStartRunning() const = 0; - - /** - * Access to execution state and event data. Don't store these cross - * callbacks as their content becomes invalid. These objects are from the - * debugger event that started the debug message loop. - */ - virtual Local GetExecutionState() const = 0; - virtual Local GetEventData() const = 0; - - /** - * Get the debugger protocol JSON. - */ - virtual Local GetJSON() const = 0; - - /** - * Get the context active when the debug event happened. Note this is not - * the current active context as the JavaScript part of the debugger is - * running in its own context which is entered at this point. - */ - virtual Local GetEventContext() const = 0; - - /** - * Client data passed with the corresponding request if any. This is the - * client_data data value passed into Debug::SendCommand along with the - * request that led to the message or NULL if the message is an event. The - * debugger takes ownership of the data and will delete it even if there is - * no message handler. - */ - virtual ClientData* GetClientData() const = 0; - - virtual Isolate* GetIsolate() const = 0; - - virtual ~Message() {} - }; - - /** - * An event details object passed to the debug event listener. - */ - class EventDetails { - public: - /** - * Event type. - */ - virtual DebugEvent GetEvent() const = 0; - - /** - * Access to execution state and event data of the debug event. Don't store - * these cross callbacks as their content becomes invalid. - */ - virtual Local GetExecutionState() const = 0; - virtual Local GetEventData() const = 0; - - /** - * Get the context active when the debug event happened. Note this is not - * the current active context as the JavaScript part of the debugger is - * running in its own context which is entered at this point. - */ - virtual Local GetEventContext() const = 0; - - /** - * Client data passed with the corresponding callback when it was - * registered. - */ - virtual Local GetCallbackData() const = 0; - - /** - * This is now a dummy that returns nullptr. - */ - virtual ClientData* GetClientData() const = 0; - - virtual Isolate* GetIsolate() const = 0; - - virtual ~EventDetails() {} - }; - - /** - * Debug event callback function. - * - * \param event_details object providing information about the debug event - * - * A EventCallback does not take possession of the event data, - * and must not rely on the data persisting after the handler returns. - */ - typedef void (*EventCallback)(const EventDetails& event_details); - - /** - * This is now a no-op. - */ - typedef void (*MessageHandler)(const Message& message); - - V8_DEPRECATED("No longer supported", static bool SetDebugEventListener( - Isolate* isolate, EventCallback that, - Local data = Local())); - - // Schedule a debugger break to happen when JavaScript code is run - // in the given isolate. - V8_DEPRECATED("No longer supported", - static void DebugBreak(Isolate* isolate)); - - // Remove scheduled debugger break in given isolate if it has not - // happened yet. - V8_DEPRECATED("No longer supported", - static void CancelDebugBreak(Isolate* isolate)); - - // Check if a debugger break is scheduled in the given isolate. - V8_DEPRECATED("No longer supported", - static bool CheckDebugBreak(Isolate* isolate)); - - // This is now a no-op. - V8_DEPRECATED("No longer supported", - static void SetMessageHandler(Isolate* isolate, - MessageHandler handler)); - - // This is now a no-op. - V8_DEPRECATED("No longer supported", - static void SendCommand(Isolate* isolate, - const uint16_t* command, int length, - ClientData* client_data = NULL)); - - /** - * Run a JavaScript function in the debugger. - * \param fun the function to call - * \param data passed as second argument to the function - * With this call the debugger is entered and the function specified is called - * with the execution state as the first argument. This makes it possible to - * get access to information otherwise not available during normal JavaScript - * execution e.g. details on stack frames. Receiver of the function call will - * be the debugger context global object, however this is a subject to change. - * The following example shows a JavaScript function which when passed to - * v8::Debug::Call will return the current line of JavaScript execution. - * - * \code - * function frame_source_line(exec_state) { - * return exec_state.frame(0).sourceLine(); - * } - * \endcode - */ - V8_DEPRECATED("No longer supported", - static MaybeLocal Call( - Local context, v8::Local fun, - Local data = Local())); - - // This is now a no-op. - V8_DEPRECATED("No longer supported", - static void ProcessDebugMessages(Isolate* isolate)); - - /** - * Debugger is running in its own context which is entered while debugger - * messages are being dispatched. This is an explicit getter for this - * debugger context. Note that the content of the debugger context is subject - * to change. The Context exists only when the debugger is active, i.e. at - * least one DebugEventListener or MessageHandler is set. - */ - V8_DEPRECATED("Use v8-inspector", - static Local GetDebugContext(Isolate* isolate)); - - /** - * While in the debug context, this method returns the top-most non-debug - * context, if it exists. - */ - V8_DEPRECATED( - "No longer supported", - static MaybeLocal GetDebuggedContext(Isolate* isolate)); - - /** - * Enable/disable LiveEdit functionality for the given Isolate - * (default Isolate if not provided). V8 will abort if LiveEdit is - * unexpectedly used. LiveEdit is enabled by default. - */ - V8_DEPRECATED("No longer supported", - static void SetLiveEditEnabled(Isolate* isolate, bool enable)); - - /** - * Returns array of internal properties specific to the value type. Result has - * the following format: [, ,...,, ]. Result array - * will be allocated in the current context. - */ - V8_DEPRECATED("No longer supported", - static MaybeLocal GetInternalProperties( - Isolate* isolate, Local value)); - - /** - * Defines if the ES2015 tail call elimination feature is enabled or not. - * The change of this flag triggers deoptimization of all functions that - * contain calls at tail position. - */ - V8_DEPRECATED("No longer supported", - static bool IsTailCallEliminationEnabled(Isolate* isolate)); - V8_DEPRECATED("No longer supported", - static void SetTailCallEliminationEnabled(Isolate* isolate, - bool enabled)); -}; - - -} // namespace v8 - - -#undef EXPORT - - -#endif // V8_V8_DEBUG_H_ diff --git a/win32/include/v8/v8-inspector.h b/win32/include/v8/v8-inspector.h index 43bf3b4f..70201358 100644 --- a/win32/include/v8/v8-inspector.h +++ b/win32/include/v8/v8-inspector.h @@ -62,7 +62,7 @@ class V8_EXPORT StringView { class V8_EXPORT StringBuffer { public: - virtual ~StringBuffer() {} + virtual ~StringBuffer() = default; virtual const StringView& string() = 0; // This method copies contents. static std::unique_ptr create(const StringView&); @@ -99,6 +99,7 @@ class V8_EXPORT V8ContextInfo { class V8_EXPORT V8StackTrace { public: + virtual StringView firstNonEmptySourceURL() const = 0; virtual bool isEmpty() const = 0; virtual StringView topSourceURL() const = 0; virtual int topLineNumber() const = 0; @@ -106,7 +107,7 @@ class V8_EXPORT V8StackTrace { virtual StringView topScriptId() const = 0; virtual StringView topFunctionName() const = 0; - virtual ~V8StackTrace() {} + virtual ~V8StackTrace() = default; virtual std::unique_ptr buildInspectorObject() const = 0; virtual std::unique_ptr toString() const = 0; @@ -117,13 +118,13 @@ class V8_EXPORT V8StackTrace { class V8_EXPORT V8InspectorSession { public: - virtual ~V8InspectorSession() {} + virtual ~V8InspectorSession() = default; // Cross-context inspectable values (DOM nodes in different worlds, etc.). class V8_EXPORT Inspectable { public: virtual v8::Local get(v8::Local) = 0; - virtual ~Inspectable() {} + virtual ~Inspectable() = default; }; virtual void addInspectedObject(std::unique_ptr) = 0; @@ -149,8 +150,9 @@ class V8_EXPORT V8InspectorSession { // Remote objects. virtual std::unique_ptr wrapObject( - v8::Local, v8::Local, - const StringView& groupName) = 0; + v8::Local, v8::Local, const StringView& groupName, + bool generatePreview) = 0; + virtual bool unwrapObject(std::unique_ptr* error, const StringView& objectId, v8::Local*, v8::Local*, @@ -160,7 +162,7 @@ class V8_EXPORT V8InspectorSession { class V8_EXPORT V8InspectorClient { public: - virtual ~V8InspectorClient() {} + virtual ~V8InspectorClient() = default; virtual void runMessageLoopOnPause(int contextGroupId) {} virtual void quitMessageLoopOnPause() {} @@ -211,17 +213,39 @@ class V8_EXPORT V8InspectorClient { // TODO(dgozman): this was added to support service worker shadow page. We // should not connect at all. virtual bool canExecuteScripts(int contextGroupId) { return true; } + + virtual void maxAsyncCallStackDepthChanged(int depth) {} + + virtual std::unique_ptr resourceNameToUrl( + const StringView& resourceName) { + return nullptr; + } +}; + +// These stack trace ids are intended to be passed between debuggers and be +// resolved later. This allows to track cross-debugger calls and step between +// them if a single client connects to multiple debuggers. +struct V8_EXPORT V8StackTraceId { + uintptr_t id; + std::pair debugger_id; + + V8StackTraceId(); + V8StackTraceId(uintptr_t id, const std::pair debugger_id); + ~V8StackTraceId() = default; + + bool IsInvalid() const; }; class V8_EXPORT V8Inspector { public: static std::unique_ptr create(v8::Isolate*, V8InspectorClient*); - virtual ~V8Inspector() {} + virtual ~V8Inspector() = default; // Contexts instrumentation. virtual void contextCreated(const V8ContextInfo&) = 0; virtual void contextDestroyed(v8::Local) = 0; virtual void resetContextGroup(int contextGroupId) = 0; + virtual v8::MaybeLocal contextById(int contextId) = 0; // Various instrumentation. virtual void idleStarted() = 0; @@ -235,6 +259,11 @@ class V8_EXPORT V8Inspector { virtual void asyncTaskFinished(void* task) = 0; virtual void allAsyncTasksCanceled() = 0; + virtual V8StackTraceId storeCurrentStackTrace( + const StringView& description) = 0; + virtual void externalAsyncTaskStarted(const V8StackTraceId& parent) = 0; + virtual void externalAsyncTaskFinished(const V8StackTraceId& parent) = 0; + // Exceptions instrumentation. virtual unsigned exceptionThrown( v8::Local, const StringView& message, @@ -247,7 +276,7 @@ class V8_EXPORT V8Inspector { // Connection. class V8_EXPORT Channel { public: - virtual ~Channel() {} + virtual ~Channel() = default; virtual void sendResponse(int callId, std::unique_ptr message) = 0; virtual void sendNotification(std::unique_ptr message) = 0; diff --git a/win32/include/v8/v8-platform.h b/win32/include/v8/v8-platform.h index 8f6d8042..556407d8 100644 --- a/win32/include/v8/v8-platform.h +++ b/win32/include/v8/v8-platform.h @@ -7,9 +7,12 @@ #include #include +#include // For abort. #include #include +#include "v8config.h" // NOLINT(build/include) + namespace v8 { class Isolate; @@ -36,6 +39,81 @@ class IdleTask { virtual void Run(double deadline_in_seconds) = 0; }; +/** + * A TaskRunner allows scheduling of tasks. The TaskRunner may still be used to + * post tasks after the isolate gets destructed, but these tasks may not get + * executed anymore. All tasks posted to a given TaskRunner will be invoked in + * sequence. Tasks can be posted from any thread. + */ +class TaskRunner { + public: + /** + * Schedules a task to be invoked by this TaskRunner. The TaskRunner + * implementation takes ownership of |task|. + */ + virtual void PostTask(std::unique_ptr task) = 0; + + /** + * Schedules a task to be invoked by this TaskRunner. The TaskRunner + * implementation takes ownership of |task|. The |task| cannot be nested + * within other task executions. + * + * Requires that |TaskRunner::NonNestableTasksEnabled()| is true. + */ + virtual void PostNonNestableTask(std::unique_ptr task) {} + + /** + * Schedules a task to be invoked by this TaskRunner. The task is scheduled + * after the given number of seconds |delay_in_seconds|. The TaskRunner + * implementation takes ownership of |task|. + */ + virtual void PostDelayedTask(std::unique_ptr task, + double delay_in_seconds) = 0; + + /** + * Schedules a task to be invoked by this TaskRunner. The task is scheduled + * after the given number of seconds |delay_in_seconds|. The TaskRunner + * implementation takes ownership of |task|. The |task| cannot be nested + * within other task executions. + * + * Requires that |TaskRunner::NonNestableDelayedTasksEnabled()| is true. + */ + virtual void PostNonNestableDelayedTask(std::unique_ptr task, + double delay_in_seconds) {} + + /** + * Schedules an idle task to be invoked by this TaskRunner. The task is + * scheduled when the embedder is idle. Requires that + * |TaskRunner::IdleTasksEnabled()| is true. Idle tasks may be reordered + * relative to other task types and may be starved for an arbitrarily long + * time if no idle time is available. The TaskRunner implementation takes + * ownership of |task|. + */ + virtual void PostIdleTask(std::unique_ptr task) = 0; + + /** + * Returns true if idle tasks are enabled for this TaskRunner. + */ + virtual bool IdleTasksEnabled() = 0; + + /** + * Returns true if non-nestable tasks are enabled for this TaskRunner. + */ + virtual bool NonNestableTasksEnabled() const { return false; } + + /** + * Returns true if non-nestable delayed tasks are enabled for this TaskRunner. + */ + virtual bool NonNestableDelayedTasksEnabled() const { return false; } + + TaskRunner() = default; + virtual ~TaskRunner() = default; + + private: + TaskRunner(const TaskRunner&) = delete; + TaskRunner& operator=(const TaskRunner&) = delete; +}; + /** * The interface represents complex arguments to trace events. */ @@ -53,88 +131,13 @@ class ConvertableToTraceFormat { }; /** - * V8 Platform abstraction layer. + * V8 Tracing controller. * - * The embedder has to provide an implementation of this interface before - * initializing the rest of V8. + * Can be implemented by an embedder to record trace events from V8. */ -class Platform { +class TracingController { public: - /** - * This enum is used to indicate whether a task is potentially long running, - * or causes a long wait. The embedder might want to use this hint to decide - * whether to execute the task on a dedicated thread. - */ - enum ExpectedRuntime { - kShortRunningTask, - kLongRunningTask - }; - - virtual ~Platform() = default; - - /** - * Gets the number of threads that are used to execute background tasks. Is - * used to estimate the number of tasks a work package should be split into. - * A return value of 0 means that there are no background threads available. - * Note that a value of 0 won't prohibit V8 from posting tasks using - * |CallOnBackgroundThread|. - */ - virtual size_t NumberOfAvailableBackgroundThreads() { return 0; } - - /** - * Schedules a task to be invoked on a background thread. |expected_runtime| - * indicates that the task will run a long time. The Platform implementation - * takes ownership of |task|. There is no guarantee about order of execution - * of tasks wrt order of scheduling, nor is there a guarantee about the - * thread the task will be run on. - */ - virtual void CallOnBackgroundThread(Task* task, - ExpectedRuntime expected_runtime) = 0; - - /** - * Schedules a task to be invoked on a foreground thread wrt a specific - * |isolate|. Tasks posted for the same isolate should be execute in order of - * scheduling. The definition of "foreground" is opaque to V8. - */ - virtual void CallOnForegroundThread(Isolate* isolate, Task* task) = 0; - - /** - * Schedules a task to be invoked on a foreground thread wrt a specific - * |isolate| after the given number of seconds |delay_in_seconds|. - * Tasks posted for the same isolate should be execute in order of - * scheduling. The definition of "foreground" is opaque to V8. - */ - virtual void CallDelayedOnForegroundThread(Isolate* isolate, Task* task, - double delay_in_seconds) = 0; - - /** - * Schedules a task to be invoked on a foreground thread wrt a specific - * |isolate| when the embedder is idle. - * Requires that SupportsIdleTasks(isolate) is true. - * Idle tasks may be reordered relative to other task types and may be - * starved for an arbitrarily long time if no idle time is available. - * The definition of "foreground" is opaque to V8. - */ - virtual void CallIdleOnForegroundThread(Isolate* isolate, IdleTask* task) { - // TODO(ulan): Make this function abstract after V8 roll in Chromium. - } - - /** - * Returns true if idle tasks are enabled for the given |isolate|. - */ - virtual bool IdleTasksEnabled(Isolate* isolate) { - // TODO(ulan): Make this function abstract after V8 roll in Chromium. - return false; - } - - /** - * Monotonically increasing time in seconds from an arbitrary fixed point in - * the past. This function is expected to return at least - * millisecond-precision values. For this reason, - * it is recommended that the fixed point be no further in the past than - * the epoch. - **/ - virtual double MonotonicallyIncreasingTime() = 0; + virtual ~TracingController() = default; /** * Called by TRACE_EVENT* macros, don't call this directly. @@ -149,37 +152,11 @@ class Platform { } /** - * Gets the category group name of the given category_enabled_flag pointer. - * Usually used while serliazing TRACE_EVENTs. - **/ - virtual const char* GetCategoryGroupName( - const uint8_t* category_enabled_flag) { - static const char dummy[] = "dummy"; - return dummy; - } - - /** - * Adds a trace event to the platform tracing system. This function call is + * Adds a trace event to the platform tracing system. These function calls are * usually the result of a TRACE_* macro from trace_event_common.h when * tracing and the category of the particular trace are enabled. It is not - * advisable to call this function on its own; it is really only meant to be - * used by the trace macros. The returned handle can be used by - * UpdateTraceEventDuration to update the duration of COMPLETE events. - */ - virtual uint64_t AddTraceEvent( - char phase, const uint8_t* category_enabled_flag, const char* name, - const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, - const char** arg_names, const uint8_t* arg_types, - const uint64_t* arg_values, unsigned int flags) { - return 0; - } - - /** - * Adds a trace event to the platform tracing system. This function call is - * usually the result of a TRACE_* macro from trace_event_common.h when - * tracing and the category of the particular trace are enabled. It is not - * advisable to call this function on its own; it is really only meant to be - * used by the trace macros. The returned handle can be used by + * advisable to call these functions on their own; they are really only meant + * to be used by the trace macros. The returned handle can be used by * UpdateTraceEventDuration to update the duration of COMPLETE events. */ virtual uint64_t AddTraceEvent( @@ -189,8 +166,16 @@ class Platform { const uint64_t* arg_values, std::unique_ptr* arg_convertables, unsigned int flags) { - return AddTraceEvent(phase, category_enabled_flag, name, scope, id, bind_id, - num_args, arg_names, arg_types, arg_values, flags); + return 0; + } + virtual uint64_t AddTraceEventWithTimestamp( + char phase, const uint8_t* category_enabled_flag, const char* name, + const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, + const char** arg_names, const uint8_t* arg_types, + const uint64_t* arg_values, + std::unique_ptr* arg_convertables, + unsigned int flags, int64_t timestamp) { + return 0; } /** @@ -212,6 +197,229 @@ class Platform { /** Removes tracing state change observer. */ virtual void RemoveTraceStateObserver(TraceStateObserver*) {} +}; + +/** + * A V8 memory page allocator. + * + * Can be implemented by an embedder to manage large host OS allocations. + */ +class PageAllocator { + public: + virtual ~PageAllocator() = default; + + /** + * Gets the page granularity for AllocatePages and FreePages. Addresses and + * lengths for those calls should be multiples of AllocatePageSize(). + */ + virtual size_t AllocatePageSize() = 0; + + /** + * Gets the page granularity for SetPermissions and ReleasePages. Addresses + * and lengths for those calls should be multiples of CommitPageSize(). + */ + virtual size_t CommitPageSize() = 0; + + /** + * Sets the random seed so that GetRandomMmapAddr() will generate repeatable + * sequences of random mmap addresses. + */ + virtual void SetRandomMmapSeed(int64_t seed) = 0; + + /** + * Returns a randomized address, suitable for memory allocation under ASLR. + * The address will be aligned to AllocatePageSize. + */ + virtual void* GetRandomMmapAddr() = 0; + + /** + * Memory permissions. + */ + enum Permission { + kNoAccess, + kRead, + kReadWrite, + // TODO(hpayer): Remove this flag. Memory should never be rwx. + kReadWriteExecute, + kReadExecute + }; + + /** + * Allocates memory in range with the given alignment and permission. + */ + virtual void* AllocatePages(void* address, size_t length, size_t alignment, + Permission permissions) = 0; + + /** + * Frees memory in a range that was allocated by a call to AllocatePages. + */ + virtual bool FreePages(void* address, size_t length) = 0; + + /** + * Releases memory in a range that was allocated by a call to AllocatePages. + */ + virtual bool ReleasePages(void* address, size_t length, + size_t new_length) = 0; + + /** + * Sets permissions on pages in an allocated range. + */ + virtual bool SetPermissions(void* address, size_t length, + Permission permissions) = 0; + + /** + * Frees memory in the given [address, address + size) range. address and size + * should be operating system page-aligned. The next write to this + * memory area brings the memory transparently back. + */ + virtual bool DiscardSystemPages(void* address, size_t size) { return true; } +}; + +/** + * V8 Platform abstraction layer. + * + * The embedder has to provide an implementation of this interface before + * initializing the rest of V8. + */ +class Platform { + public: + virtual ~Platform() = default; + + /** + * Allows the embedder to manage memory page allocations. + */ + virtual PageAllocator* GetPageAllocator() { + // TODO(bbudge) Make this abstract after all embedders implement this. + return nullptr; + } + + /** + * Enables the embedder to respond in cases where V8 can't allocate large + * blocks of memory. V8 retries the failed allocation once after calling this + * method. On success, execution continues; otherwise V8 exits with a fatal + * error. + * Embedder overrides of this function must NOT call back into V8. + */ + virtual void OnCriticalMemoryPressure() { + // TODO(bbudge) Remove this when embedders override the following method. + // See crbug.com/634547. + } + + /** + * Enables the embedder to respond in cases where V8 can't allocate large + * memory regions. The |length| parameter is the amount of memory needed. + * Returns true if memory is now available. Returns false if no memory could + * be made available. V8 will retry allocations until this method returns + * false. + * + * Embedder overrides of this function must NOT call back into V8. + */ + virtual bool OnCriticalMemoryPressure(size_t length) { return false; } + + /** + * Gets the number of worker threads used by + * Call(BlockingTask)OnWorkerThread(). This can be used to estimate the number + * of tasks a work package should be split into. A return value of 0 means + * that there are no worker threads available. Note that a value of 0 won't + * prohibit V8 from posting tasks using |CallOnWorkerThread|. + */ + virtual int NumberOfWorkerThreads() = 0; + + /** + * Returns a TaskRunner which can be used to post a task on the foreground. + * This function should only be called from a foreground thread. + */ + virtual std::shared_ptr GetForegroundTaskRunner( + Isolate* isolate) = 0; + + /** + * Schedules a task to be invoked on a worker thread. + */ + virtual void CallOnWorkerThread(std::unique_ptr task) = 0; + + /** + * Schedules a task that blocks the main thread to be invoked with + * high-priority on a worker thread. + */ + virtual void CallBlockingTaskOnWorkerThread(std::unique_ptr task) { + // Embedders may optionally override this to process these tasks in a high + // priority pool. + CallOnWorkerThread(std::move(task)); + } + + /** + * Schedules a task to be invoked with low-priority on a worker thread. + */ + virtual void CallLowPriorityTaskOnWorkerThread(std::unique_ptr task) { + // Embedders may optionally override this to process these tasks in a low + // priority pool. + CallOnWorkerThread(std::move(task)); + } + + /** + * Schedules a task to be invoked on a worker thread after |delay_in_seconds| + * expires. + */ + virtual void CallDelayedOnWorkerThread(std::unique_ptr task, + double delay_in_seconds) = 0; + + /** + * Schedules a task to be invoked on a foreground thread wrt a specific + * |isolate|. Tasks posted for the same isolate should be execute in order of + * scheduling. The definition of "foreground" is opaque to V8. + */ + V8_DEPRECATE_SOON( + "Use a taskrunner acquired by GetForegroundTaskRunner instead.", + virtual void CallOnForegroundThread(Isolate* isolate, Task* task)) = 0; + + /** + * Schedules a task to be invoked on a foreground thread wrt a specific + * |isolate| after the given number of seconds |delay_in_seconds|. + * Tasks posted for the same isolate should be execute in order of + * scheduling. The definition of "foreground" is opaque to V8. + */ + V8_DEPRECATE_SOON( + "Use a taskrunner acquired by GetForegroundTaskRunner instead.", + virtual void CallDelayedOnForegroundThread(Isolate* isolate, Task* task, + double delay_in_seconds)) = 0; + + /** + * Schedules a task to be invoked on a foreground thread wrt a specific + * |isolate| when the embedder is idle. + * Requires that SupportsIdleTasks(isolate) is true. + * Idle tasks may be reordered relative to other task types and may be + * starved for an arbitrarily long time if no idle time is available. + * The definition of "foreground" is opaque to V8. + */ + V8_DEPRECATE_SOON( + "Use a taskrunner acquired by GetForegroundTaskRunner instead.", + virtual void CallIdleOnForegroundThread(Isolate* isolate, + IdleTask* task)) { + // This must be overriden if |IdleTasksEnabled()|. + abort(); + } + + /** + * Returns true if idle tasks are enabled for the given |isolate|. + */ + virtual bool IdleTasksEnabled(Isolate* isolate) { + return false; + } + + /** + * Monotonically increasing time in seconds from an arbitrary fixed point in + * the past. This function is expected to return at least + * millisecond-precision values. For this reason, + * it is recommended that the fixed point be no further in the past than + * the epoch. + **/ + virtual double MonotonicallyIncreasingTime() = 0; + + /** + * Current wall-clock time in milliseconds since epoch. + * This function is expected to return at least millisecond-precision values. + */ + virtual double CurrentClockTimeMillis() = 0; typedef void (*StackTracePrinter)(); @@ -220,6 +428,25 @@ class Platform { * on invocation. Disables printing of the stack trace if nullptr. */ virtual StackTracePrinter GetStackTracePrinter() { return nullptr; } + + /** + * Returns an instance of a v8::TracingController. This must be non-nullptr. + */ + virtual TracingController* GetTracingController() = 0; + + /** + * Tells the embedder to generate and upload a crashdump during an unexpected + * but non-critical scenario. + */ + virtual void DumpWithoutCrashing() {} + + protected: + /** + * Default implementation of current wall-clock time in milliseconds + * since epoch. Useful for implementing |CurrentClockTimeMillis| if + * nothing special needed. + */ + V8_EXPORT static double SystemClockTimeMillis(); }; } // namespace v8 diff --git a/win32/include/v8/v8-profiler.h b/win32/include/v8/v8-profiler.h index b60d137f..672a694e 100644 --- a/win32/include/v8/v8-profiler.h +++ b/win32/include/v8/v8-profiler.h @@ -47,22 +47,8 @@ template class V8_EXPORT std::vector; namespace v8 { -/** - * TracingCpuProfiler monitors tracing being enabled/disabled - * and emits CpuProfile trace events once v8.cpu_profiler tracing category - * is enabled. It has no overhead unless the category is enabled. - */ -class V8_EXPORT TracingCpuProfiler { - public: - static std::unique_ptr Create(Isolate*); - virtual ~TracingCpuProfiler() = default; - - protected: - TracingCpuProfiler() = default; -}; - // TickSample captures the information collected for each sample. -struct TickSample { +struct V8_EXPORT TickSample { // Internal profiling (with --prof + tools/$OS-tick-processor) wants to // include the runtime function we're calling. Externally exposed tick // samples don't care. @@ -143,6 +129,20 @@ class V8_EXPORT CpuProfileNode { unsigned int hit_count; }; + // An annotation hinting at the source of a CpuProfileNode. + enum SourceType { + // User-supplied script with associated resource information. + kScript = 0, + // Native scripts and provided builtins. + kBuiltin = 1, + // Callbacks into native code. + kCallback = 2, + // VM-internal functions or state. + kInternal = 3, + // A node that failed to symbolize. + kUnresolved = 4, + }; + /** Returns function name (empty string for anonymous functions.) */ Local GetFunctionName() const; @@ -166,6 +166,12 @@ class V8_EXPORT CpuProfileNode { */ const char* GetScriptResourceNameStr() const; + /** + * Return true if the script from where the function originates is flagged as + * being shared cross-origin. + */ + bool IsScriptSharedCrossOrigin() const; + /** * Returns the number, 1-based, of the line where the function originates. * kNoLineNumberInfo if no line number information is available. @@ -208,12 +214,20 @@ class V8_EXPORT CpuProfileNode { /** Returns id of the node. The id is unique within the tree */ unsigned GetNodeId() const; + /** + * Gets the type of the source which the node was captured from. + */ + SourceType GetSourceType() const; + /** Returns child nodes count of the node. */ int GetChildrenCount() const; /** Retrieves a child node by index. */ const CpuProfileNode* GetChild(int index) const; + /** Retrieves the ancestor node, or null if the root. */ + const CpuProfileNode* GetParent() const; + /** Retrieves deopt infos for the node. */ const std::vector& GetDeoptInfos() const; @@ -273,6 +287,16 @@ class V8_EXPORT CpuProfile { void Delete(); }; +enum CpuProfilingMode { + // In the resulting CpuProfile tree, intermediate nodes in a stack trace + // (from the root to a leaf) will have line numbers that point to the start + // line of the function, rather than the line of the callsite of the child. + kLeafNodeLineNumbers, + // In the resulting CpuProfile tree, nodes are separated based on the line + // number of their callsite in their parent. + kCallerLineNumbers, +}; + /** * Interface for controlling CPU profiling. Instance of the * profiler can be created using v8::CpuProfiler::New method. @@ -286,6 +310,13 @@ class V8_EXPORT CpuProfiler { */ static CpuProfiler* New(Isolate* isolate); + /** + * Synchronously collect current stack sample in all profilers attached to + * the |isolate|. The call does not affect number of ticks recorded for + * the current top node. + */ + static void CollectSample(Isolate* isolate); + /** * Disposes the CPU profiler object. */ @@ -298,6 +329,15 @@ class V8_EXPORT CpuProfiler { */ void SetSamplingInterval(int us); + /** + * Sets whether or not the profiler should prioritize consistency of sample + * periodicity on Windows. Disabling this can greatly reduce CPU usage, but + * may result in greater variance in sample timings from the platform's + * scheduler. Defaults to enabled. This method must be called when there are + * no profiles being recorded. + */ + void SetUsePreciseSampling(bool); + /** * Starts collecting CPU profile. Title may be an empty string. It * is allowed to have several profiles being collected at @@ -309,6 +349,13 @@ class V8_EXPORT CpuProfiler { * |record_samples| parameter controls whether individual samples should * be recorded in addition to the aggregated tree. */ + void StartProfiling(Local title, CpuProfilingMode mode, + bool record_samples = false); + /** + * The same as StartProfiling above, but the CpuProfilingMode defaults to + * kLeafNodeLineNumbers mode, which was the previous default behavior of the + * profiler. + */ void StartProfiling(Local title, bool record_samples = false); /** @@ -322,12 +369,20 @@ class V8_EXPORT CpuProfiler { * Recording the forced sample does not contribute to the aggregated * profile statistics. */ - void CollectSample(); + V8_DEPRECATED("Use static CollectSample(Isolate*) instead.", + void CollectSample()); /** * Tells the profiler whether the embedder is idle. */ - void SetIdle(bool is_idle); + V8_DEPRECATED("Use Isolate::SetIdle(bool) instead.", + void SetIdle(bool is_idle)); + + /** + * Generate more detailed source positions to code objects. This results in + * better results when mapping profiling samples to script source. + */ + static void UseDetailedSourcePositionsForProfiling(Isolate* isolate); private: CpuProfiler(); @@ -389,11 +444,12 @@ class V8_EXPORT HeapGraphNode { kRegExp = 6, // RegExp. kHeapNumber = 7, // Number stored in the heap. kNative = 8, // Native object (not from V8 heap). - kSynthetic = 9, // Synthetic object, usualy used for grouping + kSynthetic = 9, // Synthetic object, usually used for grouping // snapshot items together. kConsString = 10, // Concatenated string. A pair of pointers to strings. kSlicedString = 11, // Sliced string. A fragment of another string. - kSymbol = 12 // A Symbol (ES6). + kSymbol = 12, // A Symbol (ES6). + kBigInt = 13 // BigInt. }; /** Returns node type (see HeapGraphNode::Type). */ @@ -432,7 +488,7 @@ class V8_EXPORT OutputStream { // NOLINT kContinue = 0, kAbort = 1 }; - virtual ~OutputStream() {} + virtual ~OutputStream() = default; /** Notify about the end of stream. */ virtual void EndOfStream() = 0; /** Get preferred output chunk size. Called only once. */ @@ -526,7 +582,7 @@ class V8_EXPORT ActivityControl { // NOLINT kContinue = 0, kAbort = 1 }; - virtual ~ActivityControl() {} + virtual ~ActivityControl() = default; /** * Notify about current progress. The activity can be stopped by * returning kAbort as the callback result. @@ -592,6 +648,11 @@ class V8_EXPORT AllocationProfile { */ int column_number; + /** + * Unique id of the node. + */ + uint32_t node_id; + /** * List of callees called from this node for which we have sampled * allocations. The lifetime of the children is scoped to the containing @@ -605,19 +666,111 @@ class V8_EXPORT AllocationProfile { std::vector allocations; }; + /** + * Represent a single sample recorded for an allocation. + */ + struct Sample { + /** + * id of the node in the profile tree. + */ + uint32_t node_id; + + /** + * Size of the sampled allocation object. + */ + size_t size; + + /** + * The number of objects of such size that were sampled. + */ + unsigned int count; + + /** + * Unique time-ordered id of the allocation sample. Can be used to track + * what samples were added or removed between two snapshots. + */ + uint64_t sample_id; + }; + /** * Returns the root node of the call-graph. The root node corresponds to an * empty JS call-stack. The lifetime of the returned Node* is scoped to the * containing AllocationProfile. */ virtual Node* GetRootNode() = 0; + virtual const std::vector& GetSamples() = 0; - virtual ~AllocationProfile() {} + virtual ~AllocationProfile() = default; static const int kNoLineNumberInfo = Message::kNoLineNumberInfo; static const int kNoColumnNumberInfo = Message::kNoColumnInfo; }; +/** + * An object graph consisting of embedder objects and V8 objects. + * Edges of the graph are strong references between the objects. + * The embedder can build this graph during heap snapshot generation + * to include the embedder objects in the heap snapshot. + * Usage: + * 1) Define derived class of EmbedderGraph::Node for embedder objects. + * 2) Set the build embedder graph callback on the heap profiler using + * HeapProfiler::AddBuildEmbedderGraphCallback. + * 3) In the callback use graph->AddEdge(node1, node2) to add an edge from + * node1 to node2. + * 4) To represent references from/to V8 object, construct V8 nodes using + * graph->V8Node(value). + */ +class V8_EXPORT EmbedderGraph { + public: + class Node { + public: + Node() = default; + virtual ~Node() = default; + virtual const char* Name() = 0; + virtual size_t SizeInBytes() = 0; + /** + * The corresponding V8 wrapper node if not null. + * During heap snapshot generation the embedder node and the V8 wrapper + * node will be merged into one node to simplify retaining paths. + */ + virtual Node* WrapperNode() { return nullptr; } + virtual bool IsRootNode() { return false; } + /** Must return true for non-V8 nodes. */ + virtual bool IsEmbedderNode() { return true; } + /** + * Optional name prefix. It is used in Chrome for tagging detached nodes. + */ + virtual const char* NamePrefix() { return nullptr; } + + private: + Node(const Node&) = delete; + Node& operator=(const Node&) = delete; + }; + + /** + * Returns a node corresponding to the given V8 value. Ownership is not + * transferred. The result pointer is valid while the graph is alive. + */ + virtual Node* V8Node(const v8::Local& value) = 0; + + /** + * Adds the given node to the graph and takes ownership of the node. + * Returns a raw pointer to the node that is valid while the graph is alive. + */ + virtual Node* AddNode(std::unique_ptr node) = 0; + + /** + * Adds an edge that represents a strong reference from the given + * node |from| to the given node |to|. The nodes must be added to the graph + * before calling this function. + * + * If name is nullptr, the edge will have auto-increment indexes, otherwise + * it will be named accordingly. + */ + virtual void AddEdge(Node* from, Node* to, const char* name = nullptr) = 0; + + virtual ~EmbedderGraph() = default; +}; /** * Interface for controlling heap profiling. Instance of the @@ -630,32 +783,15 @@ class V8_EXPORT HeapProfiler { kSamplingForceGC = 1 << 0, }; - typedef std::unordered_set*> - RetainerChildren; - typedef std::vector> - RetainerGroups; - typedef std::vector*, - const v8::PersistentBase*>> - RetainerEdges; - - struct RetainerInfos { - RetainerGroups groups; - RetainerEdges edges; - }; - /** - * Callback function invoked to retrieve all RetainerInfos from the embedder. + * Callback function invoked during heap snapshot generation to retrieve + * the embedder object graph. The callback should use graph->AddEdge(..) to + * add references between the objects. + * The callback must not trigger garbage collection in V8. */ - typedef RetainerInfos (*GetRetainerInfosCallback)(v8::Isolate* isolate); - - /** - * Callback function invoked for obtaining RetainedObjectInfo for - * the given JavaScript wrapper object. It is prohibited to enter V8 - * while the callback is running: only getters on the handle and - * GetPointerFromInternalField on the objects are allowed. - */ - typedef RetainedObjectInfo* (*WrapperInfoCallback)(uint16_t class_id, - Local wrapper); + typedef void (*BuildEmbedderGraphCallback)(v8::Isolate* isolate, + v8::EmbedderGraph* graph, + void* data); /** Returns the number of snapshots taken. */ int GetSnapshotCount(); @@ -701,15 +837,15 @@ class V8_EXPORT HeapProfiler { virtual const char* GetName(Local object) = 0; protected: - virtual ~ObjectNameResolver() {} + virtual ~ObjectNameResolver() = default; }; /** * Takes a heap snapshot and returns it. */ const HeapSnapshot* TakeHeapSnapshot( - ActivityControl* control = NULL, - ObjectNameResolver* global_object_name_resolver = NULL); + ActivityControl* control = nullptr, + ObjectNameResolver* global_object_name_resolver = nullptr); /** * Starts tracking of heap objects population statistics. After calling @@ -736,7 +872,7 @@ class V8_EXPORT HeapProfiler { * method. */ SnapshotObjectId GetHeapStats(OutputStream* stream, - int64_t* timestamp_us = NULL); + int64_t* timestamp_us = nullptr); /** * Stops tracking of heap objects population statistics, cleans up all @@ -784,7 +920,7 @@ class V8_EXPORT HeapProfiler { /** * Returns the sampled profile of allocations allocated (and still live) since * StartSamplingHeapProfiler was called. The ownership of the pointer is - * transfered to the caller. Returns nullptr if sampling heap profiler is not + * transferred to the caller. Returns nullptr if sampling heap profiler is not * active. */ AllocationProfile* GetAllocationProfile(); @@ -795,12 +931,10 @@ class V8_EXPORT HeapProfiler { */ void DeleteAllHeapSnapshots(); - /** Binds a callback to embedder's class ID. */ - void SetWrapperClassInfoProvider( - uint16_t class_id, - WrapperInfoCallback callback); - - void SetGetRetainerInfosCallback(GetRetainerInfosCallback callback); + void AddBuildEmbedderGraphCallback(BuildEmbedderGraphCallback callback, + void* data); + void RemoveBuildEmbedderGraphCallback(BuildEmbedderGraphCallback callback, + void* data); /** * Default value of persistent handle class ID. Must not be used to @@ -809,9 +943,6 @@ class V8_EXPORT HeapProfiler { */ static const uint16_t kPersistentHandleNoClassId = 0; - /** Returns memory used for profiler internal data and snapshots. */ - size_t GetProfilerMemorySize(); - private: HeapProfiler(); ~HeapProfiler(); @@ -819,80 +950,6 @@ class V8_EXPORT HeapProfiler { HeapProfiler& operator=(const HeapProfiler&); }; -/** - * Interface for providing information about embedder's objects - * held by global handles. This information is reported in two ways: - * - * 1. When calling AddObjectGroup, an embedder may pass - * RetainedObjectInfo instance describing the group. To collect - * this information while taking a heap snapshot, V8 calls GC - * prologue and epilogue callbacks. - * - * 2. When a heap snapshot is collected, V8 additionally - * requests RetainedObjectInfos for persistent handles that - * were not previously reported via AddObjectGroup. - * - * Thus, if an embedder wants to provide information about native - * objects for heap snapshots, it can do it in a GC prologue - * handler, and / or by assigning wrapper class ids in the following way: - * - * 1. Bind a callback to class id by calling SetWrapperClassInfoProvider. - * 2. Call SetWrapperClassId on certain persistent handles. - * - * V8 takes ownership of RetainedObjectInfo instances passed to it and - * keeps them alive only during snapshot collection. Afterwards, they - * are freed by calling the Dispose class function. - */ -class V8_EXPORT RetainedObjectInfo { // NOLINT - public: - /** Called by V8 when it no longer needs an instance. */ - virtual void Dispose() = 0; - - /** Returns whether two instances are equivalent. */ - virtual bool IsEquivalent(RetainedObjectInfo* other) = 0; - - /** - * Returns hash value for the instance. Equivalent instances - * must have the same hash value. - */ - virtual intptr_t GetHash() = 0; - - /** - * Returns human-readable label. It must be a null-terminated UTF-8 - * encoded string. V8 copies its contents during a call to GetLabel. - */ - virtual const char* GetLabel() = 0; - - /** - * Returns human-readable group label. It must be a null-terminated UTF-8 - * encoded string. V8 copies its contents during a call to GetGroupLabel. - * Heap snapshot generator will collect all the group names, create - * top level entries with these names and attach the objects to the - * corresponding top level group objects. There is a default - * implementation which is required because embedders don't have their - * own implementation yet. - */ - virtual const char* GetGroupLabel() { return GetLabel(); } - - /** - * Returns element count in case if a global handle retains - * a subgraph by holding one of its nodes. - */ - virtual intptr_t GetElementCount() { return -1; } - - /** Returns embedder's object size in bytes. */ - virtual intptr_t GetSizeInBytes() { return -1; } - - protected: - RetainedObjectInfo() {} - virtual ~RetainedObjectInfo() {} - - private: - RetainedObjectInfo(const RetainedObjectInfo&); - RetainedObjectInfo& operator=(const RetainedObjectInfo&); -}; - - /** * A struct for exporting HeapStats data from V8, using "push" model. * See HeapProfiler::GetHeapStats. @@ -905,6 +962,76 @@ struct HeapStatsUpdate { uint32_t size; // New value of size field for the interval with this index. }; +#define CODE_EVENTS_LIST(V) \ + V(Builtin) \ + V(Callback) \ + V(Eval) \ + V(Function) \ + V(InterpretedFunction) \ + V(Handler) \ + V(BytecodeHandler) \ + V(LazyCompile) \ + V(RegExp) \ + V(Script) \ + V(Stub) + +/** + * Note that this enum may be extended in the future. Please include a default + * case if this enum is used in a switch statement. + */ +enum CodeEventType { + kUnknownType = 0 +#define V(Name) , k##Name##Type + CODE_EVENTS_LIST(V) +#undef V +}; + +/** + * Representation of a code creation event + */ +class V8_EXPORT CodeEvent { + public: + uintptr_t GetCodeStartAddress(); + size_t GetCodeSize(); + Local GetFunctionName(); + Local GetScriptName(); + int GetScriptLine(); + int GetScriptColumn(); + /** + * NOTE (mmarchini): We can't allocate objects in the heap when we collect + * existing code, and both the code type and the comment are not stored in the + * heap, so we return those as const char*. + */ + CodeEventType GetCodeType(); + const char* GetComment(); + + static const char* GetCodeEventTypeName(CodeEventType code_event_type); +}; + +/** + * Interface to listen to code creation events. + */ +class V8_EXPORT CodeEventHandler { + public: + /** + * Creates a new listener for the |isolate|. The isolate must be initialized. + * The listener object must be disposed after use by calling |Dispose| method. + * Multiple listeners can be created for the same isolate. + */ + explicit CodeEventHandler(Isolate* isolate); + virtual ~CodeEventHandler(); + + virtual void Handle(CodeEvent* code_event) = 0; + + void Enable(); + void Disable(); + + private: + CodeEventHandler(); + CodeEventHandler(const CodeEventHandler&); + CodeEventHandler& operator=(const CodeEventHandler&); + void* internal_listener_; +}; } // namespace v8 diff --git a/win32/include/v8/v8-util.h b/win32/include/v8/v8-util.h index a04a5e84..24962607 100644 --- a/win32/include/v8/v8-util.h +++ b/win32/include/v8/v8-util.h @@ -25,13 +25,11 @@ enum PersistentContainerCallbackType { kNotWeak, // These correspond to v8::WeakCallbackType kWeakWithParameter, - kWeakWithInternalFields, - kWeak = kWeakWithParameter // For backwards compatibility. Deprecate. + kWeakWithInternalFields }; - /** - * A default trait implemenation for PersistentValueMap which uses std::map + * A default trait implementation for PersistentValueMap which uses std::map * as a backing map. * * Users will have to implement their own weak callbacks & dispose traits. @@ -94,11 +92,11 @@ class DefaultPersistentValueMapTraits : public StdMapTraits { static WeakCallbackDataType* WeakCallbackParameter( MapType* map, const K& key, Local value) { - return NULL; + return nullptr; } static MapType* MapFromWeakCallbackInfo( const WeakCallbackInfo& data) { - return NULL; + return nullptr; } static K KeyFromWeakCallbackInfo( const WeakCallbackInfo& data) { @@ -196,26 +194,13 @@ class PersistentValueMapBase { return SetReturnValueFromVal(&returnValue, Traits::Get(&impl_, key)); } - /** - * Call Isolate::SetReference with the given parent and the map value. - */ - void SetReference(const K& key, - const Persistent& parent) { - GetIsolate()->SetReference( - reinterpret_cast(parent.val_), - reinterpret_cast(FromVal(Traits::Get(&impl_, key)))); - } - /** * Call V8::RegisterExternallyReferencedObject with the map value for given * key. */ - void RegisterExternallyReferencedObject(K& key) { - assert(Contains(key)); - V8::RegisterExternallyReferencedObject( - reinterpret_cast(FromVal(Traits::Get(&impl_, key))), - reinterpret_cast(GetIsolate())); - } + V8_DEPRECATED( + "Used TracedGlobal and EmbedderHeapTracer::RegisterEmbedderReference", + inline void RegisterExternallyReferencedObject(K& key)); /** * Return value for key and remove it from the map. @@ -299,7 +284,10 @@ class PersistentValueMapBase { } protected: - explicit PersistentValueMapBase(Isolate* isolate) : isolate_(isolate) {} + explicit PersistentValueMapBase(Isolate* isolate) + : isolate_(isolate), label_(nullptr) {} + PersistentValueMapBase(Isolate* isolate, const char* label) + : isolate_(isolate), label_(label) {} ~PersistentValueMapBase() { Clear(); } @@ -312,7 +300,7 @@ class PersistentValueMapBase { static PersistentContainerValue ClearAndLeak(Global* persistent) { V* v = persistent->val_; - persistent->val_ = 0; + persistent->val_ = nullptr; return reinterpret_cast(v); } @@ -341,6 +329,10 @@ class PersistentValueMapBase { p.Reset(); } + void AnnotateStrongRetainer(Global* persistent) { + persistent->AnnotateStrongRetainer(label_); + } + private: PersistentValueMapBase(PersistentValueMapBase&); void operator=(PersistentValueMapBase&); @@ -350,21 +342,33 @@ class PersistentValueMapBase { bool hasValue = value != kPersistentContainerNotFound; if (hasValue) { returnValue->SetInternal( - *reinterpret_cast(FromVal(value))); + *reinterpret_cast(FromVal(value))); } return hasValue; } Isolate* isolate_; typename Traits::Impl impl_; + const char* label_; }; +template +inline void +PersistentValueMapBase::RegisterExternallyReferencedObject( + K& key) { + assert(Contains(key)); + V8::RegisterExternallyReferencedObject( + reinterpret_cast(FromVal(Traits::Get(&impl_, key))), + reinterpret_cast(GetIsolate())); +} template class PersistentValueMap : public PersistentValueMapBase { public: explicit PersistentValueMap(Isolate* isolate) : PersistentValueMapBase(isolate) {} + PersistentValueMap(Isolate* isolate, const char* label) + : PersistentValueMapBase(isolate, label) {} typedef typename PersistentValueMapBase::PersistentValueReference @@ -392,10 +396,17 @@ class PersistentValueMap : public PersistentValueMapBase { * by the Traits class. */ Global SetUnique(const K& key, Global* persistent) { - if (Traits::kCallbackType != kNotWeak) { + if (Traits::kCallbackType == kNotWeak) { + this->AnnotateStrongRetainer(persistent); + } else { + WeakCallbackType callback_type = + Traits::kCallbackType == kWeakWithInternalFields + ? WeakCallbackType::kInternalFields + : WeakCallbackType::kParameter; Local value(Local::New(this->isolate(), *persistent)); persistent->template SetWeak( - Traits::WeakCallbackParameter(this, key, value), WeakCallback); + Traits::WeakCallbackParameter(this, key, value), WeakCallback, + callback_type); } PersistentContainerValue old_value = Traits::Set(this->impl(), key, this->ClearAndLeak(persistent)); @@ -432,6 +443,8 @@ class GlobalValueMap : public PersistentValueMapBase { public: explicit GlobalValueMap(Isolate* isolate) : PersistentValueMapBase(isolate) {} + GlobalValueMap(Isolate* isolate, const char* label) + : PersistentValueMapBase(isolate, label) {} typedef typename PersistentValueMapBase::PersistentValueReference @@ -459,7 +472,9 @@ class GlobalValueMap : public PersistentValueMapBase { * by the Traits class. */ Global SetUnique(const K& key, Global* persistent) { - if (Traits::kCallbackType != kNotWeak) { + if (Traits::kCallbackType == kNotWeak) { + this->AnnotateStrongRetainer(persistent); + } else { WeakCallbackType callback_type = Traits::kCallbackType == kWeakWithInternalFields ? WeakCallbackType::kInternalFields @@ -638,7 +653,7 @@ class PersistentValueVector { private: static PersistentContainerValue ClearAndLeak(Global* persistent) { V* v = persistent->val_; - persistent->val_ = 0; + persistent->val_ = nullptr; return reinterpret_cast(v); } diff --git a/win32/include/v8/v8-version-string.h b/win32/include/v8/v8-version-string.h index 075282de..fb84144d 100644 --- a/win32/include/v8/v8-version-string.h +++ b/win32/include/v8/v8-version-string.h @@ -16,6 +16,10 @@ #define V8_CANDIDATE_STRING "" #endif +#ifndef V8_EMBEDDER_STRING +#define V8_EMBEDDER_STRING "" +#endif + #define V8_SX(x) #x #define V8_S(x) V8_SX(x) @@ -23,11 +27,12 @@ #define V8_VERSION_STRING \ V8_S(V8_MAJOR_VERSION) \ "." V8_S(V8_MINOR_VERSION) "." V8_S(V8_BUILD_NUMBER) "." V8_S( \ - V8_PATCH_LEVEL) V8_CANDIDATE_STRING + V8_PATCH_LEVEL) V8_EMBEDDER_STRING V8_CANDIDATE_STRING #else -#define V8_VERSION_STRING \ - V8_S(V8_MAJOR_VERSION) \ - "." V8_S(V8_MINOR_VERSION) "." V8_S(V8_BUILD_NUMBER) V8_CANDIDATE_STRING +#define V8_VERSION_STRING \ + V8_S(V8_MAJOR_VERSION) \ + "." V8_S(V8_MINOR_VERSION) "." V8_S(V8_BUILD_NUMBER) \ + V8_EMBEDDER_STRING V8_CANDIDATE_STRING #endif #endif // V8_VERSION_STRING_H_ diff --git a/win32/include/v8/v8-version.h b/win32/include/v8/v8-version.h index 0889459c..dfcd5b46 100644 --- a/win32/include/v8/v8-version.h +++ b/win32/include/v8/v8-version.h @@ -8,10 +8,10 @@ // These macros define the version number for the current version. // NOTE these macros are used by some of the tool scripts and the build // system so their names cannot be changed without changing the scripts. -#define V8_MAJOR_VERSION 6 -#define V8_MINOR_VERSION 0 -#define V8_BUILD_NUMBER 286 -#define V8_PATCH_LEVEL 52 +#define V8_MAJOR_VERSION 7 +#define V8_MINOR_VERSION 5 +#define V8_BUILD_NUMBER 288 +#define V8_PATCH_LEVEL 22 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/win32/include/v8/v8.h b/win32/include/v8/v8.h index da3cdfdc..b4b92055 100644 --- a/win32/include/v8/v8.h +++ b/win32/include/v8/v8.h @@ -22,42 +22,13 @@ #include #include -#include "v8-version.h" // NOLINT(build/include) -#include "v8config.h" // NOLINT(build/include) +#include "v8-internal.h" // NOLINT(build/include) +#include "v8-version.h" // NOLINT(build/include) +#include "v8config.h" // NOLINT(build/include) // We reserve the V8_* prefix for macros defined in V8 public API and // assume there are no name conflicts with the embedder's code. -#ifdef V8_OS_WIN - -// Setup for Windows DLL export/import. When building the V8 DLL the -// BUILDING_V8_SHARED needs to be defined. When building a program which uses -// the V8 DLL USING_V8_SHARED needs to be defined. When either building the V8 -// static library or building a program which uses the V8 static library neither -// BUILDING_V8_SHARED nor USING_V8_SHARED should be defined. -#ifdef BUILDING_V8_SHARED -# define V8_EXPORT __declspec(dllexport) -#elif USING_V8_SHARED -# define V8_EXPORT __declspec(dllimport) -#else -# define V8_EXPORT -#endif // BUILDING_V8_SHARED - -#else // V8_OS_WIN - -// Setup for Linux shared library export. -#if V8_HAS_ATTRIBUTE_VISIBILITY -# ifdef BUILDING_V8_SHARED -# define V8_EXPORT __attribute__ ((visibility("default"))) -# else -# define V8_EXPORT -# endif -#else -# define V8_EXPORT -#endif - -#endif // V8_OS_WIN - /** * The v8 JavaScript engine. */ @@ -66,10 +37,11 @@ namespace v8 { class AccessorSignature; class Array; class ArrayBuffer; +class BigInt; +class BigIntObject; class Boolean; class BooleanObject; class Context; -class CpuProfiler; class Data; class Date; class External; @@ -82,6 +54,7 @@ class Integer; class Isolate; template class Maybe; +class MicrotaskQueue; class Name; class Number; class NumberObject; @@ -104,11 +77,12 @@ class String; class StringObject; class Symbol; class SymbolObject; +class PrimitiveArray; class Private; class Uint32; class Utils; class Value; -class WasmCompiledModule; +class WasmModuleObject; template class Local; template class MaybeLocal; @@ -119,6 +93,8 @@ template > class Persistent; template class Global; +template +class TracedGlobal; template class PersistentValueMap; template class PersistentValueMapBase; @@ -139,15 +115,26 @@ template class ReturnValue; namespace internal { class Arguments; +class DeferredHandles; class Heap; class HeapObject; +class ExternalString; class Isolate; -class Object; -struct StreamedSource; +class LocalEmbedderHeapTracer; +class MicrotaskQueue; +class NeverReadOnlySpaceObject; +struct ScriptStreamingData; template class CustomArguments; class PropertyCallbackArguments; class FunctionCallbackArguments; class GlobalHandles; +class ScopedExternalStringLock; + +namespace wasm { +class NativeModule; +class StreamingDecoder; +} // namespace wasm + } // namespace internal namespace debug { @@ -195,7 +182,7 @@ class ConsoleCallArguments; template class Local { public: - V8_INLINE Local() : val_(0) {} + V8_INLINE Local() : val_(nullptr) {} template V8_INLINE Local(Local that) : val_(reinterpret_cast(*that)) { @@ -210,12 +197,12 @@ class Local { /** * Returns true if the handle is empty. */ - V8_INLINE bool IsEmpty() const { return val_ == 0; } + V8_INLINE bool IsEmpty() const { return val_ == nullptr; } /** * Sets the handle to be empty. IsEmpty() will then return true. */ - V8_INLINE void Clear() { val_ = 0; } + V8_INLINE void Clear() { val_ = nullptr; } V8_INLINE T* operator->() const { return val_; } @@ -229,19 +216,19 @@ class Local { */ template V8_INLINE bool operator==(const Local& that) const { - internal::Object** a = reinterpret_cast(this->val_); - internal::Object** b = reinterpret_cast(that.val_); - if (a == 0) return b == 0; - if (b == 0) return false; + internal::Address* a = reinterpret_cast(this->val_); + internal::Address* b = reinterpret_cast(that.val_); + if (a == nullptr) return b == nullptr; + if (b == nullptr) return false; return *a == *b; } template V8_INLINE bool operator==( const PersistentBase& that) const { - internal::Object** a = reinterpret_cast(this->val_); - internal::Object** b = reinterpret_cast(that.val_); - if (a == 0) return b == 0; - if (b == 0) return false; + internal::Address* a = reinterpret_cast(this->val_); + internal::Address* b = reinterpret_cast(that.val_); + if (a == nullptr) return b == nullptr; + if (b == nullptr) return false; return *a == *b; } @@ -293,6 +280,7 @@ class Local { V8_INLINE static Local New(Isolate* isolate, Local that); V8_INLINE static Local New(Isolate* isolate, const PersistentBase& that); + V8_INLINE static Local New(Isolate* isolate, const TracedGlobal& that); private: friend class Utils; @@ -307,6 +295,7 @@ class Local { friend class String; friend class Object; friend class Context; + friend class Isolate; friend class Private; template friend class internal::CustomArguments; friend Local Undefined(Isolate* isolate); @@ -320,6 +309,8 @@ class Local { template friend class PersistentValueVector; template friend class ReturnValue; + template + friend class TracedGlobal; explicit V8_INLINE Local(T* that) : val_(that) {} V8_INLINE static Local New(Isolate* isolate, T* that); @@ -427,20 +418,6 @@ class WeakCallbackInfo { V8_INLINE T* GetParameter() const { return parameter_; } V8_INLINE void* GetInternalField(int index) const; - V8_INLINE V8_DEPRECATED("use indexed version", - void* GetInternalField1() const) { - return embedder_fields_[0]; - } - V8_INLINE V8_DEPRECATED("use indexed version", - void* GetInternalField2() const) { - return embedder_fields_[1]; - } - - V8_DEPRECATED("Not realiable once SetSecondPassCallback() was used.", - bool IsFirstPass() const) { - return callback_ != nullptr; - } - // When first called, the embedder MUST Reset() the Global which triggered the // callback. The Global itself is unusable for anything else. No v8 other api // calls may be called in the first callback. Should additional work be @@ -498,7 +475,7 @@ template class PersistentBase { template V8_INLINE void Reset(Isolate* isolate, const PersistentBase& other); - V8_INLINE bool IsEmpty() const { return val_ == NULL; } + V8_INLINE bool IsEmpty() const { return val_ == nullptr; } V8_INLINE void Empty() { val_ = 0; } V8_INLINE Local Get(Isolate* isolate) const { @@ -507,19 +484,19 @@ template class PersistentBase { template V8_INLINE bool operator==(const PersistentBase& that) const { - internal::Object** a = reinterpret_cast(this->val_); - internal::Object** b = reinterpret_cast(that.val_); - if (a == NULL) return b == NULL; - if (b == NULL) return false; + internal::Address* a = reinterpret_cast(this->val_); + internal::Address* b = reinterpret_cast(that.val_); + if (a == nullptr) return b == nullptr; + if (b == nullptr) return false; return *a == *b; } template V8_INLINE bool operator==(const Local& that) const { - internal::Object** a = reinterpret_cast(this->val_); - internal::Object** b = reinterpret_cast(that.val_); - if (a == NULL) return b == NULL; - if (b == NULL) return false; + internal::Address* a = reinterpret_cast(this->val_); + internal::Address* b = reinterpret_cast(that.val_); + if (a == nullptr) return b == nullptr; + if (b == nullptr) return false; return *a == *b; } @@ -560,12 +537,22 @@ template class PersistentBase { // TODO(dcarney): remove this. V8_INLINE void ClearWeak() { ClearWeak(); } + /** + * Annotates the strong handle with the given label, which is then used by the + * heap snapshot generator as a name of the edge from the root to the handle. + * The function does not take ownership of the label and assumes that the + * label is valid as long as the handle is valid. + */ + V8_INLINE void AnnotateStrongRetainer(const char* label); + /** * Allows the embedder to tell the v8 garbage collector that a certain object * is alive. Only allowed when the embedder is asked to trace its heap by * EmbedderHeapTracer. */ - V8_INLINE void RegisterExternalReference(Isolate* isolate) const; + V8_DEPRECATED( + "Used TracedGlobal and EmbedderHeapTracer::RegisterEmbedderReference", + V8_INLINE void RegisterExternalReference(Isolate* isolate) const); /** * Marks the reference to this object independent. Garbage collector is free @@ -573,26 +560,28 @@ template class PersistentBase { * independent handle should not assume that it will be preceded by a global * GC prologue callback or followed by a global GC epilogue callback. */ - V8_INLINE void MarkIndependent(); + V8_DEPRECATED( + "Weak objects are always considered independent. " + "Use TracedGlobal when trying to use EmbedderHeapTracer. " + "Use a strong handle when trying to keep an object alive.", + V8_INLINE void MarkIndependent()); /** * Marks the reference to this object as active. The scavenge garbage - * collection should not reclaim the objects marked as active. + * collection should not reclaim the objects marked as active, even if the + * object held by the handle is otherwise unreachable. + * * This bit is cleared after the each garbage collection pass. */ - V8_INLINE void MarkActive(); + V8_DEPRECATED("Use TracedGlobal.", V8_INLINE void MarkActive()); - V8_INLINE bool IsIndependent() const; - - /** Checks if the handle holds the only reference to an object. */ - V8_INLINE bool IsNearDeath() const; + V8_DEPRECATED("See MarkIndependent.", V8_INLINE bool IsIndependent() const); /** Returns true if the handle's reference is weak. */ V8_INLINE bool IsWeak() const; /** - * Assigns a wrapper class ID to the handle. See RetainedObjectInfo interface - * description in v8-profiler.h for details. + * Assigns a wrapper class ID to the handle. */ V8_INLINE void SetWrapperClassId(uint16_t class_id); @@ -678,7 +667,7 @@ template class Persistent : public PersistentBase { /** * A Persistent with no storage cell. */ - V8_INLINE Persistent() : PersistentBase(0) { } + V8_INLINE Persistent() : PersistentBase(nullptr) {} /** * Construct a Persistent from a Local. * When the Local is non-empty, a new storage cell is created @@ -705,14 +694,14 @@ template class Persistent : public PersistentBase { * traits class is called, allowing the setting of flags based on the * copied Persistent. */ - V8_INLINE Persistent(const Persistent& that) : PersistentBase(0) { + V8_INLINE Persistent(const Persistent& that) : PersistentBase(nullptr) { Copy(that); } template V8_INLINE Persistent(const Persistent& that) : PersistentBase(0) { Copy(that); } - V8_INLINE Persistent& operator=(const Persistent& that) { // NOLINT + V8_INLINE Persistent& operator=(const Persistent& that) { Copy(that); return *this; } @@ -773,6 +762,7 @@ class Global : public PersistentBase { * A Global with no storage cell. */ V8_INLINE Global() : PersistentBase(nullptr) {} + /** * Construct a Global from a Local. * When the Local is non-empty, a new storage cell is created @@ -783,6 +773,7 @@ class Global : public PersistentBase { : PersistentBase(PersistentBase::New(isolate, *that)) { TYPE_CHECK(T, S); } + /** * Construct a Global from a PersistentBase. * When the Persistent is non-empty, a new storage cell is created @@ -793,26 +784,20 @@ class Global : public PersistentBase { : PersistentBase(PersistentBase::New(isolate, that.val_)) { TYPE_CHECK(T, S); } + /** * Move constructor. */ - V8_INLINE Global(Global&& other) : PersistentBase(other.val_) { // NOLINT - other.val_ = nullptr; - } + V8_INLINE Global(Global&& other); + V8_INLINE ~Global() { this->Reset(); } + /** * Move via assignment. */ template - V8_INLINE Global& operator=(Global&& rhs) { // NOLINT - TYPE_CHECK(T, S); - if (this != &rhs) { - this->Reset(); - this->val_ = rhs.val_; - rhs.val_ = nullptr; - } - return *this; - } + V8_INLINE Global& operator=(Global&& rhs); + /** * Pass allows returning uniques from functions, etc. */ @@ -837,6 +822,151 @@ class Global : public PersistentBase { template using UniquePersistent = Global; +/** + * A traced handle with move semantics, similar to std::unique_ptr. The handle + * is to be used together with |v8::EmbedderHeapTracer| and specifies edges from + * the embedder into V8's heap. + * + * The exact semantics are: + * - Tracing garbage collections use |v8::EmbedderHeapTracer|. + * - Non-tracing garbage collections refer to + * |v8::EmbedderHeapTracer::IsRootForNonTracingGC()| whether the handle should + * be treated as root or not. + */ +template +class V8_EXPORT TracedGlobal { + public: + /** + * An empty TracedGlobal without storage cell. + */ + TracedGlobal() = default; + ~TracedGlobal() { Reset(); } + + /** + * Construct a TracedGlobal from a Local. + * + * When the Local is non-empty, a new storage cell is created + * pointing to the same object. + */ + template + TracedGlobal(Isolate* isolate, Local that) + : val_(New(isolate, *that, &val_)) { + TYPE_CHECK(T, S); + } + + /** + * Move constructor initializing TracedGlobal from an existing one. + */ + V8_INLINE TracedGlobal(TracedGlobal&& other); + + /** + * Move assignment operator initializing TracedGlobal from an existing one. + */ + template + V8_INLINE TracedGlobal& operator=(TracedGlobal&& rhs); + + /** + * TracedGlobal only supports move semantics and forbids copying. + */ + TracedGlobal(const TracedGlobal&) = delete; + void operator=(const TracedGlobal&) = delete; + + /** + * Returns true if this TracedGlobal is empty, i.e., has not been assigned an + * object. + */ + bool IsEmpty() const { return val_ == nullptr; } + + /** + * If non-empty, destroy the underlying storage cell. |IsEmpty| will return + * true after this call. + */ + V8_INLINE void Reset(); + + /** + * If non-empty, destroy the underlying storage cell and create a new one with + * the contents of other if other is non empty + */ + template + V8_INLINE void Reset(Isolate* isolate, const Local& other); + + /** + * Construct a Local from this handle. + */ + Local Get(Isolate* isolate) const { return Local::New(isolate, *this); } + + template + V8_INLINE TracedGlobal& As() const { + return reinterpret_cast&>( + const_cast&>(*this)); + } + + template + V8_INLINE bool operator==(const TracedGlobal& that) const { + internal::Address* a = reinterpret_cast(this->val_); + internal::Address* b = reinterpret_cast(that.val_); + if (a == nullptr) return b == nullptr; + if (b == nullptr) return false; + return *a == *b; + } + + template + V8_INLINE bool operator==(const Local& that) const { + internal::Address* a = reinterpret_cast(this->val_); + internal::Address* b = reinterpret_cast(that.val_); + if (a == nullptr) return b == nullptr; + if (b == nullptr) return false; + return *a == *b; + } + + template + V8_INLINE bool operator!=(const TracedGlobal& that) const { + return !operator==(that); + } + + template + V8_INLINE bool operator!=(const Local& that) const { + return !operator==(that); + } + + /** + * Assigns a wrapper class ID to the handle. + */ + V8_INLINE void SetWrapperClassId(uint16_t class_id); + + /** + * Returns the class ID previously assigned to this handle or 0 if no class ID + * was previously assigned. + */ + V8_INLINE uint16_t WrapperClassId() const; + + /** + * Adds a finalization callback to the handle. The type of this callback is + * similar to WeakCallbackType::kInternalFields, i.e., it will pass the + * parameter and the first two internal fields of the object. + * + * The callback is then supposed to reset the handle in the callback. No + * further V8 API may be called in this callback. In case additional work + * involving V8 needs to be done, a second callback can be scheduled using + * WeakCallbackInfo::SetSecondPassCallback. + */ + V8_INLINE void SetFinalizationCallback( + void* parameter, WeakCallbackInfo::Callback callback); + + private: + V8_INLINE static T* New(Isolate* isolate, T* that, T** slot); + + T* operator*() const { return this->val_; } + + T* val_ = nullptr; + + friend class EmbedderHeapTracer; + template + friend class Local; + friend class Object; + template + friend class ReturnValue; +}; /** * A stack-allocated class that governs a number of local handles. @@ -869,31 +999,32 @@ class V8_EXPORT HandleScope { HandleScope(const HandleScope&) = delete; void operator=(const HandleScope&) = delete; - void* operator new(size_t size); - void operator delete(void*, size_t); protected: - V8_INLINE HandleScope() {} + V8_INLINE HandleScope() = default; void Initialize(Isolate* isolate); - static internal::Object** CreateHandle(internal::Isolate* isolate, - internal::Object* value); + static internal::Address* CreateHandle(internal::Isolate* isolate, + internal::Address value); private: - // Uses heap_object to obtain the current Isolate. - static internal::Object** CreateHandle(internal::HeapObject* heap_object, - internal::Object* value); + // Declaring operator new and delete as deleted is not spec compliant. + // Therefore declare them private instead to disable dynamic alloc + void* operator new(size_t size); + void* operator new[](size_t size); + void operator delete(void*, size_t); + void operator delete[](void*, size_t); internal::Isolate* isolate_; - internal::Object** prev_next_; - internal::Object** prev_limit_; + internal::Address* prev_next_; + internal::Address* prev_limit_; // Local::New uses CreateHandle with an Isolate* parameter. template friend class Local; // Object::GetInternalField and Context::GetEmbedderData use CreateHandle with - // a HeapObject* in their shortcuts. + // a HeapObject in their shortcuts. friend class Object; friend class Context; }; @@ -906,7 +1037,7 @@ class V8_EXPORT HandleScope { class V8_EXPORT EscapableHandleScope : public HandleScope { public: explicit EscapableHandleScope(Isolate* isolate); - V8_INLINE ~EscapableHandleScope() {} + V8_INLINE ~EscapableHandleScope() = default; /** * Pushes the value into the previous scope and returns a handle to it. @@ -914,19 +1045,29 @@ class V8_EXPORT EscapableHandleScope : public HandleScope { */ template V8_INLINE Local Escape(Local value) { - internal::Object** slot = - Escape(reinterpret_cast(*value)); + internal::Address* slot = + Escape(reinterpret_cast(*value)); return Local(reinterpret_cast(slot)); } + template + V8_INLINE MaybeLocal EscapeMaybe(MaybeLocal value) { + return Escape(value.FromMaybe(Local())); + } + EscapableHandleScope(const EscapableHandleScope&) = delete; void operator=(const EscapableHandleScope&) = delete; - void* operator new(size_t size); - void operator delete(void*, size_t); private: - internal::Object** Escape(internal::Object** escape_value); - internal::Object** escape_slot_; + // Declaring operator new and delete as deleted is not spec compliant. + // Therefore declare them private instead to disable dynamic alloc + void* operator new(size_t size); + void* operator new[](size_t size); + void operator delete(void*, size_t); + void operator delete[](void*, size_t); + + internal::Address* Escape(internal::Address* escape_value); + internal::Address* escape_slot_; }; /** @@ -936,17 +1077,22 @@ class V8_EXPORT EscapableHandleScope : public HandleScope { */ class V8_EXPORT SealHandleScope { public: - SealHandleScope(Isolate* isolate); + explicit SealHandleScope(Isolate* isolate); ~SealHandleScope(); SealHandleScope(const SealHandleScope&) = delete; void operator=(const SealHandleScope&) = delete; - void* operator new(size_t size); - void operator delete(void*, size_t); private: + // Declaring operator new and delete as deleted is not spec compliant. + // Therefore declare them private instead to disable dynamic alloc + void* operator new(size_t size); + void* operator new[](size_t size); + void operator delete(void*, size_t); + void operator delete[](void*, size_t); + internal::Isolate* const isolate_; - internal::Object** prev_limit_; + internal::Address* prev_limit_; int prev_sealed_level_; }; @@ -962,6 +1108,42 @@ class V8_EXPORT Data { Data(); }; +/** + * A container type that holds relevant metadata for module loading. + * + * This is passed back to the embedder as part of + * HostImportModuleDynamicallyCallback for module loading. + */ +class V8_EXPORT ScriptOrModule { + public: + /** + * The name that was passed by the embedder as ResourceName to the + * ScriptOrigin. This can be either a v8::String or v8::Undefined. + */ + Local GetResourceName(); + + /** + * The options that were passed by the embedder as HostDefinedOptions to + * the ScriptOrigin. + */ + Local GetHostDefinedOptions(); +}; + +/** + * An array to hold Primitive values. This is used by the embedder to + * pass host defined options to the ScriptOptions during compilation. + * + * This is passed back to the embedder as part of + * HostImportModuleDynamicallyCallback for module loading. + * + */ +class V8_EXPORT PrimitiveArray { + public: + static Local New(Isolate* isolate, int length); + int Length() const; + void Set(Isolate* isolate, int index, Local item); + Local Get(Isolate* isolate, int index); +}; /** * The optional attributes of ScriptOrigin. @@ -1011,16 +1193,15 @@ class ScriptOrigin { Local source_map_url = Local(), Local resource_is_opaque = Local(), Local is_wasm = Local(), - Local is_module = Local()); + Local is_module = Local(), + Local host_defined_options = Local()); V8_INLINE Local ResourceName() const; V8_INLINE Local ResourceLineOffset() const; V8_INLINE Local ResourceColumnOffset() const; - /** - * Returns true for embedder's debugger scripts - */ V8_INLINE Local ScriptID() const; V8_INLINE Local SourceMapUrl() const; + V8_INLINE Local HostDefinedOptions() const; V8_INLINE ScriptOriginOptions Options() const { return options_; } private: @@ -1030,9 +1211,9 @@ class ScriptOrigin { ScriptOriginOptions options_; Local script_id_; Local source_map_url_; + Local host_defined_options_; }; - /** * A compiled JavaScript script, not yet tied to a Context. */ @@ -1065,13 +1246,59 @@ class V8_EXPORT UnboundScript { }; /** - * This is an unfinished experimental feature, and is only exposed - * here for internal testing purposes. DO NOT USE. - * + * A compiled JavaScript module, not yet tied to a Context. + */ +class V8_EXPORT UnboundModuleScript { + // Only used as a container for code caching. +}; + +/** + * A location in JavaScript source. + */ +class V8_EXPORT Location { + public: + int GetLineNumber() { return line_number_; } + int GetColumnNumber() { return column_number_; } + + Location(int line_number, int column_number) + : line_number_(line_number), column_number_(column_number) {} + + private: + int line_number_; + int column_number_; +}; + +/** * A compiled JavaScript module. */ class V8_EXPORT Module { public: + /** + * The different states a module can be in. + * + * This corresponds to the states used in ECMAScript except that "evaluated" + * is split into kEvaluated and kErrored, indicating success and failure, + * respectively. + */ + enum Status { + kUninstantiated, + kInstantiating, + kInstantiated, + kEvaluating, + kEvaluated, + kErrored + }; + + /** + * Returns the module's current status. + */ + Status GetStatus() const; + + /** + * For a module in kErrored status, this returns the corresponding exception. + */ + Local GetException() const; + /** * Returns the number of modules requested by this module. */ @@ -1083,6 +1310,12 @@ class V8_EXPORT Module { */ Local GetModuleRequest(int i) const; + /** + * Returns the source location (line number and column number) of the ith + * module specifier's first occurrence in this module. + */ + Location GetModuleRequestLocation(int i) const; + /** * Returns the identity hash for this object. */ @@ -1093,42 +1326,39 @@ class V8_EXPORT Module { Local referrer); /** - * ModuleDeclarationInstantiation + * Instantiates the module and its dependencies. * - * Returns false if an exception occurred during instantiation. (In the case - * where the callback throws an exception, that exception is propagated.) + * Returns an empty Maybe if an exception occurred during + * instantiation. (In the case where the callback throws an exception, that + * exception is propagated.) */ - V8_WARN_UNUSED_RESULT bool Instantiate(Local context, - ResolveCallback callback); + V8_WARN_UNUSED_RESULT Maybe InstantiateModule(Local context, + ResolveCallback callback); /** - * ModuleEvaluation + * Evaluates the module and its dependencies. * - * Returns the completion value. + * If status is kInstantiated, run the module's code. On success, set status + * to kEvaluated and return the completion value; on failure, set status to + * kErrored and propagate the thrown exception (which is then also available + * via |GetException|). */ V8_WARN_UNUSED_RESULT MaybeLocal Evaluate(Local context); -}; - -/** - * This is an unfinished experimental feature, and is only exposed - * here for internal testing purposes. DO NOT USE. - * - * A compiled JavaScript module. - */ -class V8_EXPORT DynamicImportResult { - public: - /** - * Resolves the promise with the namespace object of the given - * module. - */ - V8_WARN_UNUSED_RESULT bool FinishDynamicImportSuccess(Local context, - Local module); /** - * Rejects the promise with the given exception. + * Returns the namespace object of this module. + * + * The module's status must be at least kInstantiated. */ - V8_WARN_UNUSED_RESULT bool FinishDynamicImportFailure(Local context, - Local exception); + Local GetModuleNamespace(); + + /** + * Returns the corresponding context-unbound module script. + * + * The module must be unevaluated, i.e. its status must not be kEvaluating, + * kEvaluated or kErrored. + */ + Local GetUnboundModuleScript(); }; /** @@ -1140,24 +1370,15 @@ class V8_EXPORT Script { /** * A shorthand for ScriptCompiler::Compile(). */ - static V8_DEPRECATE_SOON( - "Use maybe version", - Local