Add methods to CefV8Value for specifying the amount of externally allocated memory associated with the V8 object (issue #478).

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@469 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2012-01-19 18:52:59 +00:00
parent ea3dcc8492
commit 0352efec64
14 changed files with 2039 additions and 1742 deletions

View File

@ -329,6 +329,7 @@
'tests/unittests/test_suite.h',
'tests/unittests/url_unittest.cc',
'tests/unittests/v8_unittest.cc',
'tests/unittests/v8_unittest_legacy.cc',
'tests/unittests/web_urlrequest_unittest.cc',
'tests/unittests/xml_reader_unittest.cc',
'tests/unittests/zip_reader_unittest.cc',

View File

@ -466,6 +466,27 @@ typedef struct _cef_v8value_t {
struct _cef_base_t* (CEF_CALLBACK *get_user_data)(
struct _cef_v8value_t* self);
///
// Returns the amount of externally allocated memory registered for the
// object.
///
int (CEF_CALLBACK *get_externally_allocated_memory)(
struct _cef_v8value_t* self);
///
// Adjusts the amount of registered external memory for the object. Used to
// give V8 an indication of the amount of externally allocated memory that is
// kept alive by JavaScript objects. V8 uses this information to decide when
// to perform global garbage collection. Each cef_v8value_t tracks the amount
// of external memory associated with it and automatically decreases the
// global total by the appropriate amount on its destruction.
// |change_in_bytes| specifies the number of bytes to adjust by. This function
// returns the number of bytes associated with the object after the
// adjustment.
///
int (CEF_CALLBACK *adjust_externally_allocated_memory)(
struct _cef_v8value_t* self, int change_in_bytes);
// ARRAY METHODS - These functions are only available on arrays.

View File

@ -535,6 +535,26 @@ class CefV8Value : public virtual CefBase {
/*--cef()--*/
virtual CefRefPtr<CefBase> GetUserData() =0;
///
// Returns the amount of externally allocated memory registered for the
// object.
///
/*--cef()--*/
virtual int GetExternallyAllocatedMemory() =0;
///
// Adjusts the amount of registered external memory for the object. Used to
// give V8 an indication of the amount of externally allocated memory that is
// kept alive by JavaScript objects. V8 uses this information to decide when
// to perform global garbage collection. Each CefV8Value tracks the amount of
// external memory associated with it and automatically decreases the global
// total by the appropriate amount on its destruction. |change_in_bytes|
// specifies the number of bytes to adjust by. This method returns the number
// of bytes associated with the object after the adjustment.
///
/*--cef()--*/
virtual int AdjustExternallyAllocatedMemory(int change_in_bytes) =0;
// ARRAY METHODS - These methods are only available on arrays.

View File

@ -1,4 +1,4 @@
// Copyright (c) 2008-2009 The Chromium Embedded Framework Authors.
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@ -1458,7 +1458,7 @@ void CefBrowserImpl::UIT_VisitDOM(CefRefPtr<CefFrame> frame,
}
void CefBrowserImpl::UIT_AddFrameObject(WebKit::WebFrame* frame,
CefTrackObject* tracked_object) {
CefTrackNode* tracked_object) {
REQUIRE_UIT();
CefRefPtr<CefTrackManager> manager;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2008-2009 The Chromium Embedded Framework Authors.
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@ -317,7 +317,7 @@ class CefBrowserImpl : public CefBrowser {
// Frame objects will be deleted immediately before the frame is closed.
void UIT_AddFrameObject(WebKit::WebFrame* frame,
CefTrackObject* tracked_object);
CefTrackNode* tracked_object);
void UIT_BeforeFrameClosed(WebKit::WebFrame* frame);
// These variables are read-only.

View File

@ -1,4 +1,4 @@
// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
@ -42,7 +42,7 @@ namespace {
// Wrapper implementation for WebDOMEventListener.
class CefDOMEventListenerWrapper : public WebDOMEventListener,
public CefTrackObject {
public CefTrackNode {
public:
CefDOMEventListenerWrapper(CefBrowserImpl* browser, WebFrame* frame,
CefRefPtr<CefDOMEventListener> listener)

View File

@ -1,4 +1,4 @@
// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
@ -10,26 +10,26 @@
// Class extended by objects that must be tracked. After creating a tracked
// object you should add it to the appropriate track manager.
class CefTrackObject {
class CefTrackNode {
public:
CefTrackObject() {
CefTrackNode() {
track_next_ = NULL;
track_prev_ = NULL;
}
virtual ~CefTrackObject() {
virtual ~CefTrackNode() {
}
// Returns true if the object is currently being tracked.
bool IsTracked() { return (track_prev_ || track_next_); }
private:
CefTrackObject* GetTrackPrev() { return track_prev_; }
void SetTrackPrev(CefTrackObject* base) { track_prev_ = base; }
CefTrackObject* GetTrackNext() { return track_next_; }
void SetTrackNext(CefTrackObject* base) { track_next_ = base; }
CefTrackNode* GetTrackPrev() { return track_prev_; }
void SetTrackPrev(CefTrackNode* base) { track_prev_ = base; }
CefTrackNode* GetTrackNext() { return track_next_; }
void SetTrackNext(CefTrackNode* base) { track_next_ = base; }
// Insert a new object into the tracking list before this object.
void InsertTrackPrev(CefTrackObject* object) {
void InsertTrackPrev(CefTrackNode* object) {
if (track_prev_)
track_prev_->SetTrackNext(object);
object->SetTrackNext(this);
@ -38,7 +38,7 @@ class CefTrackObject {
}
// Insert a new object into the tracking list after this object.
void InsertTrackNext(CefTrackObject* object) {
void InsertTrackNext(CefTrackNode* object) {
if (track_next_)
track_next_->SetTrackPrev(object);
object->SetTrackPrev(this);
@ -57,8 +57,8 @@ class CefTrackObject {
}
private:
CefTrackObject* track_next_;
CefTrackObject* track_prev_;
CefTrackNode* track_next_;
CefTrackNode* track_prev_;
friend class CefTrackManager;
};
@ -77,7 +77,7 @@ class CefTrackManager : public CefBase {
}
// Add an object to be tracked by this manager.
void Add(CefTrackObject* object) {
void Add(CefTrackNode* object) {
Lock();
if (!object->IsTracked()) {
tracker_.InsertTrackNext(object);
@ -87,7 +87,7 @@ class CefTrackManager : public CefBase {
}
// Delete an object tracked by this manager.
bool Delete(CefTrackObject* object) {
bool Delete(CefTrackNode* object) {
bool rv = false;
Lock();
if (object->IsTracked()) {
@ -103,7 +103,7 @@ class CefTrackManager : public CefBase {
// Delete all objects tracked by this manager.
void DeleteAll() {
Lock();
CefTrackObject* next;
CefTrackNode* next;
do {
next = tracker_.GetTrackNext();
if (next) {
@ -119,7 +119,7 @@ class CefTrackManager : public CefBase {
int GetCount() { return object_count_; }
private:
CefTrackObject tracker_;
CefTrackNode tracker_;
int object_count_;
IMPLEMENT_REFCOUNTING(CefTrackManager);

View File

@ -1,8 +1,11 @@
// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include "libcef/v8_impl.h"
#include <string>
#include "libcef/browser_impl.h"
#include "libcef/cef_context.h"
#include "libcef/tracker.h"
@ -23,56 +26,64 @@
return var; \
}
namespace {
static const char kCefAccessor[] = "Cef::Accessor";
static const char kCefHandler[] = "Cef::Handler";
static const char kCefUserData[] = "Cef::UserData";
static const char kCefExternalMemory[] = "Cef::ExternalMemory";
// Memory manager.
base::LazyInstance<CefTrackManager> g_v8_tracker = LAZY_INSTANCE_INITIALIZER;
class TrackBase : public CefTrackObject {
class V8TrackObject : public CefTrackNode {
public:
explicit TrackBase(CefBase* base) { base_ = base; }
protected:
CefRefPtr<CefBase> base_;
};
class TrackBase2 : public TrackBase {
public:
TrackBase2(CefBase* base, CefBase* base2): TrackBase(base) {
base2_ = base2;
V8TrackObject(CefBase* object = NULL, CefBase* user_data = NULL)
: object_(object),
user_data_(user_data),
external_memory_counter_(0) {
}
protected:
CefRefPtr<CefBase> base2_;
int* GetMemoryCounter() {
return &external_memory_counter_;
}
private:
int external_memory_counter_;
CefRefPtr<CefBase> object_;
CefRefPtr<CefBase> user_data_;
};
class TrackString : public CefTrackObject {
class V8TrackString : public CefTrackNode {
public:
explicit TrackString(const std::string& str) : string_(str) {}
explicit V8TrackString(const std::string& str) : string_(str) {}
const char* GetString() { return string_.c_str(); }
private:
std::string string_;
};
void TrackAdd(CefTrackObject* object) {
void TrackAdd(CefTrackNode* object) {
g_v8_tracker.Pointer()->Add(object);
}
void TrackDelete(CefTrackObject* object) {
void TrackDelete(CefTrackNode* object) {
g_v8_tracker.Pointer()->Delete(object);
}
// Callback for weak persistent reference destruction.
void TrackDestructor(v8::Persistent<v8::Value> object, void* parameter) {
if (parameter)
TrackDelete(static_cast<CefTrackObject*>(parameter));
if (parameter) {
if (object->IsObject()) {
V8TrackObject* tracker = static_cast<V8TrackObject*>(parameter);
DCHECK(tracker);
int adjustment = -(*tracker->GetMemoryCounter());
if (adjustment != 0)
v8::V8::AdjustAmountOfExternalAllocatedMemory(adjustment);
}
TrackDelete(static_cast<CefTrackNode*>(parameter));
}
object.Dispose();
object.Clear();
}
@ -246,7 +257,7 @@ class ExtensionWrapper : public v8::Extension {
: v8::Extension(extension_name, javascript_code), handler_(handler) {
if (handler) {
// The reference will be released when the application exits.
TrackAdd(new TrackBase(handler));
TrackAdd(new V8TrackObject(handler));
}
}
@ -326,9 +337,9 @@ bool CefRegisterExtension(const CefString& extension_name,
// Verify that the context is in a valid state.
CEF_REQUIRE_VALID_CONTEXT(false);
TrackString* name = new TrackString(extension_name);
V8TrackString* name = new V8TrackString(extension_name);
TrackAdd(name);
TrackString* code = new TrackString(javascript_code);
V8TrackString* code = new V8TrackString(javascript_code);
TrackAdd(code);
ExtensionWrapper* wrapper = new ExtensionWrapper(name->GetString(),
@ -562,14 +573,20 @@ CefRefPtr<CefV8Value> CefV8Value::CreateObject(
// Provide a tracker object that will cause the user data and/or accessor
// reference to be released when the V8 object is destroyed.
TrackBase* tracker = NULL;
V8TrackObject* tracker = NULL;
if (user_data.get() && accessor.get()) {
tracker = new TrackBase2(user_data, accessor);
tracker = new V8TrackObject(accessor, user_data);
} else if (user_data.get() || accessor.get()) {
tracker = new TrackBase(user_data.get() ?
user_data : CefRefPtr<CefBase>(accessor.get()));
CefBase* object = user_data.get() ? user_data.get() : accessor.get();
tracker = new V8TrackObject(object);
} else {
tracker = new V8TrackObject();
}
// Attach the memory counter.
obj->SetHiddenValue(v8::String::New(kCefExternalMemory),
v8::External::Wrap(tracker->GetMemoryCounter()));
// Attach the user data to the V8 object.
if (user_data.get()) {
v8::Local<v8::Value> data = v8::External::Wrap(user_data.get());
@ -637,19 +654,25 @@ CefRefPtr<CefV8Value> CefV8Value::CreateFunction(
func->SetName(GetV8String(name));
V8TrackObject* tracker = new V8TrackObject(handler.get());
// Attach the memory counter.
func->SetHiddenValue(v8::String::New(kCefExternalMemory),
v8::External::Wrap(tracker->GetMemoryCounter()));
// Attach the handler instance to the V8 object.
func->SetHiddenValue(v8::String::New(kCefHandler), data);
// Create the CefV8ValueImpl and provide a tracker object that will cause
// the handler reference to be released when the V8 object is destroyed.
return new CefV8ValueImpl(func, new TrackBase(handler));
return new CefV8ValueImpl(func, tracker);
}
// CefV8ValueImpl
CefV8ValueImpl::CefV8ValueImpl(v8::Handle<v8::Value> value,
CefTrackObject* tracker) {
CefTrackNode* tracker) {
v8_value_ = new CefV8ValueHandle(value, tracker);
}
@ -976,6 +999,45 @@ CefRefPtr<CefBase> CefV8ValueImpl::GetUserData() {
return NULL;
}
int CefV8ValueImpl::GetExternallyAllocatedMemory() {
CEF_REQUIRE_UI_THREAD(0);
if (!GetHandle()->IsObject()) {
NOTREACHED() << "V8 value is not an object";
return 0;
}
int* counter = GetExternallyAllocatedMemoryCounter();
return counter != NULL ? *counter : 0;
}
int CefV8ValueImpl::AdjustExternallyAllocatedMemory(int change_in_bytes) {
CEF_REQUIRE_UI_THREAD(0);
if (!GetHandle()->IsObject()) {
NOTREACHED() << "V8 value is not an object";
return 0;
}
int* counter = GetExternallyAllocatedMemoryCounter();
if (counter == NULL)
return 0;
v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject();
int new_value = *counter + change_in_bytes;
if (new_value < 0) {
NOTREACHED() << "External memory usage cannot be less than 0 bytes";
change_in_bytes = -(*counter);
new_value = 0;
}
if (change_in_bytes != 0)
v8::V8::AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
*counter = new_value;
return new_value;
}
int CefV8ValueImpl::GetArrayLength() {
CEF_REQUIRE_UI_THREAD(0);
if (!GetHandle()->IsArray()) {
@ -1101,3 +1163,13 @@ CefV8Accessor* CefV8ValueImpl::GetAccessor(v8::Handle<v8::Object> object) {
return NULL;
}
int* CefV8ValueImpl::GetExternallyAllocatedMemoryCounter() {
v8::HandleScope handle_scope;
v8::Local<v8::Object> obj = GetHandle()->ToObject();
v8::Local<v8::Value> value =
obj->GetHiddenValue(v8::String::New(kCefExternalMemory));
return value.IsEmpty() ? NULL : static_cast<int*>(
v8::External::Unwrap(value));
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
@ -12,7 +12,7 @@
#include "libcef/cef_thread.h"
#include "base/memory/ref_counted.h"
class CefTrackObject;
class CefTrackNode;
namespace WebKit {
class WebFrame;
@ -87,22 +87,28 @@ class CefV8ContextImpl : public CefV8Context {
// thread.
class CefV8ValueHandle: public CefReleaseV8HandleOnUIThread<v8::Value> {
public:
CefV8ValueHandle(handleType value, CefTrackObject* tracker)
CefV8ValueHandle(handleType value, CefTrackNode* tracker)
: superType(value),
tracker_(tracker) {
}
// Destructor implementation is provided in v8_impl.cc.
~CefV8ValueHandle();
CefTrackNode* GetTracker() {
return tracker_;
}
private:
// For Object and Function types, we need to hold on to a reference to their
// internal data or function handler objects that are reference counted.
CefTrackObject* tracker_;
CefTrackNode* tracker_;
DISALLOW_COPY_AND_ASSIGN(CefV8ValueHandle);
};
class CefV8ValueImpl : public CefV8Value {
public:
CefV8ValueImpl(v8::Handle<v8::Value> value, CefTrackObject* tracker = NULL);
CefV8ValueImpl(v8::Handle<v8::Value> value, CefTrackNode* tracker = NULL);
virtual ~CefV8ValueImpl();
virtual bool IsUndefined() OVERRIDE;
@ -134,6 +140,8 @@ class CefV8ValueImpl : public CefV8Value {
PropertyAttribute attribute) OVERRIDE;
virtual bool GetKeys(std::vector<CefString>& keys) OVERRIDE;
virtual CefRefPtr<CefBase> GetUserData() OVERRIDE;
virtual int GetExternallyAllocatedMemory() OVERRIDE;
virtual int AdjustExternallyAllocatedMemory(int change_in_bytes) OVERRIDE;
virtual int GetArrayLength() OVERRIDE;
virtual CefString GetFunctionName() OVERRIDE;
virtual CefRefPtr<CefV8Handler> GetFunctionHandler() OVERRIDE;
@ -158,10 +166,14 @@ class CefV8ValueImpl : public CefV8Value {
// Returns the accessor assigned for the specified object, if any.
static CefV8Accessor* GetAccessor(v8::Handle<v8::Object> object);
private:
int* GetExternallyAllocatedMemoryCounter();
protected:
scoped_refptr<CefV8ValueHandle> v8_value_;
IMPLEMENT_REFCOUNTING(CefV8ValueImpl);
DISALLOW_COPY_AND_ASSIGN(CefV8ValueImpl);
};
#endif // CEF_LIBCEF_V8_IMPL_H_

View File

@ -624,6 +624,37 @@ cef_base_t* CEF_CALLBACK v8value_get_user_data(struct _cef_v8value_t* self) {
return CefBaseCToCpp::Unwrap(_retval);
}
int CEF_CALLBACK v8value_get_externally_allocated_memory(
struct _cef_v8value_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Execute
int _retval = CefV8ValueCppToC::Get(self)->GetExternallyAllocatedMemory();
// Return type: simple
return _retval;
}
int CEF_CALLBACK v8value_adjust_externally_allocated_memory(
struct _cef_v8value_t* self, int change_in_bytes) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Execute
int _retval = CefV8ValueCppToC::Get(self)->AdjustExternallyAllocatedMemory(
change_in_bytes);
// Return type: simple
return _retval;
}
int CEF_CALLBACK v8value_get_array_length(struct _cef_v8value_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
@ -855,6 +886,10 @@ CefV8ValueCppToC::CefV8ValueCppToC(CefV8Value* cls)
struct_.struct_.set_value_byaccessor = v8value_set_value_byaccessor;
struct_.struct_.get_keys = v8value_get_keys;
struct_.struct_.get_user_data = v8value_get_user_data;
struct_.struct_.get_externally_allocated_memory =
v8value_get_externally_allocated_memory;
struct_.struct_.adjust_externally_allocated_memory =
v8value_adjust_externally_allocated_memory;
struct_.struct_.get_array_length = v8value_get_array_length;
struct_.struct_.get_function_name = v8value_get_function_name;
struct_.struct_.get_function_handler = v8value_get_function_handler;

View File

@ -590,6 +590,33 @@ CefRefPtr<CefBase> CefV8ValueCToCpp::GetUserData() {
return CefBaseCppToC::Unwrap(_retval);
}
int CefV8ValueCToCpp::GetExternallyAllocatedMemory() {
if (CEF_MEMBER_MISSING(struct_, get_externally_allocated_memory))
return 0;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
int _retval = struct_->get_externally_allocated_memory(struct_);
// Return type: simple
return _retval;
}
int CefV8ValueCToCpp::AdjustExternallyAllocatedMemory(int change_in_bytes) {
if (CEF_MEMBER_MISSING(struct_, adjust_externally_allocated_memory))
return 0;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
int _retval = struct_->adjust_externally_allocated_memory(struct_,
change_in_bytes);
// Return type: simple
return _retval;
}
int CefV8ValueCToCpp::GetArrayLength() {
if (CEF_MEMBER_MISSING(struct_, get_array_length))
return 0;

View File

@ -66,6 +66,8 @@ class CefV8ValueCToCpp
PropertyAttribute attribute) OVERRIDE;
virtual bool GetKeys(std::vector<CefString>& keys) OVERRIDE;
virtual CefRefPtr<CefBase> GetUserData() OVERRIDE;
virtual int GetExternallyAllocatedMemory() OVERRIDE;
virtual int AdjustExternallyAllocatedMemory(int change_in_bytes) OVERRIDE;
virtual int GetArrayLength() OVERRIDE;
virtual CefString GetFunctionName() OVERRIDE;
virtual CefRefPtr<CefV8Handler> GetFunctionHandler() OVERRIDE;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff