1 // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights 2 // reserved. Use of this source code is governed by a BSD-style license that 3 // can be found in the LICENSE file. 4 5 #ifndef CEF_LIBCEF_RENDERER_V8_IMPL_H_ 6 #define CEF_LIBCEF_RENDERER_V8_IMPL_H_ 7 #pragma once 8 9 #include <vector> 10 11 #include "include/cef_v8.h" 12 #include "libcef/common/tracker.h" 13 14 #include "base/location.h" 15 #include "base/logging.h" 16 #include "base/memory/ref_counted.h" 17 #include "base/task/single_thread_task_runner.h" 18 #include "v8/include/v8.h" 19 20 class CefTrackNode; 21 class GURL; 22 23 namespace blink { 24 class WebLocalFrame; 25 } 26 27 // Call after a V8 Isolate has been created and entered for the first time. 28 void CefV8IsolateCreated(); 29 30 // Call before a V8 Isolate is exited and destroyed. 31 void CefV8IsolateDestroyed(); 32 33 // Call to detach all handles associated with the specified context. 34 void CefV8ReleaseContext(v8::Local<v8::Context> context); 35 36 // Set the stack size for uncaught exceptions. 37 void CefV8SetUncaughtExceptionStackSize(int stack_size); 38 39 // Set attributes associated with a WebWorker thread. 40 void CefV8SetWorkerAttributes(int worker_id, const GURL& worker_url); 41 42 // Used to detach handles when the associated context is released. 43 class CefV8ContextState : public base::RefCounted<CefV8ContextState> { 44 public: CefV8ContextState()45 CefV8ContextState() : valid_(true) {} 46 IsValid()47 bool IsValid() { return valid_; } Detach()48 void Detach() { 49 DCHECK(valid_); 50 valid_ = false; 51 track_manager_.DeleteAll(); 52 } 53 AddTrackObject(CefTrackNode * object)54 void AddTrackObject(CefTrackNode* object) { 55 DCHECK(valid_); 56 track_manager_.Add(object); 57 } 58 DeleteTrackObject(CefTrackNode * object)59 void DeleteTrackObject(CefTrackNode* object) { 60 DCHECK(valid_); 61 track_manager_.Delete(object); 62 } 63 64 private: 65 friend class base::RefCounted<CefV8ContextState>; 66 ~CefV8ContextState()67 ~CefV8ContextState() {} 68 69 bool valid_; 70 CefTrackManager track_manager_; 71 }; 72 73 // Use this template in conjuction with RefCountedThreadSafe to ensure that a 74 // V8 object is deleted on the correct thread. 75 struct CefV8DeleteOnMessageLoopThread { 76 template <typename T> DestructCefV8DeleteOnMessageLoopThread77 static void Destruct(const T* x) { 78 if (x->task_runner()->RunsTasksInCurrentSequence()) { 79 delete x; 80 } else { 81 if (!x->task_runner()->DeleteSoon(FROM_HERE, x)) { 82 #if defined(UNIT_TEST) 83 // Only logged under unit testing because leaks at shutdown 84 // are acceptable under normal circumstances. 85 LOG(ERROR) << "DeleteSoon failed on thread " << thread; 86 #endif // UNIT_TEST 87 } 88 } 89 } 90 }; 91 92 // Base class for V8 Handle types. 93 class CefV8HandleBase 94 : public base::RefCountedThreadSafe<CefV8HandleBase, 95 CefV8DeleteOnMessageLoopThread> { 96 public: 97 // Returns true if there is no underlying context or if the underlying context 98 // is valid. IsValid()99 bool IsValid() const { 100 return (!context_state_.get() || context_state_->IsValid()); 101 } 102 103 bool BelongsToCurrentThread() const; 104 isolate()105 v8::Isolate* isolate() const { return isolate_; } task_runner()106 scoped_refptr<base::SingleThreadTaskRunner> task_runner() const { 107 return task_runner_; 108 } 109 110 protected: 111 friend class base::DeleteHelper<CefV8HandleBase>; 112 friend class base::RefCountedThreadSafe<CefV8HandleBase, 113 CefV8DeleteOnMessageLoopThread>; 114 friend struct CefV8DeleteOnMessageLoopThread; 115 116 // |context| is the context that owns this handle. If empty the current 117 // context will be used. 118 CefV8HandleBase(v8::Isolate* isolate, v8::Local<v8::Context> context); 119 virtual ~CefV8HandleBase(); 120 121 protected: 122 v8::Isolate* isolate_; 123 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 124 scoped_refptr<CefV8ContextState> context_state_; 125 }; 126 127 // Template for V8 Handle types. This class is used to ensure that V8 objects 128 // are only released on the render thread. 129 template <typename v8class> 130 class CefV8Handle : public CefV8HandleBase { 131 public: 132 using handleType = v8::Local<v8class>; 133 using persistentType = v8::Persistent<v8class>; 134 CefV8Handle(v8::Isolate * isolate,v8::Local<v8::Context> context,handleType v)135 CefV8Handle(v8::Isolate* isolate, 136 v8::Local<v8::Context> context, 137 handleType v) 138 : CefV8HandleBase(isolate, context), handle_(isolate, v) {} 139 140 CefV8Handle(const CefV8Handle&) = delete; 141 CefV8Handle& operator=(const CefV8Handle&) = delete; 142 GetNewV8Handle()143 handleType GetNewV8Handle() { 144 DCHECK(IsValid()); 145 return handleType::New(isolate(), handle_); 146 } 147 GetPersistentV8Handle()148 persistentType& GetPersistentV8Handle() { return handle_; } 149 150 protected: ~CefV8Handle()151 ~CefV8Handle() override { handle_.Reset(); } 152 153 persistentType handle_; 154 }; 155 156 // Specialization for v8::Value with empty implementation to avoid incorrect 157 // usage. 158 template <> 159 class CefV8Handle<v8::Value> {}; 160 161 class CefV8ContextImpl : public CefV8Context { 162 public: 163 CefV8ContextImpl(v8::Isolate* isolate, v8::Local<v8::Context> context); 164 165 CefV8ContextImpl(const CefV8ContextImpl&) = delete; 166 CefV8ContextImpl& operator=(const CefV8ContextImpl&) = delete; 167 168 ~CefV8ContextImpl() override; 169 170 CefRefPtr<CefTaskRunner> GetTaskRunner() override; 171 bool IsValid() override; 172 CefRefPtr<CefBrowser> GetBrowser() override; 173 CefRefPtr<CefFrame> GetFrame() override; 174 CefRefPtr<CefV8Value> GetGlobal() override; 175 bool Enter() override; 176 bool Exit() override; 177 bool IsSame(CefRefPtr<CefV8Context> that) override; 178 bool Eval(const CefString& code, 179 const CefString& script_url, 180 int start_line, 181 CefRefPtr<CefV8Value>& retval, 182 CefRefPtr<CefV8Exception>& exception) override; 183 184 v8::Local<v8::Context> GetV8Context(); 185 blink::WebLocalFrame* GetWebFrame(); 186 187 private: 188 using Handle = CefV8Handle<v8::Context>; 189 scoped_refptr<Handle> handle_; 190 191 int enter_count_; 192 std::unique_ptr<v8::MicrotasksScope> microtasks_scope_; 193 194 IMPLEMENT_REFCOUNTING(CefV8ContextImpl); 195 }; 196 197 class CefV8ValueImpl : public CefV8Value { 198 public: 199 explicit CefV8ValueImpl(v8::Isolate* isolate); 200 CefV8ValueImpl(v8::Isolate* isolate, 201 v8::Local<v8::Context> context, 202 v8::Local<v8::Value> value); 203 204 CefV8ValueImpl(const CefV8ValueImpl&) = delete; 205 CefV8ValueImpl& operator=(const CefV8ValueImpl&) = delete; 206 207 ~CefV8ValueImpl() override; 208 209 // Used for initializing the CefV8ValueImpl. Should be called a single time 210 // after the CefV8ValueImpl is created. 211 void InitFromV8Value(v8::Local<v8::Context> context, 212 v8::Local<v8::Value> value); 213 void InitUndefined(); 214 void InitNull(); 215 void InitBool(bool value); 216 void InitInt(int32 value); 217 void InitUInt(uint32 value); 218 void InitDouble(double value); 219 void InitDate(const CefTime& value); 220 void InitString(CefString& value); 221 void InitObject(v8::Local<v8::Value> value, CefTrackNode* tracker); 222 223 // Creates a new V8 value for the underlying value or returns the existing 224 // object handle. 225 v8::Local<v8::Value> GetV8Value(bool should_persist); 226 227 bool IsValid() override; 228 bool IsUndefined() override; 229 bool IsNull() override; 230 bool IsBool() override; 231 bool IsInt() override; 232 bool IsUInt() override; 233 bool IsDouble() override; 234 bool IsDate() override; 235 bool IsString() override; 236 bool IsObject() override; 237 bool IsArray() override; 238 bool IsArrayBuffer() override; 239 bool IsFunction() override; 240 bool IsSame(CefRefPtr<CefV8Value> value) override; 241 bool GetBoolValue() override; 242 int32 GetIntValue() override; 243 uint32 GetUIntValue() override; 244 double GetDoubleValue() override; 245 CefTime GetDateValue() override; 246 CefString GetStringValue() override; 247 bool IsUserCreated() override; 248 bool HasException() override; 249 CefRefPtr<CefV8Exception> GetException() override; 250 bool ClearException() override; 251 bool WillRethrowExceptions() override; 252 bool SetRethrowExceptions(bool rethrow) override; 253 bool HasValue(const CefString& key) override; 254 bool HasValue(int index) override; 255 bool DeleteValue(const CefString& key) override; 256 bool DeleteValue(int index) override; 257 CefRefPtr<CefV8Value> GetValue(const CefString& key) override; 258 CefRefPtr<CefV8Value> GetValue(int index) override; 259 bool SetValue(const CefString& key, 260 CefRefPtr<CefV8Value> value, 261 PropertyAttribute attribute) override; 262 bool SetValue(int index, CefRefPtr<CefV8Value> value) override; 263 bool SetValue(const CefString& key, 264 AccessControl settings, 265 PropertyAttribute attribute) override; 266 bool GetKeys(std::vector<CefString>& keys) override; 267 bool SetUserData(CefRefPtr<CefBaseRefCounted> user_data) override; 268 CefRefPtr<CefBaseRefCounted> GetUserData() override; 269 int GetExternallyAllocatedMemory() override; 270 int AdjustExternallyAllocatedMemory(int change_in_bytes) override; 271 int GetArrayLength() override; 272 CefRefPtr<CefV8ArrayBufferReleaseCallback> GetArrayBufferReleaseCallback() 273 override; 274 bool NeuterArrayBuffer() override; 275 CefString GetFunctionName() override; 276 CefRefPtr<CefV8Handler> GetFunctionHandler() override; 277 CefRefPtr<CefV8Value> ExecuteFunction( 278 CefRefPtr<CefV8Value> object, 279 const CefV8ValueList& arguments) override; 280 CefRefPtr<CefV8Value> ExecuteFunctionWithContext( 281 CefRefPtr<CefV8Context> context, 282 CefRefPtr<CefV8Value> object, 283 const CefV8ValueList& arguments) override; 284 285 private: 286 // Test for and record any exception. 287 bool HasCaught(v8::Local<v8::Context> context, v8::TryCatch& try_catch); 288 289 class Handle : public CefV8HandleBase { 290 public: 291 using handleType = v8::Local<v8::Value>; 292 using persistentType = v8::Persistent<v8::Value>; 293 294 Handle(v8::Isolate* isolate, 295 v8::Local<v8::Context> context, 296 handleType v, 297 CefTrackNode* tracker); 298 299 Handle(const Handle&) = delete; 300 Handle& operator=(const Handle&) = delete; 301 302 handleType GetNewV8Handle(bool should_persist); 303 304 persistentType& GetPersistentV8Handle(); 305 306 void SetWeakIfNecessary(); 307 308 private: 309 ~Handle() override; 310 311 private: 312 // Callbacks for weak persistent reference destruction. 313 static void FirstWeakCallback(const v8::WeakCallbackInfo<Handle>& data); 314 static void SecondWeakCallback(const v8::WeakCallbackInfo<Handle>& data); 315 316 persistentType handle_; 317 318 // For Object and Function types, we need to hold on to a reference to their 319 // internal data or function handler objects that are reference counted. 320 CefTrackNode* tracker_; 321 322 // True if the handle needs to persist due to it being passed into V8. 323 bool should_persist_; 324 325 // True if the handle has been set as weak. 326 bool is_set_weak_; 327 }; 328 329 v8::Isolate* isolate_; 330 331 enum { 332 TYPE_INVALID = 0, 333 TYPE_UNDEFINED, 334 TYPE_NULL, 335 TYPE_BOOL, 336 TYPE_INT, 337 TYPE_UINT, 338 TYPE_DOUBLE, 339 TYPE_DATE, 340 TYPE_STRING, 341 TYPE_OBJECT, 342 } type_; 343 344 union { 345 bool bool_value_; 346 int32 int_value_; 347 uint32 uint_value_; 348 double double_value_; 349 cef_time_t date_value_; 350 cef_string_t string_value_; 351 }; 352 353 // Used with Object, Function and Array types. 354 scoped_refptr<Handle> handle_; 355 356 CefRefPtr<CefV8Exception> last_exception_; 357 bool rethrow_exceptions_; 358 359 IMPLEMENT_REFCOUNTING(CefV8ValueImpl); 360 }; 361 362 class CefV8StackTraceImpl : public CefV8StackTrace { 363 public: 364 CefV8StackTraceImpl(v8::Isolate* isolate, v8::Local<v8::StackTrace> handle); 365 366 CefV8StackTraceImpl(const CefV8StackTraceImpl&) = delete; 367 CefV8StackTraceImpl& operator=(const CefV8StackTraceImpl&) = delete; 368 369 ~CefV8StackTraceImpl() override; 370 371 bool IsValid() override; 372 int GetFrameCount() override; 373 CefRefPtr<CefV8StackFrame> GetFrame(int index) override; 374 375 private: 376 std::vector<CefRefPtr<CefV8StackFrame>> frames_; 377 378 IMPLEMENT_REFCOUNTING(CefV8StackTraceImpl); 379 }; 380 381 class CefV8StackFrameImpl : public CefV8StackFrame { 382 public: 383 CefV8StackFrameImpl(v8::Isolate* isolate, v8::Local<v8::StackFrame> handle); 384 385 CefV8StackFrameImpl(const CefV8StackFrameImpl&) = delete; 386 CefV8StackFrameImpl& operator=(const CefV8StackFrameImpl&) = delete; 387 388 ~CefV8StackFrameImpl() override; 389 390 bool IsValid() override; 391 CefString GetScriptName() override; 392 CefString GetScriptNameOrSourceURL() override; 393 CefString GetFunctionName() override; 394 int GetLineNumber() override; 395 int GetColumn() override; 396 bool IsEval() override; 397 bool IsConstructor() override; 398 399 private: 400 CefString script_name_; 401 CefString script_name_or_source_url_; 402 CefString function_name_; 403 int line_number_; 404 int column_; 405 bool is_eval_; 406 bool is_constructor_; 407 408 IMPLEMENT_REFCOUNTING(CefV8StackFrameImpl); 409 }; 410 411 #endif // CEF_LIBCEF_RENDERER_V8_IMPL_H_ 412