class StackTrace;
class StackFrame;
class Isolate;
+class DeclaredAccessorDescriptor;
+class ObjectOperationDescriptor;
+class RawOperationDescriptor;
namespace internal {
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
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,
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.
*
};
+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.
}
+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);
}
-static i::Handle<i::AccessorInfo> MakeAccessorInfo(
- 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));
+static i::Handle<i::AccessorInfo> SetAccessorInfoProperties(
+ i::Handle<i::AccessorInfo> obj,
+ v8::Handle<String> name,
+ v8::AccessControl settings,
+ v8::PropertyAttribute attributes,
+ v8::Handle<AccessorSignature> signature) {
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);
}
-void FunctionTemplate::AddInstancePropertyAccessor(
+static i::Handle<i::AccessorInfo> MakeAccessorInfo(
v8::Handle<String> name,
AccessorGetter getter,
AccessorSetter setter,
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);
}
}
+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,
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,
- signature);
+ 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;
}
}
+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,
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);
}
V(Context, Context) \
V(External, Foreign) \
V(StackTrace, JSArray) \
- V(StackFrame, JSObject)
+ V(StackFrame, JSObject) \
+ V(DeclaredAccessorDescriptor, DeclaredAccessorDescriptor)
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> \
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
}
+Handle<DeclaredAccessorDescriptor> Factory::NewDeclaredAccessorDescriptor() {
+ return Handle<DeclaredAccessorDescriptor>::cast(
+ NewStruct(DECLARED_ACCESSOR_DESCRIPTOR_TYPE));
+}
+
+
Handle<DeclaredAccessorInfo> Factory::NewDeclaredAccessorInfo() {
Handle<DeclaredAccessorInfo> info =
Handle<DeclaredAccessorInfo>::cast(
// the old generation).
Handle<Struct> NewStruct(InstanceType type);
+ Handle<DeclaredAccessorDescriptor> NewDeclaredAccessorDescriptor();
+
Handle<DeclaredAccessorInfo> NewDeclaredAccessorInfo();
Handle<ExecutableAccessorInfo> NewExecutableAccessorInfo();
void DeclaredAccessorDescriptor::DeclaredAccessorDescriptorVerify() {
CHECK(IsDeclaredAccessorDescriptor());
- VerifySmiField(kInternalFieldOffset);
+ VerifyPointer(serialized_data());
}
ACCESSORS(AccessorInfo, expected_receiver_type, Object,
kExpectedReceiverTypeOffset)
-ACCESSORS(DeclaredAccessorDescriptor, internal_field, Smi, kInternalFieldOffset)
+ACCESSORS(DeclaredAccessorDescriptor, serialized_data, ByteArray,
+ kSerializedDataOffset)
ACCESSORS(DeclaredAccessorInfo, descriptor, DeclaredAccessorDescriptor,
kDescriptorOffset)
void DeclaredAccessorDescriptor::DeclaredAccessorDescriptorPrint(FILE* out) {
HeapObject::PrintHeader(out, "DeclaredAccessorDescriptor");
PrintF(out, "\n - internal field: ");
- internal_field()->ShortPrint(out);
+ serialized_data()->ShortPrint(out);
}
}
+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) {
}
// 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 };
// 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();
return isolate->heap()->undefined_value();
}
- // TODO(dcarney): Handle correctly.
- if (structure->IsDeclaredAccessorInfo()) {
- return isolate->heap()->undefined_value();
- }
-
UNREACHABLE();
return NULL;
}
}
if (structure->IsDeclaredAccessorInfo()) {
- // TODO(dcarney): Handle correctly.
- return isolate->heap()->undefined_value();
+ return GetDeclaredAccessorProperty(receiver,
+ DeclaredAccessorInfo::cast(structure),
+ isolate);
}
UNREACHABLE();
}
+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) {
};
+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);
'test-dataflow.cc',
'test-date.cc',
'test-debug.cc',
+ 'test-declarative-accessors.cc',
'test-decls.cc',
'test-deoptimization.cc',
'test-dictionary.cc',
'test-dataflow.cc',
'test-date.cc',
'test-debug.cc',
+ 'test-declarative-accessors.cc',
'test-decls.cc',
'test-deoptimization.cc',
'test-dictionary.cc',
--- /dev/null
+// 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);
+}
+