| 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..2abf3c2926c434a5ff9c2a41ebc55c9dd026bf37
|
| --- /dev/null
|
| +++ b/test/cctest/test-unboxed-doubles.cc
|
| @@ -0,0 +1,668 @@
|
| +// 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)
|
| +
|
| +
|
| +static double GetDoubleFieldValue(JSObject* obj, FieldIndex field_index) {
|
| + if (obj->IsUnboxedDoubleField(field_index)) {
|
| + return obj->RawFastDoublePropertyAt(field_index);
|
| + } else {
|
| + Object* value = obj->RawFastPropertyAt(field_index);
|
| + DCHECK(value->IsMutableHeapNumber());
|
| + return HeapNumber::cast(value)->value();
|
| + }
|
| +}
|
| +
|
| +
|
| +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, layout_desc->capacity());
|
| +
|
| + 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 = layout_desc->SetTaggedForTesting(i, false);
|
| + CHECK_EQ(false, layout_desc->IsTagged(i));
|
| + layout_desc = layout_desc->SetTaggedForTesting(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, layout_descriptor->capacity());
|
| + 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(layout_descriptor->capacity() > 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 = layout_desc->SetTaggedForTesting(i, false);
|
| + CHECK_EQ(false, layout_desc->IsTagged(i));
|
| + layout_desc = layout_desc->SetTaggedForTesting(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 = Map::CopyInstallDescriptorsForTesting(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));
|
| + CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
|
| + }
|
| + CHECK(isolate->heap()->new_space()->Contains(*obj));
|
| +
|
| + // Trigger GCs so that the newly allocated object moves to old gen.
|
| + 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);
|
| +
|
| + CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
|
| +}
|
| +
|
| +#endif
|
|
|