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();
|
||||
static void CheckCast(Value* obj);
|
||||
Local<Value> 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<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) {
|
||||
int representation = (instance_type & kFullStringRepresentationMask);
|
||||
return representation == kExternalTwoByteRepresentationTag;
|
||||
@ -2939,9 +2955,7 @@ Local<Value> Object::UncheckedGetInternalField(int index) {
|
||||
typedef internal::Object O;
|
||||
typedef internal::Internals I;
|
||||
O* obj = *reinterpret_cast<O**>(this);
|
||||
O* map = I::ReadField<O*>(obj, I::kHeapObjectMapOffset);
|
||||
int instance_type = I::ReadField<uint8_t>(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<v8::Value> obj) {
|
||||
|
||||
void* External::QuickUnwrap(Handle<v8::Value> wrapper) {
|
||||
typedef internal::Object O;
|
||||
typedef internal::Internals I;
|
||||
O* obj = *reinterpret_cast<O**>(const_cast<v8::Value*>(*wrapper));
|
||||
if (I::HasSmiTag(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;
|
||||
}
|
||||
}
|
||||
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<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::Internals I;
|
||||
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;
|
||||
if (I::IsExternalTwoByteString(instance_type)) {
|
||||
if (I::IsExternalTwoByteString(I::GetInstanceType(obj))) {
|
||||
void* value = I::ReadField<void*>(obj, I::kStringResourceOffset);
|
||||
result = reinterpret_cast<String::ExternalStringResource*>(value);
|
||||
} else {
|
||||
@ -3029,9 +3043,7 @@ bool Value::QuickIsString() const {
|
||||
typedef internal::Internals I;
|
||||
O* obj = *reinterpret_cast<O**>(const_cast<Value*>(this));
|
||||
if (!I::HasHeapObjectTag(obj)) return false;
|
||||
O* map = I::ReadField<O*>(obj, I::kHeapObjectMapOffset);
|
||||
int instance_type = I::ReadField<uint8_t>(map, I::kMapInstanceTypeOffset);
|
||||
return (instance_type < I::kFirstNonstringType);
|
||||
return (I::GetInstanceType(obj) < 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) {
|
||||
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) {
|
||||
STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
|
||||
LOG_API("External::Wrap");
|
||||
EnsureInitialized("v8::External::Wrap()");
|
||||
ENTER_V8;
|
||||
if ((reinterpret_cast<intptr_t>(data) & kAlignedPointerMask) == 0) {
|
||||
uintptr_t data_ptr = reinterpret_cast<uintptr_t>(data);
|
||||
intptr_t data_value =
|
||||
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);
|
||||
}
|
||||
i::Object* as_object = reinterpret_cast<i::Object*>(data);
|
||||
if (as_object->IsSmi()) {
|
||||
return Utils::ToLocal(i::Handle<i::Object>(as_object));
|
||||
}
|
||||
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) {
|
||||
if (IsDeadCheck("v8::External::Unwrap()")) return 0;
|
||||
i::Handle<i::Object> obj = Utils::OpenHandle(*wrapper);
|
||||
void* result;
|
||||
if (obj->IsSmi()) {
|
||||
// The external value was an aligned pointer.
|
||||
uintptr_t value = static_cast<uintptr_t>(
|
||||
i::Smi::cast(*obj)->value()) << i::Internals::kAlignedPointerShift;
|
||||
result = reinterpret_cast<void*>(value);
|
||||
result = *obj;
|
||||
} else if (obj->IsProxy()) {
|
||||
result = ExternalValueImpl(obj);
|
||||
} 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) {
|
||||
v8::HandleScope scope;
|
||||
LocalContext env;
|
||||
|
Loading…
Reference in New Issue
Block a user