Partially revert r2761.
Do not create handles for values of internal fields---this operation is performance critical and plain pointers are safe. Appy the same approach to External wrapping and unwrapping. Plus some minor refactorings. Review URL: http://codereview.chromium.org/270085 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3064 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
8d47ca4ed2
commit
1f8399bdda
60
include/v8.h
60
include/v8.h
@ -1278,6 +1278,7 @@ class V8EXPORT Object : public Value {
|
|||||||
Object();
|
Object();
|
||||||
static void CheckCast(Value* obj);
|
static void CheckCast(Value* obj);
|
||||||
Local<Value> CheckedGetInternalField(int index);
|
Local<Value> CheckedGetInternalField(int index);
|
||||||
|
void* SlowGetPointerFromInternalField(int index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If quick access to the internal field is possible this method
|
* If quick access to the internal field is possible this method
|
||||||
@ -2753,7 +2754,6 @@ class Internals {
|
|||||||
static const int kJSObjectHeaderSize = 3 * sizeof(void*);
|
static const int kJSObjectHeaderSize = 3 * sizeof(void*);
|
||||||
static const int kFullStringRepresentationMask = 0x07;
|
static const int kFullStringRepresentationMask = 0x07;
|
||||||
static const int kExternalTwoByteRepresentationTag = 0x03;
|
static const int kExternalTwoByteRepresentationTag = 0x03;
|
||||||
static const int kAlignedPointerShift = 2;
|
|
||||||
|
|
||||||
// These constants are compiler dependent so their values must be
|
// These constants are compiler dependent so their values must be
|
||||||
// defined within the implementation.
|
// defined within the implementation.
|
||||||
@ -2782,6 +2782,22 @@ class Internals {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int GetInstanceType(internal::Object* obj) {
|
||||||
|
typedef internal::Object O;
|
||||||
|
O* map = ReadField<O*>(obj, kHeapObjectMapOffset);
|
||||||
|
return ReadField<uint8_t>(map, kMapInstanceTypeOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void* GetExternalPointer(internal::Object* obj) {
|
||||||
|
if (HasSmiTag(obj)) {
|
||||||
|
return obj;
|
||||||
|
} else if (GetInstanceType(obj) == kProxyType) {
|
||||||
|
return ReadField<void*>(obj, kProxyProxyOffset);
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool IsExternalTwoByteString(int instance_type) {
|
static inline bool IsExternalTwoByteString(int instance_type) {
|
||||||
int representation = (instance_type & kFullStringRepresentationMask);
|
int representation = (instance_type & kFullStringRepresentationMask);
|
||||||
return representation == kExternalTwoByteRepresentationTag;
|
return representation == kExternalTwoByteRepresentationTag;
|
||||||
@ -2939,9 +2955,7 @@ Local<Value> Object::UncheckedGetInternalField(int index) {
|
|||||||
typedef internal::Object O;
|
typedef internal::Object O;
|
||||||
typedef internal::Internals I;
|
typedef internal::Internals I;
|
||||||
O* obj = *reinterpret_cast<O**>(this);
|
O* obj = *reinterpret_cast<O**>(this);
|
||||||
O* map = I::ReadField<O*>(obj, I::kHeapObjectMapOffset);
|
if (I::GetInstanceType(obj) == I::kJSObjectType) {
|
||||||
int instance_type = I::ReadField<uint8_t>(map, I::kMapInstanceTypeOffset);
|
|
||||||
if (instance_type == I::kJSObjectType) {
|
|
||||||
// If the object is a plain JSObject, which is the common case,
|
// If the object is a plain JSObject, which is the common case,
|
||||||
// we know where to find the internal fields and can return the
|
// we know where to find the internal fields and can return the
|
||||||
// value directly.
|
// value directly.
|
||||||
@ -2966,25 +2980,27 @@ void* External::Unwrap(Handle<v8::Value> obj) {
|
|||||||
|
|
||||||
void* External::QuickUnwrap(Handle<v8::Value> wrapper) {
|
void* External::QuickUnwrap(Handle<v8::Value> wrapper) {
|
||||||
typedef internal::Object O;
|
typedef internal::Object O;
|
||||||
typedef internal::Internals I;
|
|
||||||
O* obj = *reinterpret_cast<O**>(const_cast<v8::Value*>(*wrapper));
|
O* obj = *reinterpret_cast<O**>(const_cast<v8::Value*>(*wrapper));
|
||||||
if (I::HasSmiTag(obj)) {
|
return internal::Internals::GetExternalPointer(obj);
|
||||||
int value = I::SmiValue(obj) << I::kAlignedPointerShift;
|
|
||||||
return reinterpret_cast<void*>(value);
|
|
||||||
} else {
|
|
||||||
O* map = I::ReadField<O*>(obj, I::kHeapObjectMapOffset);
|
|
||||||
int instance_type = I::ReadField<uint8_t>(map, I::kMapInstanceTypeOffset);
|
|
||||||
if (instance_type == I::kProxyType) {
|
|
||||||
return I::ReadField<void*>(obj, I::kProxyProxyOffset);
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void* Object::GetPointerFromInternalField(int index) {
|
void* Object::GetPointerFromInternalField(int index) {
|
||||||
return External::Unwrap(GetInternalField(index));
|
typedef internal::Object O;
|
||||||
|
typedef internal::Internals I;
|
||||||
|
|
||||||
|
O* obj = *reinterpret_cast<O**>(this);
|
||||||
|
|
||||||
|
if (I::GetInstanceType(obj) == I::kJSObjectType) {
|
||||||
|
// If the object is a plain JSObject, which is the common case,
|
||||||
|
// we know where to find the internal fields and can return the
|
||||||
|
// value directly.
|
||||||
|
int offset = I::kJSObjectHeaderSize + (sizeof(void*) * index);
|
||||||
|
O* value = I::ReadField<O*>(obj, offset);
|
||||||
|
return I::GetExternalPointer(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SlowGetPointerFromInternalField(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3000,10 +3016,8 @@ String::ExternalStringResource* String::GetExternalStringResource() const {
|
|||||||
typedef internal::Object O;
|
typedef internal::Object O;
|
||||||
typedef internal::Internals I;
|
typedef internal::Internals I;
|
||||||
O* obj = *reinterpret_cast<O**>(const_cast<String*>(this));
|
O* obj = *reinterpret_cast<O**>(const_cast<String*>(this));
|
||||||
O* map = I::ReadField<O*>(obj, I::kHeapObjectMapOffset);
|
|
||||||
int instance_type = I::ReadField<uint8_t>(map, I::kMapInstanceTypeOffset);
|
|
||||||
String::ExternalStringResource* result;
|
String::ExternalStringResource* result;
|
||||||
if (I::IsExternalTwoByteString(instance_type)) {
|
if (I::IsExternalTwoByteString(I::GetInstanceType(obj))) {
|
||||||
void* value = I::ReadField<void*>(obj, I::kStringResourceOffset);
|
void* value = I::ReadField<void*>(obj, I::kStringResourceOffset);
|
||||||
result = reinterpret_cast<String::ExternalStringResource*>(value);
|
result = reinterpret_cast<String::ExternalStringResource*>(value);
|
||||||
} else {
|
} else {
|
||||||
@ -3029,9 +3043,7 @@ bool Value::QuickIsString() const {
|
|||||||
typedef internal::Internals I;
|
typedef internal::Internals I;
|
||||||
O* obj = *reinterpret_cast<O**>(const_cast<Value*>(this));
|
O* obj = *reinterpret_cast<O**>(const_cast<Value*>(this));
|
||||||
if (!I::HasHeapObjectTag(obj)) return false;
|
if (!I::HasHeapObjectTag(obj)) return false;
|
||||||
O* map = I::ReadField<O*>(obj, I::kHeapObjectMapOffset);
|
return (I::GetInstanceType(obj) < I::kFirstNonstringType);
|
||||||
int instance_type = I::ReadField<uint8_t>(map, I::kMapInstanceTypeOffset);
|
|
||||||
return (instance_type < I::kFirstNonstringType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
42
src/api.cc
42
src/api.cc
@ -2578,7 +2578,16 @@ void v8::Object::SetInternalField(int index, v8::Handle<Value> value) {
|
|||||||
|
|
||||||
|
|
||||||
void v8::Object::SetPointerInInternalField(int index, void* value) {
|
void v8::Object::SetPointerInInternalField(int index, void* value) {
|
||||||
SetInternalField(index, External::Wrap(value));
|
i::Object* as_object = reinterpret_cast<i::Object*>(value);
|
||||||
|
if (as_object->IsSmi()) {
|
||||||
|
Utils::OpenHandle(this)->SetInternalField(index, as_object);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HandleScope scope;
|
||||||
|
i::Handle<i::Proxy> proxy =
|
||||||
|
i::Factory::NewProxy(reinterpret_cast<i::Address>(value), i::TENURED);
|
||||||
|
if (!proxy.is_null())
|
||||||
|
Utils::OpenHandle(this)->SetInternalField(index, *proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2839,36 +2848,39 @@ static void* ExternalValueImpl(i::Handle<i::Object> obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const intptr_t kAlignedPointerMask = 3;
|
|
||||||
|
|
||||||
Local<Value> v8::External::Wrap(void* data) {
|
Local<Value> v8::External::Wrap(void* data) {
|
||||||
STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
|
STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
|
||||||
LOG_API("External::Wrap");
|
LOG_API("External::Wrap");
|
||||||
EnsureInitialized("v8::External::Wrap()");
|
EnsureInitialized("v8::External::Wrap()");
|
||||||
ENTER_V8;
|
ENTER_V8;
|
||||||
if ((reinterpret_cast<intptr_t>(data) & kAlignedPointerMask) == 0) {
|
i::Object* as_object = reinterpret_cast<i::Object*>(data);
|
||||||
uintptr_t data_ptr = reinterpret_cast<uintptr_t>(data);
|
if (as_object->IsSmi()) {
|
||||||
intptr_t data_value =
|
return Utils::ToLocal(i::Handle<i::Object>(as_object));
|
||||||
static_cast<intptr_t>(data_ptr >> i::Internals::kAlignedPointerShift);
|
|
||||||
STATIC_ASSERT(sizeof(data_ptr) == sizeof(data_value));
|
|
||||||
if (i::Smi::IsValid(data_value)) {
|
|
||||||
i::Handle<i::Object> obj(i::Smi::FromIntptr(data_value));
|
|
||||||
return Utils::ToLocal(obj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ExternalNewImpl(data);
|
return ExternalNewImpl(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void* v8::Object::SlowGetPointerFromInternalField(int index) {
|
||||||
|
i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
|
||||||
|
i::Object* value = obj->GetInternalField(index);
|
||||||
|
if (value->IsSmi()) {
|
||||||
|
return value;
|
||||||
|
} else if (value->IsProxy()) {
|
||||||
|
return reinterpret_cast<void*>(i::Proxy::cast(value)->proxy());
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void* v8::External::FullUnwrap(v8::Handle<v8::Value> wrapper) {
|
void* v8::External::FullUnwrap(v8::Handle<v8::Value> wrapper) {
|
||||||
if (IsDeadCheck("v8::External::Unwrap()")) return 0;
|
if (IsDeadCheck("v8::External::Unwrap()")) return 0;
|
||||||
i::Handle<i::Object> obj = Utils::OpenHandle(*wrapper);
|
i::Handle<i::Object> obj = Utils::OpenHandle(*wrapper);
|
||||||
void* result;
|
void* result;
|
||||||
if (obj->IsSmi()) {
|
if (obj->IsSmi()) {
|
||||||
// The external value was an aligned pointer.
|
// The external value was an aligned pointer.
|
||||||
uintptr_t value = static_cast<uintptr_t>(
|
result = *obj;
|
||||||
i::Smi::cast(*obj)->value()) << i::Internals::kAlignedPointerShift;
|
|
||||||
result = reinterpret_cast<void*>(value);
|
|
||||||
} else if (obj->IsProxy()) {
|
} else if (obj->IsProxy()) {
|
||||||
result = ExternalValueImpl(obj);
|
result = ExternalValueImpl(obj);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1426,6 +1426,44 @@ THREADED_TEST(InternalFieldsNativePointers) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
THREADED_TEST(InternalFieldsNativePointersAndExternal) {
|
||||||
|
v8::HandleScope scope;
|
||||||
|
LocalContext env;
|
||||||
|
|
||||||
|
Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
|
||||||
|
Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
|
||||||
|
instance_templ->SetInternalFieldCount(1);
|
||||||
|
Local<v8::Object> obj = templ->GetFunction()->NewInstance();
|
||||||
|
CHECK_EQ(1, obj->InternalFieldCount());
|
||||||
|
CHECK(obj->GetPointerFromInternalField(0) == NULL);
|
||||||
|
|
||||||
|
char* data = new char[100];
|
||||||
|
|
||||||
|
void* aligned = data;
|
||||||
|
CHECK_EQ(0, reinterpret_cast<uintptr_t>(aligned) & 0x1);
|
||||||
|
void* unaligned = data + 1;
|
||||||
|
CHECK_EQ(1, reinterpret_cast<uintptr_t>(unaligned) & 0x1);
|
||||||
|
|
||||||
|
obj->SetPointerInInternalField(0, aligned);
|
||||||
|
i::Heap::CollectAllGarbage(false);
|
||||||
|
CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0)));
|
||||||
|
|
||||||
|
obj->SetPointerInInternalField(0, unaligned);
|
||||||
|
i::Heap::CollectAllGarbage(false);
|
||||||
|
CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0)));
|
||||||
|
|
||||||
|
obj->SetInternalField(0, v8::External::Wrap(aligned));
|
||||||
|
i::Heap::CollectAllGarbage(false);
|
||||||
|
CHECK_EQ(aligned, obj->GetPointerFromInternalField(0));
|
||||||
|
|
||||||
|
obj->SetInternalField(0, v8::External::Wrap(unaligned));
|
||||||
|
i::Heap::CollectAllGarbage(false);
|
||||||
|
CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0));
|
||||||
|
|
||||||
|
delete[] data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
THREADED_TEST(IdentityHash) {
|
THREADED_TEST(IdentityHash) {
|
||||||
v8::HandleScope scope;
|
v8::HandleScope scope;
|
||||||
LocalContext env;
|
LocalContext env;
|
||||||
|
Loading…
Reference in New Issue
Block a user