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:
antonm@chromium.org 2009-10-14 14:32:39 +00:00
parent 8d47ca4ed2
commit 1f8399bdda
3 changed files with 101 additions and 39 deletions

View File

@ -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);
} }

View File

@ -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 {

View File

@ -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;