From 1f8399bdda73b6ae0f273607ca2e9e295d446b48 Mon Sep 17 00:00:00 2001 From: "antonm@chromium.org" Date: Wed, 14 Oct 2009 14:32:39 +0000 Subject: [PATCH] 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 --- include/v8.h | 60 +++++++++++++++++++++++++++++-------------------- src/api.cc | 42 +++++++++++++++++++++------------- test/cctest/test-api.cc | 38 +++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 39 deletions(-) diff --git a/include/v8.h b/include/v8.h index 25024d9..680c387 100644 --- a/include/v8.h +++ b/include/v8.h @@ -1278,6 +1278,7 @@ class V8EXPORT Object : public Value { Object(); static void CheckCast(Value* obj); Local CheckedGetInternalField(int index); + void* SlowGetPointerFromInternalField(int index); /** * 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 kFullStringRepresentationMask = 0x07; static const int kExternalTwoByteRepresentationTag = 0x03; - static const int kAlignedPointerShift = 2; // These constants are compiler dependent so their values must be // defined within the implementation. @@ -2782,6 +2782,22 @@ class Internals { #endif } + static inline int GetInstanceType(internal::Object* obj) { + typedef internal::Object O; + O* map = ReadField(obj, kHeapObjectMapOffset); + return ReadField(map, kMapInstanceTypeOffset); + } + + static inline void* GetExternalPointer(internal::Object* obj) { + if (HasSmiTag(obj)) { + return obj; + } else if (GetInstanceType(obj) == kProxyType) { + return ReadField(obj, kProxyProxyOffset); + } else { + return NULL; + } + } + static inline bool IsExternalTwoByteString(int instance_type) { int representation = (instance_type & kFullStringRepresentationMask); return representation == kExternalTwoByteRepresentationTag; @@ -2939,9 +2955,7 @@ Local Object::UncheckedGetInternalField(int index) { typedef internal::Object O; typedef internal::Internals I; O* obj = *reinterpret_cast(this); - O* map = I::ReadField(obj, I::kHeapObjectMapOffset); - int instance_type = I::ReadField(map, I::kMapInstanceTypeOffset); - if (instance_type == I::kJSObjectType) { + 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. @@ -2966,25 +2980,27 @@ void* External::Unwrap(Handle obj) { void* External::QuickUnwrap(Handle wrapper) { typedef internal::Object O; - typedef internal::Internals I; O* obj = *reinterpret_cast(const_cast(*wrapper)); - if (I::HasSmiTag(obj)) { - int value = I::SmiValue(obj) << I::kAlignedPointerShift; - return reinterpret_cast(value); - } else { - O* map = I::ReadField(obj, I::kHeapObjectMapOffset); - int instance_type = I::ReadField(map, I::kMapInstanceTypeOffset); - if (instance_type == I::kProxyType) { - return I::ReadField(obj, I::kProxyProxyOffset); - } else { - return NULL; - } - } + return internal::Internals::GetExternalPointer(obj); } void* Object::GetPointerFromInternalField(int index) { - return External::Unwrap(GetInternalField(index)); + typedef internal::Object O; + typedef internal::Internals I; + + O* obj = *reinterpret_cast(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(obj, offset); + return I::GetExternalPointer(value); + } + + return SlowGetPointerFromInternalField(index); } @@ -3000,10 +3016,8 @@ String::ExternalStringResource* String::GetExternalStringResource() const { typedef internal::Object O; typedef internal::Internals I; O* obj = *reinterpret_cast(const_cast(this)); - O* map = I::ReadField(obj, I::kHeapObjectMapOffset); - int instance_type = I::ReadField(map, I::kMapInstanceTypeOffset); String::ExternalStringResource* result; - if (I::IsExternalTwoByteString(instance_type)) { + if (I::IsExternalTwoByteString(I::GetInstanceType(obj))) { void* value = I::ReadField(obj, I::kStringResourceOffset); result = reinterpret_cast(value); } else { @@ -3029,9 +3043,7 @@ bool Value::QuickIsString() const { typedef internal::Internals I; O* obj = *reinterpret_cast(const_cast(this)); if (!I::HasHeapObjectTag(obj)) return false; - O* map = I::ReadField(obj, I::kHeapObjectMapOffset); - int instance_type = I::ReadField(map, I::kMapInstanceTypeOffset); - return (instance_type < I::kFirstNonstringType); + return (I::GetInstanceType(obj) < I::kFirstNonstringType); } diff --git a/src/api.cc b/src/api.cc index 23ffa6f..68d0979 100644 --- a/src/api.cc +++ b/src/api.cc @@ -2578,7 +2578,16 @@ void v8::Object::SetInternalField(int index, v8::Handle value) { void v8::Object::SetPointerInInternalField(int index, void* value) { - SetInternalField(index, External::Wrap(value)); + i::Object* as_object = reinterpret_cast(value); + if (as_object->IsSmi()) { + Utils::OpenHandle(this)->SetInternalField(index, as_object); + return; + } + HandleScope scope; + i::Handle proxy = + i::Factory::NewProxy(reinterpret_cast(value), i::TENURED); + if (!proxy.is_null()) + Utils::OpenHandle(this)->SetInternalField(index, *proxy); } @@ -2839,36 +2848,39 @@ static void* ExternalValueImpl(i::Handle obj) { } -static const intptr_t kAlignedPointerMask = 3; - Local v8::External::Wrap(void* data) { STATIC_ASSERT(sizeof(data) == sizeof(i::Address)); LOG_API("External::Wrap"); EnsureInitialized("v8::External::Wrap()"); ENTER_V8; - if ((reinterpret_cast(data) & kAlignedPointerMask) == 0) { - uintptr_t data_ptr = reinterpret_cast(data); - intptr_t data_value = - static_cast(data_ptr >> i::Internals::kAlignedPointerShift); - STATIC_ASSERT(sizeof(data_ptr) == sizeof(data_value)); - if (i::Smi::IsValid(data_value)) { - i::Handle obj(i::Smi::FromIntptr(data_value)); - return Utils::ToLocal(obj); - } + i::Object* as_object = reinterpret_cast(data); + if (as_object->IsSmi()) { + return Utils::ToLocal(i::Handle(as_object)); } return ExternalNewImpl(data); } +void* v8::Object::SlowGetPointerFromInternalField(int index) { + i::Handle obj = Utils::OpenHandle(this); + i::Object* value = obj->GetInternalField(index); + if (value->IsSmi()) { + return value; + } else if (value->IsProxy()) { + return reinterpret_cast(i::Proxy::cast(value)->proxy()); + } else { + return NULL; + } +} + + void* v8::External::FullUnwrap(v8::Handle wrapper) { if (IsDeadCheck("v8::External::Unwrap()")) return 0; i::Handle obj = Utils::OpenHandle(*wrapper); void* result; if (obj->IsSmi()) { // The external value was an aligned pointer. - uintptr_t value = static_cast( - i::Smi::cast(*obj)->value()) << i::Internals::kAlignedPointerShift; - result = reinterpret_cast(value); + result = *obj; } else if (obj->IsProxy()) { result = ExternalValueImpl(obj); } else { diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 1d1874c..a1f9e72 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -1426,6 +1426,44 @@ THREADED_TEST(InternalFieldsNativePointers) { } +THREADED_TEST(InternalFieldsNativePointersAndExternal) { + v8::HandleScope scope; + LocalContext env; + + Local templ = v8::FunctionTemplate::New(); + Local instance_templ = templ->InstanceTemplate(); + instance_templ->SetInternalFieldCount(1); + Local 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(aligned) & 0x1); + void* unaligned = data + 1; + CHECK_EQ(1, reinterpret_cast(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) { v8::HandleScope scope; LocalContext env; -- 2.7.4