LCOV - code coverage report
Current view: top level - test/cctest - test-unboxed-doubles.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 687 690 99.6 %
Date: 2017-10-20 Functions: 42 42 100.0 %

          Line data    Source code
       1             : // Copyright 2014 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include <stdlib.h>
       6             : #include <utility>
       7             : 
       8             : #include "src/v8.h"
       9             : 
      10             : #include "src/accessors.h"
      11             : #include "src/api.h"
      12             : #include "src/compilation-cache.h"
      13             : #include "src/execution.h"
      14             : #include "src/factory.h"
      15             : #include "src/field-type.h"
      16             : #include "src/global-handles.h"
      17             : #include "src/heap/incremental-marking.h"
      18             : #include "src/heap/spaces.h"
      19             : #include "src/ic/ic.h"
      20             : #include "src/layout-descriptor.h"
      21             : #include "src/macro-assembler.h"
      22             : #include "src/objects-inl.h"
      23             : #include "src/property.h"
      24             : #include "test/cctest/cctest.h"
      25             : #include "test/cctest/heap/heap-utils.h"
      26             : 
      27             : namespace v8 {
      28             : namespace internal {
      29             : namespace test_unboxed_doubles {
      30             : 
      31             : #if V8_DOUBLE_FIELDS_UNBOXING
      32             : 
      33             : 
      34             : //
      35             : // Helper functions.
      36             : //
      37             : 
      38             : 
      39         150 : static void InitializeVerifiedMapDescriptors(
      40             :     Map* map, DescriptorArray* descriptors,
      41             :     LayoutDescriptor* layout_descriptor) {
      42         150 :   map->InitializeDescriptors(descriptors, layout_descriptor);
      43         150 :   CHECK(layout_descriptor->IsConsistentWithMap(map, true));
      44         150 : }
      45             : 
      46             : 
      47             : static Handle<String> MakeString(const char* str) {
      48             :   Isolate* isolate = CcTest::i_isolate();
      49             :   Factory* factory = isolate->factory();
      50        1602 :   return factory->InternalizeUtf8String(str);
      51             : }
      52             : 
      53             : 
      54        1578 : static Handle<String> MakeName(const char* str, int suffix) {
      55             :   EmbeddedVector<char, 128> buffer;
      56        1578 :   SNPrintF(buffer, "%s%d", str, suffix);
      57        3156 :   return MakeString(buffer.start());
      58             : }
      59             : 
      60             : 
      61          12 : Handle<JSObject> GetObject(const char* name) {
      62             :   return Handle<JSObject>::cast(
      63             :       v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(
      64             :           CcTest::global()
      65             :               ->Get(v8::Isolate::GetCurrent()->GetCurrentContext(),
      66          36 :                     v8_str(name))
      67          24 :               .ToLocalChecked())));
      68             : }
      69             : 
      70             : 
      71          18 : static double GetDoubleFieldValue(JSObject* obj, FieldIndex field_index) {
      72          18 :   if (obj->IsUnboxedDoubleField(field_index)) {
      73          18 :     return obj->RawFastDoublePropertyAt(field_index);
      74             :   } else {
      75           0 :     Object* value = obj->RawFastPropertyAt(field_index);
      76           0 :     CHECK(value->IsMutableHeapNumber());
      77           0 :     return HeapNumber::cast(value)->value();
      78             :   }
      79             : }
      80             : 
      81          18 : void WriteToField(JSObject* object, int descriptor, Object* value) {
      82             :   DescriptorArray* descriptors = object->map()->instance_descriptors();
      83          18 :   PropertyDetails details = descriptors->GetDetails(descriptor);
      84          18 :   object->WriteToField(descriptor, details, value);
      85          18 : }
      86             : 
      87             : const int kNumberOfBits = 32;
      88             : 
      89             : enum TestPropertyKind {
      90             :   PROP_ACCESSOR_INFO,
      91             :   PROP_SMI,
      92             :   PROP_DOUBLE,
      93             :   PROP_TAGGED,
      94             :   PROP_KIND_NUMBER
      95             : };
      96             : 
      97             : static Representation representations[PROP_KIND_NUMBER] = {
      98             :     Representation::None(), Representation::Smi(), Representation::Double(),
      99       23718 :     Representation::Tagged()};
     100             : 
     101             : 
     102          60 : static Handle<DescriptorArray> CreateDescriptorArray(Isolate* isolate,
     103             :                                                      TestPropertyKind* props,
     104             :                                                      int kPropsCount) {
     105             :   Factory* factory = isolate->factory();
     106             : 
     107             :   Handle<DescriptorArray> descriptors =
     108          60 :       DescriptorArray::Allocate(isolate, 0, kPropsCount);
     109             : 
     110             :   int next_field_offset = 0;
     111        5286 :   for (int i = 0; i < kPropsCount; i++) {
     112             :     EmbeddedVector<char, 64> buffer;
     113        5226 :     SNPrintF(buffer, "prop%d", i);
     114        5226 :     Handle<String> name = factory->InternalizeUtf8String(buffer.start());
     115             : 
     116        5226 :     TestPropertyKind kind = props[i];
     117             : 
     118             :     Descriptor d;
     119        5226 :     if (kind == PROP_ACCESSOR_INFO) {
     120             :       Handle<AccessorInfo> info =
     121         456 :           Accessors::MakeAccessor(isolate, name, nullptr, nullptr, NONE);
     122         456 :       d = Descriptor::AccessorConstant(name, info, NONE);
     123             : 
     124             :     } else {
     125             :       d = Descriptor::DataField(name, next_field_offset, NONE,
     126        9540 :                                 representations[kind]);
     127             :     }
     128        5226 :     descriptors->Append(&d);
     129             :     PropertyDetails details = d.GetDetails();
     130        5226 :     if (details.location() == kField) {
     131        4770 :       next_field_offset += details.field_width_in_words();
     132             :     }
     133             :   }
     134          60 :   return descriptors;
     135             : }
     136             : 
     137             : 
     138       23724 : TEST(LayoutDescriptorBasicFast) {
     139           6 :   CcTest::InitializeVM();
     140           6 :   v8::HandleScope scope(CcTest::isolate());
     141             : 
     142             :   LayoutDescriptor* layout_desc = LayoutDescriptor::FastPointerLayout();
     143             : 
     144             :   CHECK(!layout_desc->IsSlowLayout());
     145             :   CHECK(layout_desc->IsFastPointerLayout());
     146             :   CHECK_EQ(kSmiValueSize, layout_desc->capacity());
     147             : 
     148             :   for (int i = 0; i < kSmiValueSize + 13; i++) {
     149             :     CHECK(layout_desc->IsTagged(i));
     150             :   }
     151             :   CHECK(layout_desc->IsTagged(-1));
     152             :   CHECK(layout_desc->IsTagged(-12347));
     153             :   CHECK(layout_desc->IsTagged(15635));
     154             :   CHECK(layout_desc->IsFastPointerLayout());
     155             : 
     156         192 :   for (int i = 0; i < kSmiValueSize; i++) {
     157         192 :     layout_desc = layout_desc->SetTaggedForTesting(i, false);
     158         192 :     CHECK(!layout_desc->IsTagged(i));
     159         192 :     layout_desc = layout_desc->SetTaggedForTesting(i, true);
     160         192 :     CHECK(layout_desc->IsTagged(i));
     161             :   }
     162           6 :   CHECK(layout_desc->IsFastPointerLayout());
     163             : 
     164             :   int sequence_length;
     165           6 :   CHECK_EQ(true, layout_desc->IsTagged(0, std::numeric_limits<int>::max(),
     166             :                                        &sequence_length));
     167           6 :   CHECK_EQ(std::numeric_limits<int>::max(), sequence_length);
     168             : 
     169           6 :   CHECK(layout_desc->IsTagged(0, 7, &sequence_length));
     170           6 :   CHECK_EQ(7, sequence_length);
     171           6 : }
     172             : 
     173             : 
     174       23724 : TEST(LayoutDescriptorBasicSlow) {
     175           6 :   CcTest::InitializeVM();
     176             :   Isolate* isolate = CcTest::i_isolate();
     177           6 :   v8::HandleScope scope(CcTest::isolate());
     178             : 
     179             :   Handle<LayoutDescriptor> layout_descriptor;
     180             :   const int kPropsCount = kSmiValueSize * 3;
     181             :   TestPropertyKind props[kPropsCount];
     182         582 :   for (int i = 0; i < kPropsCount; i++) {
     183             :     // All properties tagged.
     184         576 :     props[i] = PROP_TAGGED;
     185             :   }
     186             : 
     187             :   {
     188             :     Handle<DescriptorArray> descriptors =
     189           6 :         CreateDescriptorArray(isolate, props, kPropsCount);
     190             : 
     191           6 :     Handle<Map> map = Map::Create(isolate, kPropsCount);
     192             : 
     193           6 :     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
     194           6 :     CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
     195           6 :     CHECK_EQ(kSmiValueSize, layout_descriptor->capacity());
     196           6 :     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
     197             :   }
     198             : 
     199           6 :   props[0] = PROP_DOUBLE;
     200           6 :   props[kPropsCount - 1] = PROP_DOUBLE;
     201             : 
     202             :   Handle<DescriptorArray> descriptors =
     203           6 :       CreateDescriptorArray(isolate, props, kPropsCount);
     204             : 
     205             :   {
     206             :     int inobject_properties = kPropsCount - 1;
     207           6 :     Handle<Map> map = Map::Create(isolate, inobject_properties);
     208             : 
     209             :     // Should be fast as the only double property is the first one.
     210           6 :     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
     211           6 :     CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
     212           6 :     CHECK(!layout_descriptor->IsSlowLayout());
     213           6 :     CHECK(!layout_descriptor->IsFastPointerLayout());
     214             : 
     215           6 :     CHECK(!layout_descriptor->IsTagged(0));
     216         570 :     for (int i = 1; i < kPropsCount; i++) {
     217         570 :       CHECK(layout_descriptor->IsTagged(i));
     218             :     }
     219           6 :     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
     220             :   }
     221             : 
     222             :   {
     223             :     int inobject_properties = kPropsCount;
     224           6 :     Handle<Map> map = Map::Create(isolate, inobject_properties);
     225             : 
     226           6 :     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
     227           6 :     CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
     228           6 :     CHECK(layout_descriptor->IsSlowLayout());
     229           6 :     CHECK(!layout_descriptor->IsFastPointerLayout());
     230           6 :     CHECK_GT(layout_descriptor->capacity(), kSmiValueSize);
     231             : 
     232           6 :     CHECK(!layout_descriptor->IsTagged(0));
     233           6 :     CHECK(!layout_descriptor->IsTagged(kPropsCount - 1));
     234         564 :     for (int i = 1; i < kPropsCount - 1; i++) {
     235         564 :       CHECK(layout_descriptor->IsTagged(i));
     236             :     }
     237             : 
     238           6 :     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
     239             : 
     240             :     // Here we have truly slow layout descriptor, so play with the bits.
     241             :     CHECK(layout_descriptor->IsTagged(-1));
     242             :     CHECK(layout_descriptor->IsTagged(-12347));
     243           6 :     CHECK(layout_descriptor->IsTagged(15635));
     244             : 
     245             :     LayoutDescriptor* layout_desc = *layout_descriptor;
     246             :     // Play with the bits but leave it in consistent state with map at the end.
     247         570 :     for (int i = 1; i < kPropsCount - 1; i++) {
     248         564 :       layout_desc = layout_desc->SetTaggedForTesting(i, false);
     249         564 :       CHECK(!layout_desc->IsTagged(i));
     250         564 :       layout_desc = layout_desc->SetTaggedForTesting(i, true);
     251         564 :       CHECK(layout_desc->IsTagged(i));
     252             :     }
     253           6 :     CHECK(layout_desc->IsSlowLayout());
     254           6 :     CHECK(!layout_desc->IsFastPointerLayout());
     255           6 :     CHECK(layout_descriptor->IsConsistentWithMap(*map, true));
     256           6 :   }
     257           6 : }
     258             : 
     259             : 
     260         258 : static void TestLayoutDescriptorQueries(int layout_descriptor_length,
     261             :                                         int* bit_flip_positions,
     262             :                                         int max_sequence_length) {
     263             :   Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::NewForTesting(
     264         258 :       CcTest::i_isolate(), layout_descriptor_length);
     265             :   layout_descriptor_length = layout_descriptor->capacity();
     266             :   LayoutDescriptor* layout_desc = *layout_descriptor;
     267             : 
     268             :   {
     269             :     // Fill in the layout descriptor.
     270             :     int cur_bit_flip_index = 0;
     271             :     bool tagged = true;
     272      175170 :     for (int i = 0; i < layout_descriptor_length; i++) {
     273      174912 :       if (i == bit_flip_positions[cur_bit_flip_index]) {
     274       26538 :         tagged = !tagged;
     275       26538 :         ++cur_bit_flip_index;
     276       26538 :         CHECK(i < bit_flip_positions[cur_bit_flip_index]);  // check test data
     277             :       }
     278      174912 :       layout_desc = layout_desc->SetTaggedForTesting(i, tagged);
     279             :     }
     280             :   }
     281             : 
     282         258 :   if (layout_desc->IsFastPointerLayout()) {
     283         258 :     return;
     284             :   }
     285             : 
     286             :   {
     287             :     // Check queries.
     288             :     int cur_bit_flip_index = 0;
     289             :     bool tagged = true;
     290      174336 :     for (int i = 0; i < layout_descriptor_length; i++) {
     291      174336 :       if (i == bit_flip_positions[cur_bit_flip_index]) {
     292       26538 :         tagged = !tagged;
     293       26538 :         ++cur_bit_flip_index;
     294             :       }
     295      174336 :       CHECK_EQ(tagged, layout_desc->IsTagged(i));
     296             : 
     297      174336 :       int next_bit_flip_position = bit_flip_positions[cur_bit_flip_index];
     298             :       int expected_sequence_length;
     299      174336 :       if (next_bit_flip_position < layout_desc->capacity()) {
     300       82116 :         expected_sequence_length = next_bit_flip_position - i;
     301             :       } else {
     302             :         expected_sequence_length = tagged ? std::numeric_limits<int>::max()
     303      135078 :                                           : (layout_desc->capacity() - i);
     304             :       }
     305             :       expected_sequence_length =
     306             :           Min(expected_sequence_length, max_sequence_length);
     307             :       int sequence_length;
     308      174336 :       CHECK_EQ(tagged,
     309             :                layout_desc->IsTagged(i, max_sequence_length, &sequence_length));
     310      174336 :       CHECK_GT(sequence_length, 0);
     311             : 
     312      174336 :       CHECK_EQ(expected_sequence_length, sequence_length);
     313             :     }
     314             : 
     315             :     int sequence_length;
     316         240 :     CHECK_EQ(true,
     317             :              layout_desc->IsTagged(layout_descriptor_length,
     318             :                                    max_sequence_length, &sequence_length));
     319         240 :     CHECK_EQ(max_sequence_length, sequence_length);
     320             :   }
     321             : }
     322             : 
     323             : 
     324          18 : static void TestLayoutDescriptorQueriesFast(int max_sequence_length) {
     325             :   {
     326             :     LayoutDescriptor* layout_desc = LayoutDescriptor::FastPointerLayout();
     327             :     int sequence_length;
     328         594 :     for (int i = 0; i < kNumberOfBits; i++) {
     329         576 :       CHECK_EQ(true,
     330             :                layout_desc->IsTagged(i, max_sequence_length, &sequence_length));
     331         576 :       CHECK_GT(sequence_length, 0);
     332         576 :       CHECK_EQ(max_sequence_length, sequence_length);
     333             :     }
     334             :   }
     335             : 
     336             :   {
     337          18 :     int bit_flip_positions[] = {1000};
     338             :     TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
     339          18 :                                 max_sequence_length);
     340             :   }
     341             : 
     342             :   {
     343          18 :     int bit_flip_positions[] = {0, 1000};
     344             :     TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
     345          18 :                                 max_sequence_length);
     346             :   }
     347             : 
     348             :   {
     349             :     int bit_flip_positions[kNumberOfBits + 1];
     350         612 :     for (int i = 0; i <= kNumberOfBits; i++) {
     351         594 :       bit_flip_positions[i] = i;
     352             :     }
     353             :     TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
     354          18 :                                 max_sequence_length);
     355             :   }
     356             : 
     357             :   {
     358          18 :     int bit_flip_positions[] = {3, 7, 8, 10, 15, 21, 30, 1000};
     359             :     TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
     360          18 :                                 max_sequence_length);
     361             :   }
     362             : 
     363             :   {
     364             :     int bit_flip_positions[] = {0,  1,  2,  3,  5,  7,  9,
     365          18 :                                 12, 15, 18, 22, 26, 29, 1000};
     366             :     TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
     367          18 :                                 max_sequence_length);
     368             :   }
     369          18 : }
     370             : 
     371             : 
     372       23724 : TEST(LayoutDescriptorQueriesFastLimited7) {
     373           6 :   CcTest::InitializeVM();
     374           6 :   v8::HandleScope scope(CcTest::isolate());
     375             : 
     376           6 :   TestLayoutDescriptorQueriesFast(7);
     377           6 : }
     378             : 
     379             : 
     380       23724 : TEST(LayoutDescriptorQueriesFastLimited13) {
     381           6 :   CcTest::InitializeVM();
     382           6 :   v8::HandleScope scope(CcTest::isolate());
     383             : 
     384           6 :   TestLayoutDescriptorQueriesFast(13);
     385           6 : }
     386             : 
     387             : 
     388       23724 : TEST(LayoutDescriptorQueriesFastUnlimited) {
     389           6 :   CcTest::InitializeVM();
     390           6 :   v8::HandleScope scope(CcTest::isolate());
     391             : 
     392           6 :   TestLayoutDescriptorQueriesFast(std::numeric_limits<int>::max());
     393           6 : }
     394             : 
     395             : 
     396          24 : static void TestLayoutDescriptorQueriesSlow(int max_sequence_length) {
     397             :   {
     398          24 :     int bit_flip_positions[] = {10000};
     399             :     TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
     400          24 :                                 max_sequence_length);
     401             :   }
     402             : 
     403             :   {
     404          24 :     int bit_flip_positions[] = {0, 10000};
     405             :     TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
     406          24 :                                 max_sequence_length);
     407             :   }
     408             : 
     409             :   {
     410             :     int bit_flip_positions[kMaxNumberOfDescriptors + 1];
     411       24552 :     for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
     412       24528 :       bit_flip_positions[i] = i;
     413             :     }
     414          24 :     bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
     415             :     TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
     416          24 :                                 max_sequence_length);
     417             :   }
     418             : 
     419             :   {
     420             :     int bit_flip_positions[] = {3,  7,  8,  10, 15,  21,   30,
     421          24 :                                 37, 54, 80, 99, 383, 10000};
     422             :     TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
     423          24 :                                 max_sequence_length);
     424             :   }
     425             : 
     426             :   {
     427             :     int bit_flip_positions[] = {0,   10,  20,  30,  50,  70,  90,
     428          24 :                                 120, 150, 180, 220, 260, 290, 10000};
     429             :     TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
     430          24 :                                 max_sequence_length);
     431             :   }
     432             : 
     433             :   {
     434             :     int bit_flip_positions[kMaxNumberOfDescriptors + 1];
     435             :     int cur = 0;
     436       24552 :     for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
     437       24528 :       bit_flip_positions[i] = cur;
     438       24528 :       cur = (cur + 1) * 2;
     439             :     }
     440          24 :     CHECK_LT(cur, 10000);
     441          24 :     bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
     442             :     TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
     443          24 :                                 max_sequence_length);
     444             :   }
     445             : 
     446             :   {
     447             :     int bit_flip_positions[kMaxNumberOfDescriptors + 1];
     448             :     int cur = 3;
     449       24552 :     for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
     450       24528 :       bit_flip_positions[i] = cur;
     451       24528 :       cur = (cur + 1) * 2;
     452             :     }
     453          24 :     CHECK_LT(cur, 10000);
     454          24 :     bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
     455             :     TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
     456          24 :                                 max_sequence_length);
     457             :   }
     458          24 : }
     459             : 
     460             : 
     461       23724 : TEST(LayoutDescriptorQueriesSlowLimited7) {
     462           6 :   CcTest::InitializeVM();
     463           6 :   v8::HandleScope scope(CcTest::isolate());
     464             : 
     465           6 :   TestLayoutDescriptorQueriesSlow(7);
     466           6 : }
     467             : 
     468             : 
     469       23724 : TEST(LayoutDescriptorQueriesSlowLimited13) {
     470           6 :   CcTest::InitializeVM();
     471           6 :   v8::HandleScope scope(CcTest::isolate());
     472             : 
     473           6 :   TestLayoutDescriptorQueriesSlow(13);
     474           6 : }
     475             : 
     476             : 
     477       23724 : TEST(LayoutDescriptorQueriesSlowLimited42) {
     478           6 :   CcTest::InitializeVM();
     479           6 :   v8::HandleScope scope(CcTest::isolate());
     480             : 
     481           6 :   TestLayoutDescriptorQueriesSlow(42);
     482           6 : }
     483             : 
     484             : 
     485       23724 : TEST(LayoutDescriptorQueriesSlowUnlimited) {
     486           6 :   CcTest::InitializeVM();
     487           6 :   v8::HandleScope scope(CcTest::isolate());
     488             : 
     489           6 :   TestLayoutDescriptorQueriesSlow(std::numeric_limits<int>::max());
     490           6 : }
     491             : 
     492             : 
     493       23724 : TEST(LayoutDescriptorCreateNewFast) {
     494           6 :   CcTest::InitializeVM();
     495             :   Isolate* isolate = CcTest::i_isolate();
     496           6 :   v8::HandleScope scope(CcTest::isolate());
     497             : 
     498             :   Handle<LayoutDescriptor> layout_descriptor;
     499             :   TestPropertyKind props[] = {
     500             :       PROP_ACCESSOR_INFO,
     501             :       PROP_TAGGED,  // field #0
     502             :       PROP_ACCESSOR_INFO,
     503             :       PROP_DOUBLE,  // field #1
     504             :       PROP_ACCESSOR_INFO,
     505             :       PROP_TAGGED,  // field #2
     506             :       PROP_ACCESSOR_INFO,
     507           6 :   };
     508             :   const int kPropsCount = arraysize(props);
     509             : 
     510             :   Handle<DescriptorArray> descriptors =
     511           6 :       CreateDescriptorArray(isolate, props, kPropsCount);
     512             : 
     513             :   {
     514           6 :     Handle<Map> map = Map::Create(isolate, 0);
     515           6 :     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
     516           6 :     CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
     517           6 :     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
     518             :   }
     519             : 
     520             :   {
     521           6 :     Handle<Map> map = Map::Create(isolate, 1);
     522           6 :     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
     523           6 :     CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
     524           6 :     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
     525             :   }
     526             : 
     527             :   {
     528           6 :     Handle<Map> map = Map::Create(isolate, 2);
     529           6 :     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
     530           6 :     CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
     531           6 :     CHECK(!layout_descriptor->IsSlowLayout());
     532           6 :     CHECK(layout_descriptor->IsTagged(0));
     533           6 :     CHECK(!layout_descriptor->IsTagged(1));
     534           6 :     CHECK(layout_descriptor->IsTagged(2));
     535           6 :     CHECK(layout_descriptor->IsTagged(125));
     536           6 :     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
     537           6 :   }
     538           6 : }
     539             : 
     540             : 
     541       23724 : TEST(LayoutDescriptorCreateNewSlow) {
     542           6 :   CcTest::InitializeVM();
     543             :   Isolate* isolate = CcTest::i_isolate();
     544           6 :   v8::HandleScope scope(CcTest::isolate());
     545             : 
     546             :   Handle<LayoutDescriptor> layout_descriptor;
     547             :   const int kPropsCount = kSmiValueSize * 3;
     548             :   TestPropertyKind props[kPropsCount];
     549         582 :   for (int i = 0; i < kPropsCount; i++) {
     550         576 :     props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
     551             :   }
     552             : 
     553             :   Handle<DescriptorArray> descriptors =
     554           6 :       CreateDescriptorArray(isolate, props, kPropsCount);
     555             : 
     556             :   {
     557           6 :     Handle<Map> map = Map::Create(isolate, 0);
     558           6 :     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
     559           6 :     CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
     560           6 :     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
     561             :   }
     562             : 
     563             :   {
     564           6 :     Handle<Map> map = Map::Create(isolate, 1);
     565           6 :     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
     566           6 :     CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
     567           6 :     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
     568             :   }
     569             : 
     570             :   {
     571           6 :     Handle<Map> map = Map::Create(isolate, 2);
     572           6 :     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
     573           6 :     CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
     574           6 :     CHECK(!layout_descriptor->IsSlowLayout());
     575           6 :     CHECK(layout_descriptor->IsTagged(0));
     576           6 :     CHECK(!layout_descriptor->IsTagged(1));
     577           6 :     CHECK(layout_descriptor->IsTagged(2));
     578           6 :     CHECK(layout_descriptor->IsTagged(125));
     579           6 :     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
     580             :   }
     581             : 
     582             :   {
     583             :     int inobject_properties = kPropsCount / 2;
     584           6 :     Handle<Map> map = Map::Create(isolate, inobject_properties);
     585           6 :     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
     586           6 :     CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
     587           6 :     CHECK(layout_descriptor->IsSlowLayout());
     588         288 :     for (int i = 0; i < inobject_properties; i++) {
     589             :       // PROP_DOUBLE has index 1 among DATA properties.
     590         288 :       const bool tagged = (i % (PROP_KIND_NUMBER - 1)) != 1;
     591         288 :       CHECK_EQ(tagged, layout_descriptor->IsTagged(i));
     592             :     }
     593             :     // Every property after inobject_properties must be tagged.
     594         288 :     for (int i = inobject_properties; i < kPropsCount; i++) {
     595         288 :       CHECK(layout_descriptor->IsTagged(i));
     596             :     }
     597           6 :     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
     598             : 
     599             :     // Now test LayoutDescriptor::cast_gc_safe().
     600             :     Handle<LayoutDescriptor> layout_descriptor_copy =
     601           6 :         LayoutDescriptor::New(map, descriptors, kPropsCount);
     602             : 
     603             :     LayoutDescriptor* layout_desc = *layout_descriptor;
     604           6 :     CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
     605           6 :     CHECK_EQ(layout_desc, LayoutDescriptor::cast_gc_safe(layout_desc));
     606           6 :     CHECK(layout_desc->IsSlowLayout());
     607             :     // Now make it look like a forwarding pointer to layout_descriptor_copy.
     608             :     MapWord map_word = layout_desc->map_word();
     609           6 :     CHECK(!map_word.IsForwardingAddress());
     610             :     layout_desc->set_map_word(
     611             :         MapWord::FromForwardingAddress(*layout_descriptor_copy));
     612           6 :     CHECK(layout_desc->map_word().IsForwardingAddress());
     613           6 :     CHECK_EQ(layout_desc, LayoutDescriptor::cast_gc_safe(layout_desc));
     614             : 
     615             :     // Restore it back.
     616             :     layout_desc->set_map_word(map_word);
     617           6 :     CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
     618           6 :   }
     619           6 : }
     620             : 
     621             : 
     622          78 : static Handle<LayoutDescriptor> TestLayoutDescriptorAppend(
     623             :     Isolate* isolate, int inobject_properties, TestPropertyKind* props,
     624             :     int kPropsCount) {
     625             :   Factory* factory = isolate->factory();
     626             : 
     627             :   Handle<DescriptorArray> descriptors =
     628          78 :       DescriptorArray::Allocate(isolate, 0, kPropsCount);
     629             : 
     630          78 :   Handle<Map> map = Map::Create(isolate, inobject_properties);
     631             :   map->InitializeDescriptors(*descriptors,
     632          78 :                              LayoutDescriptor::FastPointerLayout());
     633             : 
     634             :   int next_field_offset = 0;
     635        6804 :   for (int i = 0; i < kPropsCount; i++) {
     636             :     EmbeddedVector<char, 64> buffer;
     637        6726 :     SNPrintF(buffer, "prop%d", i);
     638        6726 :     Handle<String> name = factory->InternalizeUtf8String(buffer.start());
     639             : 
     640             :     Handle<LayoutDescriptor> layout_descriptor;
     641        6726 :     TestPropertyKind kind = props[i];
     642             :     Descriptor d;
     643        6726 :     if (kind == PROP_ACCESSOR_INFO) {
     644             :       Handle<AccessorInfo> info =
     645         720 :           Accessors::MakeAccessor(isolate, name, nullptr, nullptr, NONE);
     646         720 :       d = Descriptor::AccessorConstant(name, info, NONE);
     647             : 
     648             :     } else {
     649             :       d = Descriptor::DataField(name, next_field_offset, NONE,
     650       12012 :                                 representations[kind]);
     651             :     }
     652             :     PropertyDetails details = d.GetDetails();
     653        6726 :     layout_descriptor = LayoutDescriptor::ShareAppend(map, details);
     654        6726 :     descriptors->Append(&d);
     655        6726 :     if (details.location() == kField) {
     656             :       int field_width_in_words = details.field_width_in_words();
     657        6006 :       next_field_offset += field_width_in_words;
     658             : 
     659             :       int field_index = details.field_index();
     660        6006 :       bool is_inobject = field_index < map->GetInObjectProperties();
     661       12012 :       for (int bit = 0; bit < field_width_in_words; bit++) {
     662       12012 :         CHECK_EQ(is_inobject && (kind == PROP_DOUBLE),
     663             :                  !layout_descriptor->IsTagged(field_index + bit));
     664             :       }
     665        6006 :       CHECK(layout_descriptor->IsTagged(next_field_offset));
     666             :     }
     667        6726 :     map->InitializeDescriptors(*descriptors, *layout_descriptor);
     668             :   }
     669             :   Handle<LayoutDescriptor> layout_descriptor(map->layout_descriptor(), isolate);
     670          78 :   CHECK(layout_descriptor->IsConsistentWithMap(*map, true));
     671          78 :   return layout_descriptor;
     672             : }
     673             : 
     674             : 
     675       23724 : TEST(LayoutDescriptorAppend) {
     676           6 :   CcTest::InitializeVM();
     677             :   Isolate* isolate = CcTest::i_isolate();
     678           6 :   v8::HandleScope scope(CcTest::isolate());
     679             : 
     680             :   Handle<LayoutDescriptor> layout_descriptor;
     681             :   const int kPropsCount = kSmiValueSize * 3;
     682             :   TestPropertyKind props[kPropsCount];
     683         582 :   for (int i = 0; i < kPropsCount; i++) {
     684         576 :     props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
     685             :   }
     686             : 
     687             :   layout_descriptor =
     688           6 :       TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount);
     689           6 :   CHECK(!layout_descriptor->IsSlowLayout());
     690             : 
     691             :   layout_descriptor =
     692           6 :       TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
     693           6 :   CHECK(!layout_descriptor->IsSlowLayout());
     694             : 
     695             :   layout_descriptor =
     696           6 :       TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount);
     697           6 :   CHECK(!layout_descriptor->IsSlowLayout());
     698             : 
     699             :   layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2,
     700           6 :                                                  props, kPropsCount);
     701           6 :   CHECK(layout_descriptor->IsSlowLayout());
     702             : 
     703             :   layout_descriptor =
     704           6 :       TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
     705           6 :   CHECK(layout_descriptor->IsSlowLayout());
     706           6 : }
     707             : 
     708             : 
     709       23724 : TEST(LayoutDescriptorAppendAllDoubles) {
     710           6 :   CcTest::InitializeVM();
     711             :   Isolate* isolate = CcTest::i_isolate();
     712           6 :   v8::HandleScope scope(CcTest::isolate());
     713             : 
     714             :   Handle<LayoutDescriptor> layout_descriptor;
     715             :   const int kPropsCount = kSmiValueSize * 3;
     716             :   TestPropertyKind props[kPropsCount];
     717         582 :   for (int i = 0; i < kPropsCount; i++) {
     718         576 :     props[i] = PROP_DOUBLE;
     719             :   }
     720             : 
     721             :   layout_descriptor =
     722           6 :       TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount);
     723           6 :   CHECK(!layout_descriptor->IsSlowLayout());
     724             : 
     725             :   layout_descriptor =
     726           6 :       TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
     727           6 :   CHECK(!layout_descriptor->IsSlowLayout());
     728             : 
     729             :   layout_descriptor =
     730           6 :       TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount);
     731           6 :   CHECK(!layout_descriptor->IsSlowLayout());
     732             : 
     733             :   layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize + 1,
     734           6 :                                                  props, kPropsCount);
     735           6 :   CHECK(layout_descriptor->IsSlowLayout());
     736             : 
     737             :   layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2,
     738           6 :                                                  props, kPropsCount);
     739           6 :   CHECK(layout_descriptor->IsSlowLayout());
     740             : 
     741             :   layout_descriptor =
     742           6 :       TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
     743           6 :   CHECK(layout_descriptor->IsSlowLayout());
     744             : 
     745             :   {
     746             :     // Ensure layout descriptor switches into slow mode at the right moment.
     747             :     layout_descriptor =
     748           6 :         TestLayoutDescriptorAppend(isolate, kPropsCount, props, kSmiValueSize);
     749           6 :     CHECK(!layout_descriptor->IsSlowLayout());
     750             : 
     751             :     layout_descriptor = TestLayoutDescriptorAppend(isolate, kPropsCount, props,
     752           6 :                                                    kSmiValueSize + 1);
     753           6 :     CHECK(layout_descriptor->IsSlowLayout());
     754           6 :   }
     755           6 : }
     756             : 
     757             : 
     758          78 : static Handle<LayoutDescriptor> TestLayoutDescriptorAppendIfFastOrUseFull(
     759             :     Isolate* isolate, int inobject_properties,
     760             :     Handle<DescriptorArray> descriptors, int number_of_descriptors) {
     761          78 :   Handle<Map> initial_map = Map::Create(isolate, inobject_properties);
     762             : 
     763             :   Handle<LayoutDescriptor> full_layout_descriptor = LayoutDescriptor::New(
     764          78 :       initial_map, descriptors, descriptors->number_of_descriptors());
     765             : 
     766             :   int nof = 0;
     767             :   bool switched_to_slow_mode = false;
     768             : 
     769             :   // This method calls LayoutDescriptor::AppendIfFastOrUseFull() internally
     770             :   // and does all the required map-descriptors related book keeping.
     771             :   Handle<Map> last_map = Map::AddMissingTransitionsForTesting(
     772             :       initial_map, descriptors, full_layout_descriptor);
     773             : 
     774             :   // Follow back pointers to construct a sequence of maps from |map|
     775             :   // to |last_map|.
     776             :   int descriptors_length = descriptors->number_of_descriptors();
     777          78 :   std::vector<Handle<Map>> maps(descriptors_length);
     778             :   {
     779          78 :     CHECK(last_map->is_stable());
     780             :     Map* map = *last_map;
     781        7488 :     for (int i = 0; i < descriptors_length; i++) {
     782       14976 :       maps[descriptors_length - 1 - i] = handle(map, isolate);
     783        7488 :       Object* maybe_map = map->GetBackPointer();
     784        7488 :       CHECK(maybe_map->IsMap());
     785             :       map = Map::cast(maybe_map);
     786        7488 :       CHECK(!map->is_stable());
     787             :     }
     788         156 :     CHECK_EQ(1, maps[0]->NumberOfOwnDescriptors());
     789             :   }
     790             : 
     791             :   Handle<Map> map;
     792             :   // Now check layout descriptors of all intermediate maps.
     793        6726 :   for (int i = 0; i < number_of_descriptors; i++) {
     794        6726 :     PropertyDetails details = descriptors->GetDetails(i);
     795       13452 :     map = maps[i];
     796             :     LayoutDescriptor* layout_desc = map->layout_descriptor();
     797             : 
     798        6726 :     if (layout_desc->IsSlowLayout()) {
     799             :       switched_to_slow_mode = true;
     800        1758 :       CHECK_EQ(*full_layout_descriptor, layout_desc);
     801             :     } else {
     802        4968 :       CHECK(!switched_to_slow_mode);
     803        4968 :       if (details.location() == kField) {
     804             :         nof++;
     805             :         int field_index = details.field_index();
     806             :         int field_width_in_words = details.field_width_in_words();
     807             : 
     808             :         bool is_inobject = field_index < map->GetInObjectProperties();
     809        8784 :         for (int bit = 0; bit < field_width_in_words; bit++) {
     810       10692 :           CHECK_EQ(is_inobject && details.representation().IsDouble(),
     811             :                    !layout_desc->IsTagged(field_index + bit));
     812             :         }
     813        8784 :         CHECK(layout_desc->IsTagged(field_index + field_width_in_words));
     814             :       }
     815             :     }
     816        6726 :     CHECK(map->layout_descriptor()->IsConsistentWithMap(*map));
     817             :   }
     818             : 
     819             :   Handle<LayoutDescriptor> layout_descriptor(map->GetLayoutDescriptor(),
     820             :                                              isolate);
     821          78 :   CHECK(layout_descriptor->IsConsistentWithMap(*map));
     822         156 :   return layout_descriptor;
     823             : }
     824             : 
     825             : 
     826       23724 : TEST(LayoutDescriptorAppendIfFastOrUseFull) {
     827           6 :   CcTest::InitializeVM();
     828             :   Isolate* isolate = CcTest::i_isolate();
     829           6 :   v8::HandleScope scope(CcTest::isolate());
     830             : 
     831             :   Handle<LayoutDescriptor> layout_descriptor;
     832             :   const int kPropsCount = kSmiValueSize * 3;
     833             :   TestPropertyKind props[kPropsCount];
     834         582 :   for (int i = 0; i < kPropsCount; i++) {
     835         576 :     props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
     836             :   }
     837             :   Handle<DescriptorArray> descriptors =
     838           6 :       CreateDescriptorArray(isolate, props, kPropsCount);
     839             : 
     840             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     841           6 :       isolate, 0, descriptors, kPropsCount);
     842           6 :   CHECK(!layout_descriptor->IsSlowLayout());
     843             : 
     844             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     845           6 :       isolate, 13, descriptors, kPropsCount);
     846           6 :   CHECK(!layout_descriptor->IsSlowLayout());
     847             : 
     848             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     849           6 :       isolate, kSmiValueSize, descriptors, kPropsCount);
     850           6 :   CHECK(!layout_descriptor->IsSlowLayout());
     851             : 
     852             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     853           6 :       isolate, kSmiValueSize * 2, descriptors, kPropsCount);
     854           6 :   CHECK(layout_descriptor->IsSlowLayout());
     855             : 
     856             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     857           6 :       isolate, kPropsCount, descriptors, kPropsCount);
     858           6 :   CHECK(layout_descriptor->IsSlowLayout());
     859           6 : }
     860             : 
     861             : 
     862       23724 : TEST(LayoutDescriptorAppendIfFastOrUseFullAllDoubles) {
     863           6 :   CcTest::InitializeVM();
     864             :   Isolate* isolate = CcTest::i_isolate();
     865           6 :   v8::HandleScope scope(CcTest::isolate());
     866             : 
     867             :   Handle<LayoutDescriptor> layout_descriptor;
     868             :   const int kPropsCount = kSmiValueSize * 3;
     869             :   TestPropertyKind props[kPropsCount];
     870         582 :   for (int i = 0; i < kPropsCount; i++) {
     871         576 :     props[i] = PROP_DOUBLE;
     872             :   }
     873             :   Handle<DescriptorArray> descriptors =
     874           6 :       CreateDescriptorArray(isolate, props, kPropsCount);
     875             : 
     876             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     877           6 :       isolate, 0, descriptors, kPropsCount);
     878           6 :   CHECK(!layout_descriptor->IsSlowLayout());
     879             : 
     880             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     881           6 :       isolate, 13, descriptors, kPropsCount);
     882           6 :   CHECK(!layout_descriptor->IsSlowLayout());
     883             : 
     884             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     885           6 :       isolate, kSmiValueSize, descriptors, kPropsCount);
     886           6 :   CHECK(!layout_descriptor->IsSlowLayout());
     887             : 
     888             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     889           6 :       isolate, kSmiValueSize + 1, descriptors, kPropsCount);
     890           6 :   CHECK(layout_descriptor->IsSlowLayout());
     891             : 
     892             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     893           6 :       isolate, kSmiValueSize * 2, descriptors, kPropsCount);
     894           6 :   CHECK(layout_descriptor->IsSlowLayout());
     895             : 
     896             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     897           6 :       isolate, kPropsCount, descriptors, kPropsCount);
     898           6 :   CHECK(layout_descriptor->IsSlowLayout());
     899             : 
     900             :   {
     901             :     // Ensure layout descriptor switches into slow mode at the right moment.
     902             :     layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     903           6 :         isolate, kPropsCount, descriptors, kSmiValueSize);
     904           6 :     CHECK(!layout_descriptor->IsSlowLayout());
     905             : 
     906             :     layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     907           6 :         isolate, kPropsCount, descriptors, kSmiValueSize + 1);
     908           6 :     CHECK(layout_descriptor->IsSlowLayout());
     909           6 :   }
     910           6 : }
     911             : 
     912             : 
     913       23724 : TEST(Regress436816) {
     914             :   ManualGCScope manual_gc_scope;
     915           6 :   CcTest::InitializeVM();
     916             :   Isolate* isolate = CcTest::i_isolate();
     917             :   Factory* factory = isolate->factory();
     918          12 :   v8::HandleScope scope(CcTest::isolate());
     919             : 
     920             :   // Force a GC to free up space before we allocate objects whose
     921             :   // mid-test states would fail heap verification.
     922           6 :   CcTest::CollectAllGarbage();
     923             : 
     924             :   const int kPropsCount = kSmiValueSize * 3;
     925             :   TestPropertyKind props[kPropsCount];
     926         582 :   for (int i = 0; i < kPropsCount; i++) {
     927         576 :     props[i] = PROP_DOUBLE;
     928             :   }
     929             :   Handle<DescriptorArray> descriptors =
     930           6 :       CreateDescriptorArray(isolate, props, kPropsCount);
     931             : 
     932           6 :   Handle<Map> map = Map::Create(isolate, kPropsCount);
     933             :   Handle<LayoutDescriptor> layout_descriptor =
     934           6 :       LayoutDescriptor::New(map, descriptors, kPropsCount);
     935           6 :   map->InitializeDescriptors(*descriptors, *layout_descriptor);
     936             : 
     937           6 :   Handle<JSObject> object = factory->NewJSObjectFromMap(map, TENURED);
     938             : 
     939             :   Address fake_address = reinterpret_cast<Address>(~kHeapObjectTagMask);
     940             :   HeapObject* fake_object = HeapObject::FromAddress(fake_address);
     941             :   CHECK(fake_object->IsHeapObject());
     942             : 
     943             :   uint64_t boom_value = bit_cast<uint64_t>(fake_object);
     944         582 :   for (int i = 0; i < kPropsCount; i++) {
     945         576 :     FieldIndex index = FieldIndex::ForDescriptor(*map, i);
     946         576 :     CHECK(map->IsUnboxedDoubleField(index));
     947             :     object->RawFastDoublePropertyAsBitsAtPut(index, boom_value);
     948             :   }
     949           6 :   CHECK(object->HasFastProperties());
     950           6 :   CHECK(!object->map()->HasFastPointerLayout());
     951             : 
     952             :   Handle<Map> normalized_map =
     953           6 :       Map::Normalize(map, KEEP_INOBJECT_PROPERTIES, "testing");
     954           6 :   JSObject::MigrateToMap(object, normalized_map);
     955           6 :   CHECK(!object->HasFastProperties());
     956           6 :   CHECK(object->map()->HasFastPointerLayout());
     957             : 
     958             :   // Trigger GCs and heap verification.
     959           6 :   CcTest::CollectAllGarbage();
     960           6 : }
     961             : 
     962             : 
     963       23724 : TEST(DescriptorArrayTrimming) {
     964             :   ManualGCScope manual_gc_scope;
     965           6 :   CcTest::InitializeVM();
     966          12 :   v8::HandleScope scope(CcTest::isolate());
     967             :   Isolate* isolate = CcTest::i_isolate();
     968             : 
     969             :   const int kFieldCount = 128;
     970             :   const int kSplitFieldIndex = 32;
     971             :   const int kTrimmedLayoutDescriptorLength = 64;
     972             : 
     973           6 :   Handle<FieldType> any_type = FieldType::Any(isolate);
     974           6 :   Handle<Map> map = Map::Create(isolate, kFieldCount);
     975         198 :   for (int i = 0; i < kSplitFieldIndex; i++) {
     976             :     map = Map::CopyWithField(map, MakeName("prop", i), any_type, NONE, kMutable,
     977         384 :                              Representation::Smi(), INSERT_TRANSITION)
     978         384 :               .ToHandleChecked();
     979             :   }
     980             :   map =
     981             :       Map::CopyWithField(map, MakeName("dbl", kSplitFieldIndex), any_type, NONE,
     982          12 :                          kMutable, Representation::Double(), INSERT_TRANSITION)
     983          12 :           .ToHandleChecked();
     984           6 :   CHECK(map->layout_descriptor()->IsConsistentWithMap(*map, true));
     985           6 :   CHECK(map->layout_descriptor()->IsSlowLayout());
     986           6 :   CHECK(map->owns_descriptors());
     987           6 :   CHECK_EQ(8, map->layout_descriptor()->length());
     988             : 
     989             :   {
     990             :     // Add transitions to double fields.
     991           6 :     v8::HandleScope scope(CcTest::isolate());
     992             : 
     993             :     Handle<Map> tmp_map = map;
     994         576 :     for (int i = kSplitFieldIndex + 1; i < kFieldCount; i++) {
     995             :       tmp_map = Map::CopyWithField(tmp_map, MakeName("dbl", i), any_type, NONE,
     996             :                                    kMutable, Representation::Double(),
     997        1140 :                                    INSERT_TRANSITION)
     998        1140 :                     .ToHandleChecked();
     999         570 :       CHECK(tmp_map->layout_descriptor()->IsConsistentWithMap(*tmp_map, true));
    1000             :     }
    1001             :     // Check that descriptors are shared.
    1002           6 :     CHECK(tmp_map->owns_descriptors());
    1003           6 :     CHECK_EQ(map->instance_descriptors(), tmp_map->instance_descriptors());
    1004           6 :     CHECK_EQ(map->layout_descriptor(), tmp_map->layout_descriptor());
    1005             :   }
    1006           6 :   CHECK(map->layout_descriptor()->IsSlowLayout());
    1007           6 :   CHECK_EQ(16, map->layout_descriptor()->length());
    1008             : 
    1009             :   // The unused tail of the layout descriptor is now "durty" because of sharing.
    1010           6 :   CHECK(map->layout_descriptor()->IsConsistentWithMap(*map));
    1011         186 :   for (int i = kSplitFieldIndex + 1; i < kTrimmedLayoutDescriptorLength; i++) {
    1012         186 :     CHECK(!map->layout_descriptor()->IsTagged(i));
    1013             :   }
    1014           6 :   CHECK_LT(map->NumberOfOwnDescriptors(),
    1015             :            map->instance_descriptors()->number_of_descriptors());
    1016             : 
    1017             :   // Call GC that should trim both |map|'s descriptor array and layout
    1018             :   // descriptor.
    1019           6 :   CcTest::CollectAllGarbage();
    1020             : 
    1021             :   // The unused tail of the layout descriptor is now "clean" again.
    1022           6 :   CHECK(map->layout_descriptor()->IsConsistentWithMap(*map, true));
    1023           6 :   CHECK(map->owns_descriptors());
    1024           6 :   CHECK_EQ(map->NumberOfOwnDescriptors(),
    1025             :            map->instance_descriptors()->number_of_descriptors());
    1026           6 :   CHECK(map->layout_descriptor()->IsSlowLayout());
    1027           6 :   CHECK_EQ(8, map->layout_descriptor()->length());
    1028             : 
    1029             :   {
    1030             :     // Add transitions to tagged fields.
    1031           6 :     v8::HandleScope scope(CcTest::isolate());
    1032             : 
    1033             :     Handle<Map> tmp_map = map;
    1034         570 :     for (int i = kSplitFieldIndex + 1; i < kFieldCount - 1; i++) {
    1035             :       tmp_map = Map::CopyWithField(tmp_map, MakeName("tagged", i), any_type,
    1036             :                                    NONE, kMutable, Representation::Tagged(),
    1037        1128 :                                    INSERT_TRANSITION)
    1038        1128 :                     .ToHandleChecked();
    1039         564 :       CHECK(tmp_map->layout_descriptor()->IsConsistentWithMap(*tmp_map, true));
    1040             :     }
    1041             :     tmp_map =
    1042             :         Map::CopyWithField(tmp_map, MakeString("dbl"), any_type, NONE, kMutable,
    1043           6 :                            Representation::Double(), INSERT_TRANSITION)
    1044          12 :             .ToHandleChecked();
    1045           6 :     CHECK(tmp_map->layout_descriptor()->IsConsistentWithMap(*tmp_map, true));
    1046             :     // Check that descriptors are shared.
    1047           6 :     CHECK(tmp_map->owns_descriptors());
    1048           6 :     CHECK_EQ(map->instance_descriptors(), tmp_map->instance_descriptors());
    1049             :   }
    1050           6 :   CHECK(map->layout_descriptor()->IsSlowLayout());
    1051           6 : }
    1052             : 
    1053             : 
    1054       23724 : TEST(DoScavenge) {
    1055           6 :   CcTest::InitializeVM();
    1056           6 :   v8::HandleScope scope(CcTest::isolate());
    1057             :   Isolate* isolate = CcTest::i_isolate();
    1058             :   Factory* factory = isolate->factory();
    1059             : 
    1060             :   // The plan: create |obj| with double field in new space, do scanvenge so
    1061             :   // that |obj| is moved to old space, construct a double value that looks like
    1062             :   // a pointer to "from space" pointer. Do scavenge one more time and ensure
    1063             :   // that it didn't crash or corrupt the double value stored in the object.
    1064             : 
    1065           6 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    1066           6 :   Handle<Map> map = Map::Create(isolate, 10);
    1067             :   map = Map::CopyWithField(map, MakeName("prop", 0), any_type, NONE, kMutable,
    1068          12 :                            Representation::Double(), INSERT_TRANSITION)
    1069          12 :             .ToHandleChecked();
    1070             : 
    1071             :   // Create object in new space.
    1072           6 :   Handle<JSObject> obj = factory->NewJSObjectFromMap(map, NOT_TENURED);
    1073             : 
    1074             :   Handle<HeapNumber> heap_number = factory->NewHeapNumber(42.5);
    1075           6 :   WriteToField(*obj, 0, *heap_number);
    1076             : 
    1077             :   {
    1078             :     // Ensure the object is properly set up.
    1079           6 :     FieldIndex field_index = FieldIndex::ForDescriptor(*map, 0);
    1080          12 :     CHECK(field_index.is_inobject() && field_index.is_double());
    1081           6 :     CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
    1082           6 :     CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
    1083             :   }
    1084           6 :   CHECK(isolate->heap()->new_space()->Contains(*obj));
    1085             : 
    1086             :   // Do scavenge so that |obj| is moved to survivor space.
    1087           6 :   CcTest::CollectGarbage(i::NEW_SPACE);
    1088             : 
    1089             :   // Create temp object in the new space.
    1090           6 :   Handle<JSArray> temp = factory->NewJSArray(0, PACKED_ELEMENTS);
    1091           6 :   CHECK(isolate->heap()->new_space()->Contains(*temp));
    1092             : 
    1093             :   // Construct a double value that looks like a pointer to the new space object
    1094             :   // and store it into the obj.
    1095           6 :   Address fake_object = reinterpret_cast<Address>(*temp) + kPointerSize;
    1096             :   double boom_value = bit_cast<double>(fake_object);
    1097             : 
    1098           6 :   FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0);
    1099             :   Handle<HeapNumber> boom_number = factory->NewHeapNumber(boom_value, MUTABLE);
    1100           6 :   obj->FastPropertyAtPut(field_index, *boom_number);
    1101             : 
    1102             :   // Now |obj| moves to old gen and it has a double field that looks like
    1103             :   // a pointer to a from semi-space.
    1104           6 :   CcTest::CollectGarbage(i::NEW_SPACE);
    1105             : 
    1106           6 :   CHECK(isolate->heap()->old_space()->Contains(*obj));
    1107             : 
    1108           6 :   CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
    1109           6 : }
    1110             : 
    1111             : 
    1112       23724 : TEST(DoScavengeWithIncrementalWriteBarrier) {
    1113           6 :   if (FLAG_never_compact || !FLAG_incremental_marking) return;
    1114             :   ManualGCScope manual_gc_scope;
    1115           6 :   CcTest::InitializeVM();
    1116          12 :   v8::HandleScope scope(CcTest::isolate());
    1117             :   Isolate* isolate = CcTest::i_isolate();
    1118             :   Factory* factory = isolate->factory();
    1119          12 :   Heap* heap = CcTest::heap();
    1120             :   PagedSpace* old_space = heap->old_space();
    1121             : 
    1122             :   // The plan: create |obj_value| in old space and ensure that it is allocated
    1123             :   // on evacuation candidate page, create |obj| with double and tagged fields
    1124             :   // in new space and write |obj_value| to tagged field of |obj|, do two
    1125             :   // scavenges to promote |obj| to old space, a GC in old space and ensure that
    1126             :   // the tagged value was properly updated after candidates evacuation.
    1127             : 
    1128           6 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    1129           6 :   Handle<Map> map = Map::Create(isolate, 10);
    1130             :   map = Map::CopyWithField(map, MakeName("prop", 0), any_type, NONE, kMutable,
    1131          12 :                            Representation::Double(), INSERT_TRANSITION)
    1132          12 :             .ToHandleChecked();
    1133             :   map = Map::CopyWithField(map, MakeName("prop", 1), any_type, NONE, kMutable,
    1134          12 :                            Representation::Tagged(), INSERT_TRANSITION)
    1135          12 :             .ToHandleChecked();
    1136             : 
    1137             :   // Create |obj_value| in old space.
    1138             :   Handle<HeapObject> obj_value;
    1139             :   Page* ec_page;
    1140             :   {
    1141             :     AlwaysAllocateScope always_allocate(isolate);
    1142             :     // Make sure |obj_value| is placed on an old-space evacuation candidate.
    1143           6 :     heap::SimulateFullSpace(old_space);
    1144           6 :     obj_value = factory->NewJSArray(32 * KB, HOLEY_ELEMENTS, TENURED);
    1145           6 :     ec_page = Page::FromAddress(obj_value->address());
    1146             :   }
    1147             : 
    1148             :   // Create object in new space.
    1149           6 :   Handle<JSObject> obj = factory->NewJSObjectFromMap(map, NOT_TENURED);
    1150             : 
    1151             :   Handle<HeapNumber> heap_number = factory->NewHeapNumber(42.5);
    1152           6 :   WriteToField(*obj, 0, *heap_number);
    1153           6 :   WriteToField(*obj, 1, *obj_value);
    1154             : 
    1155             :   {
    1156             :     // Ensure the object is properly set up.
    1157           6 :     FieldIndex field_index = FieldIndex::ForDescriptor(*map, 0);
    1158          12 :     CHECK(field_index.is_inobject() && field_index.is_double());
    1159           6 :     CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
    1160           6 :     CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
    1161             : 
    1162           6 :     field_index = FieldIndex::ForDescriptor(*map, 1);
    1163          12 :     CHECK(field_index.is_inobject() && !field_index.is_double());
    1164           6 :     CHECK(!map->IsUnboxedDoubleField(field_index));
    1165             :   }
    1166           6 :   CHECK(isolate->heap()->new_space()->Contains(*obj));
    1167             : 
    1168             :   // Heap is ready, force |ec_page| to become an evacuation candidate and
    1169             :   // simulate incremental marking.
    1170           6 :   FLAG_stress_compaction = true;
    1171           6 :   FLAG_manual_evacuation_candidates_selection = true;
    1172           6 :   heap::ForceEvacuationCandidate(ec_page);
    1173           6 :   heap::SimulateIncrementalMarking(heap);
    1174             :   // Disable stress compaction mode in order to let GC do scavenge.
    1175           6 :   FLAG_stress_compaction = false;
    1176             : 
    1177             :   // Check that everything is ready for triggering incremental write barrier
    1178             :   // during scavenge (i.e. that |obj| is black and incremental marking is
    1179             :   // in compacting mode and |obj_value|'s page is an evacuation candidate).
    1180             :   IncrementalMarking* marking = heap->incremental_marking();
    1181           6 :   CHECK(marking->IsCompacting());
    1182             :   IncrementalMarking::MarkingState* marking_state =
    1183             :       heap->incremental_marking()->marking_state();
    1184           6 :   CHECK(marking_state->IsBlack(*obj));
    1185           6 :   CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
    1186             : 
    1187             :   // Trigger GCs so that |obj| moves to old gen.
    1188           6 :   CcTest::CollectGarbage(i::NEW_SPACE);  // in survivor space now
    1189           6 :   CcTest::CollectGarbage(i::NEW_SPACE);  // in old gen now
    1190             : 
    1191           6 :   CHECK(isolate->heap()->old_space()->Contains(*obj));
    1192           6 :   CHECK(isolate->heap()->old_space()->Contains(*obj_value));
    1193           6 :   CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
    1194             : 
    1195           6 :   CcTest::CollectGarbage(i::OLD_SPACE);
    1196             : 
    1197             :   // |obj_value| must be evacuated.
    1198           6 :   CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
    1199             : 
    1200           6 :   FieldIndex field_index = FieldIndex::ForDescriptor(*map, 1);
    1201          12 :   CHECK_EQ(*obj_value, obj->RawFastPropertyAt(field_index));
    1202             : }
    1203             : 
    1204             : 
    1205          90 : static void TestLayoutDescriptorHelper(Isolate* isolate,
    1206             :                                        int inobject_properties,
    1207             :                                        Handle<DescriptorArray> descriptors,
    1208             :                                        int number_of_descriptors) {
    1209          90 :   Handle<Map> map = Map::Create(isolate, inobject_properties);
    1210             : 
    1211             :   Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
    1212          90 :       map, descriptors, descriptors->number_of_descriptors());
    1213          90 :   InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
    1214             : 
    1215          90 :   LayoutDescriptorHelper helper(*map);
    1216             :   bool all_fields_tagged = true;
    1217             : 
    1218             :   int instance_size = map->instance_size();
    1219             : 
    1220          90 :   int end_offset = instance_size * 2;
    1221             :   int first_non_tagged_field_offset = end_offset;
    1222        8730 :   for (int i = 0; i < number_of_descriptors; i++) {
    1223        8640 :     PropertyDetails details = descriptors->GetDetails(i);
    1224       13734 :     if (details.location() != kField) continue;
    1225        7920 :     FieldIndex index = FieldIndex::ForDescriptor(*map, i);
    1226        7920 :     if (!index.is_inobject()) continue;
    1227        3546 :     all_fields_tagged &= !details.representation().IsDouble();
    1228        3546 :     bool expected_tagged = !index.is_double();
    1229        3546 :     if (!expected_tagged) {
    1230             :       first_non_tagged_field_offset =
    1231             :           Min(first_non_tagged_field_offset, index.offset());
    1232             :     }
    1233             : 
    1234             :     int end_of_region_offset;
    1235        3546 :     CHECK_EQ(expected_tagged, helper.IsTagged(index.offset()));
    1236        3546 :     CHECK_EQ(expected_tagged, helper.IsTagged(index.offset(), instance_size,
    1237             :                                               &end_of_region_offset));
    1238        3546 :     CHECK_GT(end_of_region_offset, 0);
    1239        3546 :     CHECK_EQ(end_of_region_offset % kPointerSize, 0);
    1240        3546 :     CHECK(end_of_region_offset <= instance_size);
    1241             : 
    1242       89838 :     for (int offset = index.offset(); offset < end_of_region_offset;
    1243             :          offset += kPointerSize) {
    1244       89838 :       CHECK_EQ(expected_tagged, helper.IsTagged(index.offset()));
    1245             :     }
    1246        3546 :     if (end_of_region_offset < instance_size) {
    1247        1050 :       CHECK_EQ(!expected_tagged, helper.IsTagged(end_of_region_offset));
    1248             :     } else {
    1249        2496 :       CHECK(helper.IsTagged(end_of_region_offset));
    1250             :     }
    1251             :   }
    1252             : 
    1253         270 :   for (int offset = 0; offset < JSObject::kHeaderSize; offset += kPointerSize) {
    1254             :     // Header queries
    1255         270 :     CHECK(helper.IsTagged(offset));
    1256             :     int end_of_region_offset;
    1257         270 :     CHECK(helper.IsTagged(offset, end_offset, &end_of_region_offset));
    1258         270 :     CHECK_EQ(first_non_tagged_field_offset, end_of_region_offset);
    1259             : 
    1260             :     // Out of bounds queries
    1261         270 :     CHECK(helper.IsTagged(offset + instance_size));
    1262             :   }
    1263             : 
    1264          90 :   CHECK_EQ(all_fields_tagged, helper.all_fields_tagged());
    1265          90 : }
    1266             : 
    1267             : 
    1268       23724 : TEST(LayoutDescriptorHelperMixed) {
    1269           6 :   CcTest::InitializeVM();
    1270             :   Isolate* isolate = CcTest::i_isolate();
    1271           6 :   v8::HandleScope scope(CcTest::isolate());
    1272             : 
    1273             :   Handle<LayoutDescriptor> layout_descriptor;
    1274             :   const int kPropsCount = kSmiValueSize * 3;
    1275             :   TestPropertyKind props[kPropsCount];
    1276         582 :   for (int i = 0; i < kPropsCount; i++) {
    1277         576 :     props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
    1278             :   }
    1279             :   Handle<DescriptorArray> descriptors =
    1280           6 :       CreateDescriptorArray(isolate, props, kPropsCount);
    1281             : 
    1282           6 :   TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
    1283             : 
    1284           6 :   TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
    1285             : 
    1286           6 :   TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
    1287             : 
    1288             :   TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
    1289           6 :                              kPropsCount);
    1290             : 
    1291           6 :   TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
    1292           6 : }
    1293             : 
    1294             : 
    1295       23724 : TEST(LayoutDescriptorHelperAllTagged) {
    1296           6 :   CcTest::InitializeVM();
    1297             :   Isolate* isolate = CcTest::i_isolate();
    1298           6 :   v8::HandleScope scope(CcTest::isolate());
    1299             : 
    1300             :   Handle<LayoutDescriptor> layout_descriptor;
    1301             :   const int kPropsCount = kSmiValueSize * 3;
    1302             :   TestPropertyKind props[kPropsCount];
    1303         582 :   for (int i = 0; i < kPropsCount; i++) {
    1304         576 :     props[i] = PROP_TAGGED;
    1305             :   }
    1306             :   Handle<DescriptorArray> descriptors =
    1307           6 :       CreateDescriptorArray(isolate, props, kPropsCount);
    1308             : 
    1309           6 :   TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
    1310             : 
    1311           6 :   TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
    1312             : 
    1313           6 :   TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
    1314             : 
    1315             :   TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
    1316           6 :                              kPropsCount);
    1317             : 
    1318           6 :   TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
    1319           6 : }
    1320             : 
    1321             : 
    1322       23724 : TEST(LayoutDescriptorHelperAllDoubles) {
    1323           6 :   CcTest::InitializeVM();
    1324             :   Isolate* isolate = CcTest::i_isolate();
    1325           6 :   v8::HandleScope scope(CcTest::isolate());
    1326             : 
    1327             :   Handle<LayoutDescriptor> layout_descriptor;
    1328             :   const int kPropsCount = kSmiValueSize * 3;
    1329             :   TestPropertyKind props[kPropsCount];
    1330         582 :   for (int i = 0; i < kPropsCount; i++) {
    1331         576 :     props[i] = PROP_DOUBLE;
    1332             :   }
    1333             :   Handle<DescriptorArray> descriptors =
    1334           6 :       CreateDescriptorArray(isolate, props, kPropsCount);
    1335             : 
    1336           6 :   TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
    1337             : 
    1338           6 :   TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
    1339             : 
    1340           6 :   TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
    1341             : 
    1342             :   TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
    1343           6 :                              kPropsCount);
    1344             : 
    1345           6 :   TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
    1346           6 : }
    1347             : 
    1348             : 
    1349       23724 : TEST(LayoutDescriptorSharing) {
    1350           6 :   CcTest::InitializeVM();
    1351           6 :   v8::HandleScope scope(CcTest::isolate());
    1352             :   Isolate* isolate = CcTest::i_isolate();
    1353           6 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    1354             : 
    1355             :   Handle<Map> split_map;
    1356             :   {
    1357           6 :     Handle<Map> map = Map::Create(isolate, 64);
    1358         198 :     for (int i = 0; i < 32; i++) {
    1359         192 :       Handle<String> name = MakeName("prop", i);
    1360             :       map = Map::CopyWithField(map, name, any_type, NONE, kMutable,
    1361         192 :                                Representation::Smi(), INSERT_TRANSITION)
    1362         384 :                 .ToHandleChecked();
    1363             :     }
    1364             :     split_map =
    1365             :         Map::CopyWithField(map, MakeString("dbl"), any_type, NONE, kMutable,
    1366           6 :                            Representation::Double(), INSERT_TRANSITION)
    1367          12 :             .ToHandleChecked();
    1368             :   }
    1369             :   Handle<LayoutDescriptor> split_layout_descriptor(
    1370             :       split_map->layout_descriptor(), isolate);
    1371           6 :   CHECK(split_layout_descriptor->IsConsistentWithMap(*split_map, true));
    1372           6 :   CHECK(split_layout_descriptor->IsSlowLayout());
    1373           6 :   CHECK(split_map->owns_descriptors());
    1374             : 
    1375             :   Handle<Map> map1 =
    1376             :       Map::CopyWithField(split_map, MakeString("foo"), any_type, NONE, kMutable,
    1377           6 :                          Representation::Double(), INSERT_TRANSITION)
    1378          12 :           .ToHandleChecked();
    1379           6 :   CHECK(!split_map->owns_descriptors());
    1380           6 :   CHECK_EQ(*split_layout_descriptor, split_map->layout_descriptor());
    1381             : 
    1382             :   // Layout descriptors should be shared with |split_map|.
    1383           6 :   CHECK(map1->owns_descriptors());
    1384           6 :   CHECK_EQ(*split_layout_descriptor, map1->layout_descriptor());
    1385           6 :   CHECK(map1->layout_descriptor()->IsConsistentWithMap(*map1, true));
    1386             : 
    1387             :   Handle<Map> map2 =
    1388             :       Map::CopyWithField(split_map, MakeString("bar"), any_type, NONE, kMutable,
    1389           6 :                          Representation::Tagged(), INSERT_TRANSITION)
    1390          12 :           .ToHandleChecked();
    1391             : 
    1392             :   // Layout descriptors should not be shared with |split_map|.
    1393           6 :   CHECK(map2->owns_descriptors());
    1394           6 :   CHECK_NE(*split_layout_descriptor, map2->layout_descriptor());
    1395           6 :   CHECK(map2->layout_descriptor()->IsConsistentWithMap(*map2, true));
    1396           6 : }
    1397             : 
    1398             : 
    1399           6 : static void TestWriteBarrier(Handle<Map> map, Handle<Map> new_map,
    1400             :                              int tagged_descriptor, int double_descriptor,
    1401             :                              bool check_tagged_value = true) {
    1402           6 :   FLAG_stress_compaction = true;
    1403           6 :   FLAG_manual_evacuation_candidates_selection = true;
    1404             :   Isolate* isolate = CcTest::i_isolate();
    1405             :   Factory* factory = isolate->factory();
    1406           6 :   Heap* heap = CcTest::heap();
    1407             :   PagedSpace* old_space = heap->old_space();
    1408             : 
    1409             :   // The plan: create |obj| by |map| in old space, create |obj_value| in
    1410             :   // new space and ensure that write barrier is triggered when |obj_value| is
    1411             :   // written to property |tagged_descriptor| of |obj|.
    1412             :   // Then migrate object to |new_map| and set proper value for property
    1413             :   // |double_descriptor|. Call GC and ensure that it did not crash during
    1414             :   // store buffer entries updating.
    1415             : 
    1416             :   Handle<JSObject> obj;
    1417             :   Handle<HeapObject> obj_value;
    1418             :   {
    1419             :     AlwaysAllocateScope always_allocate(isolate);
    1420           6 :     obj = factory->NewJSObjectFromMap(map, TENURED);
    1421           6 :     CHECK(old_space->Contains(*obj));
    1422             : 
    1423             :     obj_value = factory->NewHeapNumber(0.);
    1424             :   }
    1425             : 
    1426           6 :   CHECK(heap->InNewSpace(*obj_value));
    1427             : 
    1428             :   {
    1429           6 :     FieldIndex index = FieldIndex::ForDescriptor(*map, tagged_descriptor);
    1430             :     const int n = 153;
    1431         924 :     for (int i = 0; i < n; i++) {
    1432         918 :       obj->FastPropertyAtPut(index, *obj_value);
    1433             :     }
    1434             :   }
    1435             : 
    1436             :   // Migrate |obj| to |new_map| which should shift fields and put the
    1437             :   // |boom_value| to the slot that was earlier recorded by write barrier.
    1438           6 :   JSObject::MigrateToMap(obj, new_map);
    1439             : 
    1440           6 :   Address fake_object = reinterpret_cast<Address>(*obj_value) + kPointerSize;
    1441             :   uint64_t boom_value = bit_cast<uint64_t>(fake_object);
    1442             : 
    1443             :   FieldIndex double_field_index =
    1444           6 :       FieldIndex::ForDescriptor(*new_map, double_descriptor);
    1445           6 :   CHECK(obj->IsUnboxedDoubleField(double_field_index));
    1446             :   obj->RawFastDoublePropertyAsBitsAtPut(double_field_index, boom_value);
    1447             : 
    1448             :   // Trigger GC to evacuate all candidates.
    1449           6 :   CcTest::CollectGarbage(NEW_SPACE);
    1450             : 
    1451           6 :   if (check_tagged_value) {
    1452             :     FieldIndex tagged_field_index =
    1453           6 :         FieldIndex::ForDescriptor(*new_map, tagged_descriptor);
    1454          12 :     CHECK_EQ(*obj_value, obj->RawFastPropertyAt(tagged_field_index));
    1455             :   }
    1456           6 :   CHECK_EQ(boom_value, obj->RawFastDoublePropertyAsBitsAt(double_field_index));
    1457           6 : }
    1458             : 
    1459             : 
    1460           6 : static void TestIncrementalWriteBarrier(Handle<Map> map, Handle<Map> new_map,
    1461             :                                         int tagged_descriptor,
    1462             :                                         int double_descriptor,
    1463             :                                         bool check_tagged_value = true) {
    1464           6 :   if (FLAG_never_compact || !FLAG_incremental_marking) return;
    1465             :   ManualGCScope manual_gc_scope;
    1466           6 :   FLAG_manual_evacuation_candidates_selection = true;
    1467             :   Isolate* isolate = CcTest::i_isolate();
    1468             :   Factory* factory = isolate->factory();
    1469          12 :   Heap* heap = CcTest::heap();
    1470             :   PagedSpace* old_space = heap->old_space();
    1471             : 
    1472             :   // The plan: create |obj| by |map| in old space, create |obj_value| in
    1473             :   // old space and ensure it end up in evacuation candidate page. Start
    1474             :   // incremental marking and ensure that incremental write barrier is triggered
    1475             :   // when |obj_value| is written to property |tagged_descriptor| of |obj|.
    1476             :   // Then migrate object to |new_map| and set proper value for property
    1477             :   // |double_descriptor|. Call GC and ensure that it did not crash during
    1478             :   // slots buffer entries updating.
    1479             : 
    1480             :   Handle<JSObject> obj;
    1481             :   Handle<HeapObject> obj_value;
    1482             :   Page* ec_page;
    1483             :   {
    1484             :     AlwaysAllocateScope always_allocate(isolate);
    1485           6 :     obj = factory->NewJSObjectFromMap(map, TENURED);
    1486           6 :     CHECK(old_space->Contains(*obj));
    1487             : 
    1488             :     // Make sure |obj_value| is placed on an old-space evacuation candidate.
    1489           6 :     heap::SimulateFullSpace(old_space);
    1490           6 :     obj_value = factory->NewJSArray(32 * KB, HOLEY_ELEMENTS, TENURED);
    1491           6 :     ec_page = Page::FromAddress(obj_value->address());
    1492          12 :     CHECK_NE(ec_page, Page::FromAddress(obj->address()));
    1493             :   }
    1494             : 
    1495             :   // Heap is ready, force |ec_page| to become an evacuation candidate and
    1496             :   // simulate incremental marking.
    1497           6 :   heap::ForceEvacuationCandidate(ec_page);
    1498           6 :   heap::SimulateIncrementalMarking(heap);
    1499             : 
    1500             :   // Check that everything is ready for triggering incremental write barrier
    1501             :   // (i.e. that both |obj| and |obj_value| are black and the marking phase is
    1502             :   // still active and |obj_value|'s page is indeed an evacuation candidate).
    1503             :   IncrementalMarking* marking = heap->incremental_marking();
    1504           6 :   CHECK(marking->IsMarking());
    1505             :   IncrementalMarking::MarkingState* marking_state = marking->marking_state();
    1506           6 :   CHECK(marking_state->IsBlack(*obj));
    1507           6 :   CHECK(marking_state->IsBlack(*obj_value));
    1508           6 :   CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
    1509             : 
    1510             :   // Trigger incremental write barrier, which should add a slot to remembered
    1511             :   // set.
    1512             :   {
    1513           6 :     FieldIndex index = FieldIndex::ForDescriptor(*map, tagged_descriptor);
    1514           6 :     obj->FastPropertyAtPut(index, *obj_value);
    1515             :   }
    1516             : 
    1517             :   // Migrate |obj| to |new_map| which should shift fields and put the
    1518             :   // |boom_value| to the slot that was earlier recorded by incremental write
    1519             :   // barrier.
    1520           6 :   JSObject::MigrateToMap(obj, new_map);
    1521             : 
    1522             :   uint64_t boom_value = UINT64_C(0xbaad0176a37c28e1);
    1523             : 
    1524             :   FieldIndex double_field_index =
    1525           6 :       FieldIndex::ForDescriptor(*new_map, double_descriptor);
    1526           6 :   CHECK(obj->IsUnboxedDoubleField(double_field_index));
    1527             :   obj->RawFastDoublePropertyAsBitsAtPut(double_field_index, boom_value);
    1528             : 
    1529             :   // Trigger GC to evacuate all candidates.
    1530           6 :   CcTest::CollectGarbage(OLD_SPACE);
    1531             : 
    1532             :   // Ensure that the values are still there and correct.
    1533           6 :   CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
    1534             : 
    1535           6 :   if (check_tagged_value) {
    1536             :     FieldIndex tagged_field_index =
    1537           6 :         FieldIndex::ForDescriptor(*new_map, tagged_descriptor);
    1538          12 :     CHECK_EQ(*obj_value, obj->RawFastPropertyAt(tagged_field_index));
    1539             :   }
    1540           6 :   CHECK_EQ(boom_value, obj->RawFastDoublePropertyAsBitsAt(double_field_index));
    1541             : }
    1542             : 
    1543             : enum OldToWriteBarrierKind {
    1544             :   OLD_TO_OLD_WRITE_BARRIER,
    1545             :   OLD_TO_NEW_WRITE_BARRIER
    1546             : };
    1547          12 : static void TestWriteBarrierObjectShiftFieldsRight(
    1548             :     OldToWriteBarrierKind write_barrier_kind) {
    1549             :   ManualGCScope manual_gc_scope;
    1550          12 :   CcTest::InitializeVM();
    1551             :   Isolate* isolate = CcTest::i_isolate();
    1552          24 :   v8::HandleScope scope(CcTest::isolate());
    1553             : 
    1554          12 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    1555             : 
    1556             :   CompileRun("function func() { return 1; }");
    1557             : 
    1558          12 :   Handle<JSObject> func = GetObject("func");
    1559             : 
    1560          12 :   Handle<Map> map = Map::Create(isolate, 10);
    1561             :   map = Map::CopyWithConstant(map, MakeName("prop", 0), func, NONE,
    1562          36 :                               INSERT_TRANSITION).ToHandleChecked();
    1563             :   map = Map::CopyWithField(map, MakeName("prop", 1), any_type, NONE, kMutable,
    1564          24 :                            Representation::Double(), INSERT_TRANSITION)
    1565          24 :             .ToHandleChecked();
    1566             :   map = Map::CopyWithField(map, MakeName("prop", 2), any_type, NONE, kMutable,
    1567          24 :                            Representation::Tagged(), INSERT_TRANSITION)
    1568          24 :             .ToHandleChecked();
    1569             : 
    1570             :   // Shift fields right by turning constant property to a field.
    1571             :   Handle<Map> new_map = Map::ReconfigureProperty(
    1572          12 :       map, 0, kData, NONE, Representation::Tagged(), any_type);
    1573             : 
    1574          12 :   if (write_barrier_kind == OLD_TO_NEW_WRITE_BARRIER) {
    1575           6 :     TestWriteBarrier(map, new_map, 2, 1);
    1576             :   } else {
    1577           6 :     CHECK_EQ(OLD_TO_OLD_WRITE_BARRIER, write_barrier_kind);
    1578           6 :     TestIncrementalWriteBarrier(map, new_map, 2, 1);
    1579             :   }
    1580          12 : }
    1581             : 
    1582       23724 : TEST(WriteBarrierObjectShiftFieldsRight) {
    1583           6 :   TestWriteBarrierObjectShiftFieldsRight(OLD_TO_NEW_WRITE_BARRIER);
    1584           6 : }
    1585             : 
    1586             : 
    1587       23724 : TEST(IncrementalWriteBarrierObjectShiftFieldsRight) {
    1588           6 :   TestWriteBarrierObjectShiftFieldsRight(OLD_TO_OLD_WRITE_BARRIER);
    1589           6 : }
    1590             : 
    1591             : 
    1592             : // TODO(ishell): add respective tests for property kind reconfiguring from
    1593             : // accessor field to double, once accessor fields are supported by
    1594             : // Map::ReconfigureProperty().
    1595             : 
    1596             : 
    1597             : // TODO(ishell): add respective tests for fast property removal case once
    1598             : // Map::ReconfigureProperty() supports that.
    1599             : 
    1600             : #endif
    1601             : 
    1602             : }  // namespace test_unboxed_doubles
    1603             : }  // namespace internal
    1604       71154 : }  // namespace v8

Generated by: LCOV version 1.10