| Index: test/cctest/test-declarative-accessors.cc
|
| diff --git a/test/cctest/test-declarative-accessors.cc b/test/cctest/test-declarative-accessors.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3bec95744f22b1ddafac705f4896e48554ce0f2d
|
| --- /dev/null
|
| +++ b/test/cctest/test-declarative-accessors.cc
|
| @@ -0,0 +1,405 @@
|
| +// 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;
|
| +
|
| +
|
| +template<typename Type>
|
| +struct Checker {
|
| + static void CheckEq(const Type expected, const Type value) {
|
| + CHECK_EQ(static_cast<int64_t>(expected), static_cast<int64_t>(value));
|
| + }
|
| +};
|
| +
|
| +
|
| +template<>
|
| +struct Checker<void*> {
|
| + static void CheckEq(const void* expected, const void* value) {
|
| + CHECK_EQ(expected, value);
|
| + }
|
| +};
|
| +
|
| +
|
| +template<typename Type>
|
| +static void CheckSerialization(const Type expected) {
|
| + using namespace v8;
|
| + uint8_t smi_storage[AccessorDescriptorSerialization<Type>::kArraySize];
|
| + AccessorDescriptorSerialization<Type>::Serialize(expected, smi_storage);
|
| + const Type value =
|
| + AccessorDescriptorSerialization<Type>::Deserialize(smi_storage);
|
| + Checker<Type>::CheckEq(expected, value);
|
| +}
|
| +
|
| +
|
| +template<typename Type>
|
| +static void CheckBounds(Type min, Type max) {
|
| + CheckSerialization<Type>(static_cast<Type>(0));
|
| + CheckSerialization(min);
|
| + CheckSerialization(max);
|
| +}
|
| +
|
| +
|
| +TEST(MemberSerialization) {
|
| + CheckBounds<v8::AccessorDescriptorDataType>(
|
| + static_cast<v8::AccessorDescriptorDataType>(0),
|
| + static_cast<v8::AccessorDescriptorDataType>(INT16_MAX));
|
| + CheckBounds<v8::AccessorDescriptorType>(
|
| + static_cast<v8::AccessorDescriptorType>(0),
|
| + static_cast<v8::AccessorDescriptorType>(INT16_MAX));
|
| + CheckBounds<uint8_t>(0, UINT8_MAX);
|
| + CheckBounds<int8_t>(INT8_MIN, INT8_MAX);
|
| + CheckBounds<uint16_t>(0, INT16_MAX);
|
| + CheckBounds<int16_t>(INT16_MIN, INT16_MAX);
|
| + CheckBounds<uint32_t>(0, INT32_MAX);
|
| + CheckBounds<int32_t>(INT32_MIN, INT32_MAX);
|
| + CheckBounds<uint64_t>(0, INT64_MAX);
|
| + CheckBounds<int64_t>(INT64_MIN, INT64_MAX);
|
| + CheckBounds<void*>(reinterpret_cast<void*>(INTPTR_MIN),
|
| + reinterpret_cast<void*>(INTPTR_MAX));
|
| +}
|
| +
|
| +
|
| +TEST(DescriptorSerialization) {
|
| + v8::V8::Initialize();
|
| + v8::HandleScope scope;
|
| + LocalContext context;
|
| + // Create a descriptor.
|
| + v8::AccessorDescriptor accessor_descriptor =
|
| + { 6, -12, v8::kDescriptorPointerDereference, { NULL } };
|
| + v8::AccessorDescriptor sub_descriptor =
|
| + { 7, -11, v8::kDescriptorPointerCompare, { NULL } };
|
| + int arbitrary_value;
|
| + v8::PointerCompareDescriptor pointer_compare_descriptor =
|
| + { &arbitrary_value };
|
| + sub_descriptor.pointer_compare_descriptor = pointer_compare_descriptor;
|
| + accessor_descriptor.derefence_descriptor = &sub_descriptor;
|
| + // Serialize
|
| + uint16_t length;
|
| + uint8_t* storage;
|
| + {
|
| + length = DeclaredAccessorDescriptor::SerializedLength(&accessor_descriptor);
|
| + Handle<DeclaredAccessorDescriptor> descriptor =
|
| + DeclaredAccessorDescriptor::Create(&accessor_descriptor,
|
| + Isolate::Current());
|
| + AssertNoAllocation no_allocation;
|
| + ByteArray* array = descriptor->serialized_descriptor();
|
| + CHECK_EQ(length, array->length());
|
| + storage = new uint8_t[length];
|
| + for (int i = 0; i < length; i++) {
|
| + storage[i] = array->get(i);
|
| + }
|
| + }
|
| + // Deserialize
|
| + AccessorDescriptorDeserializer deserializer(length, storage);
|
| + v8::AccessorDescriptor deserialized;
|
| + deserializer.Next(&deserialized);
|
| + CHECK(!deserializer.Complete());
|
| + CHECK_EQ(6, deserialized.internal_field);
|
| + CHECK_EQ(-12, deserialized.byte_offset);
|
| + CHECK_EQ(v8::kDescriptorPointerDereference, deserialized.type);
|
| + deserializer.Next(&deserialized);
|
| + CHECK(deserializer.Complete());
|
| + CHECK_EQ(7, deserialized.internal_field);
|
| + CHECK_EQ(-11, deserialized.byte_offset);
|
| + CHECK_EQ(v8::kDescriptorPointerCompare, deserialized.type);
|
| + CHECK_EQ(&arbitrary_value,
|
| + deserialized.pointer_compare_descriptor.compare_value);
|
| + delete[] storage;
|
| +}
|
| +
|
| +
|
| +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_fields,
|
| + const char* descriptor_name = NULL,
|
| + const v8::AccessorDescriptor* descriptor = NULL) {
|
| + v8::Local<v8::FunctionTemplate> constructor = v8::FunctionTemplate::New();
|
| + v8::Local<v8::ObjectTemplate> obj_template = constructor->InstanceTemplate();
|
| + // Setup object template.
|
| + if (descriptor_name != NULL && descriptor != NULL) {
|
| + bool added_accessor =
|
| + obj_template->SetAccessor(v8_str(descriptor_name), descriptor);
|
| + CHECK(added_accessor);
|
| + }
|
| + obj_template->SetInternalFieldCount(internal_fields);
|
| + context->Global()->Set(v8_str(class_name), constructor->GetFunction());
|
| + return obj_template;
|
| +}
|
| +
|
| +
|
| +static void VerifyRead(const v8::AccessorDescriptor* descriptor,
|
| + void* internal_object,
|
| + v8::Handle<v8::Value> expected_value,
|
| + v8::Local<v8::Context> context =
|
| + v8::Local<v8::Context>()) {
|
| + v8::HandleScope scope;
|
| + // Generate a context if necessary and retry.
|
| + if (context.IsEmpty()) {
|
| + LocalContext local_context;
|
| + VerifyRead(descriptor,
|
| + internal_object,
|
| + expected_value,
|
| + local_context.local());
|
| + return;
|
| + }
|
| + int internal_field = descriptor->internal_field;
|
| + int total_fields = (internal_field+1)*2 + 7;
|
| + CreateConstructor(context, "Accessible", total_fields, "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);
|
| +}
|
| +
|
| +
|
| +template<typename T>
|
| +static void TestPrimitiveValue(T value,
|
| + v8::AccessorDescriptorDataType data_type,
|
| + DescriptorTestHelper* helper) {
|
| + v8::HandleScope handle_scope;
|
| + int index = 17;
|
| + v8::AccessorDescriptor descriptor =
|
| + { 3, index*sizeof(T), v8::kDescriptorPrimitiveValue, { NULL } };
|
| + v8::PrimitiveValueDescriptor sub_descriptor = { data_type, 0 };
|
| + descriptor.primitive_value_descriptor = sub_descriptor;
|
| + v8::Handle<v8::Value> expected = Convert(value, helper->isolate_);
|
| + helper->array_->Reset();
|
| + helper->array_->As<T*>()[index] = value;
|
| + VerifyRead(&descriptor, *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(uint32_t bitmask,
|
| + uint32_t compare_value,
|
| + DescriptorTestHelper* helper) {
|
| + v8::HandleScope handle_scope;
|
| + int index = 13;
|
| + v8::AccessorDescriptor descriptor =
|
| + { 3, index*sizeof(T), v8::kDescriptorBitmaskCompare, { NULL } };
|
| + v8::BitmaskCompareDescriptor sub_descriptor =
|
| + { bitmask, compare_value, sizeof(T) };
|
| + descriptor.bitmask_compare_descriptor = sub_descriptor;
|
| + helper->array_->Reset();
|
| + VerifyRead(&descriptor, *helper->array_, v8::False(helper->isolate_));
|
| + helper->array_->As<T*>()[index] = compare_value;
|
| + VerifyRead(&descriptor, *helper->array_, v8::True(helper->isolate_));
|
| + helper->array_->As<T*>()[index] = compare_value & bitmask;
|
| + VerifyRead(&descriptor, *helper->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;
|
| + void* ptr = helper.isolate_;
|
| + int index = 35;
|
| + v8::AccessorDescriptor descriptor =
|
| + { 3, index * sizeof(ptr), v8::kDescriptorPointerCompare, { NULL } };
|
| + v8::PointerCompareDescriptor sub_descriptor = { ptr };
|
| + descriptor.pointer_compare_descriptor = sub_descriptor;
|
| + VerifyRead(&descriptor, *helper.array_, v8::False(helper.isolate_));
|
| + helper.array_->As<uintptr_t*>()[index] = reinterpret_cast<uintptr_t>(ptr);
|
| + VerifyRead(&descriptor, *helper.array_, v8::True(helper.isolate_));
|
| +}
|
| +
|
| +
|
| +TEST(PointerDeferenceRead) {
|
| + DescriptorTestHelper helper;
|
| + v8::HandleScope handle_scope;
|
| + int first_index = 13;
|
| + int pointed_to_index = 75;
|
| + int second_index = 11;
|
| + uint16_t expected = 0x1425;
|
| + v8::AccessorDescriptor descriptor =
|
| + { 3, first_index*kPointerSize, v8::kDescriptorPointerDereference,
|
| + { NULL } };
|
| + v8::AccessorDescriptor sub_descriptor =
|
| + { 0, second_index*sizeof(int16_t), v8::kDescriptorPrimitiveValue,
|
| + { NULL } };
|
| + v8::PrimitiveValueDescriptor sub_sub_descriptor =
|
| + { v8::kDescriptorInt16Type, 0 };
|
| + descriptor.derefence_descriptor = &sub_descriptor;
|
| + sub_descriptor.primitive_value_descriptor = sub_sub_descriptor;
|
| + AlignedArray* array = *helper.array_;
|
| + array->As<uintptr_t**>()[first_index] =
|
| + &array->As<uintptr_t*>()[pointed_to_index];
|
| + VerifyRead(&descriptor, 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, array, v8::Integer::New(expected));
|
| +}
|
| +
|
| +TEST(HandleDeferenceRead) {
|
| + DescriptorTestHelper helper;
|
| + v8::HandleScope handle_scope;
|
| + int first_index = 13;
|
| + int second_index = 11;
|
| + uint16_t expected = 0x1425;
|
| + v8::AccessorDescriptor descriptor =
|
| + { 3, first_index*kPointerSize, v8::kDescriptorInternalFieldDereference,
|
| + { NULL } };
|
| + v8::AccessorDescriptor sub_descriptor =
|
| + { 2, second_index*sizeof(int16_t), v8::kDescriptorPrimitiveValue,
|
| + { NULL } };
|
| + v8::PrimitiveValueDescriptor sub_sub_descriptor =
|
| + { v8::kDescriptorInt16Type, 0 };
|
| + descriptor.derefence_descriptor = &sub_descriptor;
|
| + sub_descriptor.primitive_value_descriptor = sub_sub_descriptor;
|
| + // Setup object.
|
| + LocalContext local_context;
|
| + v8::Local<v8::Context> context = local_context.local();
|
| + v8::Local<v8::Object> object;
|
| + {
|
| + CreateConstructor(context, "SomeObject", 7);
|
| + CompileRun("var some_object = new SomeObject();");
|
| + v8::Local<v8::Object> object(
|
| + v8::Object::Cast(*context->Global()->Get(v8_str("some_object"))));
|
| + object->SetAlignedPointerInInternalField(
|
| + sub_descriptor.internal_field, *helper.array_);
|
| + helper.handle_array_->handles[first_index] =
|
| + v8::Persistent<v8::Value>::New(helper.isolate_, object);
|
| + }
|
| + VerifyRead(&descriptor, *helper.handle_array_, v8::Integer::New(0), context);
|
| + helper.array_->As<uint16_t*>()[second_index] = expected;
|
| + VerifyRead(&descriptor, *helper.handle_array_, v8::Integer::New(expected));
|
| +}
|
| +
|
|
|