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.
......
This diff is collapsed.
......@@ -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',
......
This diff is collapsed.
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