Support implicit detachment of CEF V8 references when the associated context is released (issue #484).

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@883 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt
2012-10-29 21:54:57 +00:00
parent 3ac5952636
commit 59fe4fbab3
25 changed files with 522 additions and 43 deletions

View File

@ -114,6 +114,12 @@ typedef struct _cef_v8context_t {
/// ///
cef_base_t base; cef_base_t base;
///
// Returns true (1) if this object is valid. Do not call any other functions
// if this function returns false (0).
///
int (CEF_CALLBACK *is_valid)(struct _cef_v8context_t* self);
/// ///
// Returns the browser for this context. // Returns the browser for this context.
/// ///
@ -314,6 +320,12 @@ typedef struct _cef_v8value_t {
/// ///
cef_base_t base; cef_base_t base;
///
// Returns true (1) if this object is valid. Do not call any other functions
// if this function returns false (0).
///
int (CEF_CALLBACK *is_valid)(struct _cef_v8value_t* self);
/// ///
// True if the value type is undefined. // True if the value type is undefined.
/// ///
@ -708,6 +720,12 @@ typedef struct _cef_v8stack_trace_t {
/// ///
cef_base_t base; cef_base_t base;
///
// Returns true (1) if this object is valid. Do not call any other functions
// if this function returns false (0).
///
int (CEF_CALLBACK *is_valid)(struct _cef_v8stack_trace_t* self);
/// ///
// Returns the number of stack frames. // Returns the number of stack frames.
/// ///
@ -738,6 +756,12 @@ typedef struct _cef_v8stack_frame_t {
/// ///
cef_base_t base; cef_base_t base;
///
// Returns true (1) if this object is valid. Do not call any other functions
// if this function returns false (0).
///
int (CEF_CALLBACK *is_valid)(struct _cef_v8stack_frame_t* self);
/// ///
// Returns the name of the resource script that contains the function. // Returns the name of the resource script that contains the function.
/// ///

View File

@ -140,6 +140,13 @@ class CefV8Context : public virtual CefBase {
/*--cef()--*/ /*--cef()--*/
static bool InContext(); static bool InContext();
///
// Returns true if this object is valid. Do not call any other methods if this
// method returns false.
///
/*--cef()--*/
virtual bool IsValid() =0;
/// ///
// Returns the browser for this context. // Returns the browser for this context.
/// ///
@ -407,6 +414,13 @@ class CefV8Value : public virtual CefBase {
static CefRefPtr<CefV8Value> CreateFunction(const CefString& name, static CefRefPtr<CefV8Value> CreateFunction(const CefString& name,
CefRefPtr<CefV8Handler> handler); CefRefPtr<CefV8Handler> handler);
///
// Returns true if this object is valid. Do not call any other methods if this
// method returns false.
///
/*--cef()--*/
virtual bool IsValid() =0;
/// ///
// True if the value type is undefined. // True if the value type is undefined.
/// ///
@ -754,6 +768,13 @@ class CefV8StackTrace : public virtual CefBase {
/*--cef()--*/ /*--cef()--*/
static CefRefPtr<CefV8StackTrace> GetCurrent(int frame_limit); static CefRefPtr<CefV8StackTrace> GetCurrent(int frame_limit);
///
// Returns true if this object is valid. Do not call any other methods if this
// method returns false.
///
/*--cef()--*/
virtual bool IsValid() =0;
/// ///
// Returns the number of stack frames. // Returns the number of stack frames.
/// ///
@ -774,6 +795,13 @@ class CefV8StackTrace : public virtual CefBase {
/*--cef(source=library)--*/ /*--cef(source=library)--*/
class CefV8StackFrame : public virtual CefBase { class CefV8StackFrame : public virtual CefBase {
public: public:
///
// Returns true if this object is valid. Do not call any other methods if this
// method returns false.
///
/*--cef()--*/
virtual bool IsValid() =0;
/// ///
// Returns the name of the resource script that contains the function. // Returns the name of the resource script that contains the function.
/// ///

View File

@ -218,6 +218,25 @@ typedef struct _cef_settings_t {
// OnUncaughtException() will not be called. // OnUncaughtException() will not be called.
/// ///
int uncaught_exception_stack_size; int uncaught_exception_stack_size;
///
// By default CEF V8 references will be invalidated (the IsValid() method will
// return false) after the owning context has been released. This reduces the
// need for external record keeping and avoids crashes due to the use of V8
// references after the associated context has been released.
//
// CEF currently offers two context safety implementations with different
// performance characteristics. The default implementation (value of 0) uses a
// map of hash values and should provide better performance in situations with
// a small number contexts. The alternate implementation (value of 1) uses a
// hidden value attached to each context and should provide better performance
// in situations with a large number of contexts.
//
// If you need better performance in the creation of V8 references and you
// plan to manually track context lifespan you can disable context safety by
// specifying a value of -1.
///
int context_safety_implementation;
} cef_settings_t; } cef_settings_t;
/// ///

View File

@ -300,6 +300,7 @@ struct CefSettingsTraits {
&target->locales_dir_path, copy); &target->locales_dir_path, copy);
target->pack_loading_disabled = src->pack_loading_disabled; target->pack_loading_disabled = src->pack_loading_disabled;
target->uncaught_exception_stack_size = src->uncaught_exception_stack_size; target->uncaught_exception_stack_size = src->uncaught_exception_stack_size;
target->context_safety_implementation = src->context_safety_implementation;
} }
}; };

View File

@ -921,20 +921,21 @@ void BrowserWebViewDelegate::didCreateScriptContext(
void BrowserWebViewDelegate::willReleaseScriptContext( void BrowserWebViewDelegate::willReleaseScriptContext(
WebFrame* frame, v8::Handle<v8::Context> context, int worldId) { WebFrame* frame, v8::Handle<v8::Context> context, int worldId) {
CefRefPtr<CefClient> client = browser_->GetClient(); CefRefPtr<CefClient> client = browser_->GetClient();
if (!client.get()) if (client.get()) {
return; CefRefPtr<CefV8ContextHandler> handler = client->GetV8ContextHandler();
if (handler.get()) {
v8::HandleScope handle_scope;
v8::Context::Scope scope(context);
CefRefPtr<CefV8ContextHandler> handler = client->GetV8ContextHandler(); CefRefPtr<CefFrame> framePtr(browser_->UIT_GetCefFrame(frame));
if (!handler.get()) CefRefPtr<CefV8Context> contextPtr(new CefV8ContextImpl(context));
return;
v8::HandleScope handle_scope; handler->OnContextReleased(browser_, framePtr, contextPtr);
v8::Context::Scope scope(context); }
}
CefRefPtr<CefFrame> framePtr(browser_->UIT_GetCefFrame(frame)); // Disconnect any handles still associated with the context.
CefRefPtr<CefV8Context> contextPtr(new CefV8ContextImpl(context)); CefV8ReleaseContext(context);
handler->OnContextReleased(browser_, framePtr, contextPtr);
} }
void BrowserWebViewDelegate::didReceiveTitle( void BrowserWebViewDelegate::didReceiveTitle(

View File

@ -3,6 +3,7 @@
// can be found in the LICENSE file. // can be found in the LICENSE file.
#include <string> #include <string>
#include <vector>
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
@ -43,10 +44,110 @@ MSVC_POP_WARNING();
namespace { namespace {
static const char kCefTrackObject[] = "Cef::TrackObject"; static const char kCefTrackObject[] = "Cef::TrackObject";
static const char kCefContextState[] = "Cef::ContextState";
// Memory manager. // Memory manager.
base::LazyInstance<CefTrackManager> g_v8_tracker = LAZY_INSTANCE_INITIALIZER; class CefV8TrackManager : public CefTrackManager {
public:
CefV8TrackManager() {
const CefSettings& settings = _Context->settings();
if (settings.context_safety_implementation < 0)
context_safety_impl_ = IMPL_DISABLED;
else if (settings.context_safety_implementation == 1)
context_safety_impl_ = IMPL_VALUE;
else
context_safety_impl_ = IMPL_HASH;
}
scoped_refptr<CefV8ContextState> GetContextState(
v8::Handle<v8::Context> context) {
if (context_safety_impl_ == IMPL_DISABLED)
return scoped_refptr<CefV8ContextState>();
if (context.IsEmpty()) {
if (v8::Context::InContext())
context = v8::Context::GetCurrent();
else
return scoped_refptr<CefV8ContextState>();
}
if (context_safety_impl_ == IMPL_HASH) {
int hash = context->Global()->GetIdentityHash();
ContextMap::const_iterator it = context_map_.find(hash);
if (it != context_map_.end())
return it->second;
scoped_refptr<CefV8ContextState> state = new CefV8ContextState();
context_map_.insert(std::make_pair(hash, state));
return state;
} else {
if (context_state_key_.IsEmpty()) {
context_state_key_ =
v8::Persistent<v8::String>::New(v8::String::New(kCefContextState));
}
v8::Handle<v8::Object> object = context->Global();
v8::Handle<v8::Value> value = object->GetHiddenValue(context_state_key_);
if (!value.IsEmpty())
return static_cast<CefV8ContextState*>(v8::External::Unwrap(value));
scoped_refptr<CefV8ContextState> state = new CefV8ContextState();
object->SetHiddenValue(context_state_key_,
v8::External::New(state.get()));
// Reference will be released in ReleaseContext.
state->AddRef();
return state;
}
}
void ReleaseContext(v8::Handle<v8::Context> context) {
if (context_safety_impl_ == IMPL_DISABLED)
return;
if (context_safety_impl_ == IMPL_HASH) {
int hash = context->Global()->GetIdentityHash();
ContextMap::iterator it = context_map_.find(hash);
if (it != context_map_.end()) {
it->second->Detach();
context_map_.erase(it);
}
} else {
if (context_state_key_.IsEmpty())
return;
v8::Handle<v8::Object> object = context->Global();
v8::Handle<v8::Value> value = object->GetHiddenValue(context_state_key_);
scoped_refptr<CefV8ContextState> state =
static_cast<CefV8ContextState*>(v8::External::Unwrap(value));
state->Detach();
object->DeleteHiddenValue(context_state_key_);
// Match the AddRef in GetContextState.
state->Release();
}
}
private:
enum ContextSafetyImpl {
IMPL_DISABLED,
IMPL_HASH,
IMPL_VALUE,
};
ContextSafetyImpl context_safety_impl_;
// Used with IMPL_HASH.
typedef std::map<int, scoped_refptr<CefV8ContextState> > ContextMap;
ContextMap context_map_;
// Used with IMPL_VALUE.
v8::Persistent<v8::String> context_state_key_;
};
base::LazyInstance<CefV8TrackManager> g_v8_tracker = LAZY_INSTANCE_INITIALIZER;
class V8TrackObject : public CefTrackNode { class V8TrackObject : public CefTrackNode {
public: public:
@ -417,6 +518,10 @@ class CefV8ExceptionImpl : public CefV8Exception {
// Global functions. // Global functions.
void CefV8ReleaseContext(v8::Handle<v8::Context> context) {
g_v8_tracker.Pointer()->ReleaseContext(context);
}
bool CefRegisterExtension(const CefString& extension_name, bool CefRegisterExtension(const CefString& extension_name,
const CefString& javascript_code, const CefString& javascript_code,
CefRefPtr<CefV8Handler> handler) { CefRefPtr<CefV8Handler> handler) {
@ -437,6 +542,13 @@ bool CefRegisterExtension(const CefString& extension_name,
} }
// CefV8HandleBase
CefV8HandleBase::CefV8HandleBase(v8::Handle<v8::Context> context) {
context_state_ = g_v8_tracker.Pointer()->GetContextState(context);
}
// CefV8Context // CefV8Context
// static // static
@ -473,26 +585,35 @@ bool CefV8Context::InContext() {
// CefV8ContextImpl // CefV8ContextImpl
#define CEF_V8_REQUIRE_VALID_RETURN(ret) \
if (!handle_->IsValid()) { \
NOTREACHED() << "V8 handle is not valid"; \
return ret; \
}
#define CEF_V8_REQUIRE_OBJECT_RETURN(ret) \ #define CEF_V8_REQUIRE_OBJECT_RETURN(ret) \
CEF_V8_REQUIRE_VALID_RETURN(ret); \
if (!GetHandle()->IsObject()) { \ if (!GetHandle()->IsObject()) { \
NOTREACHED() << "V8 value is not an object"; \ NOTREACHED() << "V8 value is not an object"; \
return ret; \ return ret; \
} }
#define CEF_V8_REQUIRE_ARRAY_RETURN(ret) \ #define CEF_V8_REQUIRE_ARRAY_RETURN(ret) \
CEF_V8_REQUIRE_VALID_RETURN(ret); \
if (!GetHandle()->IsArray()) { \ if (!GetHandle()->IsArray()) { \
NOTREACHED() << "V8 value is not an array"; \ NOTREACHED() << "V8 value is not an array"; \
return ret; \ return ret; \
} }
#define CEF_V8_REQUIRE_FUNCTION_RETURN(ret) \ #define CEF_V8_REQUIRE_FUNCTION_RETURN(ret) \
CEF_V8_REQUIRE_VALID_RETURN(ret); \
if (!GetHandle()->IsFunction()) { \ if (!GetHandle()->IsFunction()) { \
NOTREACHED() << "V8 value is not a function"; \ NOTREACHED() << "V8 value is not a function"; \
return ret; \ return ret; \
} }
CefV8ContextImpl::CefV8ContextImpl(v8::Handle<v8::Context> context) CefV8ContextImpl::CefV8ContextImpl(v8::Handle<v8::Context> context)
: handle_(new Handle(context)) : handle_(new Handle(context, context))
#ifndef NDEBUG #ifndef NDEBUG
, enter_count_(0) , enter_count_(0)
#endif #endif
@ -503,9 +624,15 @@ CefV8ContextImpl::~CefV8ContextImpl() {
DLOG_ASSERT(0 == enter_count_); DLOG_ASSERT(0 == enter_count_);
} }
bool CefV8ContextImpl::IsValid() {
CEF_REQUIRE_UI_THREAD(false);
return handle_->IsValid();
}
CefRefPtr<CefBrowser> CefV8ContextImpl::GetBrowser() { CefRefPtr<CefBrowser> CefV8ContextImpl::GetBrowser() {
CefRefPtr<CefBrowser> browser; CefRefPtr<CefBrowser> browser;
CEF_REQUIRE_UI_THREAD(browser); CEF_REQUIRE_UI_THREAD(browser);
CEF_V8_REQUIRE_VALID_RETURN(browser);
WebKit::WebFrame* webframe = GetWebFrame(); WebKit::WebFrame* webframe = GetWebFrame();
if (webframe) if (webframe)
@ -517,6 +644,7 @@ CefRefPtr<CefBrowser> CefV8ContextImpl::GetBrowser() {
CefRefPtr<CefFrame> CefV8ContextImpl::GetFrame() { CefRefPtr<CefFrame> CefV8ContextImpl::GetFrame() {
CefRefPtr<CefFrame> frame; CefRefPtr<CefFrame> frame;
CEF_REQUIRE_UI_THREAD(frame); CEF_REQUIRE_UI_THREAD(frame);
CEF_V8_REQUIRE_VALID_RETURN(frame);
WebKit::WebFrame* webframe = GetWebFrame(); WebKit::WebFrame* webframe = GetWebFrame();
if (webframe) { if (webframe) {
@ -531,6 +659,7 @@ CefRefPtr<CefFrame> CefV8ContextImpl::GetFrame() {
CefRefPtr<CefV8Value> CefV8ContextImpl::GetGlobal() { CefRefPtr<CefV8Value> CefV8ContextImpl::GetGlobal() {
CEF_REQUIRE_UI_THREAD(NULL); CEF_REQUIRE_UI_THREAD(NULL);
CEF_V8_REQUIRE_VALID_RETURN(NULL);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Context::Scope context_scope(GetHandle()); v8::Context::Scope context_scope(GetHandle());
@ -539,6 +668,8 @@ CefRefPtr<CefV8Value> CefV8ContextImpl::GetGlobal() {
bool CefV8ContextImpl::Enter() { bool CefV8ContextImpl::Enter() {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
GetHandle()->Enter(); GetHandle()->Enter();
#ifndef NDEBUG #ifndef NDEBUG
++enter_count_; ++enter_count_;
@ -548,6 +679,8 @@ bool CefV8ContextImpl::Enter() {
bool CefV8ContextImpl::Exit() { bool CefV8ContextImpl::Exit() {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
DLOG_ASSERT(enter_count_ > 0); DLOG_ASSERT(enter_count_ > 0);
GetHandle()->Exit(); GetHandle()->Exit();
#ifndef NDEBUG #ifndef NDEBUG
@ -558,6 +691,7 @@ bool CefV8ContextImpl::Exit() {
bool CefV8ContextImpl::IsSame(CefRefPtr<CefV8Context> that) { bool CefV8ContextImpl::IsSame(CefRefPtr<CefV8Context> that) {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
@ -575,6 +709,7 @@ bool CefV8ContextImpl::Eval(const CefString& code,
CefRefPtr<CefV8Value>& retval, CefRefPtr<CefV8Value>& retval,
CefRefPtr<CefV8Exception>& exception) { CefRefPtr<CefV8Exception>& exception) {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
if (code.empty()) { if (code.empty()) {
NOTREACHED() << "invalid input parameter"; NOTREACHED() << "invalid input parameter";
@ -820,71 +955,89 @@ CefRefPtr<CefV8Value> CefV8Value::CreateFunction(
CefV8ValueImpl::CefV8ValueImpl(v8::Handle<v8::Value> value, CefV8ValueImpl::CefV8ValueImpl(v8::Handle<v8::Value> value,
CefTrackNode* tracker) CefTrackNode* tracker)
: handle_(new Handle(value, tracker)), : handle_(new Handle(v8::Handle<v8::Context>(), value, tracker)),
rethrow_exceptions_(false) { rethrow_exceptions_(false) {
} }
CefV8ValueImpl::~CefV8ValueImpl() { CefV8ValueImpl::~CefV8ValueImpl() {
} }
bool CefV8ValueImpl::IsValid() {
CEF_REQUIRE_UI_THREAD(false);
return handle_->IsValid();
}
bool CefV8ValueImpl::IsUndefined() { bool CefV8ValueImpl::IsUndefined() {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsUndefined(); return GetHandle()->IsUndefined();
} }
bool CefV8ValueImpl::IsNull() { bool CefV8ValueImpl::IsNull() {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsNull(); return GetHandle()->IsNull();
} }
bool CefV8ValueImpl::IsBool() { bool CefV8ValueImpl::IsBool() {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
return (GetHandle()->IsBoolean() || GetHandle()->IsTrue() return (GetHandle()->IsBoolean() || GetHandle()->IsTrue()
|| GetHandle()->IsFalse()); || GetHandle()->IsFalse());
} }
bool CefV8ValueImpl::IsInt() { bool CefV8ValueImpl::IsInt() {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsInt32(); return GetHandle()->IsInt32();
} }
bool CefV8ValueImpl::IsUInt() { bool CefV8ValueImpl::IsUInt() {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsUint32(); return GetHandle()->IsUint32();
} }
bool CefV8ValueImpl::IsDouble() { bool CefV8ValueImpl::IsDouble() {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsNumber(); return GetHandle()->IsNumber();
} }
bool CefV8ValueImpl::IsDate() { bool CefV8ValueImpl::IsDate() {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsDate(); return GetHandle()->IsDate();
} }
bool CefV8ValueImpl::IsString() { bool CefV8ValueImpl::IsString() {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsString(); return GetHandle()->IsString();
} }
bool CefV8ValueImpl::IsObject() { bool CefV8ValueImpl::IsObject() {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsObject(); return GetHandle()->IsObject();
} }
bool CefV8ValueImpl::IsArray() { bool CefV8ValueImpl::IsArray() {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsArray(); return GetHandle()->IsArray();
} }
bool CefV8ValueImpl::IsFunction() { bool CefV8ValueImpl::IsFunction() {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsFunction(); return GetHandle()->IsFunction();
} }
bool CefV8ValueImpl::IsSame(CefRefPtr<CefV8Value> that) { bool CefV8ValueImpl::IsSame(CefRefPtr<CefV8Value> that) {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
@ -900,6 +1053,7 @@ bool CefV8ValueImpl::IsSame(CefRefPtr<CefV8Value> that) {
bool CefV8ValueImpl::GetBoolValue() { bool CefV8ValueImpl::GetBoolValue() {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
if (GetHandle()->IsTrue()) { if (GetHandle()->IsTrue()) {
return true; return true;
} else if (GetHandle()->IsFalse()) { } else if (GetHandle()->IsFalse()) {
@ -913,6 +1067,7 @@ bool CefV8ValueImpl::GetBoolValue() {
int32 CefV8ValueImpl::GetIntValue() { int32 CefV8ValueImpl::GetIntValue() {
CEF_REQUIRE_UI_THREAD(0); CEF_REQUIRE_UI_THREAD(0);
CEF_V8_REQUIRE_VALID_RETURN(0);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Int32> val = GetHandle()->ToInt32(); v8::Local<v8::Int32> val = GetHandle()->ToInt32();
return val->Value(); return val->Value();
@ -920,6 +1075,7 @@ int32 CefV8ValueImpl::GetIntValue() {
uint32 CefV8ValueImpl::GetUIntValue() { uint32 CefV8ValueImpl::GetUIntValue() {
CEF_REQUIRE_UI_THREAD(0); CEF_REQUIRE_UI_THREAD(0);
CEF_V8_REQUIRE_VALID_RETURN(0);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Uint32> val = GetHandle()->ToUint32(); v8::Local<v8::Uint32> val = GetHandle()->ToUint32();
return val->Value(); return val->Value();
@ -927,6 +1083,7 @@ uint32 CefV8ValueImpl::GetUIntValue() {
double CefV8ValueImpl::GetDoubleValue() { double CefV8ValueImpl::GetDoubleValue() {
CEF_REQUIRE_UI_THREAD(0.); CEF_REQUIRE_UI_THREAD(0.);
CEF_V8_REQUIRE_VALID_RETURN(0.);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Number> val = GetHandle()->ToNumber(); v8::Local<v8::Number> val = GetHandle()->ToNumber();
return val->Value(); return val->Value();
@ -934,6 +1091,7 @@ double CefV8ValueImpl::GetDoubleValue() {
CefTime CefV8ValueImpl::GetDateValue() { CefTime CefV8ValueImpl::GetDateValue() {
CEF_REQUIRE_UI_THREAD(CefTime(0.)); CEF_REQUIRE_UI_THREAD(CefTime(0.));
CEF_V8_REQUIRE_VALID_RETURN(CefTime(0.));
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Number> val = GetHandle()->ToNumber(); v8::Local<v8::Number> val = GetHandle()->ToNumber();
// Convert from milliseconds to seconds. // Convert from milliseconds to seconds.
@ -943,6 +1101,7 @@ CefTime CefV8ValueImpl::GetDateValue() {
CefString CefV8ValueImpl::GetStringValue() { CefString CefV8ValueImpl::GetStringValue() {
CefString rv; CefString rv;
CEF_REQUIRE_UI_THREAD(rv); CEF_REQUIRE_UI_THREAD(rv);
CEF_V8_REQUIRE_VALID_RETURN(rv);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
GetCefString(GetHandle()->ToString(), rv); GetCefString(GetHandle()->ToString(), rv);
return rv; return rv;
@ -1367,6 +1526,7 @@ CefRefPtr<CefV8StackTrace> CefV8StackTrace::GetCurrent(int frame_limit) {
CEF_REQUIRE_VALID_CONTEXT(NULL); CEF_REQUIRE_VALID_CONTEXT(NULL);
CEF_REQUIRE_UI_THREAD(NULL); CEF_REQUIRE_UI_THREAD(NULL);
v8::HandleScope handle_scope;
v8::Handle<v8::StackTrace> stackTrace = v8::Handle<v8::StackTrace> stackTrace =
v8::StackTrace::CurrentStackTrace( v8::StackTrace::CurrentStackTrace(
frame_limit, v8::StackTrace::kDetailed); frame_limit, v8::StackTrace::kDetailed);
@ -1379,20 +1539,27 @@ CefRefPtr<CefV8StackTrace> CefV8StackTrace::GetCurrent(int frame_limit) {
// CefV8StackTraceImpl // CefV8StackTraceImpl
CefV8StackTraceImpl::CefV8StackTraceImpl(v8::Handle<v8::StackTrace> handle) CefV8StackTraceImpl::CefV8StackTraceImpl(v8::Handle<v8::StackTrace> handle)
: handle_(new Handle(handle)) { : handle_(new Handle(v8::Handle<v8::Context>(), handle)) {
} }
CefV8StackTraceImpl::~CefV8StackTraceImpl() { CefV8StackTraceImpl::~CefV8StackTraceImpl() {
} }
bool CefV8StackTraceImpl::IsValid() {
CEF_REQUIRE_UI_THREAD(false);
return handle_->IsValid();
}
int CefV8StackTraceImpl::GetFrameCount() { int CefV8StackTraceImpl::GetFrameCount() {
CEF_REQUIRE_UI_THREAD(0); CEF_REQUIRE_UI_THREAD(0);
CEF_V8_REQUIRE_VALID_RETURN(0);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
return GetHandle()->GetFrameCount(); return GetHandle()->GetFrameCount();
} }
CefRefPtr<CefV8StackFrame> CefV8StackTraceImpl::GetFrame(int index) { CefRefPtr<CefV8StackFrame> CefV8StackTraceImpl::GetFrame(int index) {
CEF_REQUIRE_UI_THREAD(NULL); CEF_REQUIRE_UI_THREAD(NULL);
CEF_V8_REQUIRE_VALID_RETURN(NULL);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Handle<v8::StackFrame> stackFrame = GetHandle()->GetFrame(index); v8::Handle<v8::StackFrame> stackFrame = GetHandle()->GetFrame(index);
if (stackFrame.IsEmpty()) if (stackFrame.IsEmpty())
@ -1404,15 +1571,21 @@ CefRefPtr<CefV8StackFrame> CefV8StackTraceImpl::GetFrame(int index) {
// CefV8StackFrameImpl // CefV8StackFrameImpl
CefV8StackFrameImpl::CefV8StackFrameImpl(v8::Handle<v8::StackFrame> handle) CefV8StackFrameImpl::CefV8StackFrameImpl(v8::Handle<v8::StackFrame> handle)
: handle_(new Handle(handle)) { : handle_(new Handle(v8::Handle<v8::Context>(), handle)) {
} }
CefV8StackFrameImpl::~CefV8StackFrameImpl() { CefV8StackFrameImpl::~CefV8StackFrameImpl() {
} }
bool CefV8StackFrameImpl::IsValid() {
CEF_REQUIRE_UI_THREAD(false);
return handle_->IsValid();
}
CefString CefV8StackFrameImpl::GetScriptName() { CefString CefV8StackFrameImpl::GetScriptName() {
CefString rv; CefString rv;
CEF_REQUIRE_UI_THREAD(rv); CEF_REQUIRE_UI_THREAD(rv);
CEF_V8_REQUIRE_VALID_RETURN(rv);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
GetCefString(v8::Handle<v8::String>::Cast(GetHandle()->GetScriptName()), rv); GetCefString(v8::Handle<v8::String>::Cast(GetHandle()->GetScriptName()), rv);
return rv; return rv;
@ -1421,6 +1594,7 @@ CefString CefV8StackFrameImpl::GetScriptName() {
CefString CefV8StackFrameImpl::GetScriptNameOrSourceURL() { CefString CefV8StackFrameImpl::GetScriptNameOrSourceURL() {
CefString rv; CefString rv;
CEF_REQUIRE_UI_THREAD(rv); CEF_REQUIRE_UI_THREAD(rv);
CEF_V8_REQUIRE_VALID_RETURN(rv);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
GetCefString( GetCefString(
v8::Handle<v8::String>::Cast(GetHandle()->GetScriptNameOrSourceURL()), v8::Handle<v8::String>::Cast(GetHandle()->GetScriptNameOrSourceURL()),
@ -1431,6 +1605,7 @@ CefString CefV8StackFrameImpl::GetScriptNameOrSourceURL() {
CefString CefV8StackFrameImpl::GetFunctionName() { CefString CefV8StackFrameImpl::GetFunctionName() {
CefString rv; CefString rv;
CEF_REQUIRE_UI_THREAD(rv); CEF_REQUIRE_UI_THREAD(rv);
CEF_V8_REQUIRE_VALID_RETURN(rv);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
GetCefString( GetCefString(
v8::Handle<v8::String>::Cast(GetHandle()->GetFunctionName()), rv); v8::Handle<v8::String>::Cast(GetHandle()->GetFunctionName()), rv);
@ -1439,24 +1614,28 @@ CefString CefV8StackFrameImpl::GetFunctionName() {
int CefV8StackFrameImpl::GetLineNumber() { int CefV8StackFrameImpl::GetLineNumber() {
CEF_REQUIRE_UI_THREAD(0); CEF_REQUIRE_UI_THREAD(0);
CEF_V8_REQUIRE_VALID_RETURN(0);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
return GetHandle()->GetLineNumber(); return GetHandle()->GetLineNumber();
} }
int CefV8StackFrameImpl::GetColumn() { int CefV8StackFrameImpl::GetColumn() {
CEF_REQUIRE_UI_THREAD(0); CEF_REQUIRE_UI_THREAD(0);
CEF_V8_REQUIRE_VALID_RETURN(0);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
return GetHandle()->GetColumn(); return GetHandle()->GetColumn();
} }
bool CefV8StackFrameImpl::IsEval() { bool CefV8StackFrameImpl::IsEval() {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
return GetHandle()->IsEval(); return GetHandle()->IsEval();
} }
bool CefV8StackFrameImpl::IsConstructor() { bool CefV8StackFrameImpl::IsConstructor() {
CEF_REQUIRE_UI_THREAD(false); CEF_REQUIRE_UI_THREAD(false);
CEF_V8_REQUIRE_VALID_RETURN(false);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
return GetHandle()->IsConstructor(); return GetHandle()->IsConstructor();
} }

View File

@ -19,25 +19,65 @@ namespace WebKit {
class WebFrame; class WebFrame;
}; };
// Call to detach all handles associated with the specified contxt.
void CefV8ReleaseContext(v8::Handle<v8::Context> context);
// Used to detach handles when the associated context is released.
class CefV8ContextState : public base::RefCounted<CefV8ContextState> {
public:
CefV8ContextState() : valid_(true) {}
virtual ~CefV8ContextState() {}
bool IsValid() { return valid_; }
void Detach() { valid_ = false; }
private:
bool valid_;
};
// Base class for V8 Handle types.
class CefV8HandleBase :
public base::RefCountedThreadSafe<CefV8HandleBase,
CefThread::DeleteOnUIThread> {
public:
virtual ~CefV8HandleBase() {}
// Returns true if there is no underlying context or if the underlying context
// is valid.
bool IsValid() {
return (!context_state_.get() || context_state_->IsValid());
}
protected:
// |context| is the context that owns this handle. If empty the current
// context will be used.
explicit CefV8HandleBase(v8::Handle<v8::Context> context);
private:
scoped_refptr<CefV8ContextState> context_state_;
};
// Template for V8 Handle types. This class is used to ensure that V8 objects // Template for V8 Handle types. This class is used to ensure that V8 objects
// are only released on the UI thread. // are only released on the UI thread.
template <typename v8class> template <typename v8class>
class CefV8Handle : class CefV8Handle : public CefV8HandleBase {
public base::RefCountedThreadSafe<CefV8Handle<v8class>,
CefThread::DeleteOnUIThread> {
public: public:
typedef v8::Handle<v8class> handleType; typedef v8::Handle<v8class> handleType;
typedef v8::Persistent<v8class> persistentType; typedef v8::Persistent<v8class> persistentType;
CefV8Handle(handleType v) CefV8Handle(v8::Handle<v8::Context> context, handleType v)
: handle_(persistentType::New(v)) { : CefV8HandleBase(context),
handle_(persistentType::New(v)) {
} }
~CefV8Handle() { virtual ~CefV8Handle() {
handle_.Dispose(); handle_.Dispose();
handle_.Clear(); handle_.Clear();
} }
handleType GetHandle() { return handle_; } handleType GetHandle() {
DCHECK(IsValid());
return handle_;
}
protected: protected:
persistentType handle_; persistentType handle_;
@ -57,6 +97,7 @@ class CefV8ContextImpl : public CefV8Context {
explicit CefV8ContextImpl(v8::Handle<v8::Context> context); explicit CefV8ContextImpl(v8::Handle<v8::Context> context);
virtual ~CefV8ContextImpl(); virtual ~CefV8ContextImpl();
virtual bool IsValid() OVERRIDE;
virtual CefRefPtr<CefBrowser> GetBrowser() OVERRIDE; virtual CefRefPtr<CefBrowser> GetBrowser() OVERRIDE;
virtual CefRefPtr<CefFrame> GetFrame() OVERRIDE; virtual CefRefPtr<CefFrame> GetFrame() OVERRIDE;
virtual CefRefPtr<CefV8Value> GetGlobal() OVERRIDE; virtual CefRefPtr<CefV8Value> GetGlobal() OVERRIDE;
@ -90,6 +131,7 @@ class CefV8ValueImpl : public CefV8Value {
CefV8ValueImpl(v8::Handle<v8::Value> value, CefTrackNode* tracker = NULL); CefV8ValueImpl(v8::Handle<v8::Value> value, CefTrackNode* tracker = NULL);
virtual ~CefV8ValueImpl(); virtual ~CefV8ValueImpl();
virtual bool IsValid() OVERRIDE;
virtual bool IsUndefined() OVERRIDE; virtual bool IsUndefined() OVERRIDE;
virtual bool IsNull() OVERRIDE; virtual bool IsNull() OVERRIDE;
virtual bool IsBool() OVERRIDE; virtual bool IsBool() OVERRIDE;
@ -147,19 +189,22 @@ class CefV8ValueImpl : public CefV8Value {
// Test for and record any exception. // Test for and record any exception.
bool HasCaught(v8::TryCatch& try_catch); bool HasCaught(v8::TryCatch& try_catch);
class Handle : class Handle : public CefV8HandleBase {
public base::RefCountedThreadSafe<Handle, CefThread::DeleteOnUIThread> {
public: public:
typedef v8::Handle<v8::Value> handleType; typedef v8::Handle<v8::Value> handleType;
typedef v8::Persistent<v8::Value> persistentType; typedef v8::Persistent<v8::Value> persistentType;
Handle(handleType v, CefTrackNode* tracker) Handle(v8::Handle<v8::Context> context, handleType v, CefTrackNode* tracker)
: handle_(persistentType::New(v)), : CefV8HandleBase(context),
handle_(persistentType::New(v)),
tracker_(tracker) { tracker_(tracker) {
} }
~Handle(); virtual ~Handle();
handleType GetHandle() { return handle_; } handleType GetHandle() {
DCHECK(IsValid());
return handle_;
}
private: private:
persistentType handle_; persistentType handle_;
@ -184,6 +229,7 @@ class CefV8StackTraceImpl : public CefV8StackTrace {
explicit CefV8StackTraceImpl(v8::Handle<v8::StackTrace> handle); explicit CefV8StackTraceImpl(v8::Handle<v8::StackTrace> handle);
virtual ~CefV8StackTraceImpl(); virtual ~CefV8StackTraceImpl();
virtual bool IsValid() OVERRIDE;
virtual int GetFrameCount() OVERRIDE; virtual int GetFrameCount() OVERRIDE;
virtual CefRefPtr<CefV8StackFrame> GetFrame(int index) OVERRIDE; virtual CefRefPtr<CefV8StackFrame> GetFrame(int index) OVERRIDE;
@ -202,6 +248,7 @@ class CefV8StackFrameImpl : public CefV8StackFrame {
explicit CefV8StackFrameImpl(v8::Handle<v8::StackFrame> handle); explicit CefV8StackFrameImpl(v8::Handle<v8::StackFrame> handle);
virtual ~CefV8StackFrameImpl(); virtual ~CefV8StackFrameImpl();
virtual bool IsValid() OVERRIDE;
virtual CefString GetScriptName() OVERRIDE; virtual CefString GetScriptName() OVERRIDE;
virtual CefString GetScriptNameOrSourceURL() OVERRIDE; virtual CefString GetScriptNameOrSourceURL() OVERRIDE;
virtual CefString GetFunctionName() OVERRIDE; virtual CefString GetFunctionName() OVERRIDE;

View File

@ -52,6 +52,20 @@ CEF_EXPORT int cef_v8context_in_context() {
// MEMBER FUNCTIONS - Body may be edited by hand. // MEMBER FUNCTIONS - Body may be edited by hand.
int CEF_CALLBACK v8context_is_valid(struct _cef_v8context_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Execute
bool _retval = CefV8ContextCppToC::Get(self)->IsValid();
// Return type: bool
return _retval;
}
cef_browser_t* CEF_CALLBACK v8context_get_browser( cef_browser_t* CEF_CALLBACK v8context_get_browser(
struct _cef_v8context_t* self) { struct _cef_v8context_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
@ -212,6 +226,7 @@ int CEF_CALLBACK v8context_eval(struct _cef_v8context_t* self,
CefV8ContextCppToC::CefV8ContextCppToC(CefV8Context* cls) CefV8ContextCppToC::CefV8ContextCppToC(CefV8Context* cls)
: CefCppToC<CefV8ContextCppToC, CefV8Context, cef_v8context_t>(cls) { : CefCppToC<CefV8ContextCppToC, CefV8Context, cef_v8context_t>(cls) {
struct_.struct_.is_valid = v8context_is_valid;
struct_.struct_.get_browser = v8context_get_browser; struct_.struct_.get_browser = v8context_get_browser;
struct_.struct_.get_frame = v8context_get_frame; struct_.struct_.get_frame = v8context_get_frame;
struct_.struct_.get_global = v8context_get_global; struct_.struct_.get_global = v8context_get_global;

View File

@ -15,6 +15,20 @@
// MEMBER FUNCTIONS - Body may be edited by hand. // MEMBER FUNCTIONS - Body may be edited by hand.
int CEF_CALLBACK v8stack_frame_is_valid(struct _cef_v8stack_frame_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Execute
bool _retval = CefV8StackFrameCppToC::Get(self)->IsValid();
// Return type: bool
return _retval;
}
cef_string_userfree_t CEF_CALLBACK v8stack_frame_get_script_name( cef_string_userfree_t CEF_CALLBACK v8stack_frame_get_script_name(
struct _cef_v8stack_frame_t* self) { struct _cef_v8stack_frame_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
@ -125,6 +139,7 @@ int CEF_CALLBACK v8stack_frame_is_constructor(
CefV8StackFrameCppToC::CefV8StackFrameCppToC(CefV8StackFrame* cls) CefV8StackFrameCppToC::CefV8StackFrameCppToC(CefV8StackFrame* cls)
: CefCppToC<CefV8StackFrameCppToC, CefV8StackFrame, cef_v8stack_frame_t>( : CefCppToC<CefV8StackFrameCppToC, CefV8StackFrame, cef_v8stack_frame_t>(
cls) { cls) {
struct_.struct_.is_valid = v8stack_frame_is_valid;
struct_.struct_.get_script_name = v8stack_frame_get_script_name; struct_.struct_.get_script_name = v8stack_frame_get_script_name;
struct_.struct_.get_script_name_or_source_url = struct_.struct_.get_script_name_or_source_url =
v8stack_frame_get_script_name_or_source_url; v8stack_frame_get_script_name_or_source_url;

View File

@ -30,6 +30,20 @@ CEF_EXPORT cef_v8stack_trace_t* cef_v8stack_trace_get_current(int frame_limit) {
// MEMBER FUNCTIONS - Body may be edited by hand. // MEMBER FUNCTIONS - Body may be edited by hand.
int CEF_CALLBACK v8stack_trace_is_valid(struct _cef_v8stack_trace_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Execute
bool _retval = CefV8StackTraceCppToC::Get(self)->IsValid();
// Return type: bool
return _retval;
}
int CEF_CALLBACK v8stack_trace_get_frame_count( int CEF_CALLBACK v8stack_trace_get_frame_count(
struct _cef_v8stack_trace_t* self) { struct _cef_v8stack_trace_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
@ -68,6 +82,7 @@ struct _cef_v8stack_frame_t* CEF_CALLBACK v8stack_trace_get_frame(
CefV8StackTraceCppToC::CefV8StackTraceCppToC(CefV8StackTrace* cls) CefV8StackTraceCppToC::CefV8StackTraceCppToC(CefV8StackTrace* cls)
: CefCppToC<CefV8StackTraceCppToC, CefV8StackTrace, cef_v8stack_trace_t>( : CefCppToC<CefV8StackTraceCppToC, CefV8StackTrace, cef_v8stack_trace_t>(
cls) { cls) {
struct_.struct_.is_valid = v8stack_trace_is_valid;
struct_.struct_.get_frame_count = v8stack_trace_get_frame_count; struct_.struct_.get_frame_count = v8stack_trace_get_frame_count;
struct_.struct_.get_frame = v8stack_trace_get_frame; struct_.struct_.get_frame = v8stack_trace_get_frame;
} }

View File

@ -167,6 +167,20 @@ CEF_EXPORT cef_v8value_t* cef_v8value_create_function(const cef_string_t* name,
// MEMBER FUNCTIONS - Body may be edited by hand. // MEMBER FUNCTIONS - Body may be edited by hand.
int CEF_CALLBACK v8value_is_valid(struct _cef_v8value_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Execute
bool _retval = CefV8ValueCppToC::Get(self)->IsValid();
// Return type: bool
return _retval;
}
int CEF_CALLBACK v8value_is_undefined(struct _cef_v8value_t* self) { int CEF_CALLBACK v8value_is_undefined(struct _cef_v8value_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
@ -903,6 +917,7 @@ struct _cef_v8value_t* CEF_CALLBACK v8value_execute_function_with_context(
CefV8ValueCppToC::CefV8ValueCppToC(CefV8Value* cls) CefV8ValueCppToC::CefV8ValueCppToC(CefV8Value* cls)
: CefCppToC<CefV8ValueCppToC, CefV8Value, cef_v8value_t>(cls) { : CefCppToC<CefV8ValueCppToC, CefV8Value, cef_v8value_t>(cls) {
struct_.struct_.is_valid = v8value_is_valid;
struct_.struct_.is_undefined = v8value_is_undefined; struct_.struct_.is_undefined = v8value_is_undefined;
struct_.struct_.is_null = v8value_is_null; struct_.struct_.is_null = v8value_is_null;
struct_.struct_.is_bool = v8value_is_bool; struct_.struct_.is_bool = v8value_is_bool;

View File

@ -52,6 +52,19 @@ bool CefV8Context::InContext() {
// VIRTUAL METHODS - Body may be edited by hand. // VIRTUAL METHODS - Body may be edited by hand.
bool CefV8ContextCToCpp::IsValid() {
if (CEF_MEMBER_MISSING(struct_, is_valid))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
int _retval = struct_->is_valid(struct_);
// Return type: bool
return _retval?true:false;
}
CefRefPtr<CefBrowser> CefV8ContextCToCpp::GetBrowser() { CefRefPtr<CefBrowser> CefV8ContextCToCpp::GetBrowser() {
if (CEF_MEMBER_MISSING(struct_, get_browser)) if (CEF_MEMBER_MISSING(struct_, get_browser))
return NULL; return NULL;

View File

@ -32,6 +32,7 @@ class CefV8ContextCToCpp
virtual ~CefV8ContextCToCpp() {} virtual ~CefV8ContextCToCpp() {}
// CefV8Context methods // CefV8Context methods
virtual bool IsValid() OVERRIDE;
virtual CefRefPtr<CefBrowser> GetBrowser() OVERRIDE; virtual CefRefPtr<CefBrowser> GetBrowser() OVERRIDE;
virtual CefRefPtr<CefFrame> GetFrame() OVERRIDE; virtual CefRefPtr<CefFrame> GetFrame() OVERRIDE;
virtual CefRefPtr<CefV8Value> GetGlobal() OVERRIDE; virtual CefRefPtr<CefV8Value> GetGlobal() OVERRIDE;

View File

@ -15,6 +15,19 @@
// VIRTUAL METHODS - Body may be edited by hand. // VIRTUAL METHODS - Body may be edited by hand.
bool CefV8StackFrameCToCpp::IsValid() {
if (CEF_MEMBER_MISSING(struct_, is_valid))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
int _retval = struct_->is_valid(struct_);
// Return type: bool
return _retval?true:false;
}
CefString CefV8StackFrameCToCpp::GetScriptName() { CefString CefV8StackFrameCToCpp::GetScriptName() {
if (CEF_MEMBER_MISSING(struct_, get_script_name)) if (CEF_MEMBER_MISSING(struct_, get_script_name))
return CefString(); return CefString();

View File

@ -34,6 +34,7 @@ class CefV8StackFrameCToCpp
virtual ~CefV8StackFrameCToCpp() {} virtual ~CefV8StackFrameCToCpp() {}
// CefV8StackFrame methods // CefV8StackFrame methods
virtual bool IsValid() OVERRIDE;
virtual CefString GetScriptName() OVERRIDE; virtual CefString GetScriptName() OVERRIDE;
virtual CefString GetScriptNameOrSourceURL() OVERRIDE; virtual CefString GetScriptNameOrSourceURL() OVERRIDE;
virtual CefString GetFunctionName() OVERRIDE; virtual CefString GetFunctionName() OVERRIDE;

View File

@ -30,6 +30,19 @@ CefRefPtr<CefV8StackTrace> CefV8StackTrace::GetCurrent(int frame_limit) {
// VIRTUAL METHODS - Body may be edited by hand. // VIRTUAL METHODS - Body may be edited by hand.
bool CefV8StackTraceCToCpp::IsValid() {
if (CEF_MEMBER_MISSING(struct_, is_valid))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
int _retval = struct_->is_valid(struct_);
// Return type: bool
return _retval?true:false;
}
int CefV8StackTraceCToCpp::GetFrameCount() { int CefV8StackTraceCToCpp::GetFrameCount() {
if (CEF_MEMBER_MISSING(struct_, get_frame_count)) if (CEF_MEMBER_MISSING(struct_, get_frame_count))
return 0; return 0;

View File

@ -34,6 +34,7 @@ class CefV8StackTraceCToCpp
virtual ~CefV8StackTraceCToCpp() {} virtual ~CefV8StackTraceCToCpp() {}
// CefV8StackTrace methods // CefV8StackTrace methods
virtual bool IsValid() OVERRIDE;
virtual int GetFrameCount() OVERRIDE; virtual int GetFrameCount() OVERRIDE;
virtual CefRefPtr<CefV8StackFrame> GetFrame(int index) OVERRIDE; virtual CefRefPtr<CefV8StackFrame> GetFrame(int index) OVERRIDE;
}; };

View File

@ -159,6 +159,19 @@ CefRefPtr<CefV8Value> CefV8Value::CreateFunction(const CefString& name,
// VIRTUAL METHODS - Body may be edited by hand. // VIRTUAL METHODS - Body may be edited by hand.
bool CefV8ValueCToCpp::IsValid() {
if (CEF_MEMBER_MISSING(struct_, is_valid))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
int _retval = struct_->is_valid(struct_);
// Return type: bool
return _retval?true:false;
}
bool CefV8ValueCToCpp::IsUndefined() { bool CefV8ValueCToCpp::IsUndefined() {
if (CEF_MEMBER_MISSING(struct_, is_undefined)) if (CEF_MEMBER_MISSING(struct_, is_undefined))
return false; return false;

View File

@ -33,6 +33,7 @@ class CefV8ValueCToCpp
virtual ~CefV8ValueCToCpp() {} virtual ~CefV8ValueCToCpp() {}
// CefV8Value methods // CefV8Value methods
virtual bool IsValid() OVERRIDE;
virtual bool IsUndefined() OVERRIDE; virtual bool IsUndefined() OVERRIDE;
virtual bool IsNull() OVERRIDE; virtual bool IsNull() OVERRIDE;
virtual bool IsBool() OVERRIDE; virtual bool IsBool() OVERRIDE;

View File

@ -259,6 +259,8 @@ void AppGetSettings(CefSettings& settings, CefRefPtr<CefApp>& app) {
g_command_line->HasSwitch(cefclient::kPackLoadingDisabled); g_command_line->HasSwitch(cefclient::kPackLoadingDisabled);
settings.uncaught_exception_stack_size = GetIntValue( settings.uncaught_exception_stack_size = GetIntValue(
g_command_line->GetSwitchValue(cefclient::kUncaughtExceptionStackSize)); g_command_line->GetSwitchValue(cefclient::kUncaughtExceptionStackSize));
settings.context_safety_implementation = GetIntValue(
g_command_line->GetSwitchValue(cefclient::kContextSafetyImplementation));
// Retrieve command-line proxy configuration, if any. // Retrieve command-line proxy configuration, if any.
bool has_proxy = false; bool has_proxy = false;

View File

@ -36,6 +36,7 @@ const char kResourcesDirPath[] = "resources-dir-path";
const char kLocalesDirPath[] = "locales-dir-path"; const char kLocalesDirPath[] = "locales-dir-path";
const char kPackLoadingDisabled[] = "pack-loading-disabled"; const char kPackLoadingDisabled[] = "pack-loading-disabled";
const char kUncaughtExceptionStackSize[] = "uncaught-exception-stack-size"; const char kUncaughtExceptionStackSize[] = "uncaught-exception-stack-size";
const char kContextSafetyImplementation[] = "context-safety-implementation";
// CefBrowserSettings attributes. // CefBrowserSettings attributes.
const char kDragDropDisabled[] = "drag-drop-disabled"; const char kDragDropDisabled[] = "drag-drop-disabled";

View File

@ -38,6 +38,7 @@ extern const char kResourcesDirPath[];
extern const char kLocalesDirPath[]; extern const char kLocalesDirPath[];
extern const char kPackLoadingDisabled[]; extern const char kPackLoadingDisabled[];
extern const char kUncaughtExceptionStackSize[]; extern const char kUncaughtExceptionStackSize[];
extern const char kContextSafetyImplementation[];
// CefBrowserSettings attributes. // CefBrowserSettings attributes.
extern const char kDragDropDisabled[]; extern const char kDragDropDisabled[];

View File

@ -13,7 +13,13 @@
namespace performance_test { namespace performance_test {
// Use more interations for a Release build.
#ifdef NDEBUG
const size_t kDefaultIterations = 100000;
#else
const size_t kDefaultIterations = 10000; const size_t kDefaultIterations = 10000;
#endif
const char kTestUrl[] = "http://tests/performance"; const char kTestUrl[] = "http://tests/performance";
namespace { namespace {

View File

@ -3,6 +3,9 @@
// can be found in the LICENSE file. // can be found in the LICENSE file.
#include "tests/unittests/test_suite.h" #include "tests/unittests/test_suite.h"
#include <cstdlib>
#include "tests/cefclient/cefclient_switches.h" #include "tests/cefclient/cefclient_switches.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/logging.h" #include "base/logging.h"
@ -16,6 +19,18 @@
#include "base/test/test_timeouts.h" #include "base/test/test_timeouts.h"
#endif #endif
namespace {
// Return the int representation of the specified string.
int GetIntValue(const std::string& str) {
if (str.empty())
return 0;
return atoi(str.c_str());
}
} // namespace
CommandLine* CefTestSuite::commandline_ = NULL; CommandLine* CefTestSuite::commandline_ = NULL;
CefTestSuite::CefTestSuite(int argc, char** argv) CefTestSuite::CefTestSuite(int argc, char** argv)
@ -127,6 +142,10 @@ void CefTestSuite::GetSettings(CefSettings& settings) {
// Necessary for V8Test.OnUncaughtException tests. // Necessary for V8Test.OnUncaughtException tests.
settings.uncaught_exception_stack_size = 10; settings.uncaught_exception_stack_size = 10;
settings.context_safety_implementation = GetIntValue(
commandline_->GetSwitchValueASCII(
cefclient::kContextSafetyImplementation));
} }
// static // static

View File

@ -18,12 +18,13 @@
namespace { namespace {
// Unique values for V8 tests. // Unique values for V8 tests.
const char* kV8TestUrl = "http://tests/V8Test.Test"; const char kV8TestUrl[] = "http://tests/V8Test.Test";
const char* kV8BindingTestUrl = "http://tests/V8Test.BindingTest"; const char kV8BindingTestUrl[] = "http://tests/V8Test.BindingTest";
const char* kV8ContextParentTestUrl = "http://tests/V8Test.ContextParentTest"; const char kV8ContextParentTestUrl[] = "http://tests/V8Test.ContextParentTest";
const char* kV8ContextChildTestUrl = "http://tests/V8Test.ContextChildTest"; const char kV8ContextChildTestUrl[] = "http://tests/V8Test.ContextChildTest";
const char* kV8OnUncaughtExceptionTestUrl = const char kV8OnUncaughtExceptionTestUrl[] =
"http://tests/V8Test.OnUncaughtException"; "http://tests/V8Test.OnUncaughtException";
const char kV8NavTestUrl[] = "http://tests/V8Test.NavTest";
enum V8TestMode { enum V8TestMode {
V8TEST_NULL_CREATE = 0, V8TEST_NULL_CREATE = 0,
@ -57,6 +58,7 @@ enum V8TestMode {
V8TEST_CONTEXT_EVAL, V8TEST_CONTEXT_EVAL,
V8TEST_CONTEXT_EVAL_EXCEPTION, V8TEST_CONTEXT_EVAL_EXCEPTION,
V8TEST_CONTEXT_ENTERED, V8TEST_CONTEXT_ENTERED,
V8TEST_CONTEXT_INVALID,
V8TEST_BINDING, V8TEST_BINDING,
V8TEST_STACK_TRACE, V8TEST_STACK_TRACE,
V8TEST_ON_UNCAUGHT_EXCEPTION, V8TEST_ON_UNCAUGHT_EXCEPTION,
@ -73,11 +75,14 @@ class V8TestHandler : public TestHandler {
} }
virtual void RunTest() OVERRIDE { virtual void RunTest() OVERRIDE {
// Nested script tag forces creation of the V8 context.
if (test_mode_ == V8TEST_CONTEXT_ENTERED) { if (test_mode_ == V8TEST_CONTEXT_ENTERED) {
AddResource(kV8ContextParentTestUrl, "<html><body><iframe src=\"" + AddResource(kV8ContextParentTestUrl, "<html><body>"
"<script>var i = 0;</script><iframe src=\"" +
std::string(kV8ContextChildTestUrl) + "\" id=\"f\"></iframe></body>" std::string(kV8ContextChildTestUrl) + "\" id=\"f\"></iframe></body>"
"</html>", "text/html"); "</html>", "text/html");
AddResource(kV8ContextChildTestUrl, "<html><body>CHILD</body></html>", AddResource(kV8ContextChildTestUrl, "<html><body>"
"<script>var i = 0;</script>CHILD</body></html>",
"text/html"); "text/html");
CreateBrowser(kV8ContextParentTestUrl); CreateBrowser(kV8ContextParentTestUrl);
} else if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION || } else if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION ||
@ -92,8 +97,14 @@ class V8TestHandler : public TestHandler {
"text/html"); "text/html");
CreateBrowser(kV8OnUncaughtExceptionTestUrl); CreateBrowser(kV8OnUncaughtExceptionTestUrl);
} else { } else {
if (test_mode_ == V8TEST_CONTEXT_INVALID) {
AddResource(kV8NavTestUrl, "<html><body>"
"<script>var i = 0;</script>TEST</body></html>", "text/html");
}
EXPECT_TRUE(test_url_ != NULL); EXPECT_TRUE(test_url_ != NULL);
AddResource(test_url_, "<html><body>TEST</body></html>", "text/html"); AddResource(test_url_, "<html><body>"
"<script>var i = 0;</script>TEST</body></html>", "text/html");
CreateBrowser(test_url_); CreateBrowser(test_url_);
} }
} }
@ -194,6 +205,10 @@ class V8TestHandler : public TestHandler {
case V8TEST_CONTEXT_ENTERED: case V8TEST_CONTEXT_ENTERED:
RunContextEnteredTest(); RunContextEnteredTest();
break; break;
case V8TEST_CONTEXT_INVALID:
// The test is triggered when the context is released.
GetBrowser()->GetMainFrame()->LoadURL(kV8NavTestUrl);
break;
case V8TEST_BINDING: case V8TEST_BINDING:
RunBindingTest(); RunBindingTest();
break; break;
@ -1545,14 +1560,14 @@ class V8TestHandler : public TestHandler {
} }
void RunOnUncaughtExceptionTest() { void RunOnUncaughtExceptionTest() {
on_uncaught_exception_context_ = test_context_ =
GetBrowser()->GetMainFrame()->GetV8Context(); GetBrowser()->GetMainFrame()->GetV8Context();
GetBrowser()->GetMainFrame()->ExecuteJavaScript("test()", GetBrowser()->GetMainFrame()->ExecuteJavaScript("test()",
CefString(), 0); CefString(), 0);
} }
void RunOnUncaughtExceptionDevToolsTest() { void RunOnUncaughtExceptionDevToolsTest() {
on_uncaught_exception_context_ = test_context_ =
GetBrowser()->GetMainFrame()->GetV8Context(); GetBrowser()->GetMainFrame()->GetV8Context();
GetBrowser()->ShowDevTools(); GetBrowser()->ShowDevTools();
} }
@ -1566,7 +1581,7 @@ class V8TestHandler : public TestHandler {
if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION || if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION ||
test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS) { test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS) {
EXPECT_TRUE(on_uncaught_exception_context_->IsSame(context)); EXPECT_TRUE(test_context_->IsSame(context));
EXPECT_STREQ("Uncaught ReferenceError: asd is not defined", EXPECT_STREQ("Uncaught ReferenceError: asd is not defined",
exception->GetMessage().ToString().c_str()); exception->GetMessage().ToString().c_str());
std::ostringstream stackFormatted; std::ostringstream stackFormatted;
@ -1587,7 +1602,8 @@ class V8TestHandler : public TestHandler {
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser, virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, CefRefPtr<CefFrame> frame,
int httpStatusCode) OVERRIDE { int httpStatusCode) OVERRIDE {
if (frame->IsMain()) std::string url = frame->GetURL();
if (frame->IsMain() && url != kV8NavTestUrl)
RunTest(test_mode_); RunTest(test_mode_);
if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS && if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS &&
browser->IsPopup()) { browser->IsPopup()) {
@ -1654,8 +1670,25 @@ class V8TestHandler : public TestHandler {
} }
} }
virtual void OnContextReleased(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) OVERRIDE {
std::string url = frame->GetURL();
if (test_mode_ == V8TEST_CONTEXT_INVALID && url == test_url_) {
test_context_ = context;
test_object_ = CefV8Value::CreateArray(10);
CefPostTask(TID_UI,
NewCefRunnableMethod(this, &V8TestHandler::DestroyTest));
}
}
virtual void DestroyTest() OVERRIDE { virtual void DestroyTest() OVERRIDE {
if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION || if (test_mode_ == V8TEST_CONTEXT_INVALID) {
// Verify that objects related to a particular context are not valid after
// OnContextReleased is called for that context.
EXPECT_FALSE(test_context_->IsValid());
EXPECT_FALSE(test_object_->IsValid());
} else if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION ||
test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS) { test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS) {
EXPECT_TRUE(got_on_uncaught_exception_); EXPECT_TRUE(got_on_uncaught_exception_);
} }
@ -1674,7 +1707,8 @@ class V8TestHandler : public TestHandler {
V8TestMode test_mode_; V8TestMode test_mode_;
const char* test_url_; const char* test_url_;
CefRefPtr<CefV8Context> on_uncaught_exception_context_; CefRefPtr<CefV8Context> test_context_;
CefRefPtr<CefV8Value> test_object_;
TrackCallback got_destroy_test_; TrackCallback got_destroy_test_;
TrackCallback got_on_uncaught_exception_; TrackCallback got_on_uncaught_exception_;
@ -1728,6 +1762,7 @@ V8_TEST(FunctionHandlerWithContext, V8TEST_FUNCTION_HANDLER_WITH_CONTEXT);
V8_TEST(ContextEval, V8TEST_CONTEXT_EVAL); V8_TEST(ContextEval, V8TEST_CONTEXT_EVAL);
V8_TEST(ContextEvalException, V8TEST_CONTEXT_EVAL_EXCEPTION); V8_TEST(ContextEvalException, V8TEST_CONTEXT_EVAL_EXCEPTION);
V8_TEST_EX(ContextEntered, V8TEST_CONTEXT_ENTERED, NULL); V8_TEST_EX(ContextEntered, V8TEST_CONTEXT_ENTERED, NULL);
V8_TEST(ContextInvalid, V8TEST_CONTEXT_INVALID);
V8_TEST_EX(Binding, V8TEST_BINDING, kV8BindingTestUrl); V8_TEST_EX(Binding, V8TEST_BINDING, kV8BindingTestUrl);
V8_TEST(StackTrace, V8TEST_STACK_TRACE); V8_TEST(StackTrace, V8TEST_STACK_TRACE);
V8_TEST(OnUncaughtException, V8TEST_ON_UNCAUGHT_EXCEPTION); V8_TEST(OnUncaughtException, V8TEST_ON_UNCAUGHT_EXCEPTION);