Commit 66c8b527 authored by dcarney@chromium.org's avatar dcarney@chromium.org

new persistent semantics

adds copying and autodispose as traits

R=marja@chromium.org, mstarzinger@chromium.org, svenpanne@chromium.org

BUG=

Review URL: https://codereview.chromium.org/23401003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16588 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 79830236
This diff is collapsed.
......@@ -660,11 +660,22 @@ i::Object** V8::GlobalizeReference(i::Isolate* isolate, i::Object** obj) {
}
i::Object** V8::CopyPersistent(i::Object** obj) {
i::Handle<i::Object> result = i::GlobalHandles::CopyGlobal(obj);
#ifdef DEBUG
(*obj)->Verify();
#endif // DEBUG
return result.location();
}
void V8::MakeWeak(i::Object** object,
void* parameters,
WeakCallback weak_callback,
RevivableCallback weak_reference_callback) {
i::GlobalHandles::MakeWeak(object,
parameters,
weak_callback,
weak_reference_callback);
}
......@@ -5435,26 +5446,6 @@ static i::Handle<i::Context> CreateEnvironment(
return env;
}
#ifdef V8_USE_UNSAFE_HANDLES
Persistent<Context> v8::Context::New(
v8::ExtensionConfiguration* extensions,
v8::Handle<ObjectTemplate> global_template,
v8::Handle<Value> global_object) {
i::Isolate::EnsureDefaultIsolate();
i::Isolate* isolate = i::Isolate::Current();
Isolate* external_isolate = reinterpret_cast<Isolate*>(isolate);
EnsureInitializedForIsolate(isolate, "v8::Context::New()");
LOG_API(isolate, "Context::New");
ON_BAILOUT(isolate, "v8::Context::New()", return Persistent<Context>());
i::HandleScope scope(isolate);
i::Handle<i::Context> env =
CreateEnvironment(isolate, extensions, global_template, global_object);
if (env.is_null()) return Persistent<Context>();
return Persistent<Context>::New(external_isolate, Utils::ToLocal(env));
}
#endif
Local<Context> v8::Context::New(
v8::Isolate* external_isolate,
v8::ExtensionConfiguration* extensions,
......
......@@ -90,7 +90,7 @@ class GlobalHandles::Node {
set_partially_dependent(false);
set_in_new_space_list(false);
parameter_or_next_free_.next_free = NULL;
weak_reference_callback_ = NULL;
weak_callback_ = NULL;
}
#endif
......@@ -111,7 +111,7 @@ class GlobalHandles::Node {
set_partially_dependent(false);
set_state(NORMAL);
parameter_or_next_free_.parameter = NULL;
weak_reference_callback_ = NULL;
weak_callback_ = NULL;
IncreaseBlockUses();
}
......@@ -123,7 +123,7 @@ class GlobalHandles::Node {
class_id_ = v8::HeapProfiler::kPersistentHandleNoClassId;
set_independent(false);
set_partially_dependent(false);
weak_reference_callback_ = NULL;
weak_callback_ = NULL;
DecreaseBlockUses();
}
......@@ -169,6 +169,13 @@ class GlobalHandles::Node {
flags_ = IsInNewSpaceList::update(flags_, v);
}
bool is_revivable_callback() {
return IsRevivableCallback::decode(flags_);
}
void set_revivable_callback(bool v) {
flags_ = IsRevivableCallback::update(flags_, v);
}
bool IsNearDeath() const {
// Check for PENDING to ensure correct answer when processing callbacks.
return state() == PENDING || state() == NEAR_DEATH;
......@@ -228,11 +235,20 @@ class GlobalHandles::Node {
}
void MakeWeak(void* parameter,
RevivableCallback weak_reference_callback) {
WeakCallback weak_callback,
RevivableCallback revivable_callback) {
ASSERT((weak_callback == NULL) != (revivable_callback == NULL));
ASSERT(state() != FREE);
set_state(WEAK);
set_parameter(parameter);
weak_reference_callback_ = weak_reference_callback;
if (weak_callback != NULL) {
weak_callback_ = weak_callback;
set_revivable_callback(false);
} else {
weak_callback_ =
reinterpret_cast<WeakCallback>(revivable_callback);
set_revivable_callback(true);
}
}
void ClearWeakness() {
......@@ -243,7 +259,7 @@ class GlobalHandles::Node {
bool PostGarbageCollectionProcessing(Isolate* isolate) {
if (state() != Node::PENDING) return false;
if (weak_reference_callback_ == NULL) {
if (weak_callback_ == NULL) {
Release();
return false;
}
......@@ -262,9 +278,20 @@ class GlobalHandles::Node {
// Leaving V8.
VMState<EXTERNAL> state(isolate);
HandleScope handle_scope(isolate);
weak_reference_callback_(reinterpret_cast<v8::Isolate*>(isolate),
reinterpret_cast<Persistent<Value>*>(&object),
par);
if (is_revivable_callback()) {
RevivableCallback revivable =
reinterpret_cast<RevivableCallback>(weak_callback_);
revivable(reinterpret_cast<v8::Isolate*>(isolate),
reinterpret_cast<Persistent<Value>*>(&object),
par);
} else {
Handle<Object> handle(*object, isolate);
v8::WeakCallbackData<v8::Value, void> data(
reinterpret_cast<v8::Isolate*>(isolate),
v8::Utils::ToLocal(handle),
par);
weak_callback_(data);
}
}
// Absence of explicit cleanup or revival of weak handle
// in most of the cases would lead to memory leak.
......@@ -272,9 +299,10 @@ class GlobalHandles::Node {
return true;
}
inline GlobalHandles* GetGlobalHandles();
private:
inline NodeBlock* FindBlock();
inline GlobalHandles* GetGlobalHandles();
inline void IncreaseBlockUses();
inline void DecreaseBlockUses();
......@@ -297,11 +325,12 @@ class GlobalHandles::Node {
class IsIndependent: public BitField<bool, 4, 1> {};
class IsPartiallyDependent: public BitField<bool, 5, 1> {};
class IsInNewSpaceList: public BitField<bool, 6, 1> {};
class IsRevivableCallback: public BitField<bool, 7, 1> {};
uint8_t flags_;
// Handle specific callback - might be a weak reference in disguise.
RevivableCallback weak_reference_callback_;
WeakCallback weak_callback_;
// Provided data for callback. In FREE state, this is used for
// the free list link.
......@@ -480,6 +509,12 @@ Handle<Object> GlobalHandles::Create(Object* value) {
}
Handle<Object> GlobalHandles::CopyGlobal(Object** location) {
ASSERT(location != NULL);
return Node::FromLocation(location)->GetGlobalHandles()->Create(*location);
}
void GlobalHandles::Destroy(Object** location) {
if (location != NULL) Node::FromLocation(location)->Release();
}
......@@ -487,9 +522,10 @@ void GlobalHandles::Destroy(Object** location) {
void GlobalHandles::MakeWeak(Object** location,
void* parameter,
RevivableCallback weak_reference_callback) {
ASSERT(weak_reference_callback != NULL);
Node::FromLocation(location)->MakeWeak(parameter, weak_reference_callback);
WeakCallback weak_callback,
RevivableCallback revivable_callback) {
Node::FromLocation(location)->MakeWeak(
parameter, weak_callback, revivable_callback);
}
......
......@@ -128,9 +128,13 @@ class GlobalHandles {
// Creates a new global handle that is alive until Destroy is called.
Handle<Object> Create(Object* value);
// Copy a global handle
static Handle<Object> CopyGlobal(Object** location);
// Destroy a global handle.
static void Destroy(Object** location);
typedef WeakCallbackData<v8::Value, void>::Callback WeakCallback;
typedef WeakReferenceCallbacks<v8::Value, void>::Revivable RevivableCallback;
// Make the global handle weak and set the callback parameter for the
......@@ -141,7 +145,14 @@ class GlobalHandles {
// reason is that Smi::FromInt(0) does not change during garage collection.
static void MakeWeak(Object** location,
void* parameter,
RevivableCallback weak_reference_callback);
WeakCallback weak_callback,
RevivableCallback revivable_callback);
static inline void MakeWeak(Object** location,
void* parameter,
RevivableCallback revivable_callback) {
MakeWeak(location, parameter, NULL, revivable_callback);
}
void RecordStats(HeapStats* stats);
......
......@@ -3246,13 +3246,8 @@ THREADED_TEST(GlobalHandleUpcast) {
v8::HandleScope scope(isolate);
v8::Local<String> local = v8::Local<String>::New(v8_str("str"));
v8::Persistent<String> global_string(isolate, local);
#ifdef V8_USE_UNSAFE_HANDLES
v8::Persistent<Value> global_value =
v8::Persistent<Value>::Cast(global_string);
#else
v8::Persistent<Value>& global_value =
v8::Persistent<Value>::Cast(global_string);
#endif
CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
CHECK(global_string == v8::Persistent<String>::Cast(global_value));
global_string.Dispose();
......@@ -12670,6 +12665,75 @@ TEST(DontLeakGlobalObjects) {
}
}
template<class T>
struct CopyablePersistentTraits {
typedef Persistent<T, CopyablePersistentTraits<T> > CopyablePersistent;
static const bool kResetInDestructor = true;
template<class S, class M>
V8_INLINE(static void Copy(const Persistent<S, M>& source,
CopyablePersistent* dest)) {
// do nothing, just allow copy
}
};
TEST(CopyablePersistent) {
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
i::GlobalHandles* globals =
reinterpret_cast<i::Isolate*>(isolate)->global_handles();
int initial_handles = globals->global_handles_count();
{
v8::Persistent<v8::Object, CopyablePersistentTraits<v8::Object> > handle1;
{
v8::HandleScope scope(isolate);
handle1.Reset(isolate, v8::Object::New());
}
CHECK_EQ(initial_handles + 1, globals->global_handles_count());
v8::Persistent<v8::Object, CopyablePersistentTraits<v8::Object> > handle2;
handle2 = handle1;
CHECK(handle1 == handle2);
CHECK_EQ(initial_handles + 2, globals->global_handles_count());
v8::Persistent<v8::Object, CopyablePersistentTraits<v8::Object> >
handle3(handle2);
CHECK(handle1 == handle3);
CHECK_EQ(initial_handles + 3, globals->global_handles_count());
}
// Verify autodispose
CHECK_EQ(initial_handles, globals->global_handles_count());
}
static void WeakApiCallback(
const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
Local<Value> value = data.GetValue()->Get(v8_str("key"));
CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
data.GetParameter()->Reset();
delete data.GetParameter();
}
TEST(WeakCallbackApi) {
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
i::GlobalHandles* globals =
reinterpret_cast<i::Isolate*>(isolate)->global_handles();
int initial_handles = globals->global_handles_count();
{
v8::HandleScope scope(isolate);
v8::Local<v8::Object> obj = v8::Object::New();
obj->Set(v8_str("key"), v8::Integer::New(231, isolate));
v8::Persistent<v8::Object>* handle =
new v8::Persistent<v8::Object>(isolate, obj);
handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
WeakApiCallback);
}
reinterpret_cast<i::Isolate*>(isolate)->heap()->
CollectAllGarbage(i::Heap::kNoGCFlags);
// Verify disposed.
CHECK_EQ(initial_handles, globals->global_handles_count());
}
v8::Persistent<v8::Object> some_object;
v8::Persistent<v8::Object> bad_handle;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment