• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // MSVC++ requires this to be set before any other includes to get M_PI.
6 // Otherwise there will be compile errors in wtf/MathExtras.h.
7 #define _USE_MATH_DEFINES
8 
9 #include <map>
10 #include <string>
11 
12 #include "base/command_line.h"
13 #include "base/compiler_specific.h"
14 
15 // Enable deprecation warnings for MSVC and Clang. See http://crbug.com/585142.
16 #if BUILDFLAG(IS_WIN)
17 #if defined(__clang__)
18 #pragma GCC diagnostic push
19 #pragma GCC diagnostic error "-Wdeprecated-declarations"
20 #else
21 #pragma warning(push)
22 #pragma warning(default : 4996)
23 #endif
24 #endif
25 
26 #include "libcef/renderer/v8_impl.h"
27 
28 #include "libcef/common/app_manager.h"
29 #include "libcef/common/cef_switches.h"
30 #include "libcef/common/task_runner_impl.h"
31 #include "libcef/common/tracker.h"
32 #include "libcef/renderer/blink_glue.h"
33 #include "libcef/renderer/browser_impl.h"
34 #include "libcef/renderer/render_frame_util.h"
35 #include "libcef/renderer/thread_util.h"
36 
37 #include "base/bind.h"
38 #include "base/lazy_instance.h"
39 #include "base/strings/string_number_conversions.h"
40 #include "base/threading/thread_local.h"
41 #include "third_party/blink/public/web/blink.h"
42 #include "third_party/blink/public/web/web_frame.h"
43 #include "third_party/blink/public/web/web_local_frame.h"
44 #include "url/gurl.h"
45 
46 namespace {
47 
48 static const char kCefTrackObject[] = "Cef::TrackObject";
49 
50 void MessageListenerCallbackImpl(v8::Handle<v8::Message> message,
51                                  v8::Handle<v8::Value> data);
52 
53 // The following *Private functions are convenience wrappers for methods on
54 // v8::Object with the corresponding names.
55 // Based on extensions/renderer/object_backed_native_handler.cc.
56 
SetPrivate(v8::Local<v8::Context> context,v8::Local<v8::Object> obj,const char * key,v8::Local<v8::Value> value)57 void SetPrivate(v8::Local<v8::Context> context,
58                 v8::Local<v8::Object> obj,
59                 const char* key,
60                 v8::Local<v8::Value> value) {
61   v8::Isolate* isolate = context->GetIsolate();
62   obj->SetPrivate(context,
63                   v8::Private::ForApi(
64                       isolate, v8::String::NewFromUtf8(
65                                    isolate, key, v8::NewStringType::kNormal)
66                                    .ToLocalChecked()),
67                   value)
68       .FromJust();
69 }
70 
GetPrivate(v8::Local<v8::Context> context,v8::Local<v8::Object> obj,const char * key,v8::Local<v8::Value> * result)71 bool GetPrivate(v8::Local<v8::Context> context,
72                 v8::Local<v8::Object> obj,
73                 const char* key,
74                 v8::Local<v8::Value>* result) {
75   v8::Isolate* isolate = context->GetIsolate();
76   return obj
77       ->GetPrivate(context,
78                    v8::Private::ForApi(
79                        isolate, v8::String::NewFromUtf8(
80                                     isolate, key, v8::NewStringType::kNormal)
81                                     .ToLocalChecked()))
82       .ToLocal(result);
83 }
84 
85 // Manages memory and state information associated with a single Isolate.
86 class CefV8IsolateManager {
87  public:
CefV8IsolateManager()88   CefV8IsolateManager()
89       : isolate_(v8::Isolate::GetCurrent()),
90         task_runner_(CEF_RENDER_TASK_RUNNER()),
91         message_listener_registered_(false),
92         worker_id_(0) {
93     DCHECK(isolate_);
94     DCHECK(task_runner_.get());
95   }
~CefV8IsolateManager()96   ~CefV8IsolateManager() {
97     DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
98     DCHECK(context_map_.empty());
99   }
100 
GetContextState(v8::Local<v8::Context> context)101   scoped_refptr<CefV8ContextState> GetContextState(
102       v8::Local<v8::Context> context) {
103     DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
104     DCHECK(context.IsEmpty() || isolate_ == context->GetIsolate());
105 
106     if (context.IsEmpty()) {
107       if (isolate_->InContext())
108         context = isolate_->GetCurrentContext();
109       else
110         return scoped_refptr<CefV8ContextState>();
111     }
112 
113     int hash = context->Global()->GetIdentityHash();
114     ContextMap::const_iterator it = context_map_.find(hash);
115     if (it != context_map_.end())
116       return it->second;
117 
118     scoped_refptr<CefV8ContextState> state = new CefV8ContextState();
119     context_map_.insert(std::make_pair(hash, state));
120 
121     return state;
122   }
123 
ReleaseContext(v8::Local<v8::Context> context)124   void ReleaseContext(v8::Local<v8::Context> context) {
125     DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
126     DCHECK_EQ(isolate_, context->GetIsolate());
127 
128     int hash = context->Global()->GetIdentityHash();
129     ContextMap::iterator it = context_map_.find(hash);
130     if (it != context_map_.end()) {
131       it->second->Detach();
132       context_map_.erase(it);
133     }
134   }
135 
AddGlobalTrackObject(CefTrackNode * object)136   void AddGlobalTrackObject(CefTrackNode* object) {
137     DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
138     global_manager_.Add(object);
139   }
140 
DeleteGlobalTrackObject(CefTrackNode * object)141   void DeleteGlobalTrackObject(CefTrackNode* object) {
142     DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
143     global_manager_.Delete(object);
144   }
145 
SetUncaughtExceptionStackSize(int stack_size)146   void SetUncaughtExceptionStackSize(int stack_size) {
147     if (stack_size <= 0)
148       return;
149 
150     if (!message_listener_registered_) {
151       isolate_->AddMessageListener(&MessageListenerCallbackImpl);
152       message_listener_registered_ = true;
153     }
154 
155     isolate_->SetCaptureStackTraceForUncaughtExceptions(
156         true, stack_size, v8::StackTrace::kDetailed);
157   }
158 
SetWorkerAttributes(int worker_id,const GURL & worker_url)159   void SetWorkerAttributes(int worker_id, const GURL& worker_url) {
160     worker_id_ = worker_id;
161     worker_url_ = worker_url;
162   }
163 
isolate() const164   v8::Isolate* isolate() const { return isolate_; }
task_runner() const165   scoped_refptr<base::SingleThreadTaskRunner> task_runner() const {
166     return task_runner_;
167   }
168 
worker_id() const169   int worker_id() const { return worker_id_; }
170 
worker_url() const171   const GURL& worker_url() const { return worker_url_; }
172 
173  private:
174   v8::Isolate* isolate_;
175   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
176 
177   using ContextMap = std::map<int, scoped_refptr<CefV8ContextState>>;
178   ContextMap context_map_;
179 
180   // Used for globally tracked objects that are not associated with a particular
181   // context.
182   CefTrackManager global_manager_;
183 
184   // True if the message listener has been registered.
185   bool message_listener_registered_;
186 
187   // Attributes associated with WebWorker threads.
188   int worker_id_;
189   GURL worker_url_;
190 };
191 
192 // Chromium uses the default Isolate for the main render process thread and a
193 // new Isolate for each WebWorker thread. Continue this pattern by tracking
194 // Isolate information on a per-thread basis. This implementation will need to
195 // be re-worked (perhaps using a map keyed on v8::Isolate::GetCurrent()) if
196 // in the future Chromium begins using the same Isolate across multiple threads.
197 class CefV8StateManager {
198  public:
CefV8StateManager()199   CefV8StateManager() {}
200 
CreateIsolateManager()201   void CreateIsolateManager() {
202     DCHECK(!current_tls_.Get());
203     current_tls_.Set(new CefV8IsolateManager());
204   }
205 
DestroyIsolateManager()206   void DestroyIsolateManager() {
207     DCHECK(current_tls_.Get());
208     delete current_tls_.Get();
209     current_tls_.Set(nullptr);
210   }
211 
GetIsolateManager()212   CefV8IsolateManager* GetIsolateManager() {
213     CefV8IsolateManager* manager = current_tls_.Get();
214     DCHECK(manager);
215     return manager;
216   }
217 
218  private:
219   base::ThreadLocalPointer<CefV8IsolateManager> current_tls_;
220 };
221 
222 base::LazyInstance<CefV8StateManager>::Leaky g_v8_state =
223     LAZY_INSTANCE_INITIALIZER;
224 
GetIsolateManager()225 CefV8IsolateManager* GetIsolateManager() {
226   return g_v8_state.Pointer()->GetIsolateManager();
227 }
228 
229 class V8TrackObject : public CefTrackNode {
230  public:
V8TrackObject(v8::Isolate * isolate)231   explicit V8TrackObject(v8::Isolate* isolate)
232       : isolate_(isolate), external_memory_(0) {
233     DCHECK(isolate_);
234     isolate_->AdjustAmountOfExternalAllocatedMemory(
235         static_cast<int>(sizeof(V8TrackObject)));
236   }
~V8TrackObject()237   ~V8TrackObject() {
238     isolate_->AdjustAmountOfExternalAllocatedMemory(
239         -static_cast<int>(sizeof(V8TrackObject)) - external_memory_);
240   }
241 
GetExternallyAllocatedMemory()242   inline int GetExternallyAllocatedMemory() { return external_memory_; }
243 
AdjustExternallyAllocatedMemory(int change_in_bytes)244   int AdjustExternallyAllocatedMemory(int change_in_bytes) {
245     int new_value = external_memory_ + change_in_bytes;
246     if (new_value < 0) {
247       NOTREACHED() << "External memory usage cannot be less than 0 bytes";
248       change_in_bytes = -(external_memory_);
249       new_value = 0;
250     }
251 
252     if (change_in_bytes != 0)
253       isolate_->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
254     external_memory_ = new_value;
255 
256     return new_value;
257   }
258 
SetAccessor(CefRefPtr<CefV8Accessor> accessor)259   inline void SetAccessor(CefRefPtr<CefV8Accessor> accessor) {
260     accessor_ = accessor;
261   }
262 
GetAccessor()263   inline CefRefPtr<CefV8Accessor> GetAccessor() { return accessor_; }
264 
SetInterceptor(CefRefPtr<CefV8Interceptor> interceptor)265   inline void SetInterceptor(CefRefPtr<CefV8Interceptor> interceptor) {
266     interceptor_ = interceptor;
267   }
268 
GetInterceptor()269   inline CefRefPtr<CefV8Interceptor> GetInterceptor() { return interceptor_; }
270 
SetHandler(CefRefPtr<CefV8Handler> handler)271   inline void SetHandler(CefRefPtr<CefV8Handler> handler) {
272     handler_ = handler;
273   }
274 
GetHandler()275   inline CefRefPtr<CefV8Handler> GetHandler() { return handler_; }
276 
SetUserData(CefRefPtr<CefBaseRefCounted> user_data)277   inline void SetUserData(CefRefPtr<CefBaseRefCounted> user_data) {
278     user_data_ = user_data;
279   }
280 
GetUserData()281   inline CefRefPtr<CefBaseRefCounted> GetUserData() { return user_data_; }
282 
283   // Attach this track object to the specified V8 object.
AttachTo(v8::Local<v8::Context> context,v8::Local<v8::Object> object)284   void AttachTo(v8::Local<v8::Context> context, v8::Local<v8::Object> object) {
285     SetPrivate(context, object, kCefTrackObject,
286                v8::External::New(isolate_, this));
287   }
288 
289   // Retrieve the track object for the specified V8 object.
Unwrap(v8::Local<v8::Context> context,v8::Local<v8::Object> object)290   static V8TrackObject* Unwrap(v8::Local<v8::Context> context,
291                                v8::Local<v8::Object> object) {
292     v8::Local<v8::Value> value;
293     if (GetPrivate(context, object, kCefTrackObject, &value))
294       return static_cast<V8TrackObject*>(v8::External::Cast(*value)->Value());
295 
296     return nullptr;
297   }
298 
299  private:
300   v8::Isolate* isolate_;
301   CefRefPtr<CefV8Accessor> accessor_;
302   CefRefPtr<CefV8Interceptor> interceptor_;
303   CefRefPtr<CefV8Handler> handler_;
304   CefRefPtr<CefBaseRefCounted> user_data_;
305   int external_memory_;
306 };
307 
308 class V8TrackString : public CefTrackNode {
309  public:
V8TrackString(const std::string & str)310   explicit V8TrackString(const std::string& str) : string_(str) {}
GetString()311   const char* GetString() { return string_.c_str(); }
312 
313  private:
314   std::string string_;
315 };
316 
317 class V8TrackArrayBuffer : public CefTrackNode {
318  public:
V8TrackArrayBuffer(v8::Isolate * isolate,CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback)319   explicit V8TrackArrayBuffer(
320       v8::Isolate* isolate,
321       CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback)
322       : isolate_(isolate), release_callback_(release_callback) {
323     DCHECK(isolate_);
324     isolate_->AdjustAmountOfExternalAllocatedMemory(
325         static_cast<int>(sizeof(V8TrackArrayBuffer)));
326   }
327 
~V8TrackArrayBuffer()328   ~V8TrackArrayBuffer() {
329     isolate_->AdjustAmountOfExternalAllocatedMemory(
330         -static_cast<int>(sizeof(V8TrackArrayBuffer)));
331   }
332 
GetReleaseCallback()333   CefRefPtr<CefV8ArrayBufferReleaseCallback> GetReleaseCallback() {
334     return release_callback_;
335   }
336 
337   // Attach this track object to the specified V8 object.
AttachTo(v8::Local<v8::Context> context,v8::Local<v8::ArrayBuffer> arrayBuffer)338   void AttachTo(v8::Local<v8::Context> context,
339                 v8::Local<v8::ArrayBuffer> arrayBuffer) {
340     SetPrivate(context, arrayBuffer, kCefTrackObject,
341                v8::External::New(isolate_, this));
342   }
343 
344   // Retrieve the track object for the specified V8 object.
Unwrap(v8::Local<v8::Context> context,v8::Local<v8::Object> object)345   static V8TrackArrayBuffer* Unwrap(v8::Local<v8::Context> context,
346                                     v8::Local<v8::Object> object) {
347     v8::Local<v8::Value> value;
348     if (GetPrivate(context, object, kCefTrackObject, &value))
349       return static_cast<V8TrackArrayBuffer*>(
350           v8::External::Cast(*value)->Value());
351 
352     return nullptr;
353   }
354 
355  private:
356   v8::Isolate* isolate_;
357   CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback_;
358 };
359 
360 // Object wrapped in a v8::External and passed as the Data argument to
361 // v8::FunctionTemplate::New.
362 class V8FunctionData {
363  public:
Create(v8::Isolate * isolate,const CefString & function_name,CefRefPtr<CefV8Handler> handler)364   static v8::Local<v8::External> Create(v8::Isolate* isolate,
365                                         const CefString& function_name,
366                                         CefRefPtr<CefV8Handler> handler) {
367     // |data| will be deleted if/when the returned v8::External is GC'd.
368     V8FunctionData* data = new V8FunctionData(isolate, function_name, handler);
369     return data->CreateExternal();
370   }
371 
Unwrap(v8::Local<v8::Value> data)372   static V8FunctionData* Unwrap(v8::Local<v8::Value> data) {
373     DCHECK(data->IsExternal());
374     return static_cast<V8FunctionData*>(v8::External::Cast(*data)->Value());
375   }
376 
function_name() const377   CefString function_name() const { return function_name_; }
378 
handler() const379   CefV8Handler* handler() const {
380     if (!handler_)
381       return nullptr;
382     return handler_.get();
383   }
384 
385  private:
V8FunctionData(v8::Isolate * isolate,const CefString & function_name,CefRefPtr<CefV8Handler> handler)386   V8FunctionData(v8::Isolate* isolate,
387                  const CefString& function_name,
388                  CefRefPtr<CefV8Handler> handler)
389       : isolate_(isolate), function_name_(function_name), handler_(handler) {
390     DCHECK(isolate_);
391     DCHECK(handler_);
392   }
393 
~V8FunctionData()394   ~V8FunctionData() {
395     isolate_->AdjustAmountOfExternalAllocatedMemory(
396         -static_cast<int>(sizeof(V8FunctionData)));
397     handler_ = nullptr;
398     function_name_ = "FreedFunction";
399   }
400 
CreateExternal()401   v8::Local<v8::External> CreateExternal() {
402     v8::Local<v8::External> external = v8::External::New(isolate_, this);
403 
404     isolate_->AdjustAmountOfExternalAllocatedMemory(
405         static_cast<int>(sizeof(V8FunctionData)));
406 
407     handle_.Reset(isolate_, external);
408     handle_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter);
409 
410     return external;
411   }
412 
FirstWeakCallback(const v8::WeakCallbackInfo<V8FunctionData> & data)413   static void FirstWeakCallback(
414       const v8::WeakCallbackInfo<V8FunctionData>& data) {
415     V8FunctionData* wrapper = data.GetParameter();
416     wrapper->handle_.Reset();
417     data.SetSecondPassCallback(SecondWeakCallback);
418   }
419 
SecondWeakCallback(const v8::WeakCallbackInfo<V8FunctionData> & data)420   static void SecondWeakCallback(
421       const v8::WeakCallbackInfo<V8FunctionData>& data) {
422     V8FunctionData* wrapper = data.GetParameter();
423     delete wrapper;
424   }
425 
426   v8::Isolate* isolate_;
427   CefString function_name_;
428   CefRefPtr<CefV8Handler> handler_;
429   v8::Persistent<v8::External> handle_;
430 };
431 
432 // Convert a CefString to a V8::String.
GetV8String(v8::Isolate * isolate,const CefString & str)433 v8::Local<v8::String> GetV8String(v8::Isolate* isolate, const CefString& str) {
434 #if defined(CEF_STRING_TYPE_UTF16)
435   // Already a UTF16 string.
436   return v8::String::NewFromTwoByte(
437              isolate,
438              reinterpret_cast<uint16_t*>(
439                  const_cast<CefString::char_type*>(str.c_str())),
440              v8::NewStringType::kNormal, str.length())
441       .ToLocalChecked();
442 #elif defined(CEF_STRING_TYPE_UTF8)
443   // Already a UTF8 string.
444   return v8::String::NewFromUtf8(isolate, const_cast<char*>(str.c_str()),
445                                  v8::NewStringType::kNormal, str.length())
446       .ToLocalChecked();
447 #else
448   // Convert the string to UTF8.
449   std::string tmpStr = str;
450   return v8::String::NewFromUtf8(isolate, tmpStr.c_str(),
451                                  v8::NewStringType::kNormal, tmpStr.length())
452       .ToLocalChecked();
453 #endif
454 }
455 
456 #if defined(CEF_STRING_TYPE_UTF16)
v8impl_string_dtor(char16 * str)457 void v8impl_string_dtor(char16* str) {
458   delete[] str;
459 }
460 #elif defined(CEF_STRING_TYPE_UTF8)
v8impl_string_dtor(char * str)461 void v8impl_string_dtor(char* str) {
462   delete[] str;
463 }
464 #endif
465 
466 // Convert a v8::String to CefString.
GetCefString(v8::Isolate * isolate,v8::Local<v8::String> str,CefString & out)467 void GetCefString(v8::Isolate* isolate,
468                   v8::Local<v8::String> str,
469                   CefString& out) {
470   if (str.IsEmpty())
471     return;
472 
473 #if defined(CEF_STRING_TYPE_WIDE)
474   // Allocate enough space for a worst-case conversion.
475   int len = str->Utf8Length();
476   if (len == 0)
477     return;
478   char* buf = new char[len + 1];
479   str->WriteUtf8(isolate, buf, len + 1);
480 
481   // Perform conversion to the wide type.
482   cef_string_t* retws = out.GetWritableStruct();
483   cef_string_utf8_to_wide(buf, len, retws);
484 
485   delete[] buf;
486 #else  // !defined(CEF_STRING_TYPE_WIDE)
487 #if defined(CEF_STRING_TYPE_UTF16)
488   int len = str->Length();
489   if (len == 0)
490     return;
491   char16* buf = new char16[len + 1];
492   str->Write(isolate, reinterpret_cast<uint16_t*>(buf), 0, len + 1);
493 #else
494   // Allocate enough space for a worst-case conversion.
495   int len = str->Utf8Length();
496   if (len == 0)
497     return;
498   char* buf = new char[len + 1];
499   str->WriteUtf8(isolate, buf, len + 1);
500 #endif
501 
502   // Don't perform an extra string copy.
503   out.clear();
504   cef_string_t* retws = out.GetWritableStruct();
505   retws->str = buf;
506   retws->length = len;
507   retws->dtor = v8impl_string_dtor;
508 #endif  // !defined(CEF_STRING_TYPE_WIDE)
509 }
510 
511 // V8 function callback.
FunctionCallbackImpl(const v8::FunctionCallbackInfo<v8::Value> & info)512 void FunctionCallbackImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
513   v8::Isolate* isolate = info.GetIsolate();
514   v8::Local<v8::Context> context = isolate->GetCurrentContext();
515 
516   V8FunctionData* data = V8FunctionData::Unwrap(info.Data());
517   if (!data->handler()) {
518     // handler has gone away, bail!
519     info.GetReturnValue().SetUndefined();
520     return;
521   }
522   CefV8ValueList params;
523   for (int i = 0; i < info.Length(); i++)
524     params.push_back(new CefV8ValueImpl(isolate, context, info[i]));
525 
526   CefRefPtr<CefV8Value> object =
527       new CefV8ValueImpl(isolate, context, info.This());
528   CefRefPtr<CefV8Value> retval;
529   CefString exception;
530 
531   if (data->handler()->Execute(data->function_name(), object, params, retval,
532                                exception)) {
533     if (!exception.empty()) {
534       info.GetReturnValue().Set(isolate->ThrowException(
535           v8::Exception::Error(GetV8String(isolate, exception))));
536       return;
537     } else {
538       CefV8ValueImpl* rv = static_cast<CefV8ValueImpl*>(retval.get());
539       if (rv && rv->IsValid()) {
540         info.GetReturnValue().Set(rv->GetV8Value(true));
541         return;
542       }
543     }
544   }
545 
546   info.GetReturnValue().SetUndefined();
547 }
548 
549 // V8 Accessor callbacks
AccessorNameGetterCallbackImpl(v8::Local<v8::Name> property,const v8::PropertyCallbackInfo<v8::Value> & info)550 void AccessorNameGetterCallbackImpl(
551     v8::Local<v8::Name> property,
552     const v8::PropertyCallbackInfo<v8::Value>& info) {
553   v8::Isolate* isolate = info.GetIsolate();
554   v8::Local<v8::Context> context = isolate->GetCurrentContext();
555 
556   v8::Local<v8::Object> obj = info.This();
557 
558   CefRefPtr<CefV8Accessor> accessorPtr;
559 
560   V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
561   if (tracker)
562     accessorPtr = tracker->GetAccessor();
563 
564   if (accessorPtr.get()) {
565     CefRefPtr<CefV8Value> retval;
566     CefRefPtr<CefV8Value> object = new CefV8ValueImpl(isolate, context, obj);
567     CefString name, exception;
568     GetCefString(isolate, v8::Local<v8::String>::Cast(property), name);
569     if (accessorPtr->Get(name, object, retval, exception)) {
570       if (!exception.empty()) {
571         info.GetReturnValue().Set(isolate->ThrowException(
572             v8::Exception::Error(GetV8String(isolate, exception))));
573         return;
574       } else {
575         CefV8ValueImpl* rv = static_cast<CefV8ValueImpl*>(retval.get());
576         if (rv && rv->IsValid()) {
577           info.GetReturnValue().Set(rv->GetV8Value(true));
578           return;
579         }
580       }
581     }
582   }
583 
584   return info.GetReturnValue().SetUndefined();
585 }
586 
AccessorNameSetterCallbackImpl(v8::Local<v8::Name> property,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)587 void AccessorNameSetterCallbackImpl(
588     v8::Local<v8::Name> property,
589     v8::Local<v8::Value> value,
590     const v8::PropertyCallbackInfo<void>& info) {
591   v8::Isolate* isolate = info.GetIsolate();
592   v8::Local<v8::Context> context = isolate->GetCurrentContext();
593 
594   v8::Local<v8::Object> obj = info.This();
595 
596   CefRefPtr<CefV8Accessor> accessorPtr;
597 
598   V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
599   if (tracker)
600     accessorPtr = tracker->GetAccessor();
601 
602   if (accessorPtr.get()) {
603     CefRefPtr<CefV8Value> object = new CefV8ValueImpl(isolate, context, obj);
604     CefRefPtr<CefV8Value> cefValue =
605         new CefV8ValueImpl(isolate, context, value);
606     CefString name, exception;
607     GetCefString(isolate, v8::Local<v8::String>::Cast(property), name);
608     accessorPtr->Set(name, object, cefValue, exception);
609     if (!exception.empty()) {
610       isolate->ThrowException(
611           v8::Exception::Error(GetV8String(isolate, exception)));
612       return;
613     }
614   }
615 }
616 
617 // Two helper functions for V8 Interceptor callbacks.
PropertyToIndex(v8::Isolate * isolate,v8::Local<v8::Name> property)618 CefString PropertyToIndex(v8::Isolate* isolate, v8::Local<v8::Name> property) {
619   CefString name;
620   GetCefString(isolate, property.As<v8::String>(), name);
621   return name;
622 }
623 
PropertyToIndex(v8::Isolate * isolate,uint32_t index)624 int PropertyToIndex(v8::Isolate* isolate, uint32_t index) {
625   return static_cast<int>(index);
626 }
627 
628 // V8 Interceptor callbacks.
629 // T == v8::Local<v8::Name> for named property handlers and
630 // T == uint32_t for indexed property handlers
631 template <typename T>
InterceptorGetterCallbackImpl(T property,const v8::PropertyCallbackInfo<v8::Value> & info)632 void InterceptorGetterCallbackImpl(
633     T property,
634     const v8::PropertyCallbackInfo<v8::Value>& info) {
635   v8::Isolate* isolate = info.GetIsolate();
636   v8::Local<v8::Context> context = isolate->GetCurrentContext();
637 
638   v8::Handle<v8::Object> obj = info.This();
639   CefRefPtr<CefV8Interceptor> interceptorPtr;
640 
641   V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
642   if (tracker)
643     interceptorPtr = tracker->GetInterceptor();
644   if (!interceptorPtr.get())
645     return;
646 
647   CefRefPtr<CefV8Value> object = new CefV8ValueImpl(isolate, context, obj);
648   CefRefPtr<CefV8Value> retval;
649   CefString exception;
650   interceptorPtr->Get(PropertyToIndex(isolate, property), object, retval,
651                       exception);
652   if (!exception.empty()) {
653     info.GetReturnValue().Set(isolate->ThrowException(
654         v8::Exception::Error(GetV8String(isolate, exception))));
655   } else {
656     CefV8ValueImpl* retval_impl = static_cast<CefV8ValueImpl*>(retval.get());
657     if (retval_impl && retval_impl->IsValid()) {
658       info.GetReturnValue().Set(retval_impl->GetV8Value(true));
659     }
660   }
661 }
662 
663 template <typename T>
InterceptorSetterCallbackImpl(T property,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)664 void InterceptorSetterCallbackImpl(
665     T property,
666     v8::Local<v8::Value> value,
667     const v8::PropertyCallbackInfo<v8::Value>& info) {
668   v8::Isolate* isolate = info.GetIsolate();
669   v8::Local<v8::Context> context = isolate->GetCurrentContext();
670   v8::Handle<v8::Object> obj = info.This();
671   CefRefPtr<CefV8Interceptor> interceptorPtr;
672 
673   V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
674   if (tracker)
675     interceptorPtr = tracker->GetInterceptor();
676 
677   if (!interceptorPtr.get())
678     return;
679   CefRefPtr<CefV8Value> object = new CefV8ValueImpl(isolate, context, obj);
680   CefRefPtr<CefV8Value> cefValue = new CefV8ValueImpl(isolate, context, value);
681   CefString exception;
682   interceptorPtr->Set(PropertyToIndex(isolate, property), object, cefValue,
683                       exception);
684   if (!exception.empty()) {
685     isolate->ThrowException(
686         v8::Exception::Error(GetV8String(isolate, exception)));
687   }
688 }
689 
690 // V8 extension registration.
691 
692 class ExtensionWrapper : public v8::Extension {
693  public:
ExtensionWrapper(const char * extension_name,const char * javascript_code,CefV8Handler * handler)694   ExtensionWrapper(const char* extension_name,
695                    const char* javascript_code,
696                    CefV8Handler* handler)
697       : v8::Extension(extension_name, javascript_code), handler_(handler) {}
698 
GetNativeFunctionTemplate(v8::Isolate * isolate,v8::Handle<v8::String> name)699   v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
700       v8::Isolate* isolate,
701       v8::Handle<v8::String> name) override {
702     if (!handler_)
703       return v8::Local<v8::FunctionTemplate>();
704 
705     CefString func_name;
706     GetCefString(isolate, name, func_name);
707 
708     v8::Local<v8::External> function_data =
709         V8FunctionData::Create(isolate, func_name, handler_);
710 
711     return v8::FunctionTemplate::New(isolate, FunctionCallbackImpl,
712                                      function_data);
713   }
714 
715  private:
716   CefV8Handler* handler_;
717 };
718 
719 class CefV8ExceptionImpl : public CefV8Exception {
720  public:
CefV8ExceptionImpl(v8::Local<v8::Context> context,v8::Local<v8::Message> message)721   CefV8ExceptionImpl(v8::Local<v8::Context> context,
722                      v8::Local<v8::Message> message)
723       : line_number_(0),
724         start_position_(0),
725         end_position_(0),
726         start_column_(0),
727         end_column_(0) {
728     if (message.IsEmpty())
729       return;
730 
731     v8::Isolate* isolate = context->GetIsolate();
732     GetCefString(isolate, message->Get(), message_);
733     v8::MaybeLocal<v8::String> source_line = message->GetSourceLine(context);
734     if (!source_line.IsEmpty())
735       GetCefString(isolate, source_line.ToLocalChecked(), source_line_);
736 
737     if (!message->GetScriptResourceName().IsEmpty()) {
738       GetCefString(
739           isolate,
740           message->GetScriptResourceName()->ToString(context).ToLocalChecked(),
741           script_);
742     }
743 
744     v8::Maybe<int> line_number = message->GetLineNumber(context);
745     if (!line_number.IsNothing())
746       line_number_ = line_number.ToChecked();
747     start_position_ = message->GetStartPosition();
748     end_position_ = message->GetEndPosition();
749     start_column_ = message->GetStartColumn(context).FromJust();
750     end_column_ = message->GetEndColumn(context).FromJust();
751   }
752 
GetMessage()753   CefString GetMessage() override { return message_; }
GetSourceLine()754   CefString GetSourceLine() override { return source_line_; }
GetScriptResourceName()755   CefString GetScriptResourceName() override { return script_; }
GetLineNumber()756   int GetLineNumber() override { return line_number_; }
GetStartPosition()757   int GetStartPosition() override { return start_position_; }
GetEndPosition()758   int GetEndPosition() override { return end_position_; }
GetStartColumn()759   int GetStartColumn() override { return start_column_; }
GetEndColumn()760   int GetEndColumn() override { return end_column_; }
761 
762  protected:
763   CefString message_;
764   CefString source_line_;
765   CefString script_;
766   int line_number_;
767   int start_position_;
768   int end_position_;
769   int start_column_;
770   int end_column_;
771 
772   IMPLEMENT_REFCOUNTING(CefV8ExceptionImpl);
773 };
774 
MessageListenerCallbackImpl(v8::Handle<v8::Message> message,v8::Handle<v8::Value> data)775 void MessageListenerCallbackImpl(v8::Handle<v8::Message> message,
776                                  v8::Handle<v8::Value> data) {
777   CefRefPtr<CefApp> application = CefAppManager::Get()->GetApplication();
778   if (!application.get())
779     return;
780 
781   CefRefPtr<CefRenderProcessHandler> handler =
782       application->GetRenderProcessHandler();
783   if (!handler.get())
784     return;
785 
786   v8::Isolate* isolate = GetIsolateManager()->isolate();
787   CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
788   v8::Local<v8::StackTrace> v8Stack = message->GetStackTrace();
789   CefRefPtr<CefV8StackTrace> stackTrace =
790       new CefV8StackTraceImpl(isolate, v8Stack);
791 
792   CefRefPtr<CefV8Exception> exception = new CefV8ExceptionImpl(
793       static_cast<CefV8ContextImpl*>(context.get())->GetV8Context(), message);
794 
795   CefRefPtr<CefBrowser> browser = context->GetBrowser();
796   if (browser) {
797     handler->OnUncaughtException(browser, context->GetFrame(), context,
798                                  exception, stackTrace);
799   }
800 }
801 
802 }  // namespace
803 
804 // Global functions.
805 
CefV8IsolateCreated()806 void CefV8IsolateCreated() {
807   g_v8_state.Pointer()->CreateIsolateManager();
808 }
809 
CefV8IsolateDestroyed()810 void CefV8IsolateDestroyed() {
811   g_v8_state.Pointer()->DestroyIsolateManager();
812 }
813 
CefV8ReleaseContext(v8::Local<v8::Context> context)814 void CefV8ReleaseContext(v8::Local<v8::Context> context) {
815   GetIsolateManager()->ReleaseContext(context);
816 }
817 
CefV8SetUncaughtExceptionStackSize(int stack_size)818 void CefV8SetUncaughtExceptionStackSize(int stack_size) {
819   GetIsolateManager()->SetUncaughtExceptionStackSize(stack_size);
820 }
821 
CefV8SetWorkerAttributes(int worker_id,const GURL & worker_url)822 void CefV8SetWorkerAttributes(int worker_id, const GURL& worker_url) {
823   GetIsolateManager()->SetWorkerAttributes(worker_id, worker_url);
824 }
825 
CefRegisterExtension(const CefString & extension_name,const CefString & javascript_code,CefRefPtr<CefV8Handler> handler)826 bool CefRegisterExtension(const CefString& extension_name,
827                           const CefString& javascript_code,
828                           CefRefPtr<CefV8Handler> handler) {
829   // Verify that this method was called on the correct thread.
830   CEF_REQUIRE_RT_RETURN(false);
831 
832   CefV8IsolateManager* isolate_manager = GetIsolateManager();
833 
834   V8TrackString* name = new V8TrackString(extension_name);
835   isolate_manager->AddGlobalTrackObject(name);
836   V8TrackString* code = new V8TrackString(javascript_code);
837   isolate_manager->AddGlobalTrackObject(code);
838 
839   if (handler.get()) {
840     // The reference will be released when the process exits.
841     V8TrackObject* object = new V8TrackObject(isolate_manager->isolate());
842     object->SetHandler(handler);
843     isolate_manager->AddGlobalTrackObject(object);
844   }
845 
846   std::unique_ptr<v8::Extension> wrapper(new ExtensionWrapper(
847       name->GetString(), code->GetString(), handler.get()));
848 
849   content::RenderThread::Get()->RegisterExtension(std::move(wrapper));
850   return true;
851 }
852 
853 // Helper macros
854 
855 #define CEF_V8_HAS_ISOLATE() (!!GetIsolateManager())
856 #define CEF_V8_REQUIRE_ISOLATE_RETURN(var)     \
857   if (!CEF_V8_HAS_ISOLATE()) {                 \
858     NOTREACHED() << "V8 isolate is not valid"; \
859     return var;                                \
860   }
861 
862 #define CEF_V8_CURRENTLY_ON_MLT() \
863   (!handle_.get() || handle_->BelongsToCurrentThread())
864 #define CEF_V8_REQUIRE_MLT_RETURN(var)            \
865   CEF_V8_REQUIRE_ISOLATE_RETURN(var);             \
866   if (!CEF_V8_CURRENTLY_ON_MLT()) {               \
867     NOTREACHED() << "called on incorrect thread"; \
868     return var;                                   \
869   }
870 
871 #define CEF_V8_HANDLE_IS_VALID() (handle_.get() && handle_->IsValid())
872 #define CEF_V8_REQUIRE_VALID_HANDLE_RETURN(ret) \
873   CEF_V8_REQUIRE_MLT_RETURN(ret);               \
874   if (!CEF_V8_HANDLE_IS_VALID()) {              \
875     NOTREACHED() << "V8 handle is not valid";   \
876     return ret;                                 \
877   }
878 
879 #define CEF_V8_IS_VALID()                               \
880   (CEF_V8_HAS_ISOLATE() && CEF_V8_CURRENTLY_ON_MLT() && \
881    CEF_V8_HANDLE_IS_VALID())
882 
883 #define CEF_V8_REQUIRE_OBJECT_RETURN(ret)        \
884   CEF_V8_REQUIRE_VALID_HANDLE_RETURN(ret);       \
885   if (type_ != TYPE_OBJECT) {                    \
886     NOTREACHED() << "V8 value is not an object"; \
887     return ret;                                  \
888   }
889 
890 // CefV8HandleBase
891 
~CefV8HandleBase()892 CefV8HandleBase::~CefV8HandleBase() {
893   DCHECK(BelongsToCurrentThread());
894 }
895 
BelongsToCurrentThread() const896 bool CefV8HandleBase::BelongsToCurrentThread() const {
897   return task_runner_->RunsTasksInCurrentSequence();
898 }
899 
CefV8HandleBase(v8::Isolate * isolate,v8::Local<v8::Context> context)900 CefV8HandleBase::CefV8HandleBase(v8::Isolate* isolate,
901                                  v8::Local<v8::Context> context)
902     : isolate_(isolate) {
903   DCHECK(isolate_);
904 
905   CefV8IsolateManager* manager = GetIsolateManager();
906   DCHECK(manager);
907   DCHECK_EQ(isolate_, manager->isolate());
908 
909   task_runner_ = manager->task_runner();
910   context_state_ = manager->GetContextState(context);
911 }
912 
913 // CefV8Context
914 
915 // static
GetCurrentContext()916 CefRefPtr<CefV8Context> CefV8Context::GetCurrentContext() {
917   CefRefPtr<CefV8Context> context;
918   CEF_V8_REQUIRE_ISOLATE_RETURN(context);
919   v8::Isolate* isolate = GetIsolateManager()->isolate();
920   if (isolate->InContext()) {
921     v8::HandleScope handle_scope(isolate);
922     context = new CefV8ContextImpl(isolate, isolate->GetCurrentContext());
923   }
924   return context;
925 }
926 
927 // static
GetEnteredContext()928 CefRefPtr<CefV8Context> CefV8Context::GetEnteredContext() {
929   CefRefPtr<CefV8Context> context;
930   CEF_V8_REQUIRE_ISOLATE_RETURN(context);
931   v8::Isolate* isolate = GetIsolateManager()->isolate();
932   if (isolate->InContext()) {
933     v8::HandleScope handle_scope(isolate);
934     context =
935         new CefV8ContextImpl(isolate, isolate->GetEnteredOrMicrotaskContext());
936   }
937   return context;
938 }
939 
940 // static
InContext()941 bool CefV8Context::InContext() {
942   CEF_V8_REQUIRE_ISOLATE_RETURN(false);
943   v8::Isolate* isolate = GetIsolateManager()->isolate();
944   return isolate->InContext();
945 }
946 
947 // CefV8ContextImpl
948 
CefV8ContextImpl(v8::Isolate * isolate,v8::Local<v8::Context> context)949 CefV8ContextImpl::CefV8ContextImpl(v8::Isolate* isolate,
950                                    v8::Local<v8::Context> context)
951     : handle_(new Handle(isolate, context, context)), enter_count_(0) {}
952 
~CefV8ContextImpl()953 CefV8ContextImpl::~CefV8ContextImpl() {
954   DLOG_ASSERT(0 == enter_count_);
955 }
956 
GetTaskRunner()957 CefRefPtr<CefTaskRunner> CefV8ContextImpl::GetTaskRunner() {
958   return new CefTaskRunnerImpl(handle_->task_runner());
959 }
960 
IsValid()961 bool CefV8ContextImpl::IsValid() {
962   return CEF_V8_IS_VALID();
963 }
964 
GetBrowser()965 CefRefPtr<CefBrowser> CefV8ContextImpl::GetBrowser() {
966   CefRefPtr<CefBrowser> browser;
967   CEF_V8_REQUIRE_VALID_HANDLE_RETURN(browser);
968 
969   blink::WebLocalFrame* webframe = GetWebFrame();
970   if (webframe)
971     browser = CefBrowserImpl::GetBrowserForMainFrame(webframe->Top());
972 
973   return browser;
974 }
975 
GetFrame()976 CefRefPtr<CefFrame> CefV8ContextImpl::GetFrame() {
977   CefRefPtr<CefFrame> frame;
978   CEF_V8_REQUIRE_VALID_HANDLE_RETURN(frame);
979 
980   blink::WebLocalFrame* webframe = GetWebFrame();
981   if (webframe) {
982     CefRefPtr<CefBrowserImpl> browser =
983         CefBrowserImpl::GetBrowserForMainFrame(webframe->Top());
984     if (browser) {
985       frame = browser->GetFrame(render_frame_util::GetIdentifier(webframe));
986     }
987   }
988 
989   return frame;
990 }
991 
GetGlobal()992 CefRefPtr<CefV8Value> CefV8ContextImpl::GetGlobal() {
993   CEF_V8_REQUIRE_VALID_HANDLE_RETURN(nullptr);
994 
995   if (blink_glue::IsScriptForbidden())
996     return nullptr;
997 
998   v8::Isolate* isolate = handle_->isolate();
999   v8::HandleScope handle_scope(isolate);
1000   v8::Local<v8::Context> context = GetV8Context();
1001   v8::Context::Scope context_scope(context);
1002   return new CefV8ValueImpl(isolate, context, context->Global());
1003 }
1004 
Enter()1005 bool CefV8ContextImpl::Enter() {
1006   CEF_V8_REQUIRE_VALID_HANDLE_RETURN(false);
1007 
1008   if (blink_glue::IsScriptForbidden())
1009     return false;
1010 
1011   v8::Isolate* isolate = handle_->isolate();
1012   v8::HandleScope handle_scope(isolate);
1013 
1014   if (!microtasks_scope_) {
1015     // Increment the MicrotasksScope recursion level.
1016     microtasks_scope_.reset(
1017         new v8::MicrotasksScope(isolate, v8::MicrotasksScope::kRunMicrotasks));
1018   }
1019 
1020   ++enter_count_;
1021   handle_->GetNewV8Handle()->Enter();
1022 
1023   return true;
1024 }
1025 
Exit()1026 bool CefV8ContextImpl::Exit() {
1027   CEF_V8_REQUIRE_VALID_HANDLE_RETURN(false);
1028 
1029   if (blink_glue::IsScriptForbidden())
1030     return false;
1031 
1032   if (enter_count_ <= 0) {
1033     LOG(ERROR) << "Call to CefV8Context::Exit() without matching call to "
1034                   "CefV8Context::Enter()";
1035     return false;
1036   }
1037 
1038   v8::HandleScope handle_scope(handle_->isolate());
1039 
1040   handle_->GetNewV8Handle()->Exit();
1041 
1042   if (--enter_count_ == 0) {
1043     // Decrement the MicrotasksScope recursion level.
1044     microtasks_scope_.reset(nullptr);
1045   }
1046 
1047   return true;
1048 }
1049 
IsSame(CefRefPtr<CefV8Context> that)1050 bool CefV8ContextImpl::IsSame(CefRefPtr<CefV8Context> that) {
1051   CEF_V8_REQUIRE_VALID_HANDLE_RETURN(false);
1052 
1053   CefV8ContextImpl* impl = static_cast<CefV8ContextImpl*>(that.get());
1054   if (!impl || !impl->IsValid())
1055     return false;
1056 
1057   return (handle_->GetPersistentV8Handle() ==
1058           impl->handle_->GetPersistentV8Handle());
1059 }
1060 
Eval(const CefString & code,const CefString & script_url,int start_line,CefRefPtr<CefV8Value> & retval,CefRefPtr<CefV8Exception> & exception)1061 bool CefV8ContextImpl::Eval(const CefString& code,
1062                             const CefString& script_url,
1063                             int start_line,
1064                             CefRefPtr<CefV8Value>& retval,
1065                             CefRefPtr<CefV8Exception>& exception) {
1066   retval = nullptr;
1067   exception = nullptr;
1068 
1069   CEF_V8_REQUIRE_VALID_HANDLE_RETURN(false);
1070 
1071   if (blink_glue::IsScriptForbidden())
1072     return false;
1073 
1074   if (code.empty()) {
1075     NOTREACHED() << "invalid input parameter";
1076     return false;
1077   }
1078 
1079   v8::Isolate* isolate = handle_->isolate();
1080   v8::HandleScope handle_scope(isolate);
1081   v8::Local<v8::Context> context = GetV8Context();
1082   v8::Context::Scope context_scope(context);
1083 
1084   const blink::WebString& source =
1085       blink::WebString::FromUTF16(code.ToString16());
1086   const blink::WebString& source_url =
1087       blink::WebString::FromUTF16(script_url.ToString16());
1088 
1089   v8::TryCatch try_catch(isolate);
1090   try_catch.SetVerbose(true);
1091 
1092   v8::Local<v8::Value> func_rv = blink_glue::ExecuteV8ScriptAndReturnValue(
1093       source, source_url, start_line, context, try_catch);
1094 
1095   if (try_catch.HasCaught()) {
1096     exception = new CefV8ExceptionImpl(context, try_catch.Message());
1097     return false;
1098   } else if (!func_rv.IsEmpty()) {
1099     retval = new CefV8ValueImpl(isolate, context, func_rv);
1100     return true;
1101   }
1102 
1103   NOTREACHED();
1104   return false;
1105 }
1106 
GetV8Context()1107 v8::Local<v8::Context> CefV8ContextImpl::GetV8Context() {
1108   return handle_->GetNewV8Handle();
1109 }
1110 
GetWebFrame()1111 blink::WebLocalFrame* CefV8ContextImpl::GetWebFrame() {
1112   CEF_REQUIRE_RT();
1113 
1114   if (blink_glue::IsScriptForbidden())
1115     return nullptr;
1116 
1117   v8::HandleScope handle_scope(handle_->isolate());
1118   v8::Local<v8::Context> context = GetV8Context();
1119   v8::Context::Scope context_scope(context);
1120   return blink::WebLocalFrame::FrameForContext(context);
1121 }
1122 
1123 // CefV8ValueImpl::Handle
1124 
Handle(v8::Isolate * isolate,v8::Local<v8::Context> context,handleType v,CefTrackNode * tracker)1125 CefV8ValueImpl::Handle::Handle(v8::Isolate* isolate,
1126                                v8::Local<v8::Context> context,
1127                                handleType v,
1128                                CefTrackNode* tracker)
1129     : CefV8HandleBase(isolate, context),
1130       handle_(isolate, v),
1131       tracker_(tracker),
1132       should_persist_(false),
1133       is_set_weak_(false) {}
1134 
~Handle()1135 CefV8ValueImpl::Handle::~Handle() {
1136   DCHECK(BelongsToCurrentThread());
1137 
1138   if (tracker_) {
1139     if (is_set_weak_) {
1140       if (context_state_.get()) {
1141         // If the associated context is still valid then delete |tracker_|.
1142         // Otherwise, |tracker_| will already have been deleted.
1143         if (context_state_->IsValid())
1144           context_state_->DeleteTrackObject(tracker_);
1145       } else {
1146         GetIsolateManager()->DeleteGlobalTrackObject(tracker_);
1147       }
1148     } else {
1149       delete tracker_;
1150     }
1151   }
1152 
1153   if (is_set_weak_) {
1154     isolate_->AdjustAmountOfExternalAllocatedMemory(
1155         -static_cast<int>(sizeof(Handle)));
1156   } else {
1157     // SetWeak was not called so reset now.
1158     handle_.Reset();
1159   }
1160 }
1161 
GetNewV8Handle(bool should_persist)1162 CefV8ValueImpl::Handle::handleType CefV8ValueImpl::Handle::GetNewV8Handle(
1163     bool should_persist) {
1164   DCHECK(IsValid());
1165   if (should_persist && !should_persist_)
1166     should_persist_ = true;
1167   return handleType::New(isolate(), handle_);
1168 }
1169 
1170 CefV8ValueImpl::Handle::persistentType&
GetPersistentV8Handle()1171 CefV8ValueImpl::Handle::GetPersistentV8Handle() {
1172   return handle_;
1173 }
1174 
SetWeakIfNecessary()1175 void CefV8ValueImpl::Handle::SetWeakIfNecessary() {
1176   if (!BelongsToCurrentThread()) {
1177     task_runner()->PostTask(
1178         FROM_HERE,
1179         base::BindOnce(&CefV8ValueImpl::Handle::SetWeakIfNecessary, this));
1180     return;
1181   }
1182 
1183   // Persist the handle (call SetWeak) if:
1184   // A. The handle has been passed into a V8 function or used as a return value
1185   //    from a V8 callback, and
1186   // B. The associated context, if any, is still valid.
1187   if (should_persist_ && (!context_state_.get() || context_state_->IsValid())) {
1188     is_set_weak_ = true;
1189 
1190     if (tracker_) {
1191       if (context_state_.get()) {
1192         // |tracker_| will be deleted when:
1193         // A. The associated context is released, or
1194         // B. SecondWeakCallback is called for the weak handle.
1195         DCHECK(context_state_->IsValid());
1196         context_state_->AddTrackObject(tracker_);
1197       } else {
1198         // |tracker_| will be deleted when:
1199         // A. The process shuts down, or
1200         // B. SecondWeakCallback is called for the weak handle.
1201         GetIsolateManager()->AddGlobalTrackObject(tracker_);
1202       }
1203     }
1204 
1205     isolate_->AdjustAmountOfExternalAllocatedMemory(
1206         static_cast<int>(sizeof(Handle)));
1207 
1208     // The added reference will be released in SecondWeakCallback.
1209     AddRef();
1210     handle_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter);
1211   }
1212 }
1213 
1214 // static
FirstWeakCallback(const v8::WeakCallbackInfo<Handle> & data)1215 void CefV8ValueImpl::Handle::FirstWeakCallback(
1216     const v8::WeakCallbackInfo<Handle>& data) {
1217   Handle* wrapper = data.GetParameter();
1218   wrapper->handle_.Reset();
1219   data.SetSecondPassCallback(SecondWeakCallback);
1220 }
1221 
1222 // static
SecondWeakCallback(const v8::WeakCallbackInfo<Handle> & data)1223 void CefV8ValueImpl::Handle::SecondWeakCallback(
1224     const v8::WeakCallbackInfo<Handle>& data) {
1225   Handle* wrapper = data.GetParameter();
1226   wrapper->Release();
1227 }
1228 
1229 // CefV8Value
1230 
1231 // static
CreateUndefined()1232 CefRefPtr<CefV8Value> CefV8Value::CreateUndefined() {
1233   CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1234   v8::Isolate* isolate = GetIsolateManager()->isolate();
1235   CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1236   impl->InitUndefined();
1237   return impl.get();
1238 }
1239 
1240 // static
CreateNull()1241 CefRefPtr<CefV8Value> CefV8Value::CreateNull() {
1242   CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1243   v8::Isolate* isolate = GetIsolateManager()->isolate();
1244   CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1245   impl->InitNull();
1246   return impl.get();
1247 }
1248 
1249 // static
CreateBool(bool value)1250 CefRefPtr<CefV8Value> CefV8Value::CreateBool(bool value) {
1251   CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1252   v8::Isolate* isolate = GetIsolateManager()->isolate();
1253   CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1254   impl->InitBool(value);
1255   return impl.get();
1256 }
1257 
1258 // static
CreateInt(int32 value)1259 CefRefPtr<CefV8Value> CefV8Value::CreateInt(int32 value) {
1260   CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1261   v8::Isolate* isolate = GetIsolateManager()->isolate();
1262   CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1263   impl->InitInt(value);
1264   return impl.get();
1265 }
1266 
1267 // static
CreateUInt(uint32 value)1268 CefRefPtr<CefV8Value> CefV8Value::CreateUInt(uint32 value) {
1269   CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1270   v8::Isolate* isolate = GetIsolateManager()->isolate();
1271   CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1272   impl->InitUInt(value);
1273   return impl.get();
1274 }
1275 
1276 // static
CreateDouble(double value)1277 CefRefPtr<CefV8Value> CefV8Value::CreateDouble(double value) {
1278   CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1279   v8::Isolate* isolate = GetIsolateManager()->isolate();
1280   CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1281   impl->InitDouble(value);
1282   return impl.get();
1283 }
1284 
1285 // static
CreateDate(const CefTime & value)1286 CefRefPtr<CefV8Value> CefV8Value::CreateDate(const CefTime& value) {
1287   CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1288   v8::Isolate* isolate = GetIsolateManager()->isolate();
1289   CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1290   impl->InitDate(value);
1291   return impl.get();
1292 }
1293 
1294 // static
CreateString(const CefString & value)1295 CefRefPtr<CefV8Value> CefV8Value::CreateString(const CefString& value) {
1296   CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1297   v8::Isolate* isolate = GetIsolateManager()->isolate();
1298   CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1299   CefString str(value);
1300   impl->InitString(str);
1301   return impl.get();
1302 }
1303 
1304 // static
CreateObject(CefRefPtr<CefV8Accessor> accessor,CefRefPtr<CefV8Interceptor> interceptor)1305 CefRefPtr<CefV8Value> CefV8Value::CreateObject(
1306     CefRefPtr<CefV8Accessor> accessor,
1307     CefRefPtr<CefV8Interceptor> interceptor) {
1308   CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1309 
1310   v8::Isolate* isolate = GetIsolateManager()->isolate();
1311   v8::HandleScope handle_scope(isolate);
1312 
1313   v8::Local<v8::Context> context = isolate->GetCurrentContext();
1314   if (context.IsEmpty()) {
1315     NOTREACHED() << "not currently in a V8 context";
1316     return nullptr;
1317   }
1318 
1319   // Create the new V8 object. If an interceptor is passed, create object from
1320   // template and set property handlers.
1321   v8::Local<v8::Object> obj;
1322   if (interceptor.get()) {
1323     v8::Local<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
1324     tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(
1325         InterceptorGetterCallbackImpl<v8::Local<v8::Name>>,
1326         InterceptorSetterCallbackImpl<v8::Local<v8::Name>>, nullptr, nullptr,
1327         nullptr, v8::Local<v8::Value>(),
1328         v8::PropertyHandlerFlags::kOnlyInterceptStrings));
1329 
1330     tmpl->SetIndexedPropertyHandler(InterceptorGetterCallbackImpl<uint32_t>,
1331                                     InterceptorSetterCallbackImpl<uint32_t>);
1332 
1333     v8::MaybeLocal<v8::Object> maybe_object = tmpl->NewInstance(context);
1334     if (!maybe_object.ToLocal<v8::Object>(&obj)) {
1335       NOTREACHED() << "Failed to create V8 Object with interceptor";
1336       return nullptr;
1337     }
1338   } else {
1339     obj = v8::Object::New(isolate);
1340   }
1341 
1342   // Create a tracker object that will cause the user data and/or accessor
1343   // and/or interceptor reference to be released when the V8 object is
1344   // destroyed.
1345   V8TrackObject* tracker = new V8TrackObject(isolate);
1346   tracker->SetAccessor(accessor);
1347   tracker->SetInterceptor(interceptor);
1348 
1349   // Attach the tracker object.
1350   tracker->AttachTo(context, obj);
1351 
1352   CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1353   impl->InitObject(obj, tracker);
1354   return impl.get();
1355 }
1356 
1357 // static
CreateArray(int length)1358 CefRefPtr<CefV8Value> CefV8Value::CreateArray(int length) {
1359   CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1360 
1361   v8::Isolate* isolate = GetIsolateManager()->isolate();
1362   v8::HandleScope handle_scope(isolate);
1363 
1364   v8::Local<v8::Context> context = isolate->GetCurrentContext();
1365   if (context.IsEmpty()) {
1366     NOTREACHED() << "not currently in a V8 context";
1367     return nullptr;
1368   }
1369 
1370   // Create a tracker object that will cause the user data reference to be
1371   // released when the V8 object is destroyed.
1372   V8TrackObject* tracker = new V8TrackObject(isolate);
1373 
1374   // Create the new V8 array.
1375   v8::Local<v8::Array> arr = v8::Array::New(isolate, length);
1376 
1377   // Attach the tracker object.
1378   tracker->AttachTo(context, arr);
1379 
1380   CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1381   impl->InitObject(arr, tracker);
1382   return impl.get();
1383 }
1384 
1385 // static
CreateArrayBuffer(void * buffer,size_t length,CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback)1386 CefRefPtr<CefV8Value> CefV8Value::CreateArrayBuffer(
1387     void* buffer,
1388     size_t length,
1389     CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback) {
1390   CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1391 
1392   v8::Isolate* isolate = GetIsolateManager()->isolate();
1393   v8::HandleScope handle_scope(isolate);
1394   v8::Local<v8::Context> context = isolate->GetCurrentContext();
1395   if (context.IsEmpty()) {
1396     NOTREACHED() << "not currently in a V8 context";
1397     return nullptr;
1398   }
1399 
1400   // Create a tracker object that will cause the user data reference to be
1401   // released when the V8 object is destroyed.
1402   V8TrackArrayBuffer* tracker =
1403       new V8TrackArrayBuffer(isolate, release_callback);
1404 
1405   if (release_callback)
1406     release_callback->AddRef();
1407 
1408   auto deleter = [](void* data, size_t length, void* deleter_data) {
1409     auto* release_callback =
1410         reinterpret_cast<CefV8ArrayBufferReleaseCallback*>(deleter_data);
1411     if (release_callback) {
1412       release_callback->ReleaseBuffer(data);
1413       release_callback->Release();
1414     }
1415   };
1416 
1417   std::unique_ptr<v8::BackingStore> backing = v8::ArrayBuffer::NewBackingStore(
1418       buffer, length, deleter, release_callback.get());
1419   v8::Local<v8::ArrayBuffer> ab =
1420       v8::ArrayBuffer::New(isolate, std::move(backing));
1421 
1422   // Attach the tracker object.
1423   tracker->AttachTo(context, ab);
1424 
1425   CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1426   impl->InitObject(ab, tracker);
1427   return impl.get();
1428 }
1429 
1430 // static
CreateFunction(const CefString & name,CefRefPtr<CefV8Handler> handler)1431 CefRefPtr<CefV8Value> CefV8Value::CreateFunction(
1432     const CefString& name,
1433     CefRefPtr<CefV8Handler> handler) {
1434   CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1435 
1436   if (!handler.get()) {
1437     NOTREACHED() << "invalid parameter";
1438     return nullptr;
1439   }
1440 
1441   v8::Isolate* isolate = GetIsolateManager()->isolate();
1442   v8::HandleScope handle_scope(isolate);
1443 
1444   v8::Local<v8::Context> context = isolate->GetCurrentContext();
1445   if (context.IsEmpty()) {
1446     NOTREACHED() << "not currently in a V8 context";
1447     return nullptr;
1448   }
1449 
1450   v8::Local<v8::External> function_data =
1451       V8FunctionData::Create(isolate, name, handler);
1452 
1453   // Create a new V8 function template.
1454   v8::Local<v8::FunctionTemplate> tmpl =
1455       v8::FunctionTemplate::New(isolate, FunctionCallbackImpl, function_data);
1456 
1457   // Retrieve the function object and set the name.
1458   v8::MaybeLocal<v8::Function> maybe_func = tmpl->GetFunction(context);
1459   v8::Local<v8::Function> func;
1460   if (!maybe_func.ToLocal(&func)) {
1461     NOTREACHED() << "failed to create V8 function";
1462     return nullptr;
1463   }
1464 
1465   func->SetName(GetV8String(isolate, name));
1466 
1467   // Create a tracker object that will cause the user data and/or handler
1468   // reference to be released when the V8 object is destroyed.
1469   V8TrackObject* tracker = new V8TrackObject(isolate);
1470   tracker->SetHandler(handler);
1471 
1472   // Attach the tracker object.
1473   tracker->AttachTo(context, func);
1474 
1475   // Create the CefV8ValueImpl and provide a tracker object that will cause
1476   // the handler reference to be released when the V8 object is destroyed.
1477   CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1478   impl->InitObject(func, tracker);
1479   return impl.get();
1480 }
1481 
1482 // CefV8ValueImpl
1483 
CefV8ValueImpl(v8::Isolate * isolate)1484 CefV8ValueImpl::CefV8ValueImpl(v8::Isolate* isolate)
1485     : isolate_(isolate), type_(TYPE_INVALID), rethrow_exceptions_(false) {
1486   DCHECK(isolate_);
1487 }
1488 
CefV8ValueImpl(v8::Isolate * isolate,v8::Local<v8::Context> context,v8::Local<v8::Value> value)1489 CefV8ValueImpl::CefV8ValueImpl(v8::Isolate* isolate,
1490                                v8::Local<v8::Context> context,
1491                                v8::Local<v8::Value> value)
1492     : isolate_(isolate), type_(TYPE_INVALID), rethrow_exceptions_(false) {
1493   DCHECK(isolate_);
1494   InitFromV8Value(context, value);
1495 }
1496 
~CefV8ValueImpl()1497 CefV8ValueImpl::~CefV8ValueImpl() {
1498   if (type_ == TYPE_STRING)
1499     cef_string_clear(&string_value_);
1500   if (handle_.get())
1501     handle_->SetWeakIfNecessary();
1502 }
1503 
InitFromV8Value(v8::Local<v8::Context> context,v8::Local<v8::Value> value)1504 void CefV8ValueImpl::InitFromV8Value(v8::Local<v8::Context> context,
1505                                      v8::Local<v8::Value> value) {
1506   if (value->IsUndefined()) {
1507     InitUndefined();
1508   } else if (value->IsNull()) {
1509     InitNull();
1510   } else if (value->IsTrue()) {
1511     InitBool(true);
1512   } else if (value->IsFalse()) {
1513     InitBool(false);
1514   } else if (value->IsBoolean()) {
1515     InitBool(value->ToBoolean(context->GetIsolate())->Value());
1516   } else if (value->IsInt32()) {
1517     InitInt(value->ToInt32(context).ToLocalChecked()->Value());
1518   } else if (value->IsUint32()) {
1519     InitUInt(value->ToUint32(context).ToLocalChecked()->Value());
1520   } else if (value->IsNumber()) {
1521     InitDouble(value->ToNumber(context).ToLocalChecked()->Value());
1522   } else if (value->IsDate()) {
1523     // Convert from milliseconds to seconds.
1524     InitDate(
1525         CefTime(value->ToNumber(context).ToLocalChecked()->Value() / 1000));
1526   } else if (value->IsString()) {
1527     CefString rv;
1528     GetCefString(context->GetIsolate(),
1529                  value->ToString(context).ToLocalChecked(), rv);
1530     InitString(rv);
1531   } else if (value->IsObject()) {
1532     InitObject(value, nullptr);
1533   }
1534 }
1535 
InitUndefined()1536 void CefV8ValueImpl::InitUndefined() {
1537   DCHECK_EQ(type_, TYPE_INVALID);
1538   type_ = TYPE_UNDEFINED;
1539 }
1540 
InitNull()1541 void CefV8ValueImpl::InitNull() {
1542   DCHECK_EQ(type_, TYPE_INVALID);
1543   type_ = TYPE_NULL;
1544 }
1545 
InitBool(bool value)1546 void CefV8ValueImpl::InitBool(bool value) {
1547   DCHECK_EQ(type_, TYPE_INVALID);
1548   type_ = TYPE_BOOL;
1549   bool_value_ = value;
1550 }
1551 
InitInt(int32 value)1552 void CefV8ValueImpl::InitInt(int32 value) {
1553   DCHECK_EQ(type_, TYPE_INVALID);
1554   type_ = TYPE_INT;
1555   int_value_ = value;
1556 }
1557 
InitUInt(uint32 value)1558 void CefV8ValueImpl::InitUInt(uint32 value) {
1559   DCHECK_EQ(type_, TYPE_INVALID);
1560   type_ = TYPE_UINT;
1561   uint_value_ = value;
1562 }
1563 
InitDouble(double value)1564 void CefV8ValueImpl::InitDouble(double value) {
1565   DCHECK_EQ(type_, TYPE_INVALID);
1566   type_ = TYPE_DOUBLE;
1567   double_value_ = value;
1568 }
1569 
InitDate(const CefTime & value)1570 void CefV8ValueImpl::InitDate(const CefTime& value) {
1571   DCHECK_EQ(type_, TYPE_INVALID);
1572   type_ = TYPE_DATE;
1573   date_value_ = value;
1574 }
1575 
InitString(CefString & value)1576 void CefV8ValueImpl::InitString(CefString& value) {
1577   DCHECK_EQ(type_, TYPE_INVALID);
1578   type_ = TYPE_STRING;
1579   // Take ownership of the underling string value.
1580   const cef_string_t* str = value.GetStruct();
1581   if (str) {
1582     string_value_ = *str;
1583     cef_string_t* writable_struct = value.GetWritableStruct();
1584     writable_struct->str = nullptr;
1585     writable_struct->length = 0;
1586   } else {
1587     string_value_.str = nullptr;
1588     string_value_.length = 0;
1589   }
1590 }
1591 
InitObject(v8::Local<v8::Value> value,CefTrackNode * tracker)1592 void CefV8ValueImpl::InitObject(v8::Local<v8::Value> value,
1593                                 CefTrackNode* tracker) {
1594   DCHECK_EQ(type_, TYPE_INVALID);
1595   type_ = TYPE_OBJECT;
1596   handle_ = new Handle(isolate_, v8::Local<v8::Context>(), value, tracker);
1597 }
1598 
GetV8Value(bool should_persist)1599 v8::Local<v8::Value> CefV8ValueImpl::GetV8Value(bool should_persist) {
1600   switch (type_) {
1601     case TYPE_UNDEFINED:
1602       return v8::Undefined(isolate_);
1603     case TYPE_NULL:
1604       return v8::Null(isolate_);
1605     case TYPE_BOOL:
1606       return v8::Boolean::New(isolate_, bool_value_);
1607     case TYPE_INT:
1608       return v8::Int32::New(isolate_, int_value_);
1609     case TYPE_UINT:
1610       return v8::Uint32::New(isolate_, uint_value_);
1611     case TYPE_DOUBLE:
1612       return v8::Number::New(isolate_, double_value_);
1613     case TYPE_DATE:
1614       // Convert from seconds to milliseconds.
1615       return v8::Date::New(isolate_->GetCurrentContext(),
1616                            CefTime(date_value_).GetDoubleT() * 1000)
1617           .ToLocalChecked();
1618     case TYPE_STRING:
1619       return GetV8String(isolate_, CefString(&string_value_));
1620     case TYPE_OBJECT:
1621       return handle_->GetNewV8Handle(should_persist);
1622     default:
1623       break;
1624   }
1625 
1626   NOTREACHED() << "Invalid type for CefV8ValueImpl";
1627   return v8::Local<v8::Value>();
1628 }
1629 
IsValid()1630 bool CefV8ValueImpl::IsValid() {
1631   if (!CEF_V8_HAS_ISOLATE() || type_ == TYPE_INVALID ||
1632       (type_ == TYPE_OBJECT &&
1633        (!handle_->BelongsToCurrentThread() || !handle_->IsValid()))) {
1634     return false;
1635   }
1636   return true;
1637 }
1638 
IsUndefined()1639 bool CefV8ValueImpl::IsUndefined() {
1640   CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1641   return (type_ == TYPE_UNDEFINED);
1642 }
1643 
IsNull()1644 bool CefV8ValueImpl::IsNull() {
1645   CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1646   return (type_ == TYPE_NULL);
1647 }
1648 
IsBool()1649 bool CefV8ValueImpl::IsBool() {
1650   CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1651   return (type_ == TYPE_BOOL);
1652 }
1653 
IsInt()1654 bool CefV8ValueImpl::IsInt() {
1655   CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1656   return (type_ == TYPE_INT || type_ == TYPE_UINT);
1657 }
1658 
IsUInt()1659 bool CefV8ValueImpl::IsUInt() {
1660   CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1661   return (type_ == TYPE_INT || type_ == TYPE_UINT);
1662 }
1663 
IsDouble()1664 bool CefV8ValueImpl::IsDouble() {
1665   CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1666   return (type_ == TYPE_INT || type_ == TYPE_UINT || type_ == TYPE_DOUBLE);
1667 }
1668 
IsDate()1669 bool CefV8ValueImpl::IsDate() {
1670   CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1671   return (type_ == TYPE_DATE);
1672 }
1673 
IsString()1674 bool CefV8ValueImpl::IsString() {
1675   CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1676   return (type_ == TYPE_STRING);
1677 }
1678 
IsObject()1679 bool CefV8ValueImpl::IsObject() {
1680   CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1681   return (type_ == TYPE_OBJECT);
1682 }
1683 
IsArray()1684 bool CefV8ValueImpl::IsArray() {
1685   CEF_V8_REQUIRE_MLT_RETURN(false);
1686   if (type_ == TYPE_OBJECT) {
1687     v8::HandleScope handle_scope(handle_->isolate());
1688     return handle_->GetNewV8Handle(false)->IsArray();
1689   } else {
1690     return false;
1691   }
1692 }
1693 
IsArrayBuffer()1694 bool CefV8ValueImpl::IsArrayBuffer() {
1695   CEF_V8_REQUIRE_MLT_RETURN(false);
1696   if (type_ == TYPE_OBJECT) {
1697     v8::HandleScope handle_scope(handle_->isolate());
1698     return handle_->GetNewV8Handle(false)->IsArrayBuffer();
1699   } else {
1700     return false;
1701   }
1702 }
1703 
IsFunction()1704 bool CefV8ValueImpl::IsFunction() {
1705   CEF_V8_REQUIRE_MLT_RETURN(false);
1706   if (type_ == TYPE_OBJECT) {
1707     v8::HandleScope handle_scope(handle_->isolate());
1708     return handle_->GetNewV8Handle(false)->IsFunction();
1709   } else {
1710     return false;
1711   }
1712 }
1713 
IsSame(CefRefPtr<CefV8Value> that)1714 bool CefV8ValueImpl::IsSame(CefRefPtr<CefV8Value> that) {
1715   CEF_V8_REQUIRE_MLT_RETURN(false);
1716 
1717   CefV8ValueImpl* thatValue = static_cast<CefV8ValueImpl*>(that.get());
1718   if (!thatValue || !thatValue->IsValid() || type_ != thatValue->type_)
1719     return false;
1720 
1721   switch (type_) {
1722     case TYPE_UNDEFINED:
1723     case TYPE_NULL:
1724       return true;
1725     case TYPE_BOOL:
1726       return (bool_value_ == thatValue->bool_value_);
1727     case TYPE_INT:
1728       return (int_value_ == thatValue->int_value_);
1729     case TYPE_UINT:
1730       return (uint_value_ == thatValue->uint_value_);
1731     case TYPE_DOUBLE:
1732       return (double_value_ == thatValue->double_value_);
1733     case TYPE_DATE:
1734       return (CefTime(date_value_).GetTimeT() ==
1735               CefTime(thatValue->date_value_).GetTimeT());
1736     case TYPE_STRING:
1737       return (CefString(&string_value_) ==
1738               CefString(&thatValue->string_value_));
1739     case TYPE_OBJECT: {
1740       return (handle_->GetPersistentV8Handle() ==
1741               thatValue->handle_->GetPersistentV8Handle());
1742     }
1743     default:
1744       break;
1745   }
1746 
1747   return false;
1748 }
1749 
GetBoolValue()1750 bool CefV8ValueImpl::GetBoolValue() {
1751   CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1752   if (type_ == TYPE_BOOL)
1753     return bool_value_;
1754   return false;
1755 }
1756 
GetIntValue()1757 int32 CefV8ValueImpl::GetIntValue() {
1758   CEF_V8_REQUIRE_ISOLATE_RETURN(0);
1759   if (type_ == TYPE_INT || type_ == TYPE_UINT)
1760     return int_value_;
1761   return 0;
1762 }
1763 
GetUIntValue()1764 uint32 CefV8ValueImpl::GetUIntValue() {
1765   CEF_V8_REQUIRE_ISOLATE_RETURN(0);
1766   if (type_ == TYPE_INT || type_ == TYPE_UINT)
1767     return uint_value_;
1768   return 0;
1769 }
1770 
GetDoubleValue()1771 double CefV8ValueImpl::GetDoubleValue() {
1772   CEF_V8_REQUIRE_ISOLATE_RETURN(0.);
1773   if (type_ == TYPE_DOUBLE)
1774     return double_value_;
1775   else if (type_ == TYPE_INT)
1776     return int_value_;
1777   else if (type_ == TYPE_UINT)
1778     return uint_value_;
1779   return 0.;
1780 }
1781 
GetDateValue()1782 CefTime CefV8ValueImpl::GetDateValue() {
1783   CEF_V8_REQUIRE_ISOLATE_RETURN(CefTime(0.));
1784   if (type_ == TYPE_DATE)
1785     return date_value_;
1786   return CefTime(0.);
1787 }
1788 
GetStringValue()1789 CefString CefV8ValueImpl::GetStringValue() {
1790   CefString rv;
1791   CEF_V8_REQUIRE_ISOLATE_RETURN(rv);
1792   if (type_ == TYPE_STRING)
1793     rv = CefString(&string_value_);
1794   return rv;
1795 }
1796 
IsUserCreated()1797 bool CefV8ValueImpl::IsUserCreated() {
1798   CEF_V8_REQUIRE_OBJECT_RETURN(false);
1799 
1800   v8::Isolate* isolate = handle_->isolate();
1801   v8::HandleScope handle_scope(isolate);
1802 
1803   v8::Local<v8::Context> context = isolate->GetCurrentContext();
1804   if (context.IsEmpty()) {
1805     NOTREACHED() << "not currently in a V8 context";
1806     return false;
1807   }
1808 
1809   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
1810   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
1811 
1812   V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
1813   return (tracker != nullptr);
1814 }
1815 
HasException()1816 bool CefV8ValueImpl::HasException() {
1817   CEF_V8_REQUIRE_OBJECT_RETURN(false);
1818 
1819   return (last_exception_.get() != nullptr);
1820 }
1821 
GetException()1822 CefRefPtr<CefV8Exception> CefV8ValueImpl::GetException() {
1823   CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
1824 
1825   return last_exception_;
1826 }
1827 
ClearException()1828 bool CefV8ValueImpl::ClearException() {
1829   CEF_V8_REQUIRE_OBJECT_RETURN(false);
1830 
1831   last_exception_ = nullptr;
1832   return true;
1833 }
1834 
WillRethrowExceptions()1835 bool CefV8ValueImpl::WillRethrowExceptions() {
1836   CEF_V8_REQUIRE_OBJECT_RETURN(false);
1837 
1838   return rethrow_exceptions_;
1839 }
1840 
SetRethrowExceptions(bool rethrow)1841 bool CefV8ValueImpl::SetRethrowExceptions(bool rethrow) {
1842   CEF_V8_REQUIRE_OBJECT_RETURN(false);
1843 
1844   rethrow_exceptions_ = rethrow;
1845   return true;
1846 }
1847 
HasValue(const CefString & key)1848 bool CefV8ValueImpl::HasValue(const CefString& key) {
1849   CEF_V8_REQUIRE_OBJECT_RETURN(false);
1850 
1851   v8::Isolate* isolate = handle_->isolate();
1852   v8::HandleScope handle_scope(isolate);
1853 
1854   v8::Local<v8::Context> context = isolate->GetCurrentContext();
1855   if (context.IsEmpty()) {
1856     NOTREACHED() << "not currently in a V8 context";
1857     return false;
1858   }
1859 
1860   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
1861   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
1862   return obj->Has(context, GetV8String(isolate, key)).FromJust();
1863 }
1864 
HasValue(int index)1865 bool CefV8ValueImpl::HasValue(int index) {
1866   CEF_V8_REQUIRE_OBJECT_RETURN(false);
1867 
1868   if (index < 0) {
1869     NOTREACHED() << "invalid input parameter";
1870     return false;
1871   }
1872 
1873   v8::Isolate* isolate = handle_->isolate();
1874   v8::HandleScope handle_scope(isolate);
1875 
1876   v8::Local<v8::Context> context = isolate->GetCurrentContext();
1877   if (context.IsEmpty()) {
1878     NOTREACHED() << "not currently in a V8 context";
1879     return false;
1880   }
1881 
1882   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
1883   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
1884   return obj->Has(context, index).FromJust();
1885 }
1886 
DeleteValue(const CefString & key)1887 bool CefV8ValueImpl::DeleteValue(const CefString& key) {
1888   CEF_V8_REQUIRE_OBJECT_RETURN(false);
1889 
1890   v8::Isolate* isolate = handle_->isolate();
1891   v8::HandleScope handle_scope(isolate);
1892 
1893   v8::Local<v8::Context> context = isolate->GetCurrentContext();
1894   if (context.IsEmpty()) {
1895     NOTREACHED() << "not currently in a V8 context";
1896     return false;
1897   }
1898 
1899   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
1900   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
1901 
1902   v8::TryCatch try_catch(isolate);
1903   try_catch.SetVerbose(true);
1904   v8::Maybe<bool> del = obj->Delete(context, GetV8String(isolate, key));
1905   return (!HasCaught(context, try_catch) && del.FromJust());
1906 }
1907 
DeleteValue(int index)1908 bool CefV8ValueImpl::DeleteValue(int index) {
1909   CEF_V8_REQUIRE_OBJECT_RETURN(false);
1910 
1911   if (index < 0) {
1912     NOTREACHED() << "invalid input parameter";
1913     return false;
1914   }
1915 
1916   v8::Isolate* isolate = handle_->isolate();
1917   v8::HandleScope handle_scope(isolate);
1918 
1919   v8::Local<v8::Context> context = isolate->GetCurrentContext();
1920   if (context.IsEmpty()) {
1921     NOTREACHED() << "not currently in a V8 context";
1922     return false;
1923   }
1924 
1925   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
1926   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
1927 
1928   v8::TryCatch try_catch(isolate);
1929   try_catch.SetVerbose(true);
1930   v8::Maybe<bool> del = obj->Delete(context, index);
1931   return (!HasCaught(context, try_catch) && del.FromJust());
1932 }
1933 
GetValue(const CefString & key)1934 CefRefPtr<CefV8Value> CefV8ValueImpl::GetValue(const CefString& key) {
1935   CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
1936 
1937   v8::Isolate* isolate = handle_->isolate();
1938   v8::HandleScope handle_scope(isolate);
1939 
1940   v8::Local<v8::Context> context = isolate->GetCurrentContext();
1941   if (context.IsEmpty()) {
1942     NOTREACHED() << "not currently in a V8 context";
1943     return nullptr;
1944   }
1945 
1946   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
1947   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
1948 
1949   v8::TryCatch try_catch(isolate);
1950   try_catch.SetVerbose(true);
1951   v8::MaybeLocal<v8::Value> ret_value =
1952       obj->Get(context, GetV8String(isolate, key));
1953   if (!HasCaught(context, try_catch) && !ret_value.IsEmpty()) {
1954     return new CefV8ValueImpl(isolate, context, ret_value.ToLocalChecked());
1955   }
1956   return nullptr;
1957 }
1958 
GetValue(int index)1959 CefRefPtr<CefV8Value> CefV8ValueImpl::GetValue(int index) {
1960   CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
1961 
1962   if (index < 0) {
1963     NOTREACHED() << "invalid input parameter";
1964     return nullptr;
1965   }
1966 
1967   v8::Isolate* isolate = handle_->isolate();
1968   v8::HandleScope handle_scope(isolate);
1969 
1970   v8::Local<v8::Context> context = isolate->GetCurrentContext();
1971   if (context.IsEmpty()) {
1972     NOTREACHED() << "not currently in a V8 context";
1973     return nullptr;
1974   }
1975 
1976   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
1977   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
1978 
1979   v8::TryCatch try_catch(isolate);
1980   try_catch.SetVerbose(true);
1981   v8::MaybeLocal<v8::Value> ret_value =
1982       obj->Get(context, v8::Number::New(isolate, index));
1983   if (!HasCaught(context, try_catch) && !ret_value.IsEmpty()) {
1984     return new CefV8ValueImpl(isolate, context, ret_value.ToLocalChecked());
1985   }
1986   return nullptr;
1987 }
1988 
SetValue(const CefString & key,CefRefPtr<CefV8Value> value,PropertyAttribute attribute)1989 bool CefV8ValueImpl::SetValue(const CefString& key,
1990                               CefRefPtr<CefV8Value> value,
1991                               PropertyAttribute attribute) {
1992   CEF_V8_REQUIRE_OBJECT_RETURN(false);
1993 
1994   CefV8ValueImpl* impl = static_cast<CefV8ValueImpl*>(value.get());
1995   if (impl && impl->IsValid()) {
1996     v8::Isolate* isolate = handle_->isolate();
1997     v8::HandleScope handle_scope(isolate);
1998 
1999     v8::Local<v8::Context> context = isolate->GetCurrentContext();
2000     if (context.IsEmpty()) {
2001       NOTREACHED() << "not currently in a V8 context";
2002       return false;
2003     }
2004 
2005     v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2006     v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2007 
2008     v8::TryCatch try_catch(isolate);
2009     try_catch.SetVerbose(true);
2010     // TODO(cef): This usage may not exactly match the previous implementation.
2011     // Set will trigger interceptors and/or accessors whereas DefineOwnProperty
2012     // will not. It might be better to split this functionality into separate
2013     // methods.
2014     if (attribute == V8_PROPERTY_ATTRIBUTE_NONE) {
2015       v8::Maybe<bool> set =
2016           obj->Set(context, GetV8String(isolate, key), impl->GetV8Value(true));
2017       return (!HasCaught(context, try_catch) && set.FromJust());
2018     } else {
2019       v8::Maybe<bool> set = obj->DefineOwnProperty(
2020           context, GetV8String(isolate, key), impl->GetV8Value(true),
2021           static_cast<v8::PropertyAttribute>(attribute));
2022       return (!HasCaught(context, try_catch) && set.FromJust());
2023     }
2024   } else {
2025     NOTREACHED() << "invalid input parameter";
2026     return false;
2027   }
2028 }
2029 
SetValue(int index,CefRefPtr<CefV8Value> value)2030 bool CefV8ValueImpl::SetValue(int index, CefRefPtr<CefV8Value> value) {
2031   CEF_V8_REQUIRE_OBJECT_RETURN(false);
2032 
2033   if (index < 0) {
2034     NOTREACHED() << "invalid input parameter";
2035     return false;
2036   }
2037 
2038   CefV8ValueImpl* impl = static_cast<CefV8ValueImpl*>(value.get());
2039   if (impl && impl->IsValid()) {
2040     v8::Isolate* isolate = handle_->isolate();
2041     v8::HandleScope handle_scope(isolate);
2042 
2043     v8::Local<v8::Context> context = isolate->GetCurrentContext();
2044     if (context.IsEmpty()) {
2045       NOTREACHED() << "not currently in a V8 context";
2046       return false;
2047     }
2048 
2049     v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2050     v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2051 
2052     v8::TryCatch try_catch(isolate);
2053     try_catch.SetVerbose(true);
2054     v8::Maybe<bool> set = obj->Set(context, index, impl->GetV8Value(true));
2055     return (!HasCaught(context, try_catch) && set.FromJust());
2056   } else {
2057     NOTREACHED() << "invalid input parameter";
2058     return false;
2059   }
2060 }
2061 
SetValue(const CefString & key,AccessControl settings,PropertyAttribute attribute)2062 bool CefV8ValueImpl::SetValue(const CefString& key,
2063                               AccessControl settings,
2064                               PropertyAttribute attribute) {
2065   CEF_V8_REQUIRE_OBJECT_RETURN(false);
2066 
2067   v8::Isolate* isolate = handle_->isolate();
2068   v8::HandleScope handle_scope(isolate);
2069 
2070   v8::Local<v8::Context> context = isolate->GetCurrentContext();
2071   if (context.IsEmpty()) {
2072     NOTREACHED() << "not currently in a V8 context";
2073     return false;
2074   }
2075 
2076   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2077   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2078 
2079   CefRefPtr<CefV8Accessor> accessorPtr;
2080 
2081   V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
2082   if (tracker)
2083     accessorPtr = tracker->GetAccessor();
2084 
2085   // Verify that an accessor exists for this object.
2086   if (!accessorPtr.get())
2087     return false;
2088 
2089   v8::AccessorNameGetterCallback getter = AccessorNameGetterCallbackImpl;
2090   v8::AccessorNameSetterCallback setter =
2091       (attribute & V8_PROPERTY_ATTRIBUTE_READONLY)
2092           ? nullptr
2093           : AccessorNameSetterCallbackImpl;
2094 
2095   v8::TryCatch try_catch(isolate);
2096   try_catch.SetVerbose(true);
2097   v8::Maybe<bool> set =
2098       obj->SetAccessor(context, GetV8String(isolate, key), getter, setter, obj,
2099                        static_cast<v8::AccessControl>(settings),
2100                        static_cast<v8::PropertyAttribute>(attribute));
2101   return (!HasCaught(context, try_catch) && set.FromJust());
2102 }
2103 
GetKeys(std::vector<CefString> & keys)2104 bool CefV8ValueImpl::GetKeys(std::vector<CefString>& keys) {
2105   CEF_V8_REQUIRE_OBJECT_RETURN(false);
2106 
2107   v8::Isolate* isolate = handle_->isolate();
2108   v8::HandleScope handle_scope(isolate);
2109 
2110   v8::Local<v8::Context> context = isolate->GetCurrentContext();
2111   if (context.IsEmpty()) {
2112     NOTREACHED() << "not currently in a V8 context";
2113     return false;
2114   }
2115 
2116   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2117   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2118   v8::Local<v8::Array> arr_keys =
2119       obj->GetPropertyNames(context).ToLocalChecked();
2120 
2121   uint32_t len = arr_keys->Length();
2122   for (uint32_t i = 0; i < len; ++i) {
2123     v8::Local<v8::Value> value =
2124         arr_keys->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked();
2125     CefString str;
2126     GetCefString(isolate, value->ToString(context).ToLocalChecked(), str);
2127     keys.push_back(str);
2128   }
2129   return true;
2130 }
2131 
SetUserData(CefRefPtr<CefBaseRefCounted> user_data)2132 bool CefV8ValueImpl::SetUserData(CefRefPtr<CefBaseRefCounted> user_data) {
2133   CEF_V8_REQUIRE_OBJECT_RETURN(false);
2134 
2135   v8::Isolate* isolate = handle_->isolate();
2136   v8::HandleScope handle_scope(isolate);
2137 
2138   v8::Local<v8::Context> context = isolate->GetCurrentContext();
2139   if (context.IsEmpty()) {
2140     NOTREACHED() << "not currently in a V8 context";
2141     return false;
2142   }
2143 
2144   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2145   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2146 
2147   V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
2148   if (tracker) {
2149     tracker->SetUserData(user_data);
2150     return true;
2151   }
2152 
2153   return false;
2154 }
2155 
GetUserData()2156 CefRefPtr<CefBaseRefCounted> CefV8ValueImpl::GetUserData() {
2157   CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
2158 
2159   v8::Isolate* isolate = handle_->isolate();
2160   v8::HandleScope handle_scope(isolate);
2161 
2162   v8::Local<v8::Context> context = isolate->GetCurrentContext();
2163   if (context.IsEmpty()) {
2164     NOTREACHED() << "not currently in a V8 context";
2165     return nullptr;
2166   }
2167 
2168   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2169   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2170 
2171   V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
2172   if (tracker)
2173     return tracker->GetUserData();
2174 
2175   return nullptr;
2176 }
2177 
GetExternallyAllocatedMemory()2178 int CefV8ValueImpl::GetExternallyAllocatedMemory() {
2179   CEF_V8_REQUIRE_OBJECT_RETURN(0);
2180 
2181   v8::Isolate* isolate = handle_->isolate();
2182   v8::HandleScope handle_scope(isolate);
2183 
2184   v8::Local<v8::Context> context = isolate->GetCurrentContext();
2185   if (context.IsEmpty()) {
2186     NOTREACHED() << "not currently in a V8 context";
2187     return 0;
2188   }
2189 
2190   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2191   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2192 
2193   V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
2194   if (tracker)
2195     return tracker->GetExternallyAllocatedMemory();
2196 
2197   return 0;
2198 }
2199 
AdjustExternallyAllocatedMemory(int change_in_bytes)2200 int CefV8ValueImpl::AdjustExternallyAllocatedMemory(int change_in_bytes) {
2201   CEF_V8_REQUIRE_OBJECT_RETURN(0);
2202 
2203   v8::Isolate* isolate = handle_->isolate();
2204   v8::HandleScope handle_scope(isolate);
2205 
2206   v8::Local<v8::Context> context = isolate->GetCurrentContext();
2207   if (context.IsEmpty()) {
2208     NOTREACHED() << "not currently in a V8 context";
2209     return 0;
2210   }
2211 
2212   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2213   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2214 
2215   V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
2216   if (tracker)
2217     return tracker->AdjustExternallyAllocatedMemory(change_in_bytes);
2218 
2219   return 0;
2220 }
2221 
GetArrayLength()2222 int CefV8ValueImpl::GetArrayLength() {
2223   CEF_V8_REQUIRE_OBJECT_RETURN(0);
2224 
2225   v8::Isolate* isolate = handle_->isolate();
2226   v8::HandleScope handle_scope(isolate);
2227 
2228   v8::Local<v8::Context> context = isolate->GetCurrentContext();
2229   if (context.IsEmpty()) {
2230     NOTREACHED() << "not currently in a V8 context";
2231     return 0;
2232   }
2233 
2234   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2235   if (!value->IsArray()) {
2236     NOTREACHED() << "V8 value is not an array";
2237     return 0;
2238   }
2239 
2240   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2241   v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(obj);
2242   return arr->Length();
2243 }
2244 
2245 CefRefPtr<CefV8ArrayBufferReleaseCallback>
GetArrayBufferReleaseCallback()2246 CefV8ValueImpl::GetArrayBufferReleaseCallback() {
2247   CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
2248 
2249   v8::Isolate* isolate = handle_->isolate();
2250   v8::HandleScope handle_scope(isolate);
2251 
2252   v8::Local<v8::Context> context = isolate->GetCurrentContext();
2253   if (context.IsEmpty()) {
2254     NOTREACHED() << "not currently in a V8 context";
2255     return nullptr;
2256   }
2257 
2258   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2259   if (!value->IsArrayBuffer()) {
2260     NOTREACHED() << "V8 value is not an array buffer";
2261     return nullptr;
2262   }
2263 
2264   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2265 
2266   V8TrackArrayBuffer* tracker = V8TrackArrayBuffer::Unwrap(context, obj);
2267   if (tracker)
2268     return tracker->GetReleaseCallback();
2269 
2270   return nullptr;
2271 }
2272 
NeuterArrayBuffer()2273 bool CefV8ValueImpl::NeuterArrayBuffer() {
2274   CEF_V8_REQUIRE_OBJECT_RETURN(0);
2275 
2276   v8::Isolate* isolate = handle_->isolate();
2277   v8::HandleScope handle_scope(isolate);
2278 
2279   v8::Local<v8::Context> context = isolate->GetCurrentContext();
2280   if (context.IsEmpty()) {
2281     NOTREACHED() << "not currently in a V8 context";
2282     return false;
2283   }
2284 
2285   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2286   if (!value->IsArrayBuffer()) {
2287     NOTREACHED() << "V8 value is not an array buffer";
2288     return false;
2289   }
2290   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2291   v8::Local<v8::ArrayBuffer> arr = v8::Local<v8::ArrayBuffer>::Cast(obj);
2292   if (!arr->IsDetachable()) {
2293     return false;
2294   }
2295   arr->Detach();
2296 
2297   return true;
2298 }
2299 
GetFunctionName()2300 CefString CefV8ValueImpl::GetFunctionName() {
2301   CefString rv;
2302   CEF_V8_REQUIRE_OBJECT_RETURN(rv);
2303 
2304   v8::Isolate* isolate = handle_->isolate();
2305   v8::HandleScope handle_scope(isolate);
2306 
2307   v8::Local<v8::Context> context = isolate->GetCurrentContext();
2308   if (context.IsEmpty()) {
2309     NOTREACHED() << "not currently in a V8 context";
2310     return rv;
2311   }
2312 
2313   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2314   if (!value->IsFunction()) {
2315     NOTREACHED() << "V8 value is not a function";
2316     return rv;
2317   }
2318 
2319   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2320   v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(obj);
2321   GetCefString(handle_->isolate(),
2322                v8::Handle<v8::String>::Cast(func->GetName()), rv);
2323   return rv;
2324 }
2325 
GetFunctionHandler()2326 CefRefPtr<CefV8Handler> CefV8ValueImpl::GetFunctionHandler() {
2327   CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
2328 
2329   v8::Isolate* isolate = handle_->isolate();
2330   v8::HandleScope handle_scope(isolate);
2331 
2332   v8::Local<v8::Context> context = isolate->GetCurrentContext();
2333   if (context.IsEmpty()) {
2334     NOTREACHED() << "not currently in a V8 context";
2335     return nullptr;
2336   }
2337 
2338   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2339   if (!value->IsFunction()) {
2340     NOTREACHED() << "V8 value is not a function";
2341     return nullptr;
2342   }
2343 
2344   v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2345   V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
2346   if (tracker)
2347     return tracker->GetHandler();
2348 
2349   return nullptr;
2350 }
2351 
ExecuteFunction(CefRefPtr<CefV8Value> object,const CefV8ValueList & arguments)2352 CefRefPtr<CefV8Value> CefV8ValueImpl::ExecuteFunction(
2353     CefRefPtr<CefV8Value> object,
2354     const CefV8ValueList& arguments) {
2355   // An empty context value defaults to the current context.
2356   CefRefPtr<CefV8Context> context;
2357   return ExecuteFunctionWithContext(context, object, arguments);
2358 }
2359 
ExecuteFunctionWithContext(CefRefPtr<CefV8Context> context,CefRefPtr<CefV8Value> object,const CefV8ValueList & arguments)2360 CefRefPtr<CefV8Value> CefV8ValueImpl::ExecuteFunctionWithContext(
2361     CefRefPtr<CefV8Context> context,
2362     CefRefPtr<CefV8Value> object,
2363     const CefV8ValueList& arguments) {
2364   CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
2365 
2366   v8::Isolate* isolate = handle_->isolate();
2367   v8::HandleScope handle_scope(isolate);
2368   v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2369   if (!value->IsFunction()) {
2370     NOTREACHED() << "V8 value is not a function";
2371     return nullptr;
2372   }
2373 
2374   if (context.get() && !context->IsValid()) {
2375     NOTREACHED() << "invalid V8 context parameter";
2376     return nullptr;
2377   }
2378   if (object.get() && (!object->IsValid() || !object->IsObject())) {
2379     NOTREACHED() << "invalid V8 object parameter";
2380     return nullptr;
2381   }
2382 
2383   int argc = arguments.size();
2384   if (argc > 0) {
2385     for (int i = 0; i < argc; ++i) {
2386       if (!arguments[i].get() || !arguments[i]->IsValid()) {
2387         NOTREACHED() << "invalid V8 arguments parameter";
2388         return nullptr;
2389       }
2390     }
2391   }
2392 
2393   v8::Local<v8::Context> context_local;
2394   if (context.get()) {
2395     CefV8ContextImpl* context_impl =
2396         static_cast<CefV8ContextImpl*>(context.get());
2397     context_local = context_impl->GetV8Context();
2398   } else {
2399     context_local = isolate->GetCurrentContext();
2400   }
2401 
2402   v8::Context::Scope context_scope(context_local);
2403 
2404   v8::Local<v8::Object> obj = value->ToObject(context_local).ToLocalChecked();
2405   v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(obj);
2406   v8::Local<v8::Object> recv;
2407 
2408   // Default to the global object if no object was provided.
2409   if (object.get()) {
2410     CefV8ValueImpl* recv_impl = static_cast<CefV8ValueImpl*>(object.get());
2411     recv = v8::Local<v8::Object>::Cast(recv_impl->GetV8Value(true));
2412   } else {
2413     recv = context_local->Global();
2414   }
2415 
2416   v8::Local<v8::Value>* argv = nullptr;
2417   if (argc > 0) {
2418     argv = new v8::Local<v8::Value>[argc];
2419     for (int i = 0; i < argc; ++i) {
2420       argv[i] =
2421           static_cast<CefV8ValueImpl*>(arguments[i].get())->GetV8Value(true);
2422     }
2423   }
2424 
2425   CefRefPtr<CefV8Value> retval;
2426 
2427   {
2428     v8::TryCatch try_catch(isolate);
2429     try_catch.SetVerbose(true);
2430 
2431     v8::MaybeLocal<v8::Value> func_rv = blink_glue::CallV8Function(
2432         context_local, func, recv, argc, argv, handle_->isolate());
2433 
2434     if (!HasCaught(context_local, try_catch) && !func_rv.IsEmpty()) {
2435       retval =
2436           new CefV8ValueImpl(isolate, context_local, func_rv.ToLocalChecked());
2437     }
2438   }
2439 
2440   if (argv)
2441     delete[] argv;
2442 
2443   return retval;
2444 }
2445 
HasCaught(v8::Local<v8::Context> context,v8::TryCatch & try_catch)2446 bool CefV8ValueImpl::HasCaught(v8::Local<v8::Context> context,
2447                                v8::TryCatch& try_catch) {
2448   if (try_catch.HasCaught()) {
2449     last_exception_ = new CefV8ExceptionImpl(context, try_catch.Message());
2450     if (rethrow_exceptions_)
2451       try_catch.ReThrow();
2452     return true;
2453   } else {
2454     if (last_exception_.get())
2455       last_exception_ = nullptr;
2456     return false;
2457   }
2458 }
2459 
2460 // CefV8StackTrace
2461 
2462 // static
GetCurrent(int frame_limit)2463 CefRefPtr<CefV8StackTrace> CefV8StackTrace::GetCurrent(int frame_limit) {
2464   CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
2465 
2466   v8::Isolate* isolate = GetIsolateManager()->isolate();
2467   v8::HandleScope handle_scope(isolate);
2468   v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
2469       isolate, frame_limit, v8::StackTrace::kDetailed);
2470   if (stackTrace.IsEmpty())
2471     return nullptr;
2472   return new CefV8StackTraceImpl(isolate, stackTrace);
2473 }
2474 
2475 // CefV8StackTraceImpl
2476 
CefV8StackTraceImpl(v8::Isolate * isolate,v8::Local<v8::StackTrace> handle)2477 CefV8StackTraceImpl::CefV8StackTraceImpl(v8::Isolate* isolate,
2478                                          v8::Local<v8::StackTrace> handle) {
2479   if (!handle.IsEmpty()) {
2480     int frame_count = handle->GetFrameCount();
2481     if (frame_count > 0) {
2482       frames_.reserve(frame_count);
2483       for (int i = 0; i < frame_count; ++i)
2484         frames_.push_back(
2485             new CefV8StackFrameImpl(isolate, handle->GetFrame(isolate, i)));
2486     }
2487   }
2488 }
2489 
~CefV8StackTraceImpl()2490 CefV8StackTraceImpl::~CefV8StackTraceImpl() {}
2491 
IsValid()2492 bool CefV8StackTraceImpl::IsValid() {
2493   return true;
2494 }
2495 
GetFrameCount()2496 int CefV8StackTraceImpl::GetFrameCount() {
2497   return frames_.size();
2498 }
2499 
GetFrame(int index)2500 CefRefPtr<CefV8StackFrame> CefV8StackTraceImpl::GetFrame(int index) {
2501   if (index < 0 || index >= static_cast<int>(frames_.size()))
2502     return nullptr;
2503   return frames_[index];
2504 }
2505 
2506 // CefV8StackFrameImpl
2507 
CefV8StackFrameImpl(v8::Isolate * isolate,v8::Local<v8::StackFrame> handle)2508 CefV8StackFrameImpl::CefV8StackFrameImpl(v8::Isolate* isolate,
2509                                          v8::Local<v8::StackFrame> handle)
2510     : line_number_(0), column_(0), is_eval_(false), is_constructor_(false) {
2511   if (handle.IsEmpty())
2512     return;
2513   GetCefString(isolate, handle->GetScriptName(), script_name_);
2514   GetCefString(isolate, handle->GetScriptNameOrSourceURL(),
2515                script_name_or_source_url_);
2516   GetCefString(isolate, handle->GetFunctionName(), function_name_);
2517   line_number_ = handle->GetLineNumber();
2518   column_ = handle->GetColumn();
2519   is_eval_ = handle->IsEval();
2520   is_constructor_ = handle->IsConstructor();
2521 }
2522 
~CefV8StackFrameImpl()2523 CefV8StackFrameImpl::~CefV8StackFrameImpl() {}
2524 
IsValid()2525 bool CefV8StackFrameImpl::IsValid() {
2526   return true;
2527 }
2528 
GetScriptName()2529 CefString CefV8StackFrameImpl::GetScriptName() {
2530   return script_name_;
2531 }
2532 
GetScriptNameOrSourceURL()2533 CefString CefV8StackFrameImpl::GetScriptNameOrSourceURL() {
2534   return script_name_or_source_url_;
2535 }
2536 
GetFunctionName()2537 CefString CefV8StackFrameImpl::GetFunctionName() {
2538   return function_name_;
2539 }
2540 
GetLineNumber()2541 int CefV8StackFrameImpl::GetLineNumber() {
2542   return line_number_;
2543 }
2544 
GetColumn()2545 int CefV8StackFrameImpl::GetColumn() {
2546   return column_;
2547 }
2548 
IsEval()2549 bool CefV8StackFrameImpl::IsEval() {
2550   return is_eval_;
2551 }
2552 
IsConstructor()2553 bool CefV8StackFrameImpl::IsConstructor() {
2554   return is_constructor_;
2555 }
2556 
2557 // Enable deprecation warnings on Windows. See http://crbug.com/585142.
2558 #if BUILDFLAG(IS_WIN)
2559 #if defined(__clang__)
2560 #pragma GCC diagnostic pop
2561 #else
2562 #pragma warning(pop)
2563 #endif
2564 #endif
2565