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

Generated by: LCOV version 1.10