class Value;
template <class T> class Handle;
template <class T> class Local;
+template <class T> class Eternal;
template <class T> class Persistent;
class FunctionTemplate;
class ObjectTemplate;
};
-// A value which will never be returned by Local::Eternalize
-// Useful for static initialization
-const int kUninitializedEternalIndex = -1;
-
-
/**
* A light-weight stack-allocated object handle. All operations
* that return objects from within v8 return them in local handles. They
return Local<S>::Cast(*this);
}
- // Keep this Local alive for the lifetime of the Isolate.
- // It remains retrievable via the returned index,
- V8_INLINE(int Eternalize(Isolate* isolate));
- V8_INLINE(static Local<T> GetEternal(Isolate* isolate, int index));
-
/**
* Create a local handle for the content of another handle.
* The referee is kept alive by the local handle even when
private:
friend class Utils;
+ template<class F> friend class Eternal;
template<class F> friend class Persistent;
template<class F> friend class Handle;
friend class Arguments;
V8_INLINE(static Local<T> New(Isolate* isolate, T* that));
};
+
+// Eternal handles are set-once handles that live for the life of the isolate.
+template <class T> class Eternal {
+ public:
+ V8_INLINE(Eternal()) : index_(kInitialValue) { }
+ template<class S>
+ V8_INLINE(Eternal(Isolate* isolate, Local<S> handle))
+ : index_(kInitialValue) {
+ Set(isolate, handle);
+ }
+ // Can only be safely called if already set.
+ V8_INLINE(Local<T> Get(Isolate* isolate));
+ V8_INLINE(bool IsEmpty()) { return index_ != kInitialValue; }
+ template<class S>
+ V8_INLINE(void Set(Isolate* isolate, Local<S> handle));
+
+ private:
+ static const int kInitialValue = -1;
+ int index_;
+};
+
+
/**
* An object reference that is independent of any handle scope. Where
* a Local handle only lives as long as the HandleScope in which it was
void* data,
RevivableCallback weak_reference_callback);
static void ClearWeak(internal::Object** global_handle);
- static int Eternalize(internal::Isolate* isolate,
- internal::Object** handle);
- static internal::Object** GetEternal(internal::Isolate* isolate, int index);
+ static void Eternalize(Isolate* isolate,
+ Value* handle,
+ int* index);
+ static Local<Value> GetEternal(Isolate* isolate, int index);
template <class T> friend class Handle;
template <class T> friend class Local;
+ template <class T> friend class Eternal;
template <class T> friend class Persistent;
friend class Context;
};
template<class T>
-int Local<T>::Eternalize(Isolate* isolate) {
- return V8::Eternalize(reinterpret_cast<internal::Isolate*>(isolate),
- reinterpret_cast<internal::Object**>(this->val_));
+template<class S>
+void Eternal<T>::Set(Isolate* isolate, Local<S> handle) {
+ TYPE_CHECK(T, S);
+ V8::Eternalize(isolate, Value::Cast(*handle), &this->index_);
}
template<class T>
-Local<T> Local<T>::GetEternal(Isolate* isolate, int index) {
- internal::Object** handle =
- V8::GetEternal(reinterpret_cast<internal::Isolate*>(isolate), index);
- return Local<T>(T::Cast(reinterpret_cast<Value*>(handle)));
+Local<T> Eternal<T>::Get(Isolate* isolate) {
+ return Local<T>::Cast(V8::GetEternal(isolate, index_));
}
}
-int V8::Eternalize(i::Isolate* isolate, i::Object** handle) {
- return isolate->eternal_handles()->Create(isolate, *handle);
+void V8::Eternalize(Isolate* v8_isolate, Value* value, int* index) {
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ i::Object* object = *Utils::OpenHandle(value);
+ isolate->eternal_handles()->Create(isolate, object, index);
}
-i::Object** V8::GetEternal(i::Isolate* isolate, int index) {
- return isolate->eternal_handles()->Get(index).location();
+Local<Value> V8::GetEternal(Isolate* v8_isolate, int index) {
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ return Utils::ToLocal(isolate->eternal_handles()->Get(index));
}
EternalHandles::EternalHandles() : size_(0) {
- STATIC_ASSERT(v8::kUninitializedEternalIndex == kInvalidIndex);
for (unsigned i = 0; i < ARRAY_SIZE(singleton_handles_); i++) {
singleton_handles_[i] = kInvalidIndex;
}
}
-int EternalHandles::Create(Isolate* isolate, Object* object) {
- if (object == NULL) return kInvalidIndex;
+void EternalHandles::Create(Isolate* isolate, Object* object, int* index) {
+ ASSERT_EQ(kInvalidIndex, *index);
+ if (object == NULL) return;
ASSERT_NE(isolate->heap()->the_hole_value(), object);
int block = size_ >> kShift;
int offset = size_ & kMask;
if (isolate->heap()->InNewSpace(object)) {
new_space_indices_.Add(size_);
}
- return size_++;
+ *index = size_++;
}
int NumberOfHandles() { return size_; }
- // Create an EternalHandle, returning the index.
- int Create(Isolate* isolate, Object* object);
+ // Create an EternalHandle, overwriting the index.
+ void Create(Isolate* isolate, Object* object, int* index);
// Grab the handle for an existing EternalHandle.
inline Handle<Object> Get(int index) {
Handle<Object> CreateSingleton(Isolate* isolate,
Object* object,
SingletonHandle singleton) {
- ASSERT(singleton_handles_[singleton] == kInvalidIndex);
- singleton_handles_[singleton] = Create(isolate, object);
+ Create(isolate, object, &singleton_handles_[singleton]);
return Get(singleton_handles_[singleton]);
}
CcTest::InitializeVM();
Isolate* isolate = Isolate::Current();
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
- EternalHandles* eternals = isolate->eternal_handles();
+ EternalHandles* eternal_handles = isolate->eternal_handles();
// Create a number of handles that will not be on a block boundary
const int kArrayLength = 2048-1;
int indices[kArrayLength];
+ v8::Eternal<v8::Value> eternals[kArrayLength];
- CHECK_EQ(0, eternals->NumberOfHandles());
+ CHECK_EQ(0, eternal_handles->NumberOfHandles());
for (int i = 0; i < kArrayLength; i++) {
HandleScope scope(isolate);
v8::Local<v8::Object> object = v8::Object::New();
object->Set(i, v8::Integer::New(i, v8_isolate));
- if (i % 2 == 0) {
- // Create with internal api
- indices[i] = eternals->Create(isolate, *v8::Utils::OpenHandle(*object));
- } else {
- // Create with external api
- indices[i] = object.Eternalize(v8_isolate);
- }
+ // Create with internal api
+ eternal_handles->Create(
+ isolate, *v8::Utils::OpenHandle(*object), &indices[i]);
+ // Create with external api
+ CHECK(!eternals[i].IsEmpty());
+ eternals[i].Set(v8_isolate, object);
+ CHECK(eternals[i].IsEmpty());
}
isolate->heap()->CollectAllAvailableGarbage();
for (int i = 0; i < kArrayLength; i++) {
for (int j = 0; j < 2; j++) {
HandleScope scope(isolate);
- v8::Local<v8::Object> object;
+ v8::Local<v8::Value> local;
if (j == 0) {
// Test internal api
- v8::Local<v8::Value> local =
- v8::Utils::ToLocal(eternals->Get(indices[i]));
- object = v8::Handle<v8::Object>::Cast(local);
+ local = v8::Utils::ToLocal(eternal_handles->Get(indices[i]));
} else {
// Test external api
- object = v8::Local<v8::Object>::GetEternal(v8_isolate, indices[i]);
+ local = eternals[i].Get(v8_isolate);
}
+ v8::Local<v8::Object> object = v8::Handle<v8::Object>::Cast(local);
v8::Local<v8::Value> value = object->Get(i);
CHECK(value->IsInt32());
CHECK_EQ(i, value->Int32Value());
}
}
- CHECK_EQ(kArrayLength, eternals->NumberOfHandles());
+ CHECK_EQ(2*kArrayLength, eternal_handles->NumberOfHandles());
+
+ // Create an eternal via the constructor
+ {
+ HandleScope scope(isolate);
+ v8::Local<v8::Object> object = v8::Object::New();
+ v8::Eternal<v8::Object> eternal(v8_isolate, object);
+ CHECK(eternal.IsEmpty());
+ CHECK(object == eternal.Get(v8_isolate));
+ }
+
+ CHECK_EQ(2*kArrayLength + 1, eternal_handles->NumberOfHandles());
}