Commit 25058ddd authored by dcarney@chromium.org's avatar dcarney@chromium.org

Runtime version of declarative native accessors.

R=svenpanne@chromium.org
BUG=

Review URL: https://codereview.chromium.org/12297012

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13856 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 4a799132
......@@ -131,6 +131,9 @@ class AccessorInfo;
class StackTrace;
class StackFrame;
class Isolate;
class DeclaredAccessorDescriptor;
class ObjectOperationDescriptor;
class RawOperationDescriptor;
namespace internal {
......@@ -1606,6 +1609,12 @@ class V8EXPORT Object : public Value {
AccessControl settings = DEFAULT,
PropertyAttribute attribute = None);
// This function is not yet stable and should not be used at this time.
bool SetAccessor(Handle<String> name,
Handle<DeclaredAccessorDescriptor> descriptor,
AccessControl settings = DEFAULT,
PropertyAttribute attribute = None);
/**
* Returns an array containing the names of the enumerable properties
* of this object, including properties from prototype objects. The
......@@ -2377,13 +2386,6 @@ class V8EXPORT FunctionTemplate : public Template {
private:
FunctionTemplate();
void AddInstancePropertyAccessor(Handle<String> name,
AccessorGetter getter,
AccessorSetter setter,
Handle<Value> data,
AccessControl settings,
PropertyAttribute attributes,
Handle<AccessorSignature> signature);
void SetNamedInstancePropertyHandler(NamedPropertyGetter getter,
NamedPropertySetter setter,
NamedPropertyQuery query,
......@@ -2456,6 +2458,14 @@ class V8EXPORT ObjectTemplate : public Template {
Handle<AccessorSignature> signature =
Handle<AccessorSignature>());
// This function is not yet stable and should not be used at this time.
bool SetAccessor(Handle<String> name,
Handle<DeclaredAccessorDescriptor> descriptor,
AccessControl settings = DEFAULT,
PropertyAttribute attribute = None,
Handle<AccessorSignature> signature =
Handle<AccessorSignature>());
/**
* Sets a named property handler on the object template.
*
......@@ -2585,6 +2595,61 @@ class V8EXPORT AccessorSignature : public Data {
};
class V8EXPORT DeclaredAccessorDescriptor : public Data {
private:
DeclaredAccessorDescriptor();
};
class V8EXPORT ObjectOperationDescriptor : public Data {
public:
// This function is not yet stable and should not be used at this time.
static Local<RawOperationDescriptor> NewInternalFieldDereference(
Isolate* isolate,
int internal_field);
private:
ObjectOperationDescriptor();
};
enum DeclaredAccessorDescriptorDataType {
kDescriptorBoolType,
kDescriptorInt8Type, kDescriptorUint8Type,
kDescriptorInt16Type, kDescriptorUint16Type,
kDescriptorInt32Type, kDescriptorUint32Type,
kDescriptorFloatType, kDescriptorDoubleType
};
class V8EXPORT RawOperationDescriptor : public Data {
public:
Local<DeclaredAccessorDescriptor> NewHandleDereference(Isolate* isolate);
Local<RawOperationDescriptor> NewRawDereference(Isolate* isolate);
Local<RawOperationDescriptor> NewRawShift(Isolate* isolate,
int16_t byte_offset);
Local<DeclaredAccessorDescriptor> NewPointerCompare(Isolate* isolate,
void* compare_value);
Local<DeclaredAccessorDescriptor> NewPrimitiveValue(
Isolate* isolate,
DeclaredAccessorDescriptorDataType data_type,
uint8_t bool_offset = 0);
Local<DeclaredAccessorDescriptor> NewBitmaskCompare8(Isolate* isolate,
uint8_t bitmask,
uint8_t compare_value);
Local<DeclaredAccessorDescriptor> NewBitmaskCompare16(
Isolate* isolate,
uint16_t bitmask,
uint16_t compare_value);
Local<DeclaredAccessorDescriptor> NewBitmaskCompare32(
Isolate* isolate,
uint32_t bitmask,
uint32_t compare_value);
private:
RawOperationDescriptor();
};
/**
* A utility for determining the type of objects based on the template
* they were constructed from.
......
......@@ -1041,6 +1041,124 @@ Local<AccessorSignature> AccessorSignature::New(
}
template<typename Operation>
static Local<Operation> NewDescriptor(
Isolate* isolate,
const i::DeclaredAccessorDescriptorData& data,
Data* previous_descriptor
) {
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::Handle<i::DeclaredAccessorDescriptor> previous =
i::Handle<i::DeclaredAccessorDescriptor>();
if (previous_descriptor != NULL) {
previous = Utils::OpenHandle(
static_cast<DeclaredAccessorDescriptor*>(previous_descriptor));
}
i::Handle<i::DeclaredAccessorDescriptor> descriptor =
i::DeclaredAccessorDescriptor::Create(internal_isolate, data, previous);
return Local<Operation>(
reinterpret_cast<Operation*>(*Utils::ToLocal(descriptor)));
}
Local<RawOperationDescriptor>
ObjectOperationDescriptor::NewInternalFieldDereference(
Isolate* isolate,
int internal_field) {
i::DeclaredAccessorDescriptorData data;
data.type = i::kDescriptorObjectDereference;
data.object_dereference_descriptor.internal_field = internal_field;
return NewDescriptor<RawOperationDescriptor>(isolate, data, NULL);
}
Local<RawOperationDescriptor> RawOperationDescriptor::NewRawShift(
Isolate* isolate,
int16_t byte_offset) {
i::DeclaredAccessorDescriptorData data;
data.type = i::kDescriptorPointerShift;
data.pointer_shift_descriptor.byte_offset = byte_offset;
return NewDescriptor<RawOperationDescriptor>(isolate, data, this);
}
Local<DeclaredAccessorDescriptor> RawOperationDescriptor::NewHandleDereference(
Isolate* isolate) {
i::DeclaredAccessorDescriptorData data;
data.type = i::kDescriptorReturnObject;
return NewDescriptor<DeclaredAccessorDescriptor>(isolate, data, this);
}
Local<RawOperationDescriptor> RawOperationDescriptor::NewRawDereference(
Isolate* isolate) {
i::DeclaredAccessorDescriptorData data;
data.type = i::kDescriptorPointerDereference;
return NewDescriptor<RawOperationDescriptor>(isolate, data, this);
}
Local<DeclaredAccessorDescriptor> RawOperationDescriptor::NewPointerCompare(
Isolate* isolate,
void* compare_value) {
i::DeclaredAccessorDescriptorData data;
data.type = i::kDescriptorPointerCompare;
data.pointer_compare_descriptor.compare_value = compare_value;
return NewDescriptor<DeclaredAccessorDescriptor>(isolate, data, this);
}
Local<DeclaredAccessorDescriptor> RawOperationDescriptor::NewPrimitiveValue(
Isolate* isolate,
DeclaredAccessorDescriptorDataType data_type,
uint8_t bool_offset) {
i::DeclaredAccessorDescriptorData data;
data.type = i::kDescriptorPrimitiveValue;
data.primitive_value_descriptor.data_type = data_type;
data.primitive_value_descriptor.bool_offset = bool_offset;
return NewDescriptor<DeclaredAccessorDescriptor>(isolate, data, this);
}
template<typename T>
static Local<DeclaredAccessorDescriptor> NewBitmaskCompare(
Isolate* isolate,
T bitmask,
T compare_value,
RawOperationDescriptor* operation) {
i::DeclaredAccessorDescriptorData data;
data.type = i::kDescriptorBitmaskCompare;
data.bitmask_compare_descriptor.bitmask = bitmask;
data.bitmask_compare_descriptor.compare_value = compare_value;
data.bitmask_compare_descriptor.size = sizeof(T);
return NewDescriptor<DeclaredAccessorDescriptor>(isolate, data, operation);
}
Local<DeclaredAccessorDescriptor> RawOperationDescriptor::NewBitmaskCompare8(
Isolate* isolate,
uint8_t bitmask,
uint8_t compare_value) {
return NewBitmaskCompare(isolate, bitmask, compare_value, this);
}
Local<DeclaredAccessorDescriptor> RawOperationDescriptor::NewBitmaskCompare16(
Isolate* isolate,
uint16_t bitmask,
uint16_t compare_value) {
return NewBitmaskCompare(isolate, bitmask, compare_value, this);
}
Local<DeclaredAccessorDescriptor> RawOperationDescriptor::NewBitmaskCompare32(
Isolate* isolate,
uint32_t bitmask,
uint32_t compare_value) {
return NewBitmaskCompare(isolate, bitmask, compare_value, this);
}
Local<TypeSwitch> TypeSwitch::New(Handle<FunctionTemplate> type) {
Handle<FunctionTemplate> types[1] = { type };
return TypeSwitch::New(1, types);
......@@ -1102,20 +1220,12 @@ void FunctionTemplate::SetCallHandler(InvocationCallback callback,
}
static i::Handle<i::AccessorInfo> MakeAccessorInfo(
static i::Handle<i::AccessorInfo> SetAccessorInfoProperties(
i::Handle<i::AccessorInfo> obj,
v8::Handle<String> name,
AccessorGetter getter,
AccessorSetter setter,
v8::Handle<Value> data,
v8::AccessControl settings,
v8::PropertyAttribute attributes,
v8::Handle<AccessorSignature> signature) {
i::Handle<i::ExecutableAccessorInfo> obj =
FACTORY->NewExecutableAccessorInfo();
SET_FIELD_WRAPPED(obj, set_getter, getter);
SET_FIELD_WRAPPED(obj, set_setter, setter);
if (data.IsEmpty()) data = v8::Undefined();
obj->set_data(*Utils::OpenHandle(*data));
obj->set_name(*Utils::OpenHandle(*name));
if (settings & ALL_CAN_READ) obj->set_all_can_read(true);
if (settings & ALL_CAN_WRITE) obj->set_all_can_write(true);
......@@ -1128,7 +1238,7 @@ static i::Handle<i::AccessorInfo> MakeAccessorInfo(
}
void FunctionTemplate::AddInstancePropertyAccessor(
static i::Handle<i::AccessorInfo> MakeAccessorInfo(
v8::Handle<String> name,
AccessorGetter getter,
AccessorSetter setter,
......@@ -1136,25 +1246,29 @@ void FunctionTemplate::AddInstancePropertyAccessor(
v8::AccessControl settings,
v8::PropertyAttribute attributes,
v8::Handle<AccessorSignature> signature) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
if (IsDeadCheck(isolate,
"v8::FunctionTemplate::AddInstancePropertyAccessor()")) {
return;
}
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Isolate* isolate = Utils::OpenHandle(*name)->GetIsolate();
i::Handle<i::ExecutableAccessorInfo> obj =
isolate->factory()->NewExecutableAccessorInfo();
SET_FIELD_WRAPPED(obj, set_getter, getter);
SET_FIELD_WRAPPED(obj, set_setter, setter);
if (data.IsEmpty()) data = v8::Undefined();
obj->set_data(*Utils::OpenHandle(*data));
return SetAccessorInfoProperties(obj, name, settings, attributes, signature);
}
i::Handle<i::AccessorInfo> obj = MakeAccessorInfo(name, getter, setter, data,
settings, attributes,
signature);
i::Handle<i::Object> list(Utils::OpenHandle(this)->property_accessors(),
isolate);
if (list->IsUndefined()) {
list = NeanderArray().value();
Utils::OpenHandle(this)->set_property_accessors(*list);
}
NeanderArray array(list);
array.add(obj);
static i::Handle<i::AccessorInfo> MakeAccessorInfo(
v8::Handle<String> name,
v8::Handle<v8::DeclaredAccessorDescriptor> descriptor,
v8::AccessControl settings,
v8::PropertyAttribute attributes,
v8::Handle<AccessorSignature> signature) {
i::Isolate* isolate = Utils::OpenHandle(*name)->GetIsolate();
if (descriptor.IsEmpty()) return i::Handle<i::DeclaredAccessorInfo>();
i::Handle<i::DeclaredAccessorInfo> obj =
isolate->factory()->NewDeclaredAccessorInfo();
obj->set_descriptor(*Utils::OpenHandle(*descriptor));
return SetAccessorInfoProperties(obj, name, settings, attributes, signature);
}
......@@ -1335,6 +1449,19 @@ static void EnsureConstructor(ObjectTemplate* object_template) {
}
static inline void AddPropertyToFunctionTemplate(
i::Handle<i::FunctionTemplateInfo> cons,
i::Handle<i::AccessorInfo> obj) {
i::Handle<i::Object> list(cons->property_accessors(), cons->GetIsolate());
if (list->IsUndefined()) {
list = NeanderArray().value();
cons->set_property_accessors(*list);
}
NeanderArray array(list);
array.add(obj);
}
void ObjectTemplate::SetAccessor(v8::Handle<String> name,
AccessorGetter getter,
AccessorSetter setter,
......@@ -1350,13 +1477,31 @@ void ObjectTemplate::SetAccessor(v8::Handle<String> name,
i::FunctionTemplateInfo* constructor =
i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
i::Handle<i::FunctionTemplateInfo> cons(constructor);
Utils::ToLocal(cons)->AddInstancePropertyAccessor(name,
getter,
setter,
data,
settings,
attribute,
i::Handle<i::AccessorInfo> obj = MakeAccessorInfo(name, getter, setter, data,
settings, attribute,
signature);
AddPropertyToFunctionTemplate(cons, obj);
}
bool ObjectTemplate::SetAccessor(Handle<String> name,
Handle<DeclaredAccessorDescriptor> descriptor,
AccessControl settings,
PropertyAttribute attribute,
Handle<AccessorSignature> signature) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetAccessor()")) return false;
ENTER_V8(isolate);
i::HandleScope scope(isolate);
EnsureConstructor(this);
i::FunctionTemplateInfo* constructor =
i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
i::Handle<i::FunctionTemplateInfo> cons(constructor);
i::Handle<i::AccessorInfo> obj = MakeAccessorInfo(
name, descriptor, settings, attribute, signature);
if (obj.is_null()) return false;
AddPropertyToFunctionTemplate(cons, obj);
return true;
}
......@@ -3158,6 +3303,16 @@ bool v8::Object::Has(uint32_t index) {
}
static inline bool SetAccessor(Object* obj, i::Handle<i::AccessorInfo> info) {
if (info.is_null()) return false;
bool fast = Utils::OpenHandle(obj)->HasFastProperties();
i::Handle<i::Object> result = i::SetAccessor(Utils::OpenHandle(obj), info);
if (result.is_null() || result->IsUndefined()) return false;
if (fast) i::JSObject::TransformToFastProperties(Utils::OpenHandle(obj), 0);
return true;
}
bool Object::SetAccessor(Handle<String> name,
AccessorGetter getter,
AccessorSetter setter,
......@@ -3172,11 +3327,22 @@ bool Object::SetAccessor(Handle<String> name,
i::Handle<i::AccessorInfo> info = MakeAccessorInfo(name, getter, setter, data,
settings, attributes,
signature);
bool fast = Utils::OpenHandle(this)->HasFastProperties();
i::Handle<i::Object> result = i::SetAccessor(Utils::OpenHandle(this), info);
if (result.is_null() || result->IsUndefined()) return false;
if (fast) i::JSObject::TransformToFastProperties(Utils::OpenHandle(this), 0);
return true;
return v8::SetAccessor(this, info);
}
bool Object::SetAccessor(Handle<String> name,
Handle<DeclaredAccessorDescriptor> descriptor,
AccessControl settings,
PropertyAttribute attributes) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Object::SetAccessor()", return false);
ENTER_V8(isolate);
i::HandleScope scope(isolate);
v8::Handle<AccessorSignature> signature;
i::Handle<i::AccessorInfo> info = MakeAccessorInfo(
name, descriptor, settings, attributes, signature);
return v8::SetAccessor(this, info);
}
......
......@@ -177,7 +177,8 @@ class RegisteredExtension {
V(Context, Context) \
V(External, Foreign) \
V(StackTrace, JSArray) \
V(StackFrame, JSObject)
V(StackFrame, JSObject) \
V(DeclaredAccessorDescriptor, DeclaredAccessorDescriptor)
class Utils {
......@@ -225,6 +226,8 @@ class Utils {
v8::internal::Handle<v8::internal::TypeSwitchInfo> obj);
static inline Local<External> ExternalToLocal(
v8::internal::Handle<v8::internal::JSObject> obj);
static inline Local<DeclaredAccessorDescriptor> ToLocal(
v8::internal::Handle<v8::internal::DeclaredAccessorDescriptor> obj);
#define DECLARE_OPEN_HANDLE(From, To) \
static inline v8::internal::Handle<v8::internal::To> \
......@@ -280,6 +283,7 @@ MAKE_TO_LOCAL(NumberToLocal, Object, Number)
MAKE_TO_LOCAL(IntegerToLocal, Object, Integer)
MAKE_TO_LOCAL(Uint32ToLocal, Object, Uint32)
MAKE_TO_LOCAL(ExternalToLocal, JSObject, External)
MAKE_TO_LOCAL(ToLocal, DeclaredAccessorDescriptor, DeclaredAccessorDescriptor)
#undef MAKE_TO_LOCAL
......
......@@ -369,6 +369,12 @@ Handle<Struct> Factory::NewStruct(InstanceType type) {
}
Handle<DeclaredAccessorDescriptor> Factory::NewDeclaredAccessorDescriptor() {
return Handle<DeclaredAccessorDescriptor>::cast(
NewStruct(DECLARED_ACCESSOR_DESCRIPTOR_TYPE));
}
Handle<DeclaredAccessorInfo> Factory::NewDeclaredAccessorInfo() {
Handle<DeclaredAccessorInfo> info =
Handle<DeclaredAccessorInfo>::cast(
......
......@@ -205,6 +205,8 @@ class Factory {
// the old generation).
Handle<Struct> NewStruct(InstanceType type);
Handle<DeclaredAccessorDescriptor> NewDeclaredAccessorDescriptor();
Handle<DeclaredAccessorInfo> NewDeclaredAccessorInfo();
Handle<ExecutableAccessorInfo> NewExecutableAccessorInfo();
......
......@@ -744,7 +744,7 @@ void ExecutableAccessorInfo::ExecutableAccessorInfoVerify() {
void DeclaredAccessorDescriptor::DeclaredAccessorDescriptorVerify() {
CHECK(IsDeclaredAccessorDescriptor());
VerifySmiField(kInternalFieldOffset);
VerifyPointer(serialized_data());
}
......
......@@ -4178,7 +4178,8 @@ ACCESSORS_TO_SMI(AccessorInfo, flag, kFlagOffset)
ACCESSORS(AccessorInfo, expected_receiver_type, Object,
kExpectedReceiverTypeOffset)
ACCESSORS(DeclaredAccessorDescriptor, internal_field, Smi, kInternalFieldOffset)
ACCESSORS(DeclaredAccessorDescriptor, serialized_data, ByteArray,
kSerializedDataOffset)
ACCESSORS(DeclaredAccessorInfo, descriptor, DeclaredAccessorDescriptor,
kDescriptorOffset)
......
......@@ -929,7 +929,7 @@ void DeclaredAccessorInfo::DeclaredAccessorInfoPrint(FILE* out) {
void DeclaredAccessorDescriptor::DeclaredAccessorDescriptorPrint(FILE* out) {
HeapObject::PrintHeader(out, "DeclaredAccessorDescriptor");
PrintF(out, "\n - internal field: ");
internal_field()->ShortPrint(out);
serialized_data()->ShortPrint(out);
}
......
......@@ -165,6 +165,146 @@ MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
}
template<typename To>
static inline To* CheckedCast(void *from) {
uintptr_t temp = reinterpret_cast<uintptr_t>(from);
ASSERT(temp % sizeof(To) == 0);
return reinterpret_cast<To*>(temp);
}
static MaybeObject* PerformCompare(const BitmaskCompareDescriptor& descriptor,
char* ptr,
Heap* heap) {
uint32_t bitmask = descriptor.bitmask;
uint32_t compare_value = descriptor.compare_value;
uint32_t value;
switch (descriptor.size) {
case 1:
value = static_cast<uint32_t>(*CheckedCast<uint8_t>(ptr));
compare_value &= 0xff;
bitmask &= 0xff;
break;
case 2:
value = static_cast<uint32_t>(*CheckedCast<uint16_t>(ptr));
compare_value &= 0xffff;
bitmask &= 0xffff;
break;
case 4:
value = *CheckedCast<uint32_t>(ptr);
break;
default:
UNREACHABLE();
return NULL;
}
return heap->ToBoolean((bitmask & value) == (bitmask & compare_value));
}
static MaybeObject* PerformCompare(const PointerCompareDescriptor& descriptor,
char* ptr,
Heap* heap) {
uintptr_t compare_value =
reinterpret_cast<uintptr_t>(descriptor.compare_value);
uintptr_t value = *CheckedCast<uintptr_t>(ptr);
return heap->ToBoolean(compare_value == value);
}
static MaybeObject* GetPrimitiveValue(
const PrimitiveValueDescriptor& descriptor,
char* ptr,
Heap* heap) {
int32_t int32_value;
switch (descriptor.data_type) {
case kDescriptorInt8Type:
int32_value = *CheckedCast<int8_t>(ptr);
break;
case kDescriptorUint8Type:
int32_value = *CheckedCast<uint8_t>(ptr);
break;
case kDescriptorInt16Type:
int32_value = *CheckedCast<int16_t>(ptr);
break;
case kDescriptorUint16Type:
int32_value = *CheckedCast<uint16_t>(ptr);
break;
case kDescriptorInt32Type:
int32_value = *CheckedCast<int32_t>(ptr);
break;
case kDescriptorUint32Type: {
uint32_t value = *CheckedCast<uint32_t>(ptr);
return heap->NumberFromUint32(value);
}
case kDescriptorBoolType: {
uint8_t byte = *CheckedCast<uint8_t>(ptr);
return heap->ToBoolean(byte & (0x1 << descriptor.bool_offset));
}
case kDescriptorFloatType: {
float value = *CheckedCast<float>(ptr);
return heap->NumberFromDouble(value);
}
case kDescriptorDoubleType: {
double value = *CheckedCast<double>(ptr);
return heap->NumberFromDouble(value);
}
}
return heap->NumberFromInt32(int32_value);
}
static MaybeObject* GetDeclaredAccessorProperty(Object* receiver,
DeclaredAccessorInfo* info,
Isolate* isolate) {
char* current = reinterpret_cast<char*>(receiver);
DeclaredAccessorDescriptorIterator iterator(info->descriptor());
while (true) {
const DeclaredAccessorDescriptorData* data = iterator.Next();
switch (data->type) {
case kDescriptorReturnObject: {
ASSERT(iterator.Complete());
current = *CheckedCast<char*>(current);
return *CheckedCast<Object*>(current);
}
case kDescriptorPointerDereference:
ASSERT(!iterator.Complete());
current = *reinterpret_cast<char**>(current);
break;
case kDescriptorPointerShift:
ASSERT(!iterator.Complete());
current += data->pointer_shift_descriptor.byte_offset;
break;
case kDescriptorObjectDereference: {
ASSERT(!iterator.Complete());
Object* object = CheckedCast<Object>(current);
int field = data->object_dereference_descriptor.internal_field;
Object* smi = JSObject::cast(object)->GetInternalField(field);
ASSERT(smi->IsSmi());
current = reinterpret_cast<char*>(smi);
break;
}
case kDescriptorBitmaskCompare:
ASSERT(iterator.Complete());
return PerformCompare(data->bitmask_compare_descriptor,
current,
isolate->heap());
case kDescriptorPointerCompare:
ASSERT(iterator.Complete());
return PerformCompare(data->pointer_compare_descriptor,
current,
isolate->heap());
case kDescriptorPrimitiveValue:
ASSERT(iterator.Complete());
return GetPrimitiveValue(data->primitive_value_descriptor,
current,
isolate->heap());
}
}
UNREACHABLE();
return NULL;
}
MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
Object* structure,
Name* name) {
......@@ -182,9 +322,8 @@ MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
}
// api style callbacks.
if (structure->IsExecutableAccessorInfo()) {
ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(structure);
if (!data->IsCompatibleReceiver(receiver)) {
if (structure->IsAccessorInfo()) {
if (!AccessorInfo::cast(structure)->IsCompatibleReceiver(receiver)) {
Handle<Object> name_handle(name, isolate);
Handle<Object> receiver_handle(receiver, isolate);
Handle<Object> args[2] = { name_handle, receiver_handle };
......@@ -197,6 +336,12 @@ MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
// TODO(rossberg): Handling symbols in the API requires changing the API,
// so we do not support it for now.
if (name->IsSymbol()) return isolate->heap()->undefined_value();
if (structure->IsDeclaredAccessorInfo()) {
return GetDeclaredAccessorProperty(receiver,
DeclaredAccessorInfo::cast(structure),
isolate);
}
ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(structure);
Object* fun_obj = data->getter();
v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
if (call_fun == NULL) return isolate->heap()->undefined_value();
......@@ -232,11 +377,6 @@ MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
return isolate->heap()->undefined_value();
}
// TODO(dcarney): Handle correctly.
if (structure->IsDeclaredAccessorInfo()) {
return isolate->heap()->undefined_value();
}
UNREACHABLE();
return NULL;
}
......@@ -9941,8 +10081,9 @@ MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
}
if (structure->IsDeclaredAccessorInfo()) {
// TODO(dcarney): Handle correctly.
return isolate->heap()->undefined_value();
return GetDeclaredAccessorProperty(receiver,
DeclaredAccessorInfo::cast(structure),
isolate);
}
UNREACHABLE();
......@@ -13724,6 +13865,58 @@ void ObjectHashTable::RemoveEntry(int entry) {
}
DeclaredAccessorDescriptorIterator::DeclaredAccessorDescriptorIterator(
DeclaredAccessorDescriptor* descriptor)
: array_(descriptor->serialized_data()->GetDataStartAddress()),
length_(descriptor->serialized_data()->length()),
offset_(0) {
}
const DeclaredAccessorDescriptorData*
DeclaredAccessorDescriptorIterator::Next() {
ASSERT(offset_ < length_);
uint8_t* ptr = &array_[offset_];
ASSERT(reinterpret_cast<uintptr_t>(ptr) % sizeof(uintptr_t) == 0);
const DeclaredAccessorDescriptorData* data =
reinterpret_cast<const DeclaredAccessorDescriptorData*>(ptr);
offset_ += sizeof(*data);
ASSERT(offset_ <= length_);
return data;
}
Handle<DeclaredAccessorDescriptor> DeclaredAccessorDescriptor::Create(
Isolate* isolate,
const DeclaredAccessorDescriptorData& descriptor,
Handle<DeclaredAccessorDescriptor> previous) {
int previous_length =
previous.is_null() ? 0 : previous->serialized_data()->length();
int length = sizeof(descriptor) + previous_length;
Handle<ByteArray> serialized_descriptor =
isolate->factory()->NewByteArray(length);
Handle<DeclaredAccessorDescriptor> value =
isolate->factory()->NewDeclaredAccessorDescriptor();
value->set_serialized_data(*serialized_descriptor);
// Copy in the data.
{
AssertNoAllocation no_allocation;
uint8_t* array = serialized_descriptor->GetDataStartAddress();
if (previous_length != 0) {
uint8_t* previous_array =
previous->serialized_data()->GetDataStartAddress();
memcpy(array, previous_array, previous_length);
array += previous_length;
}
ASSERT(reinterpret_cast<uintptr_t>(array) % sizeof(uintptr_t) == 0);
DeclaredAccessorDescriptorData* data =
reinterpret_cast<DeclaredAccessorDescriptorData*>(array);
*data = descriptor;
}
return value;
}
#ifdef ENABLE_DEBUGGER_SUPPORT
// Check if there is a break point at this code position.
bool DebugInfo::HasBreakPoint(int code_position) {
......
......@@ -8603,19 +8603,91 @@ class AccessorInfo: public Struct {
};
enum AccessorDescriptorType {
kDescriptorBitmaskCompare,
kDescriptorPointerCompare,
kDescriptorPrimitiveValue,
kDescriptorObjectDereference,
kDescriptorPointerDereference,
kDescriptorPointerShift,
kDescriptorReturnObject
};
struct BitmaskCompareDescriptor {
uint32_t bitmask;
uint32_t compare_value;
uint8_t size; // Must be in {1,2,4}.
};
struct PointerCompareDescriptor {
void* compare_value;
};
struct PrimitiveValueDescriptor {
v8::DeclaredAccessorDescriptorDataType data_type;
uint8_t bool_offset; // Must be in [0,7], used for kDescriptorBoolType.
};
struct ObjectDerefenceDescriptor {
uint8_t internal_field;
};
struct PointerShiftDescriptor {
int16_t byte_offset;
};
struct DeclaredAccessorDescriptorData {
AccessorDescriptorType type;
union {
struct BitmaskCompareDescriptor bitmask_compare_descriptor;
struct PointerCompareDescriptor pointer_compare_descriptor;
struct PrimitiveValueDescriptor primitive_value_descriptor;
struct ObjectDerefenceDescriptor object_dereference_descriptor;
struct PointerShiftDescriptor pointer_shift_descriptor;
};
};
class DeclaredAccessorDescriptor;
class DeclaredAccessorDescriptorIterator {
public:
explicit DeclaredAccessorDescriptorIterator(
DeclaredAccessorDescriptor* descriptor);
const DeclaredAccessorDescriptorData* Next();
bool Complete() const { return length_ == offset_; }
private:
uint8_t* array_;
const int length_;
int offset_;
DISALLOW_IMPLICIT_CONSTRUCTORS(DeclaredAccessorDescriptorIterator);
};
class DeclaredAccessorDescriptor: public Struct {
public:
// TODO(dcarney): Fill out this class.
DECL_ACCESSORS(internal_field, Smi)
DECL_ACCESSORS(serialized_data, ByteArray)
static inline DeclaredAccessorDescriptor* cast(Object* obj);
static Handle<DeclaredAccessorDescriptor> Create(
Isolate* isolate,
const DeclaredAccessorDescriptorData& data,
Handle<DeclaredAccessorDescriptor> previous);
// Dispatched behavior.
DECLARE_PRINTER(DeclaredAccessorDescriptor)
DECLARE_VERIFIER(DeclaredAccessorDescriptor)
static const int kInternalFieldOffset = HeapObject::kHeaderSize;
static const int kSize = kInternalFieldOffset + kPointerSize;
static const int kSerializedDataOffset = HeapObject::kHeaderSize;
static const int kSize = kSerializedDataOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(DeclaredAccessorDescriptor);
......
......@@ -64,6 +64,7 @@ SOURCES = {
'test-dataflow.cc',
'test-date.cc',
'test-debug.cc',
'test-declarative-accessors.cc',
'test-decls.cc',
'test-deoptimization.cc',
'test-dictionary.cc',
......
......@@ -59,6 +59,7 @@
'test-dataflow.cc',
'test-date.cc',
'test-debug.cc',
'test-declarative-accessors.cc',
'test-decls.cc',
'test-deoptimization.cc',
'test-dictionary.cc',
......
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h>
#include "v8.h"
#include "cctest.h"
using namespace v8::internal;
class HandleArray : public Malloced {
public:
static const unsigned kArraySize = 200;
explicit HandleArray() {}
~HandleArray() { Reset(v8::Isolate::GetCurrent()); }
void Reset(v8::Isolate* isolate) {
for (unsigned i = 0; i < kArraySize; i++) {
if (handles_[i].IsEmpty()) continue;
handles_[i].Dispose(isolate);
handles_[i].Clear();
}
}
v8::Persistent<v8::Value> handles_[kArraySize];
private:
DISALLOW_COPY_AND_ASSIGN(HandleArray);
};
// An aligned character array of size 1024.
class AlignedArray : public Malloced {
public:
static const unsigned kArraySize = 1024/sizeof(uint64_t);
AlignedArray() { Reset(); }
void Reset() {
for (unsigned i = 0; i < kArraySize; i++) {
data_[i] = 0;
}
}
template<typename T>
T As() { return reinterpret_cast<T>(data_); }
private:
uint64_t data_[kArraySize];
DISALLOW_COPY_AND_ASSIGN(AlignedArray);
};
class DescriptorTestHelper {
public:
DescriptorTestHelper() :
isolate_(NULL), array_(new AlignedArray), handle_array_(new HandleArray) {
v8::V8::Initialize();
isolate_ = v8::Isolate::GetCurrent();
}
v8::Isolate* isolate_;
// Data objects.
SmartPointer<AlignedArray> array_;
SmartPointer<HandleArray> handle_array_;
private:
DISALLOW_COPY_AND_ASSIGN(DescriptorTestHelper);
};
static v8::Local<v8::ObjectTemplate> CreateConstructor(
v8::Handle<v8::Context> context,
const char* class_name,
int internal_field,
const char* descriptor_name = NULL,
v8::Handle<v8::DeclaredAccessorDescriptor> descriptor =
v8::Handle<v8::DeclaredAccessorDescriptor>()) {
v8::Local<v8::FunctionTemplate> constructor = v8::FunctionTemplate::New();
v8::Local<v8::ObjectTemplate> obj_template = constructor->InstanceTemplate();
// Setup object template.
if (descriptor_name != NULL && !descriptor.IsEmpty()) {
bool added_accessor =
obj_template->SetAccessor(v8_str(descriptor_name), descriptor);
CHECK(added_accessor);
}
obj_template->SetInternalFieldCount((internal_field+1)*2 + 7);
context->Global()->Set(v8_str(class_name), constructor->GetFunction());
return obj_template;
}
static void VerifyRead(v8::Handle<v8::DeclaredAccessorDescriptor> descriptor,
int internal_field,
void* internal_object,
v8::Handle<v8::Value> expected_value) {
v8::HandleScope scope;
LocalContext local_context;
v8::Handle<v8::Context> context = local_context.local();
CreateConstructor(context, "Accessible", internal_field, "x", descriptor);
// Setup object.
CompileRun("var accessible = new Accessible();");
v8::Local<v8::Object> obj(
v8::Object::Cast(*context->Global()->Get(v8_str("accessible"))));
obj->SetAlignedPointerInInternalField(internal_field, internal_object);
bool added_accessor;
added_accessor = obj->SetAccessor(v8_str("y"), descriptor);
CHECK(added_accessor);
added_accessor = obj->SetAccessor(v8_str("13"), descriptor);
CHECK(added_accessor);
// Test access from template getter.
v8::Local<v8::Value> value;
value = CompileRun("accessible.x;");
CHECK_EQ(expected_value, value);
value = CompileRun("accessible['x'];");
CHECK_EQ(expected_value, value);
// Test access from object getter.
value = CompileRun("accessible.y;");
CHECK_EQ(expected_value, value);
value = CompileRun("accessible['y'];");
CHECK_EQ(expected_value, value);
value = CompileRun("accessible[13];");
CHECK_EQ(expected_value, value);
value = CompileRun("accessible['13'];");
CHECK_EQ(expected_value, value);
}
static v8::Handle<v8::Value> Convert(int32_t value, v8::Isolate* isolate) {
return v8::Integer::New(value, isolate);
}
static v8::Handle<v8::Value> Convert(float value, v8::Isolate*) {
return v8::Number::New(value);
}
static v8::Handle<v8::Value> Convert(double value, v8::Isolate*) {
return v8::Number::New(value);
}
typedef v8::ObjectOperationDescriptor OOD;
template<typename T>
static void TestPrimitiveValue(
T value,
v8::DeclaredAccessorDescriptorDataType data_type,
DescriptorTestHelper* helper) {
v8::HandleScope handle_scope;
int index = 17;
int internal_field = 6;
v8::Handle<v8::DeclaredAccessorDescriptor> descriptor =
OOD::NewInternalFieldDereference(helper->isolate_, internal_field)
->NewRawShift(helper->isolate_, index*sizeof(T))
->NewPrimitiveValue(helper->isolate_, data_type, 0);
v8::Handle<v8::Value> expected = Convert(value, helper->isolate_);
helper->array_->Reset();
helper->array_->As<T*>()[index] = value;
VerifyRead(descriptor, internal_field, *helper->array_, expected);
}
TEST(PrimitiveValueRead) {
DescriptorTestHelper helper;
TestPrimitiveValue<int32_t>(203, v8::kDescriptorInt32Type, &helper);
TestPrimitiveValue<float>(23.7f, v8::kDescriptorFloatType, &helper);
TestPrimitiveValue<double>(23.7, v8::kDescriptorDoubleType, &helper);
}
template<typename T>
static void TestBitmaskCompare(T bitmask,
T compare_value,
DescriptorTestHelper* helper) {
v8::HandleScope handle_scope;
int index = 13;
int internal_field = 4;
v8::Handle<v8::RawOperationDescriptor> raw_descriptor =
OOD::NewInternalFieldDereference(helper->isolate_, internal_field)
->NewRawShift(helper->isolate_, index*sizeof(T));
v8::Handle<v8::DeclaredAccessorDescriptor> descriptor;
switch (sizeof(T)) {
case 1:
descriptor =raw_descriptor->NewBitmaskCompare8(
helper->isolate_, bitmask, compare_value);
break;
case 2:
descriptor = raw_descriptor->NewBitmaskCompare16(
helper->isolate_, bitmask, compare_value);
break;
case 4:
descriptor = raw_descriptor->NewBitmaskCompare32(
helper->isolate_, bitmask, compare_value);
break;
default:
CHECK(false);
break;
}
AlignedArray* array = *helper->array_;
array->Reset();
VerifyRead(descriptor, internal_field, array, v8::False(helper->isolate_));
array->As<T*>()[index] = compare_value;
VerifyRead(descriptor, internal_field, array, v8::True(helper->isolate_));
helper->array_->As<T*>()[index] = compare_value & bitmask;
VerifyRead(descriptor, internal_field, array, v8::True(helper->isolate_));
}
TEST(BitmaskCompareRead) {
DescriptorTestHelper helper;
TestBitmaskCompare<uint8_t>(0xf3, 0xa8, &helper);
TestBitmaskCompare<uint16_t>(0xfefe, 0x7d42, &helper);
TestBitmaskCompare<uint32_t>(0xfefeab18, 0x1234fdec, &helper);
}
TEST(PointerCompareRead) {
DescriptorTestHelper helper;
v8::HandleScope handle_scope;
int index = 35;
int internal_field = 3;
void* ptr = helper.isolate_;
v8::Handle<v8::DeclaredAccessorDescriptor> descriptor =
OOD::NewInternalFieldDereference(helper.isolate_, internal_field)
->NewRawShift(helper.isolate_, index*sizeof(ptr))
->NewPointerCompare(helper.isolate_, ptr);
AlignedArray* array = *helper.array_;
VerifyRead(descriptor, internal_field, array, v8::False(helper.isolate_));
array->As<uintptr_t*>()[index] = reinterpret_cast<uintptr_t>(ptr);
VerifyRead(descriptor, internal_field, array, v8::True(helper.isolate_));
}
TEST(PointerDereferenceRead) {
DescriptorTestHelper helper;
v8::HandleScope handle_scope;
int first_index = 13;
int internal_field = 7;
int second_index = 11;
int pointed_to_index = 75;
uint16_t expected = 0x1425;
v8::Handle<v8::DeclaredAccessorDescriptor> descriptor =
OOD::NewInternalFieldDereference(helper.isolate_, internal_field)
->NewRawShift(helper.isolate_, first_index*kPointerSize)
->NewRawDereference(helper.isolate_)
->NewRawShift(helper.isolate_, second_index*sizeof(int16_t))
->NewPrimitiveValue(helper.isolate_, v8::kDescriptorInt16Type, 0);
AlignedArray* array = *helper.array_;
array->As<uintptr_t**>()[first_index] =
&array->As<uintptr_t*>()[pointed_to_index];
VerifyRead(descriptor, internal_field, array, v8::Integer::New(0));
second_index += pointed_to_index*sizeof(uintptr_t)/sizeof(uint16_t);
array->As<uint16_t*>()[second_index] = expected;
VerifyRead(descriptor, internal_field, array, v8::Integer::New(expected));
}
TEST(HandleDereferenceRead) {
DescriptorTestHelper helper;
v8::HandleScope handle_scope;
int index = 13;
int internal_field = 0;
v8::Handle<v8::DeclaredAccessorDescriptor> descriptor =
OOD::NewInternalFieldDereference(helper.isolate_, internal_field)
->NewRawShift(helper.isolate_, index*kPointerSize)
->NewHandleDereference(helper.isolate_);
HandleArray* array = *helper.handle_array_;
v8::Handle<v8::String> expected = v8_str("whatever");
array->handles_[index] = v8::Persistent<v8::Value>::New(expected);
VerifyRead(descriptor, internal_field, array, expected);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment