// Copyright (c) 2013 The Chromium Embedded Framework 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 CEF_LIBCEF_RENDERER_V8_IMPL_H_ #define CEF_LIBCEF_RENDERER_V8_IMPL_H_ #pragma once #include #include "include/cef_v8.h" #include "libcef/common/tracker.h" #include "base/location.h" #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/task/single_thread_task_runner.h" #include "v8/include/v8.h" class CefTrackNode; class GURL; namespace blink { class WebLocalFrame; } // Call after a V8 Isolate has been created and entered for the first time. void CefV8IsolateCreated(); // Call before a V8 Isolate is exited and destroyed. void CefV8IsolateDestroyed(); // Call to detach all handles associated with the specified context. void CefV8ReleaseContext(v8::Local context); // Set the stack size for uncaught exceptions. void CefV8SetUncaughtExceptionStackSize(int stack_size); // Set attributes associated with a WebWorker thread. void CefV8SetWorkerAttributes(int worker_id, const GURL& worker_url); // Used to detach handles when the associated context is released. class CefV8ContextState : public base::RefCounted { public: CefV8ContextState() : valid_(true) {} bool IsValid() { return valid_; } void Detach() { DCHECK(valid_); valid_ = false; track_manager_.DeleteAll(); } void AddTrackObject(CefTrackNode* object) { DCHECK(valid_); track_manager_.Add(object); } void DeleteTrackObject(CefTrackNode* object) { DCHECK(valid_); track_manager_.Delete(object); } private: friend class base::RefCounted; ~CefV8ContextState() {} bool valid_; CefTrackManager track_manager_; }; // Use this template in conjuction with RefCountedThreadSafe to ensure that a // V8 object is deleted on the correct thread. struct CefV8DeleteOnMessageLoopThread { template static void Destruct(const T* x) { if (x->task_runner()->RunsTasksInCurrentSequence()) { delete x; } else { if (!x->task_runner()->DeleteSoon(FROM_HERE, x)) { #if defined(UNIT_TEST) // Only logged under unit testing because leaks at shutdown // are acceptable under normal circumstances. LOG(ERROR) << "DeleteSoon failed on thread " << thread; #endif // UNIT_TEST } } } }; // Base class for V8 Handle types. class CefV8HandleBase : public base::RefCountedThreadSafe { public: // Returns true if there is no underlying context or if the underlying context // is valid. bool IsValid() const { return (!context_state_.get() || context_state_->IsValid()); } bool BelongsToCurrentThread() const; v8::Isolate* isolate() const { return isolate_; } scoped_refptr task_runner() const { return task_runner_; } protected: friend class base::DeleteHelper; friend class base::RefCountedThreadSafe; friend struct CefV8DeleteOnMessageLoopThread; // |context| is the context that owns this handle. If empty the current // context will be used. CefV8HandleBase(v8::Isolate* isolate, v8::Local context); virtual ~CefV8HandleBase(); protected: v8::Isolate* isolate_; scoped_refptr task_runner_; scoped_refptr context_state_; }; // Template for V8 Handle types. This class is used to ensure that V8 objects // are only released on the render thread. template class CefV8Handle : public CefV8HandleBase { public: using handleType = v8::Local; using persistentType = v8::Persistent; CefV8Handle(v8::Isolate* isolate, v8::Local context, handleType v) : CefV8HandleBase(isolate, context), handle_(isolate, v) {} CefV8Handle(const CefV8Handle&) = delete; CefV8Handle& operator=(const CefV8Handle&) = delete; handleType GetNewV8Handle() { DCHECK(IsValid()); return handleType::New(isolate(), handle_); } persistentType& GetPersistentV8Handle() { return handle_; } protected: ~CefV8Handle() override { handle_.Reset(); } persistentType handle_; }; // Specialization for v8::Value with empty implementation to avoid incorrect // usage. template <> class CefV8Handle {}; class CefV8ContextImpl : public CefV8Context { public: CefV8ContextImpl(v8::Isolate* isolate, v8::Local context); CefV8ContextImpl(const CefV8ContextImpl&) = delete; CefV8ContextImpl& operator=(const CefV8ContextImpl&) = delete; ~CefV8ContextImpl() override; CefRefPtr GetTaskRunner() override; bool IsValid() override; CefRefPtr GetBrowser() override; CefRefPtr GetFrame() override; CefRefPtr GetGlobal() override; bool Enter() override; bool Exit() override; bool IsSame(CefRefPtr that) override; bool Eval(const CefString& code, const CefString& script_url, int start_line, CefRefPtr& retval, CefRefPtr& exception) override; v8::Local GetV8Context(); blink::WebLocalFrame* GetWebFrame(); private: using Handle = CefV8Handle; scoped_refptr handle_; v8::MicrotaskQueue* const microtask_queue_; int enter_count_ = 0; std::unique_ptr microtasks_scope_; IMPLEMENT_REFCOUNTING(CefV8ContextImpl); }; class CefV8ValueImpl : public CefV8Value { public: explicit CefV8ValueImpl(v8::Isolate* isolate); CefV8ValueImpl(v8::Isolate* isolate, v8::Local context, v8::Local value); CefV8ValueImpl(const CefV8ValueImpl&) = delete; CefV8ValueImpl& operator=(const CefV8ValueImpl&) = delete; ~CefV8ValueImpl() override; // Used for initializing the CefV8ValueImpl. Should be called a single time // after the CefV8ValueImpl is created. void InitFromV8Value(v8::Local context, v8::Local value); void InitUndefined(); void InitNull(); void InitBool(bool value); void InitInt(int32_t value); void InitUInt(uint32_t value); void InitDouble(double value); void InitDate(CefBaseTime value); void InitString(CefString& value); void InitObject(v8::Local value, CefTrackNode* tracker); // Creates a new V8 value for the underlying value or returns the existing // object handle. v8::Local GetV8Value(bool should_persist); bool IsValid() override; bool IsUndefined() override; bool IsNull() override; bool IsBool() override; bool IsInt() override; bool IsUInt() override; bool IsDouble() override; bool IsDate() override; bool IsString() override; bool IsObject() override; bool IsArray() override; bool IsArrayBuffer() override; bool IsFunction() override; bool IsPromise() override; bool IsSame(CefRefPtr value) override; bool GetBoolValue() override; int32_t GetIntValue() override; uint32_t GetUIntValue() override; double GetDoubleValue() override; CefBaseTime GetDateValue() override; CefString GetStringValue() override; bool IsUserCreated() override; bool HasException() override; CefRefPtr GetException() override; bool ClearException() override; bool WillRethrowExceptions() override; bool SetRethrowExceptions(bool rethrow) override; bool HasValue(const CefString& key) override; bool HasValue(int index) override; bool DeleteValue(const CefString& key) override; bool DeleteValue(int index) override; CefRefPtr GetValue(const CefString& key) override; CefRefPtr GetValue(int index) override; bool SetValue(const CefString& key, CefRefPtr value, PropertyAttribute attribute) override; bool SetValue(int index, CefRefPtr value) override; bool SetValue(const CefString& key, AccessControl settings, PropertyAttribute attribute) override; bool GetKeys(std::vector& keys) override; bool SetUserData(CefRefPtr user_data) override; CefRefPtr GetUserData() override; int GetExternallyAllocatedMemory() override; int AdjustExternallyAllocatedMemory(int change_in_bytes) override; int GetArrayLength() override; CefRefPtr GetArrayBufferReleaseCallback() override; bool NeuterArrayBuffer() override; size_t GetArrayBufferByteLength() override; void* GetArrayBufferData() override; CefString GetFunctionName() override; CefRefPtr GetFunctionHandler() override; CefRefPtr ExecuteFunction( CefRefPtr object, const CefV8ValueList& arguments) override; CefRefPtr ExecuteFunctionWithContext( CefRefPtr context, CefRefPtr object, const CefV8ValueList& arguments) override; bool ResolvePromise(CefRefPtr arg) override; bool RejectPromise(const CefString& errorMsg) override; private: // Test for and record any exception. bool HasCaught(v8::Local context, v8::TryCatch& try_catch); class Handle : public CefV8HandleBase { public: using handleType = v8::Local; using persistentType = v8::Persistent; Handle(v8::Isolate* isolate, v8::Local context, handleType v, CefTrackNode* tracker); Handle(const Handle&) = delete; Handle& operator=(const Handle&) = delete; handleType GetNewV8Handle(bool should_persist); persistentType& GetPersistentV8Handle(); void SetWeakIfNecessary(); private: ~Handle() override; private: // Callbacks for weak persistent reference destruction. static void FirstWeakCallback(const v8::WeakCallbackInfo& data); static void SecondWeakCallback(const v8::WeakCallbackInfo& data); persistentType handle_; // For Object and Function types, we need to hold on to a reference to their // internal data or function handler objects that are reference counted. CefTrackNode* tracker_; // True if the handle needs to persist due to it being passed into V8. bool should_persist_; // True if the handle has been set as weak. bool is_set_weak_; }; v8::Isolate* isolate_; enum { TYPE_INVALID = 0, TYPE_UNDEFINED, TYPE_NULL, TYPE_BOOL, TYPE_INT, TYPE_UINT, TYPE_DOUBLE, TYPE_DATE, TYPE_STRING, TYPE_OBJECT, } type_; union { bool bool_value_; int32_t int_value_; uint32_t uint_value_; double double_value_; cef_basetime_t date_value_; cef_string_t string_value_; }; // Used with Object, Function and Array types. scoped_refptr handle_; CefRefPtr last_exception_; bool rethrow_exceptions_; IMPLEMENT_REFCOUNTING(CefV8ValueImpl); }; class CefV8StackTraceImpl : public CefV8StackTrace { public: CefV8StackTraceImpl(v8::Isolate* isolate, v8::Local handle); CefV8StackTraceImpl(const CefV8StackTraceImpl&) = delete; CefV8StackTraceImpl& operator=(const CefV8StackTraceImpl&) = delete; ~CefV8StackTraceImpl() override; bool IsValid() override; int GetFrameCount() override; CefRefPtr GetFrame(int index) override; private: std::vector> frames_; IMPLEMENT_REFCOUNTING(CefV8StackTraceImpl); }; class CefV8StackFrameImpl : public CefV8StackFrame { public: CefV8StackFrameImpl(v8::Isolate* isolate, v8::Local handle); CefV8StackFrameImpl(const CefV8StackFrameImpl&) = delete; CefV8StackFrameImpl& operator=(const CefV8StackFrameImpl&) = delete; ~CefV8StackFrameImpl() override; bool IsValid() override; CefString GetScriptName() override; CefString GetScriptNameOrSourceURL() override; CefString GetFunctionName() override; int GetLineNumber() override; int GetColumn() override; bool IsEval() override; bool IsConstructor() override; private: CefString script_name_; CefString script_name_or_source_url_; CefString function_name_; int line_number_; int column_; bool is_eval_; bool is_constructor_; IMPLEMENT_REFCOUNTING(CefV8StackFrameImpl); }; #endif // CEF_LIBCEF_RENDERER_V8_IMPL_H_