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

Generated by: LCOV version 1.10