Chromium Code Reviews| Index: test/cctest/test-unboxed-doubles.cc |
| diff --git a/test/cctest/test-unboxed-doubles.cc b/test/cctest/test-unboxed-doubles.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..9e4b95d5d75536c9e0c81d6a0e7fce55af87c0c4 |
| --- /dev/null |
| +++ b/test/cctest/test-unboxed-doubles.cc |
| @@ -0,0 +1,690 @@ |
| +// Copyright 2014 the V8 project authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include <stdlib.h> |
| +#include <utility> |
| + |
| +#include "src/v8.h" |
| + |
| +#include "src/compilation-cache.h" |
| +#include "src/execution.h" |
| +#include "src/factory.h" |
| +#include "src/global-handles.h" |
| +#include "src/ic/ic.h" |
| +#include "src/macro-assembler.h" |
| +#include "test/cctest/cctest.h" |
| + |
| +using namespace v8::base; |
| +using namespace v8::internal; |
| + |
| +#if (V8_DOUBLE_FIELDS_UNBOXING) |
| + |
| + |
| +namespace v8 { |
| +namespace internal { |
| + |
| +class TestAccessor { |
| + public: |
| + static inline LayoutDescriptor* LayoutDescriptor_SetTagged( |
| + LayoutDescriptor* layout_descriptor, int field_index, bool tagged) { |
| + return layout_descriptor->SetTagged(field_index, tagged); |
| + } |
| + |
| + static inline int LayoutDescriptor_capacity( |
| + LayoutDescriptor* layout_descriptor) { |
| + return layout_descriptor->capacity(); |
| + } |
| + |
| + static inline Handle<Map> Map_CopyInstallDescriptors( |
| + Handle<Map> map, int new_descriptor, Handle<DescriptorArray> descriptors, |
| + Handle<LayoutDescriptor> full_layout_descriptor) { |
| + return Map::CopyInstallDescriptors(map, new_descriptor, descriptors, |
| + full_layout_descriptor); |
| + } |
| +}; |
| +} |
| +} // namespace v8::internal |
| + |
| + |
| +enum PropertyKind { |
| + PROP_CONSTANT, |
| + PROP_SMI, |
| + PROP_DOUBLE, |
| + PROP_TAGGED, |
| + PROP_KIND_NUMBER, |
| +}; |
| + |
| +static Representation representations[PROP_KIND_NUMBER] = { |
| + Representation::None(), Representation::Smi(), Representation::Double(), |
| + Representation::Tagged()}; |
| + |
| + |
| +static Handle<DescriptorArray> CreateDescriptorArray(Isolate* isolate, |
| + PropertyKind* props, |
| + int kPropsCount) { |
| + Factory* factory = isolate->factory(); |
| + |
| + Handle<String> func_name = factory->InternalizeUtf8String("func"); |
| + Handle<JSFunction> func = factory->NewFunction(func_name); |
| + |
| + Handle<DescriptorArray> descriptors = |
| + DescriptorArray::Allocate(isolate, 0, kPropsCount); |
| + |
| + int next_field_offset = 0; |
| + for (int i = 0; i < kPropsCount; i++) { |
| + EmbeddedVector<char, 64> buffer; |
| + SNPrintF(buffer, "prop%d", i); |
| + Handle<String> name = factory->InternalizeUtf8String(buffer.start()); |
| + |
| + PropertyKind kind = props[i]; |
| + |
| + if (kind == PROP_CONSTANT) { |
| + ConstantDescriptor d(name, func, NONE); |
| + descriptors->Append(&d); |
| + |
| + } else { |
| + FieldDescriptor f(name, next_field_offset, NONE, representations[kind]); |
| + next_field_offset += f.GetDetails().field_width_in_words(); |
| + descriptors->Append(&f); |
| + } |
| + } |
| + return descriptors; |
| +} |
| + |
| + |
| +TEST(LayoutDescriptorBasicFast) { |
| + CcTest::InitializeVM(); |
| + v8::HandleScope scope(CcTest::isolate()); |
| + |
| + LayoutDescriptor* layout_desc = LayoutDescriptor::FastPointerLayout(); |
| + |
| + CHECK(!layout_desc->IsSlowLayout()); |
| + CHECK(layout_desc->IsFastPointerLayout()); |
| + CHECK_EQ(kSmiValueSize, TestAccessor::LayoutDescriptor_capacity(layout_desc)); |
| + |
| + for (int i = 0; i < kSmiValueSize + 13; i++) { |
| + CHECK_EQ(true, layout_desc->IsTagged(i)); |
| + } |
| + CHECK_EQ(true, layout_desc->IsTagged(-1)); |
| + CHECK_EQ(true, layout_desc->IsTagged(-12347)); |
| + CHECK_EQ(true, layout_desc->IsTagged(15635)); |
| + CHECK(layout_desc->IsFastPointerLayout()); |
| + |
| + for (int i = 0; i < kSmiValueSize; i++) { |
| + layout_desc = |
| + TestAccessor::LayoutDescriptor_SetTagged(layout_desc, i, false); |
| + CHECK_EQ(false, layout_desc->IsTagged(i)); |
| + layout_desc = |
| + TestAccessor::LayoutDescriptor_SetTagged(layout_desc, i, true); |
| + CHECK_EQ(true, layout_desc->IsTagged(i)); |
| + } |
| + CHECK(layout_desc->IsFastPointerLayout()); |
| +} |
| + |
| + |
| +TEST(LayoutDescriptorBasicSlow) { |
| + CcTest::InitializeVM(); |
| + Isolate* isolate = CcTest::i_isolate(); |
| + v8::HandleScope scope(CcTest::isolate()); |
| + |
| + Handle<LayoutDescriptor> layout_descriptor; |
| + const int kPropsCount = kSmiValueSize * 3; |
| + PropertyKind props[kPropsCount]; |
| + for (int i = 0; i < kPropsCount; i++) { |
| + // All properties tagged. |
| + props[i] = PROP_TAGGED; |
| + } |
| + |
| + { |
| + Handle<DescriptorArray> descriptors = |
| + CreateDescriptorArray(isolate, props, kPropsCount); |
| + |
| + Handle<Map> map = Map::Create(isolate, kPropsCount); |
| + |
| + layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount); |
| + CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor); |
| + CHECK_EQ(kSmiValueSize, |
| + TestAccessor::LayoutDescriptor_capacity(*layout_descriptor)); |
| + map->InitializeDescriptors(*descriptors, *layout_descriptor); |
| + DCHECK(layout_descriptor->IsConsistentWithMap(*map)); |
| + } |
| + |
| + props[0] = PROP_DOUBLE; |
| + props[kPropsCount - 1] = PROP_DOUBLE; |
| + |
| + Handle<DescriptorArray> descriptors = |
| + CreateDescriptorArray(isolate, props, kPropsCount); |
| + |
| + { |
| + int inobject_properties = kPropsCount - 1; |
| + Handle<Map> map = Map::Create(isolate, inobject_properties); |
| + |
| + // Should be fast as the only double property is the first one. |
| + layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount); |
| + CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + CHECK(!layout_descriptor->IsFastPointerLayout()); |
| + |
| + CHECK_EQ(false, layout_descriptor->IsTagged(0)); |
| + for (int i = 1; i < kPropsCount; i++) { |
| + CHECK_EQ(true, layout_descriptor->IsTagged(i)); |
| + } |
| + map->InitializeDescriptors(*descriptors, *layout_descriptor); |
| + DCHECK(layout_descriptor->IsConsistentWithMap(*map)); |
| + } |
| + |
| + { |
| + int inobject_properties = kPropsCount; |
| + Handle<Map> map = Map::Create(isolate, inobject_properties); |
| + |
| + layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount); |
| + CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor); |
| + CHECK(layout_descriptor->IsSlowLayout()); |
| + CHECK(!layout_descriptor->IsFastPointerLayout()); |
| + CHECK(TestAccessor::LayoutDescriptor_capacity(*layout_descriptor) > |
| + kSmiValueSize); |
| + |
| + CHECK_EQ(false, layout_descriptor->IsTagged(0)); |
| + CHECK_EQ(false, layout_descriptor->IsTagged(kPropsCount - 1)); |
| + for (int i = 1; i < kPropsCount - 1; i++) { |
| + CHECK_EQ(true, layout_descriptor->IsTagged(i)); |
| + } |
| + |
| + map->InitializeDescriptors(*descriptors, *layout_descriptor); |
| + DCHECK(layout_descriptor->IsConsistentWithMap(*map)); |
| + |
| + // Here we have truly slow layout descriptor, so play with the bits. |
| + CHECK_EQ(true, layout_descriptor->IsTagged(-1)); |
| + CHECK_EQ(true, layout_descriptor->IsTagged(-12347)); |
| + CHECK_EQ(true, layout_descriptor->IsTagged(15635)); |
| + |
| + LayoutDescriptor* layout_desc = *layout_descriptor; |
| + // Play with the bits but leave it in consistent state with map at the end. |
| + for (int i = 1; i < kPropsCount - 1; i++) { |
| + layout_desc = |
| + TestAccessor::LayoutDescriptor_SetTagged(layout_desc, i, false); |
| + CHECK_EQ(false, layout_desc->IsTagged(i)); |
| + layout_desc = |
| + TestAccessor::LayoutDescriptor_SetTagged(layout_desc, i, true); |
| + CHECK_EQ(true, layout_desc->IsTagged(i)); |
| + } |
| + CHECK(layout_desc->IsSlowLayout()); |
| + CHECK(!layout_desc->IsFastPointerLayout()); |
| + |
| + DCHECK(layout_descriptor->IsConsistentWithMap(*map)); |
| + } |
| +} |
| + |
| + |
| +TEST(LayoutDescriptorCreateNewFast) { |
| + CcTest::InitializeVM(); |
| + Isolate* isolate = CcTest::i_isolate(); |
| + v8::HandleScope scope(CcTest::isolate()); |
| + |
| + Handle<LayoutDescriptor> layout_descriptor; |
| + PropertyKind props[] = { |
| + PROP_CONSTANT, |
| + PROP_TAGGED, // field #0 |
| + PROP_CONSTANT, |
| + PROP_DOUBLE, // field #1 |
| + PROP_CONSTANT, |
| + PROP_TAGGED, // field #2 |
| + PROP_CONSTANT, |
| + }; |
| + const int kPropsCount = arraysize(props); |
| + |
| + Handle<DescriptorArray> descriptors = |
| + CreateDescriptorArray(isolate, props, kPropsCount); |
| + |
| + { |
| + Handle<Map> map = Map::Create(isolate, 0); |
| + layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount); |
| + CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor); |
| + map->InitializeDescriptors(*descriptors, *layout_descriptor); |
| + DCHECK(layout_descriptor->IsConsistentWithMap(*map)); |
| + } |
| + |
| + { |
| + Handle<Map> map = Map::Create(isolate, 1); |
| + layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount); |
| + CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor); |
| + map->InitializeDescriptors(*descriptors, *layout_descriptor); |
| + DCHECK(layout_descriptor->IsConsistentWithMap(*map)); |
| + } |
| + |
| + { |
| + Handle<Map> map = Map::Create(isolate, 2); |
| + layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount); |
| + CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + CHECK_EQ(true, layout_descriptor->IsTagged(0)); |
| + CHECK_EQ(false, layout_descriptor->IsTagged(1)); |
| + CHECK_EQ(true, layout_descriptor->IsTagged(2)); |
| + CHECK_EQ(true, layout_descriptor->IsTagged(125)); |
| + map->InitializeDescriptors(*descriptors, *layout_descriptor); |
| + DCHECK(layout_descriptor->IsConsistentWithMap(*map)); |
| + } |
| +} |
| + |
| + |
| +TEST(LayoutDescriptorCreateNewSlow) { |
| + CcTest::InitializeVM(); |
| + Isolate* isolate = CcTest::i_isolate(); |
| + v8::HandleScope scope(CcTest::isolate()); |
| + |
| + Handle<LayoutDescriptor> layout_descriptor; |
| + const int kPropsCount = kSmiValueSize * 3; |
| + PropertyKind props[kPropsCount]; |
| + for (int i = 0; i < kPropsCount; i++) { |
| + props[i] = static_cast<PropertyKind>(i % PROP_KIND_NUMBER); |
| + } |
| + |
| + Handle<DescriptorArray> descriptors = |
| + CreateDescriptorArray(isolate, props, kPropsCount); |
| + |
| + { |
| + Handle<Map> map = Map::Create(isolate, 0); |
| + layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount); |
| + CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor); |
| + map->InitializeDescriptors(*descriptors, *layout_descriptor); |
| + DCHECK(layout_descriptor->IsConsistentWithMap(*map)); |
| + } |
| + |
| + { |
| + Handle<Map> map = Map::Create(isolate, 1); |
| + layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount); |
| + CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor); |
| + map->InitializeDescriptors(*descriptors, *layout_descriptor); |
| + DCHECK(layout_descriptor->IsConsistentWithMap(*map)); |
| + } |
| + |
| + { |
| + Handle<Map> map = Map::Create(isolate, 2); |
| + layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount); |
| + CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + CHECK_EQ(true, layout_descriptor->IsTagged(0)); |
| + CHECK_EQ(false, layout_descriptor->IsTagged(1)); |
| + CHECK_EQ(true, layout_descriptor->IsTagged(2)); |
| + CHECK_EQ(true, layout_descriptor->IsTagged(125)); |
| + map->InitializeDescriptors(*descriptors, *layout_descriptor); |
| + DCHECK(layout_descriptor->IsConsistentWithMap(*map)); |
| + } |
| + |
| + { |
| + int inobject_properties = kPropsCount / 2; |
| + Handle<Map> map = Map::Create(isolate, inobject_properties); |
| + layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount); |
| + CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor); |
| + CHECK(layout_descriptor->IsSlowLayout()); |
| + for (int i = 0; i < inobject_properties; i++) { |
| + // PROP_DOUBLE has index 1 among FIELD properties. |
| + const bool tagged = (i % (PROP_KIND_NUMBER - 1)) != 1; |
| + CHECK_EQ(tagged, layout_descriptor->IsTagged(i)); |
| + } |
| + // Every property after inobject_properties must be tagged. |
| + for (int i = inobject_properties; i < kPropsCount; i++) { |
| + CHECK_EQ(true, layout_descriptor->IsTagged(i)); |
| + } |
| + map->InitializeDescriptors(*descriptors, *layout_descriptor); |
| + DCHECK(layout_descriptor->IsConsistentWithMap(*map)); |
| + |
| + // Now test LayoutDescriptor::cast_gc_safe(). |
| + Handle<LayoutDescriptor> layout_descriptor_copy = |
| + LayoutDescriptor::New(map, descriptors, kPropsCount); |
| + |
| + LayoutDescriptor* layout_desc = *layout_descriptor; |
| + CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc)); |
| + CHECK_EQ(layout_desc, LayoutDescriptor::cast_gc_safe(layout_desc)); |
| + CHECK(layout_descriptor->IsFixedTypedArrayBase()); |
| + // Now make it look like a forwarding pointer to layout_descriptor_copy. |
| + MapWord map_word = layout_desc->map_word(); |
| + CHECK(!map_word.IsForwardingAddress()); |
| + layout_desc->set_map_word( |
| + MapWord::FromForwardingAddress(*layout_descriptor_copy)); |
| + CHECK(layout_desc->map_word().IsForwardingAddress()); |
| + CHECK_EQ(*layout_descriptor_copy, |
| + LayoutDescriptor::cast_gc_safe(layout_desc)); |
| + |
| + // Restore it back. |
| + layout_desc->set_map_word(map_word); |
| + CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc)); |
| + } |
| +} |
| + |
| + |
| +static Handle<LayoutDescriptor> TestLayoutDescriptorAppend( |
| + Isolate* isolate, int inobject_properties, PropertyKind* props, |
| + int kPropsCount) { |
| + Factory* factory = isolate->factory(); |
| + |
| + Handle<String> func_name = factory->InternalizeUtf8String("func"); |
| + Handle<JSFunction> func = factory->NewFunction(func_name); |
| + |
| + Handle<DescriptorArray> descriptors = |
| + DescriptorArray::Allocate(isolate, 0, kPropsCount); |
| + |
| + Handle<Map> map = Map::Create(isolate, inobject_properties); |
| + map->InitializeDescriptors(*descriptors, |
| + LayoutDescriptor::FastPointerLayout()); |
| + |
| + int next_field_offset = 0; |
| + for (int i = 0; i < kPropsCount; i++) { |
| + EmbeddedVector<char, 64> buffer; |
| + SNPrintF(buffer, "prop%d", i); |
| + Handle<String> name = factory->InternalizeUtf8String(buffer.start()); |
| + |
| + Handle<LayoutDescriptor> layout_descriptor; |
| + PropertyKind kind = props[i]; |
| + if (kind == PROP_CONSTANT) { |
| + ConstantDescriptor d(name, func, NONE); |
| + layout_descriptor = LayoutDescriptor::Append(map, d.GetDetails()); |
| + descriptors->Append(&d); |
| + |
| + } else { |
| + FieldDescriptor f(name, next_field_offset, NONE, representations[kind]); |
| + int field_width_in_words = f.GetDetails().field_width_in_words(); |
| + next_field_offset += field_width_in_words; |
| + layout_descriptor = LayoutDescriptor::Append(map, f.GetDetails()); |
| + descriptors->Append(&f); |
| + |
| + int field_index = f.GetDetails().field_index(); |
| + bool is_inobject = field_index < map->inobject_properties(); |
| + for (int bit = 0; bit < field_width_in_words; bit++) { |
| + CHECK_EQ(is_inobject && (kind == PROP_DOUBLE), |
| + !layout_descriptor->IsTagged(field_index + bit)); |
| + } |
| + CHECK(layout_descriptor->IsTagged(next_field_offset)); |
| + } |
| + map->InitializeDescriptors(*descriptors, *layout_descriptor); |
| + } |
| + Handle<LayoutDescriptor> layout_descriptor(map->layout_descriptor(), isolate); |
| + DCHECK(layout_descriptor->IsConsistentWithMap(*map)); |
| + return layout_descriptor; |
| +} |
| + |
| + |
| +TEST(LayoutDescriptorAppend) { |
| + CcTest::InitializeVM(); |
| + Isolate* isolate = CcTest::i_isolate(); |
| + v8::HandleScope scope(CcTest::isolate()); |
| + |
| + Handle<LayoutDescriptor> layout_descriptor; |
| + const int kPropsCount = kSmiValueSize * 3; |
| + PropertyKind props[kPropsCount]; |
| + for (int i = 0; i < kPropsCount; i++) { |
| + props[i] = static_cast<PropertyKind>(i % PROP_KIND_NUMBER); |
| + } |
| + |
| + layout_descriptor = |
| + TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = |
| + TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = |
| + TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2, |
| + props, kPropsCount); |
| + CHECK(layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = |
| + TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount); |
| + CHECK(layout_descriptor->IsSlowLayout()); |
| +} |
| + |
| + |
| +TEST(LayoutDescriptorAppendAllDoubles) { |
| + CcTest::InitializeVM(); |
| + Isolate* isolate = CcTest::i_isolate(); |
| + v8::HandleScope scope(CcTest::isolate()); |
| + |
| + Handle<LayoutDescriptor> layout_descriptor; |
| + const int kPropsCount = kSmiValueSize * 3; |
| + PropertyKind props[kPropsCount]; |
| + for (int i = 0; i < kPropsCount; i++) { |
| + props[i] = PROP_DOUBLE; |
| + } |
| + |
| + layout_descriptor = |
| + TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = |
| + TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = |
| + TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize + 1, |
| + props, kPropsCount); |
| + CHECK(layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2, |
| + props, kPropsCount); |
| + CHECK(layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = |
| + TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount); |
| + CHECK(layout_descriptor->IsSlowLayout()); |
| + |
| + { |
| + // Ensure layout descriptor switches into slow mode at the right moment. |
| + layout_descriptor = |
| + TestLayoutDescriptorAppend(isolate, kPropsCount, props, kSmiValueSize); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = TestLayoutDescriptorAppend(isolate, kPropsCount, props, |
| + kSmiValueSize + 1); |
| + CHECK(layout_descriptor->IsSlowLayout()); |
| + } |
| +} |
| + |
| + |
| +static Handle<LayoutDescriptor> TestLayoutDescriptorAppendIfFastOrUseFull( |
| + Isolate* isolate, int inobject_properties, |
| + Handle<DescriptorArray> descriptors, int number_of_descriptors) { |
| + Handle<Map> map = Map::Create(isolate, inobject_properties); |
| + |
| + Handle<LayoutDescriptor> full_layout_descriptor = LayoutDescriptor::New( |
| + map, descriptors, descriptors->number_of_descriptors()); |
| + |
| + int nof = 0; |
| + bool switched_to_slow_mode = false; |
| + |
| + for (int i = 0; i < number_of_descriptors; i++) { |
| + PropertyDetails details = descriptors->GetDetails(i); |
| + |
| + // This method calls LayoutDescriptor::AppendIfFastOrUseFull() internally |
| + // and does all the required map-descriptors related book keeping. |
| + map = TestAccessor::Map_CopyInstallDescriptors(map, i, descriptors, |
| + full_layout_descriptor); |
| + |
| + LayoutDescriptor* layout_desc = map->layout_descriptor(); |
| + |
| + if (layout_desc->IsSlowLayout()) { |
| + switched_to_slow_mode = true; |
| + CHECK_EQ(*full_layout_descriptor, layout_desc); |
| + } else { |
| + CHECK(!switched_to_slow_mode); |
| + if (details.type() == FIELD) { |
| + nof++; |
| + int field_index = details.field_index(); |
| + int field_width_in_words = details.field_width_in_words(); |
| + |
| + bool is_inobject = field_index < map->inobject_properties(); |
| + for (int bit = 0; bit < field_width_in_words; bit++) { |
| + CHECK_EQ(is_inobject && details.representation().IsDouble(), |
| + !layout_desc->IsTagged(field_index + bit)); |
| + } |
| + CHECK(layout_desc->IsTagged(field_index + field_width_in_words)); |
| + } |
| + } |
| + DCHECK(map->layout_descriptor()->IsConsistentWithMap(*map)); |
| + } |
| + |
| + Handle<LayoutDescriptor> layout_descriptor = map->GetLayoutDescriptor(); |
| + DCHECK(layout_descriptor->IsConsistentWithMap(*map)); |
| + return layout_descriptor; |
| +} |
| + |
| + |
| +TEST(LayoutDescriptorAppendIfFastOrUseFull) { |
| + CcTest::InitializeVM(); |
| + Isolate* isolate = CcTest::i_isolate(); |
| + v8::HandleScope scope(CcTest::isolate()); |
| + |
| + Handle<LayoutDescriptor> layout_descriptor; |
| + const int kPropsCount = kSmiValueSize * 3; |
| + PropertyKind props[kPropsCount]; |
| + for (int i = 0; i < kPropsCount; i++) { |
| + props[i] = static_cast<PropertyKind>(i % PROP_KIND_NUMBER); |
| + } |
| + Handle<DescriptorArray> descriptors = |
| + CreateDescriptorArray(isolate, props, kPropsCount); |
| + |
| + layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull( |
| + isolate, 0, descriptors, kPropsCount); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull( |
| + isolate, 13, descriptors, kPropsCount); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull( |
| + isolate, kSmiValueSize, descriptors, kPropsCount); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull( |
| + isolate, kSmiValueSize * 2, descriptors, kPropsCount); |
| + CHECK(layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull( |
| + isolate, kPropsCount, descriptors, kPropsCount); |
| + CHECK(layout_descriptor->IsSlowLayout()); |
| +} |
| + |
| + |
| +TEST(LayoutDescriptorAppendIfFastOrUseFullAllDoubles) { |
| + CcTest::InitializeVM(); |
| + Isolate* isolate = CcTest::i_isolate(); |
| + v8::HandleScope scope(CcTest::isolate()); |
| + |
| + Handle<LayoutDescriptor> layout_descriptor; |
| + const int kPropsCount = kSmiValueSize * 3; |
| + PropertyKind props[kPropsCount]; |
| + for (int i = 0; i < kPropsCount; i++) { |
| + props[i] = PROP_DOUBLE; |
| + } |
| + Handle<DescriptorArray> descriptors = |
| + CreateDescriptorArray(isolate, props, kPropsCount); |
| + |
| + layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull( |
| + isolate, 0, descriptors, kPropsCount); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull( |
| + isolate, 13, descriptors, kPropsCount); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull( |
| + isolate, kSmiValueSize, descriptors, kPropsCount); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull( |
| + isolate, kSmiValueSize + 1, descriptors, kPropsCount); |
| + CHECK(layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull( |
| + isolate, kSmiValueSize * 2, descriptors, kPropsCount); |
| + CHECK(layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull( |
| + isolate, kPropsCount, descriptors, kPropsCount); |
| + CHECK(layout_descriptor->IsSlowLayout()); |
| + |
| + { |
| + // Ensure layout descriptor switches into slow mode at the right moment. |
| + layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull( |
| + isolate, kPropsCount, descriptors, kSmiValueSize); |
| + CHECK(!layout_descriptor->IsSlowLayout()); |
| + |
| + layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull( |
| + isolate, kPropsCount, descriptors, kSmiValueSize + 1); |
| + CHECK(layout_descriptor->IsSlowLayout()); |
| + } |
| +} |
| + |
| + |
| +TEST(StoreBufferScanOnScavenge) { |
| + CcTest::InitializeVM(); |
| + Isolate* isolate = CcTest::i_isolate(); |
| + Factory* factory = isolate->factory(); |
| + v8::HandleScope scope(CcTest::isolate()); |
| + |
| + CompileRun( |
| + "function A() {" |
| + " this.x = 42.5;" |
| + " this.o = {};" |
| + "};" |
| + "var o = new A();"); |
| + |
| + Handle<String> obj_name = factory->InternalizeUtf8String("o"); |
| + |
| + Handle<Object> obj_value = |
| + Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked(); |
| + CHECK(obj_value->IsJSObject()); |
| + Handle<JSObject> obj = Handle<JSObject>::cast(obj_value); |
| + |
| + { |
| + // Ensure the object is properly set up. |
| + Map* map = obj->map(); |
| + DescriptorArray* descriptors = map->instance_descriptors(); |
| + CHECK(map->NumberOfOwnDescriptors() == 2); |
| + CHECK(descriptors->GetDetails(0).representation().IsDouble()); |
| + CHECK(descriptors->GetDetails(1).representation().IsHeapObject()); |
| + FieldIndex field_index = FieldIndex::ForDescriptor(map, 0); |
| + CHECK(field_index.is_inobject() && field_index.is_double()); |
| + CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index)); |
| + if (FLAG_unbox_double_fields) { |
| + CHECK_EQ(42.5, obj->RawFastDoublePropertyAt(field_index)); |
| + } |
| + } |
| + CHECK(isolate->heap()->new_space()->Contains(*obj)); |
| + |
| + // Trigger GCs so that the newly allocated object moves to old gen. |
| + SimulateFullSpace(CcTest::heap()->old_pointer_space()); |
|
Hannes Payer (out of office)
2014/11/06 12:29:46
You don't need the SimulateFullSpace call.
Igor Sheludko
2014/11/07 08:03:53
Done.
|
| + CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now |
| + CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now |
| + |
| + CHECK(isolate->heap()->old_pointer_space()->Contains(*obj)); |
| + |
| + // Create temp object in the new space. |
| + Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED); |
| + CHECK(isolate->heap()->new_space()->Contains(*temp)); |
| + |
| + // Construct a double value that looks like a pointer to the new space object |
| + // and store it into the obj. |
| + Address fake_object = reinterpret_cast<Address>(*temp) + kPointerSize; |
| + double boom_value = bit_cast<double>(fake_object); |
| + |
| + FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0); |
| + obj->FastPropertyAtPut(field_index, |
| + *factory->NewHeapNumber(boom_value, MUTABLE)); |
| + |
| + // Enforce scan on scavenge for the obj's page. |
| + MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address()); |
| + chunk->set_scan_on_scavenge(true); |
| + |
| + // Trigger GCs and force evacuation. Should not crash there. |
| + CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); |
|
Hannes Payer (out of office)
2014/11/06 12:29:46
Please verify here that boom_value is still boom_v
Igor Sheludko
2014/11/07 08:03:53
Good point! Done.
|
| +} |
| + |
| +#endif |