Reduce persistent CEF V8 memory usage by tracking objects on a per-context basis and not persisting objects when the underlying V8 handle is unused (issue #484).

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@884 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2012-10-30 20:49:43 +00:00
parent 59fe4fbab3
commit f4e653adca
2 changed files with 160 additions and 72 deletions

View File

@ -39,7 +39,7 @@ static const char kCefContextState[] = "Cef::ContextState";
// Memory manager. // Memory manager.
class CefV8TrackManager : public CefTrackManager { class CefV8TrackManager {
public: public:
CefV8TrackManager() CefV8TrackManager()
: context_safety_impl_(IMPL_HASH) { : context_safety_impl_(IMPL_HASH) {
@ -128,6 +128,14 @@ class CefV8TrackManager : public CefTrackManager {
} }
} }
void AddGlobalTrackObject(CefTrackNode* object) {
global_manager_.Add(object);
}
void DeleteGlobalTrackObject(CefTrackNode* object) {
global_manager_.Delete(object);
}
private: private:
enum ContextSafetyImpl { enum ContextSafetyImpl {
IMPL_DISABLED, IMPL_DISABLED,
@ -142,6 +150,10 @@ class CefV8TrackManager : public CefTrackManager {
// Used with IMPL_VALUE. // Used with IMPL_VALUE.
v8::Persistent<v8::String> context_state_key_; v8::Persistent<v8::String> context_state_key_;
// Used for globally tracked objects that are not associated with a particular
// context.
CefTrackManager global_manager_;
}; };
base::LazyInstance<CefV8TrackManager> g_v8_tracker = LAZY_INSTANCE_INITIALIZER; base::LazyInstance<CefV8TrackManager> g_v8_tracker = LAZY_INSTANCE_INITIALIZER;
@ -150,10 +162,12 @@ class V8TrackObject : public CefTrackNode {
public: public:
V8TrackObject() V8TrackObject()
: external_memory_(0) { : external_memory_(0) {
v8::V8::AdjustAmountOfExternalAllocatedMemory(
static_cast<int>(sizeof(V8TrackObject)));
} }
~V8TrackObject() { ~V8TrackObject() {
if (external_memory_ != 0) v8::V8::AdjustAmountOfExternalAllocatedMemory(
v8::V8::AdjustAmountOfExternalAllocatedMemory(-external_memory_); -static_cast<int>(sizeof(V8TrackObject)) - external_memory_);
} }
inline int GetExternallyAllocatedMemory() { inline int GetExternallyAllocatedMemory() {
@ -231,18 +245,56 @@ class V8TrackString : public CefTrackNode {
std::string string_; std::string string_;
}; };
void TrackAdd(CefTrackNode* object) {
g_v8_tracker.Pointer()->Add(object);
}
void TrackDelete(CefTrackNode* object) { // Manages the life span of a CefTrackNode associated with a persistent Object
g_v8_tracker.Pointer()->Delete(object); // or Function.
} class CefV8MakeWeakParam {
public:
CefV8MakeWeakParam(scoped_refptr<CefV8ContextState> context_state,
CefTrackNode* object)
: context_state_(context_state),
object_(object) {
DCHECK(object_);
v8::V8::AdjustAmountOfExternalAllocatedMemory(
static_cast<int>(sizeof(CefV8MakeWeakParam)));
if (context_state_.get()) {
// |object_| will be deleted when:
// A. The associated context is released, or
// B. TrackDestructor is called for the weak handle.
DCHECK(context_state_->IsValid());
context_state_->AddTrackObject(object_);
} else {
// |object_| will be deleted when:
// A. The process shuts down, or
// B. TrackDestructor is called for the weak handle.
g_v8_tracker.Pointer()->AddGlobalTrackObject(object_);
}
}
~CefV8MakeWeakParam() {
if (context_state_.get()) {
// If the associated context is still valid then delete |object_|.
// Otherwise, |object_| will already have been deleted.
if (context_state_->IsValid())
context_state_->DeleteTrackObject(object_);
} else {
g_v8_tracker.Pointer()->DeleteGlobalTrackObject(object_);
}
v8::V8::AdjustAmountOfExternalAllocatedMemory(
-static_cast<int>(sizeof(CefV8MakeWeakParam)));
}
private:
scoped_refptr<CefV8ContextState> context_state_;
CefTrackNode* object_;
};
// Callback for weak persistent reference destruction. // Callback for weak persistent reference destruction.
void TrackDestructor(v8::Persistent<v8::Value> object, void* parameter) { void TrackDestructor(v8::Persistent<v8::Value> object, void* parameter) {
if (parameter) if (parameter)
TrackDelete(static_cast<CefTrackNode*>(parameter)); delete static_cast<CefV8MakeWeakParam*>(parameter);
object.Dispose(); object.Dispose();
object.Clear(); object.Clear();
@ -346,7 +398,7 @@ v8::Handle<v8::Value> FunctionCallbackImpl(const v8::Arguments& args) {
} else { } else {
CefV8ValueImpl* rv = static_cast<CefV8ValueImpl*>(retval.get()); CefV8ValueImpl* rv = static_cast<CefV8ValueImpl*>(retval.get());
if (rv) if (rv)
return rv->GetHandle(); return rv->GetHandle(true);
} }
} }
@ -380,7 +432,7 @@ v8::Handle<v8::Value> AccessorGetterCallbackImpl(v8::Local<v8::String> property,
} else { } else {
CefV8ValueImpl* rv = static_cast<CefV8ValueImpl*>(retval.get()); CefV8ValueImpl* rv = static_cast<CefV8ValueImpl*>(retval.get());
if (rv) if (rv)
return rv->GetHandle(); return rv->GetHandle(true);
} }
} }
} }
@ -428,7 +480,7 @@ class ExtensionWrapper : public v8::Extension {
// The reference will be released when the process exits. // The reference will be released when the process exits.
V8TrackObject* object = new V8TrackObject; V8TrackObject* object = new V8TrackObject;
object->SetHandler(handler); object->SetHandler(handler);
TrackAdd(object); g_v8_tracker.Pointer()->AddGlobalTrackObject(object);
} }
} }
@ -507,9 +559,9 @@ bool CefRegisterExtension(const CefString& extension_name,
CEF_REQUIRE_RT_RETURN(false); CEF_REQUIRE_RT_RETURN(false);
V8TrackString* name = new V8TrackString(extension_name); V8TrackString* name = new V8TrackString(extension_name);
TrackAdd(name); g_v8_tracker.Pointer()->AddGlobalTrackObject(name);
V8TrackString* code = new V8TrackString(javascript_code); V8TrackString* code = new V8TrackString(javascript_code);
TrackAdd(code); g_v8_tracker.Pointer()->AddGlobalTrackObject(code);
ExtensionWrapper* wrapper = new ExtensionWrapper(name->GetString(), ExtensionWrapper* wrapper = new ExtensionWrapper(name->GetString(),
code->GetString(), handler.get()); code->GetString(), handler.get());
@ -567,21 +619,21 @@ bool CefV8Context::InContext() {
#define CEF_V8_REQUIRE_OBJECT_RETURN(ret) \ #define CEF_V8_REQUIRE_OBJECT_RETURN(ret) \
CEF_V8_REQUIRE_VALID_RETURN(ret); \ CEF_V8_REQUIRE_VALID_RETURN(ret); \
if (!GetHandle()->IsObject()) { \ if (!GetHandle(false)->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); \ CEF_V8_REQUIRE_VALID_RETURN(ret); \
if (!GetHandle()->IsArray()) { \ if (!GetHandle(false)->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); \ CEF_V8_REQUIRE_VALID_RETURN(ret); \
if (!GetHandle()->IsFunction()) { \ if (!GetHandle(false)->IsFunction()) { \
NOTREACHED() << "V8 value is not a function"; \ NOTREACHED() << "V8 value is not a function"; \
return ret; \ return ret; \
} }
@ -743,12 +795,21 @@ WebKit::WebFrame* CefV8ContextImpl::GetWebFrame() {
// CefV8ValueImpl::Handle // CefV8ValueImpl::Handle
CefV8ValueImpl::Handle::~Handle() { CefV8ValueImpl::Handle::~Handle() {
if (tracker_) { // Persist the |tracker_| object (call MakeWeak) if:
TrackAdd(tracker_); // A. The value represents an Object or Function, and
handle_.MakeWeak(tracker_, TrackDestructor); // B. The handle has been passed into a V8 function or used as a return value
// from a V8 callback, and
// C. The associated context, if any, is still valid.
if (tracker_ && tracker_should_persist_ &&
(!context_state_.get() || context_state_->IsValid())) {
handle_.MakeWeak(new CefV8MakeWeakParam(context_state_, tracker_),
TrackDestructor);
} else { } else {
handle_.Dispose(); handle_.Dispose();
handle_.Clear(); handle_.Clear();
if (tracker_)
delete tracker_;
} }
tracker_ = NULL; tracker_ = NULL;
} }
@ -935,68 +996,68 @@ bool CefV8ValueImpl::IsValid() {
bool CefV8ValueImpl::IsUndefined() { bool CefV8ValueImpl::IsUndefined() {
CEF_REQUIRE_RT_RETURN(false); CEF_REQUIRE_RT_RETURN(false);
CEF_V8_REQUIRE_VALID_RETURN(false); CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsUndefined(); return GetHandle(false)->IsUndefined();
} }
bool CefV8ValueImpl::IsNull() { bool CefV8ValueImpl::IsNull() {
CEF_REQUIRE_RT_RETURN(false); CEF_REQUIRE_RT_RETURN(false);
CEF_V8_REQUIRE_VALID_RETURN(false); CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsNull(); return GetHandle(false)->IsNull();
} }
bool CefV8ValueImpl::IsBool() { bool CefV8ValueImpl::IsBool() {
CEF_REQUIRE_RT_RETURN(false); CEF_REQUIRE_RT_RETURN(false);
CEF_V8_REQUIRE_VALID_RETURN(false); CEF_V8_REQUIRE_VALID_RETURN(false);
return (GetHandle()->IsBoolean() || GetHandle()->IsTrue() return (GetHandle(false)->IsBoolean() || GetHandle(false)->IsTrue() ||
|| GetHandle()->IsFalse()); GetHandle(false)->IsFalse());
} }
bool CefV8ValueImpl::IsInt() { bool CefV8ValueImpl::IsInt() {
CEF_REQUIRE_RT_RETURN(false); CEF_REQUIRE_RT_RETURN(false);
CEF_V8_REQUIRE_VALID_RETURN(false); CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsInt32(); return GetHandle(false)->IsInt32();
} }
bool CefV8ValueImpl::IsUInt() { bool CefV8ValueImpl::IsUInt() {
CEF_REQUIRE_RT_RETURN(false); CEF_REQUIRE_RT_RETURN(false);
CEF_V8_REQUIRE_VALID_RETURN(false); CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsUint32(); return GetHandle(false)->IsUint32();
} }
bool CefV8ValueImpl::IsDouble() { bool CefV8ValueImpl::IsDouble() {
CEF_REQUIRE_RT_RETURN(false); CEF_REQUIRE_RT_RETURN(false);
CEF_V8_REQUIRE_VALID_RETURN(false); CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsNumber(); return GetHandle(false)->IsNumber();
} }
bool CefV8ValueImpl::IsDate() { bool CefV8ValueImpl::IsDate() {
CEF_REQUIRE_RT_RETURN(false); CEF_REQUIRE_RT_RETURN(false);
CEF_V8_REQUIRE_VALID_RETURN(false); CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsDate(); return GetHandle(false)->IsDate();
} }
bool CefV8ValueImpl::IsString() { bool CefV8ValueImpl::IsString() {
CEF_REQUIRE_RT_RETURN(false); CEF_REQUIRE_RT_RETURN(false);
CEF_V8_REQUIRE_VALID_RETURN(false); CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsString(); return GetHandle(false)->IsString();
} }
bool CefV8ValueImpl::IsObject() { bool CefV8ValueImpl::IsObject() {
CEF_REQUIRE_RT_RETURN(false); CEF_REQUIRE_RT_RETURN(false);
CEF_V8_REQUIRE_VALID_RETURN(false); CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsObject(); return GetHandle(false)->IsObject();
} }
bool CefV8ValueImpl::IsArray() { bool CefV8ValueImpl::IsArray() {
CEF_REQUIRE_RT_RETURN(false); CEF_REQUIRE_RT_RETURN(false);
CEF_V8_REQUIRE_VALID_RETURN(false); CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsArray(); return GetHandle(false)->IsArray();
} }
bool CefV8ValueImpl::IsFunction() { bool CefV8ValueImpl::IsFunction() {
CEF_REQUIRE_RT_RETURN(false); CEF_REQUIRE_RT_RETURN(false);
CEF_V8_REQUIRE_VALID_RETURN(false); CEF_V8_REQUIRE_VALID_RETURN(false);
return GetHandle()->IsFunction(); return GetHandle(false)->IsFunction();
} }
bool CefV8ValueImpl::IsSame(CefRefPtr<CefV8Value> that) { bool CefV8ValueImpl::IsSame(CefRefPtr<CefV8Value> that) {
@ -1006,11 +1067,11 @@ bool CefV8ValueImpl::IsSame(CefRefPtr<CefV8Value> that) {
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Handle<v8::Value> thatHandle; v8::Handle<v8::Value> thatHandle;
v8::Handle<v8::Value> thisHandle = GetHandle(); v8::Handle<v8::Value> thisHandle = GetHandle(false);
CefV8ValueImpl* impl = static_cast<CefV8ValueImpl*>(that.get()); CefV8ValueImpl* impl = static_cast<CefV8ValueImpl*>(that.get());
if (impl) if (impl)
thatHandle = impl->GetHandle(); thatHandle = impl->GetHandle(false);
return (thisHandle == thatHandle); return (thisHandle == thatHandle);
} }
@ -1018,13 +1079,13 @@ bool CefV8ValueImpl::IsSame(CefRefPtr<CefV8Value> that) {
bool CefV8ValueImpl::GetBoolValue() { bool CefV8ValueImpl::GetBoolValue() {
CEF_REQUIRE_RT_RETURN(false); CEF_REQUIRE_RT_RETURN(false);
CEF_V8_REQUIRE_VALID_RETURN(false); CEF_V8_REQUIRE_VALID_RETURN(false);
if (GetHandle()->IsTrue()) { if (GetHandle(false)->IsTrue()) {
return true; return true;
} else if (GetHandle()->IsFalse()) { } else if (GetHandle(false)->IsFalse()) {
return false; return false;
} else { } else {
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Boolean> val = GetHandle()->ToBoolean(); v8::Local<v8::Boolean> val = GetHandle(false)->ToBoolean();
return val->Value(); return val->Value();
} }
} }
@ -1033,7 +1094,7 @@ int32 CefV8ValueImpl::GetIntValue() {
CEF_REQUIRE_RT_RETURN(0); CEF_REQUIRE_RT_RETURN(0);
CEF_V8_REQUIRE_VALID_RETURN(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(false)->ToInt32();
return val->Value(); return val->Value();
} }
@ -1041,7 +1102,7 @@ uint32 CefV8ValueImpl::GetUIntValue() {
CEF_REQUIRE_RT_RETURN(0); CEF_REQUIRE_RT_RETURN(0);
CEF_V8_REQUIRE_VALID_RETURN(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(false)->ToUint32();
return val->Value(); return val->Value();
} }
@ -1049,7 +1110,7 @@ double CefV8ValueImpl::GetDoubleValue() {
CEF_REQUIRE_RT_RETURN(0.); CEF_REQUIRE_RT_RETURN(0.);
CEF_V8_REQUIRE_VALID_RETURN(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(false)->ToNumber();
return val->Value(); return val->Value();
} }
@ -1057,7 +1118,7 @@ CefTime CefV8ValueImpl::GetDateValue() {
CEF_REQUIRE_RT_RETURN(CefTime(0.)); CEF_REQUIRE_RT_RETURN(CefTime(0.));
CEF_V8_REQUIRE_VALID_RETURN(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(false)->ToNumber();
// Convert from milliseconds to seconds. // Convert from milliseconds to seconds.
return CefTime(val->Value() / 1000); return CefTime(val->Value() / 1000);
} }
@ -1067,7 +1128,7 @@ CefString CefV8ValueImpl::GetStringValue() {
CEF_REQUIRE_RT_RETURN(rv); CEF_REQUIRE_RT_RETURN(rv);
CEF_V8_REQUIRE_VALID_RETURN(rv); CEF_V8_REQUIRE_VALID_RETURN(rv);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
GetCefString(GetHandle()->ToString(), rv); GetCefString(GetHandle(false)->ToString(), rv);
return rv; return rv;
} }
@ -1076,7 +1137,7 @@ bool CefV8ValueImpl::IsUserCreated() {
CEF_V8_REQUIRE_OBJECT_RETURN(false); CEF_V8_REQUIRE_OBJECT_RETURN(false);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
V8TrackObject* tracker = V8TrackObject::Unwrap(obj); V8TrackObject* tracker = V8TrackObject::Unwrap(obj);
return (tracker != NULL); return (tracker != NULL);
@ -1124,7 +1185,7 @@ bool CefV8ValueImpl::HasValue(const CefString& key) {
CEF_V8_REQUIRE_OBJECT_RETURN(false); CEF_V8_REQUIRE_OBJECT_RETURN(false);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
return obj->Has(GetV8String(key)); return obj->Has(GetV8String(key));
} }
@ -1138,7 +1199,7 @@ bool CefV8ValueImpl::HasValue(int index) {
} }
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
return obj->Has(index); return obj->Has(index);
} }
@ -1147,7 +1208,7 @@ bool CefV8ValueImpl::DeleteValue(const CefString& key) {
CEF_V8_REQUIRE_OBJECT_RETURN(false); CEF_V8_REQUIRE_OBJECT_RETURN(false);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
v8::TryCatch try_catch; v8::TryCatch try_catch;
try_catch.SetVerbose(true); try_catch.SetVerbose(true);
@ -1165,7 +1226,7 @@ bool CefV8ValueImpl::DeleteValue(int index) {
} }
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
v8::TryCatch try_catch; v8::TryCatch try_catch;
try_catch.SetVerbose(true); try_catch.SetVerbose(true);
@ -1178,7 +1239,7 @@ CefRefPtr<CefV8Value> CefV8ValueImpl::GetValue(const CefString& key) {
CEF_V8_REQUIRE_OBJECT_RETURN(NULL); CEF_V8_REQUIRE_OBJECT_RETURN(NULL);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
v8::TryCatch try_catch; v8::TryCatch try_catch;
try_catch.SetVerbose(true); try_catch.SetVerbose(true);
@ -1198,7 +1259,7 @@ CefRefPtr<CefV8Value> CefV8ValueImpl::GetValue(int index) {
} }
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
v8::TryCatch try_catch; v8::TryCatch try_catch;
try_catch.SetVerbose(true); try_catch.SetVerbose(true);
@ -1217,11 +1278,11 @@ bool CefV8ValueImpl::SetValue(const CefString& key,
CefV8ValueImpl* impl = static_cast<CefV8ValueImpl*>(value.get()); CefV8ValueImpl* impl = static_cast<CefV8ValueImpl*>(value.get());
if (impl) { if (impl) {
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
v8::TryCatch try_catch; v8::TryCatch try_catch;
try_catch.SetVerbose(true); try_catch.SetVerbose(true);
bool set = obj->Set(GetV8String(key), impl->GetHandle(), bool set = obj->Set(GetV8String(key), impl->GetHandle(true),
static_cast<v8::PropertyAttribute>(attribute)); static_cast<v8::PropertyAttribute>(attribute));
return (!HasCaught(try_catch) && set); return (!HasCaught(try_catch) && set);
} else { } else {
@ -1242,11 +1303,11 @@ bool CefV8ValueImpl::SetValue(int index, CefRefPtr<CefV8Value> value) {
CefV8ValueImpl* impl = static_cast<CefV8ValueImpl*>(value.get()); CefV8ValueImpl* impl = static_cast<CefV8ValueImpl*>(value.get());
if (impl) { if (impl) {
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
v8::TryCatch try_catch; v8::TryCatch try_catch;
try_catch.SetVerbose(true); try_catch.SetVerbose(true);
bool set = obj->Set(index, impl->GetHandle()); bool set = obj->Set(index, impl->GetHandle(true));
return (!HasCaught(try_catch) && set); return (!HasCaught(try_catch) && set);
} else { } else {
NOTREACHED() << "invalid input parameter"; NOTREACHED() << "invalid input parameter";
@ -1260,7 +1321,7 @@ bool CefV8ValueImpl::SetValue(const CefString& key, AccessControl settings,
CEF_V8_REQUIRE_OBJECT_RETURN(false); CEF_V8_REQUIRE_OBJECT_RETURN(false);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
CefRefPtr<CefV8Accessor> accessorPtr; CefRefPtr<CefV8Accessor> accessorPtr;
@ -1289,7 +1350,7 @@ bool CefV8ValueImpl::GetKeys(std::vector<CefString>& keys) {
CEF_V8_REQUIRE_OBJECT_RETURN(false); CEF_V8_REQUIRE_OBJECT_RETURN(false);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
v8::Local<v8::Array> arr_keys = obj->GetPropertyNames(); v8::Local<v8::Array> arr_keys = obj->GetPropertyNames();
uint32_t len = arr_keys->Length(); uint32_t len = arr_keys->Length();
for (uint32_t i = 0; i < len; ++i) { for (uint32_t i = 0; i < len; ++i) {
@ -1306,7 +1367,7 @@ bool CefV8ValueImpl::SetUserData(CefRefPtr<CefBase> user_data) {
CEF_V8_REQUIRE_OBJECT_RETURN(false); CEF_V8_REQUIRE_OBJECT_RETURN(false);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
V8TrackObject* tracker = V8TrackObject::Unwrap(obj); V8TrackObject* tracker = V8TrackObject::Unwrap(obj);
if (tracker) { if (tracker) {
@ -1322,7 +1383,7 @@ CefRefPtr<CefBase> CefV8ValueImpl::GetUserData() {
CEF_V8_REQUIRE_OBJECT_RETURN(NULL); CEF_V8_REQUIRE_OBJECT_RETURN(NULL);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
V8TrackObject* tracker = V8TrackObject::Unwrap(obj); V8TrackObject* tracker = V8TrackObject::Unwrap(obj);
if (tracker) if (tracker)
@ -1336,7 +1397,7 @@ int CefV8ValueImpl::GetExternallyAllocatedMemory() {
CEF_V8_REQUIRE_OBJECT_RETURN(0); CEF_V8_REQUIRE_OBJECT_RETURN(0);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
V8TrackObject* tracker = V8TrackObject::Unwrap(obj); V8TrackObject* tracker = V8TrackObject::Unwrap(obj);
if (tracker) if (tracker)
@ -1350,7 +1411,7 @@ int CefV8ValueImpl::AdjustExternallyAllocatedMemory(int change_in_bytes) {
CEF_V8_REQUIRE_OBJECT_RETURN(0); CEF_V8_REQUIRE_OBJECT_RETURN(0);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
V8TrackObject* tracker = V8TrackObject::Unwrap(obj); V8TrackObject* tracker = V8TrackObject::Unwrap(obj);
if (tracker) if (tracker)
@ -1364,7 +1425,7 @@ int CefV8ValueImpl::GetArrayLength() {
CEF_V8_REQUIRE_ARRAY_RETURN(0); CEF_V8_REQUIRE_ARRAY_RETURN(0);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(obj); v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(obj);
return arr->Length(); return arr->Length();
} }
@ -1375,7 +1436,7 @@ CefString CefV8ValueImpl::GetFunctionName() {
CEF_V8_REQUIRE_FUNCTION_RETURN(rv); CEF_V8_REQUIRE_FUNCTION_RETURN(rv);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(obj); v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(obj);
GetCefString(v8::Handle<v8::String>::Cast(func->GetName()), rv); GetCefString(v8::Handle<v8::String>::Cast(func->GetName()), rv);
return rv; return rv;
@ -1386,7 +1447,7 @@ CefRefPtr<CefV8Handler> CefV8ValueImpl::GetFunctionHandler() {
CEF_V8_REQUIRE_FUNCTION_RETURN(NULL); CEF_V8_REQUIRE_FUNCTION_RETURN(NULL);
v8::HandleScope handle_scope; v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
V8TrackObject* tracker = V8TrackObject::Unwrap(obj); V8TrackObject* tracker = V8TrackObject::Unwrap(obj);
if (tracker) if (tracker)
@ -1423,14 +1484,14 @@ CefRefPtr<CefV8Value> CefV8ValueImpl::ExecuteFunctionWithContext(
v8::Context::Scope context_scope(context_local); v8::Context::Scope context_scope(context_local);
v8::Local<v8::Object> obj = GetHandle()->ToObject(); v8::Local<v8::Object> obj = GetHandle(false)->ToObject();
v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(obj); v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(obj);
v8::Handle<v8::Object> recv; v8::Handle<v8::Object> recv;
// Default to the global object if no object or a non-object was provided. // Default to the global object if no object or a non-object was provided.
if (object.get() && object->IsObject()) { if (object.get() && object->IsObject()) {
CefV8ValueImpl* recv_impl = static_cast<CefV8ValueImpl*>(object.get()); CefV8ValueImpl* recv_impl = static_cast<CefV8ValueImpl*>(object.get());
recv = v8::Handle<v8::Object>::Cast(recv_impl->GetHandle()); recv = v8::Handle<v8::Object>::Cast(recv_impl->GetHandle(true));
} else { } else {
recv = context_local->Global(); recv = context_local->Global();
} }
@ -1439,8 +1500,10 @@ CefRefPtr<CefV8Value> CefV8ValueImpl::ExecuteFunctionWithContext(
v8::Handle<v8::Value> *argv = NULL; v8::Handle<v8::Value> *argv = NULL;
if (argc > 0) { if (argc > 0) {
argv = new v8::Handle<v8::Value>[argc]; argv = new v8::Handle<v8::Value>[argc];
for (int i = 0; i < argc; ++i) for (int i = 0; i < argc; ++i) {
argv[i] = static_cast<CefV8ValueImpl*>(arguments[i].get())->GetHandle(); argv[i] =
static_cast<CefV8ValueImpl*>(arguments[i].get())->GetHandle(true);
}
} }
CefRefPtr<CefV8Value> retval; CefRefPtr<CefV8Value> retval;

View File

@ -9,6 +9,7 @@
#include <vector> #include <vector>
#include "include/cef_v8.h" #include "include/cef_v8.h"
#include "libcef/common/tracker.h"
#include "libcef/renderer/thread_util.h" #include "libcef/renderer/thread_util.h"
#include "v8/include/v8.h" #include "v8/include/v8.h"
@ -30,10 +31,25 @@ class CefV8ContextState : public base::RefCounted<CefV8ContextState> {
virtual ~CefV8ContextState() {} virtual ~CefV8ContextState() {}
bool IsValid() { return valid_; } bool IsValid() { return valid_; }
void Detach() { valid_ = false; } void Detach() {
DCHECK(valid_);
valid_ = false;
track_manager_.DeleteAll();
}
void AddTrackObject(CefTrackNode* object) {
DCHECK(valid_);
track_manager_.Add(object);
}
void DeleteTrackObject(CefTrackNode* object) {
DCHECK(valid_);
track_manager_.Delete(object);
}
private: private:
bool valid_; bool valid_;
CefTrackManager track_manager_;
}; };
// Base class for V8 Handle types. // Base class for V8 Handle types.
@ -54,7 +70,7 @@ class CefV8HandleBase :
// context will be used. // context will be used.
explicit CefV8HandleBase(v8::Handle<v8::Context> context); explicit CefV8HandleBase(v8::Handle<v8::Context> context);
private: protected:
scoped_refptr<CefV8ContextState> context_state_; scoped_refptr<CefV8ContextState> context_state_;
}; };
@ -184,7 +200,9 @@ class CefV8ValueImpl : public CefV8Value {
CefRefPtr<CefV8Value> object, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments) OVERRIDE; const CefV8ValueList& arguments) OVERRIDE;
v8::Handle<v8::Value> GetHandle() { return handle_->GetHandle(); } v8::Handle<v8::Value> GetHandle(bool should_persist) {
return handle_->GetHandle(should_persist);
}
protected: protected:
// Test for and record any exception. // Test for and record any exception.
@ -198,12 +216,15 @@ class CefV8ValueImpl : public CefV8Value {
Handle(v8::Handle<v8::Context> context, handleType v, CefTrackNode* tracker) Handle(v8::Handle<v8::Context> context, handleType v, CefTrackNode* tracker)
: CefV8HandleBase(context), : CefV8HandleBase(context),
handle_(persistentType::New(v)), handle_(persistentType::New(v)),
tracker_(tracker) { tracker_(tracker),
tracker_should_persist_(false) {
} }
virtual ~Handle(); virtual ~Handle();
handleType GetHandle() { handleType GetHandle(bool should_persist) {
DCHECK(IsValid()); DCHECK(IsValid());
if (should_persist && tracker_ && !tracker_should_persist_)
tracker_should_persist_ = true;
return handle_; return handle_;
} }
@ -214,6 +235,10 @@ class CefV8ValueImpl : public CefV8Value {
// internal data or function handler objects that are reference counted. // internal data or function handler objects that are reference counted.
CefTrackNode* tracker_; CefTrackNode* tracker_;
// True if the |tracker_| object needs to persist due to an Object or
// Function type being passed into V8.
bool tracker_should_persist_;
DISALLOW_COPY_AND_ASSIGN(Handle); DISALLOW_COPY_AND_ASSIGN(Handle);
}; };
scoped_refptr<Handle> handle_; scoped_refptr<Handle> handle_;