LCOV - code coverage report
Current view: top level - test/cctest - test-unboxed-doubles.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 717 719 99.7 %
Date: 2019-01-20 Functions: 42 42 100.0 %

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

Generated by: LCOV version 1.10