LCOV - code coverage report
Current view: top level - test/cctest - test-unboxed-doubles.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 717 719 99.7 %
Date: 2019-02-19 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        2630 :   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             :           CcTest::global()
      66             :               ->Get(v8::Isolate::GetCurrent()->GetCurrentContext(),
      67          30 :                     v8_str(name))
      68          30 :               .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       25875 :     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        4405 :   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             :       d = Descriptor::DataField(isolate, name, next_field_offset, NONE,
     127        7950 :                                 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       25880 : TEST(LayoutDescriptorBasicFast) {
     140           5 :   CcTest::InitializeVM();
     141           5 :   v8::HandleScope scope(CcTest::isolate());
     142             : 
     143           5 :   LayoutDescriptor layout_desc = LayoutDescriptor::FastPointerLayout();
     144             : 
     145           5 :   CHECK(!layout_desc->IsSlowLayout());
     146           5 :   CHECK(layout_desc->IsFastPointerLayout());
     147           5 :   CHECK_EQ(kBitsInSmiLayout, layout_desc->capacity());
     148             : 
     149         225 :   for (int i = 0; i < kBitsInSmiLayout + 13; i++) {
     150         225 :     CHECK(layout_desc->IsTagged(i));
     151             :   }
     152             :   CHECK(layout_desc->IsTagged(-1));
     153             :   CHECK(layout_desc->IsTagged(-12347));
     154           5 :   CHECK(layout_desc->IsTagged(15635));
     155           5 :   CHECK(layout_desc->IsFastPointerLayout());
     156             : 
     157         160 :   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       25880 : TEST(LayoutDescriptorBasicSlow) {
     176           5 :   CcTest::InitializeVM();
     177             :   Isolate* isolate = CcTest::i_isolate();
     178           5 :   v8::HandleScope scope(CcTest::isolate());
     179             : 
     180             :   Handle<LayoutDescriptor> layout_descriptor;
     181             :   const int kPropsCount = kBitsInSmiLayout * 3;
     182             :   TestPropertyKind props[kPropsCount];
     183         485 :   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          15 :     CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
     197          10 :     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          15 :     CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
     216          10 :     CHECK(!layout_descriptor->IsSlowLayout());
     217          10 :     CHECK(!layout_descriptor->IsFastPointerLayout());
     218             : 
     219          10 :     CHECK(!layout_descriptor->IsTagged(0));
     220         475 :     for (int i = 1; i < kPropsCount; i++) {
     221         950 :       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          15 :     CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
     234          10 :     CHECK(layout_descriptor->IsSlowLayout());
     235          10 :     CHECK(!layout_descriptor->IsFastPointerLayout());
     236          10 :     CHECK_GT(layout_descriptor->capacity(), kBitsInSmiLayout);
     237             : 
     238          10 :     CHECK(!layout_descriptor->IsTagged(0));
     239          10 :     CHECK(!layout_descriptor->IsTagged(kPropsCount - 1));
     240         470 :     for (int i = 1; i < kPropsCount - 1; i++) {
     241         940 :       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          10 :     CHECK(layout_descriptor->IsTagged(-1));
     249          10 :     CHECK(layout_descriptor->IsTagged(-12347));
     250          10 :     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         475 :     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           5 :   }
     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         430 :   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      145975 :     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      145280 :     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         495 :     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         510 :     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       25880 : TEST(LayoutDescriptorQueriesFastLimited7) {
     380           5 :   CcTest::InitializeVM();
     381           5 :   v8::HandleScope scope(CcTest::isolate());
     382             : 
     383           5 :   TestLayoutDescriptorQueriesFast(7);
     384           5 : }
     385             : 
     386             : 
     387       25880 : TEST(LayoutDescriptorQueriesFastLimited13) {
     388           5 :   CcTest::InitializeVM();
     389           5 :   v8::HandleScope scope(CcTest::isolate());
     390             : 
     391           5 :   TestLayoutDescriptorQueriesFast(13);
     392           5 : }
     393             : 
     394             : 
     395       25880 : TEST(LayoutDescriptorQueriesFastUnlimited) {
     396           5 :   CcTest::InitializeVM();
     397           5 :   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       20420 :     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       20420 :     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       20420 :     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       25880 : TEST(LayoutDescriptorQueriesSlowLimited7) {
     469           5 :   CcTest::InitializeVM();
     470           5 :   v8::HandleScope scope(CcTest::isolate());
     471             : 
     472           5 :   TestLayoutDescriptorQueriesSlow(7);
     473           5 : }
     474             : 
     475             : 
     476       25880 : TEST(LayoutDescriptorQueriesSlowLimited13) {
     477           5 :   CcTest::InitializeVM();
     478           5 :   v8::HandleScope scope(CcTest::isolate());
     479             : 
     480           5 :   TestLayoutDescriptorQueriesSlow(13);
     481           5 : }
     482             : 
     483             : 
     484       25880 : TEST(LayoutDescriptorQueriesSlowLimited42) {
     485           5 :   CcTest::InitializeVM();
     486           5 :   v8::HandleScope scope(CcTest::isolate());
     487             : 
     488           5 :   TestLayoutDescriptorQueriesSlow(42);
     489           5 : }
     490             : 
     491             : 
     492       25880 : TEST(LayoutDescriptorQueriesSlowUnlimited) {
     493           5 :   CcTest::InitializeVM();
     494           5 :   v8::HandleScope scope(CcTest::isolate());
     495             : 
     496           5 :   TestLayoutDescriptorQueriesSlow(std::numeric_limits<int>::max());
     497           5 : }
     498             : 
     499             : 
     500       25880 : TEST(LayoutDescriptorCreateNewFast) {
     501           5 :   CcTest::InitializeVM();
     502             :   Isolate* isolate = CcTest::i_isolate();
     503           5 :   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          15 :     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          15 :     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          15 :     CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
     543          10 :     CHECK(!layout_descriptor->IsSlowLayout());
     544          10 :     CHECK(layout_descriptor->IsTagged(0));
     545          10 :     CHECK(!layout_descriptor->IsTagged(1));
     546          10 :     CHECK(layout_descriptor->IsTagged(2));
     547          10 :     CHECK(layout_descriptor->IsTagged(125));
     548             :     InitializeVerifiedMapDescriptors(isolate, *map, *descriptors,
     549           5 :                                      *layout_descriptor);
     550           5 :   }
     551           5 : }
     552             : 
     553             : 
     554       25880 : TEST(LayoutDescriptorCreateNewSlow) {
     555           5 :   CcTest::InitializeVM();
     556             :   Isolate* isolate = CcTest::i_isolate();
     557           5 :   v8::HandleScope scope(CcTest::isolate());
     558             : 
     559             :   Handle<LayoutDescriptor> layout_descriptor;
     560             :   const int kPropsCount = kBitsInSmiLayout * 3;
     561             :   TestPropertyKind props[kPropsCount];
     562         485 :   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          15 :     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          15 :     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          15 :     CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
     592          10 :     CHECK(!layout_descriptor->IsSlowLayout());
     593          10 :     CHECK(layout_descriptor->IsTagged(0));
     594          10 :     CHECK(!layout_descriptor->IsTagged(1));
     595          10 :     CHECK(layout_descriptor->IsTagged(2));
     596          10 :     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          15 :     CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
     607          10 :     CHECK(layout_descriptor->IsSlowLayout());
     608         240 :     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         480 :       CHECK_EQ(tagged, layout_descriptor->IsTagged(i));
     612             :     }
     613             :     // Every property after inobject_properties must be tagged.
     614         240 :     for (int i = inobject_properties; i < kPropsCount; i++) {
     615         480 :       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           5 :     LayoutDescriptor layout_desc = *layout_descriptor;
     625          10 :     CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
     626          10 :     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          10 :     CHECK_EQ(layout_desc, LayoutDescriptor::cast_gc_safe(layout_desc));
     635             : 
     636             :     // Restore it back.
     637             :     layout_desc->set_map_word(map_word);
     638          10 :     CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
     639           5 :   }
     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             :   map->InitializeDescriptors(isolate, *descriptors,
     653          65 :                              LayoutDescriptor::FastPointerLayout());
     654             : 
     655             :   int next_field_offset = 0;
     656        5670 :   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             :       d = Descriptor::DataField(isolate, name, next_field_offset, NONE,
     671       10010 :                                 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       10010 :       for (int bit = 0; bit < field_width_in_words; bit++) {
     683       15015 :         CHECK_EQ(is_inobject && (kind == PROP_DOUBLE),
     684             :                  !layout_descriptor->IsTagged(field_index + bit));
     685             :       }
     686       10010 :       CHECK(layout_descriptor->IsTagged(next_field_offset));
     687             :     }
     688        5605 :     map->InitializeDescriptors(isolate, *descriptors, *layout_descriptor);
     689             :   }
     690         130 :   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       25880 : TEST(LayoutDescriptorAppend) {
     697           5 :   CcTest::InitializeVM();
     698             :   Isolate* isolate = CcTest::i_isolate();
     699           5 :   v8::HandleScope scope(CcTest::isolate());
     700             : 
     701             :   Handle<LayoutDescriptor> layout_descriptor;
     702             :   const int kPropsCount = kBitsInSmiLayout * 3;
     703             :   TestPropertyKind props[kPropsCount];
     704         485 :   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          10 :   CHECK(!layout_descriptor->IsSlowLayout());
     711             : 
     712             :   layout_descriptor =
     713           5 :       TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
     714          10 :   CHECK(!layout_descriptor->IsSlowLayout());
     715             : 
     716             :   layout_descriptor =
     717           5 :       TestLayoutDescriptorAppend(isolate, kBitsInSmiLayout, props, kPropsCount);
     718          10 :   CHECK(!layout_descriptor->IsSlowLayout());
     719             : 
     720             :   layout_descriptor = TestLayoutDescriptorAppend(isolate, kBitsInSmiLayout * 2,
     721           5 :                                                  props, kPropsCount);
     722          10 :   CHECK(layout_descriptor->IsSlowLayout());
     723             : 
     724             :   layout_descriptor =
     725           5 :       TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
     726          10 :   CHECK(layout_descriptor->IsSlowLayout());
     727           5 : }
     728             : 
     729             : 
     730       25880 : TEST(LayoutDescriptorAppendAllDoubles) {
     731           5 :   CcTest::InitializeVM();
     732             :   Isolate* isolate = CcTest::i_isolate();
     733           5 :   v8::HandleScope scope(CcTest::isolate());
     734             : 
     735             :   Handle<LayoutDescriptor> layout_descriptor;
     736             :   const int kPropsCount = kBitsInSmiLayout * 3;
     737             :   TestPropertyKind props[kPropsCount];
     738         485 :   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          10 :   CHECK(!layout_descriptor->IsSlowLayout());
     745             : 
     746             :   layout_descriptor =
     747           5 :       TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
     748          10 :   CHECK(!layout_descriptor->IsSlowLayout());
     749             : 
     750             :   layout_descriptor =
     751           5 :       TestLayoutDescriptorAppend(isolate, kBitsInSmiLayout, props, kPropsCount);
     752          10 :   CHECK(!layout_descriptor->IsSlowLayout());
     753             : 
     754             :   layout_descriptor = TestLayoutDescriptorAppend(isolate, kBitsInSmiLayout + 1,
     755           5 :                                                  props, kPropsCount);
     756          10 :   CHECK(layout_descriptor->IsSlowLayout());
     757             : 
     758             :   layout_descriptor = TestLayoutDescriptorAppend(isolate, kBitsInSmiLayout * 2,
     759           5 :                                                  props, kPropsCount);
     760          10 :   CHECK(layout_descriptor->IsSlowLayout());
     761             : 
     762             :   layout_descriptor =
     763           5 :       TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
     764          10 :   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          10 :     CHECK(!layout_descriptor->IsSlowLayout());
     771             : 
     772             :     layout_descriptor = TestLayoutDescriptorAppend(isolate, kPropsCount, props,
     773           5 :                                                    kBitsInSmiLayout + 1);
     774          10 :     CHECK(layout_descriptor->IsSlowLayout());
     775           5 :   }
     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        6305 :     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         130 :     CHECK_EQ(1, maps[0]->NumberOfOwnDescriptors());
     810             :   }
     811             : 
     812             :   Handle<Map> map;
     813             :   // Now check layout descriptors of all intermediate maps.
     814        5670 :   for (int i = 0; i < number_of_descriptors; i++) {
     815        5605 :     PropertyDetails details = descriptors->GetDetails(i);
     816       11210 :     map = maps[i];
     817        5605 :     LayoutDescriptor layout_desc = map->layout_descriptor();
     818             : 
     819        5605 :     if (layout_desc->IsSlowLayout()) {
     820             :       switched_to_slow_mode = true;
     821        2930 :       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        7320 :         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         130 :                                              isolate);
     842          65 :   CHECK(layout_descriptor->IsConsistentWithMap(*map));
     843         130 :   return layout_descriptor;
     844             : }
     845             : 
     846             : 
     847       25880 : TEST(LayoutDescriptorAppendIfFastOrUseFull) {
     848           5 :   CcTest::InitializeVM();
     849             :   Isolate* isolate = CcTest::i_isolate();
     850           5 :   v8::HandleScope scope(CcTest::isolate());
     851             : 
     852             :   Handle<LayoutDescriptor> layout_descriptor;
     853             :   const int kPropsCount = kBitsInSmiLayout * 3;
     854             :   TestPropertyKind props[kPropsCount];
     855         485 :   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          10 :   CHECK(!layout_descriptor->IsSlowLayout());
     864             : 
     865             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     866           5 :       isolate, 13, descriptors, kPropsCount);
     867          10 :   CHECK(!layout_descriptor->IsSlowLayout());
     868             : 
     869             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     870           5 :       isolate, kBitsInSmiLayout, descriptors, kPropsCount);
     871          10 :   CHECK(!layout_descriptor->IsSlowLayout());
     872             : 
     873             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     874           5 :       isolate, kBitsInSmiLayout * 2, descriptors, kPropsCount);
     875          10 :   CHECK(layout_descriptor->IsSlowLayout());
     876             : 
     877             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     878           5 :       isolate, kPropsCount, descriptors, kPropsCount);
     879          10 :   CHECK(layout_descriptor->IsSlowLayout());
     880           5 : }
     881             : 
     882             : 
     883       25880 : TEST(LayoutDescriptorAppendIfFastOrUseFullAllDoubles) {
     884           5 :   CcTest::InitializeVM();
     885             :   Isolate* isolate = CcTest::i_isolate();
     886           5 :   v8::HandleScope scope(CcTest::isolate());
     887             : 
     888             :   Handle<LayoutDescriptor> layout_descriptor;
     889             :   const int kPropsCount = kBitsInSmiLayout * 3;
     890             :   TestPropertyKind props[kPropsCount];
     891         485 :   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          10 :   CHECK(!layout_descriptor->IsSlowLayout());
     900             : 
     901             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     902           5 :       isolate, 13, descriptors, kPropsCount);
     903          10 :   CHECK(!layout_descriptor->IsSlowLayout());
     904             : 
     905             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     906           5 :       isolate, kBitsInSmiLayout, descriptors, kPropsCount);
     907          10 :   CHECK(!layout_descriptor->IsSlowLayout());
     908             : 
     909             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     910           5 :       isolate, kBitsInSmiLayout + 1, descriptors, kPropsCount);
     911          10 :   CHECK(layout_descriptor->IsSlowLayout());
     912             : 
     913             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     914           5 :       isolate, kBitsInSmiLayout * 2, descriptors, kPropsCount);
     915          10 :   CHECK(layout_descriptor->IsSlowLayout());
     916             : 
     917             :   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     918           5 :       isolate, kPropsCount, descriptors, kPropsCount);
     919          10 :   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          10 :     CHECK(!layout_descriptor->IsSlowLayout());
     926             : 
     927             :     layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
     928           5 :         isolate, kPropsCount, descriptors, kBitsInSmiLayout + 1);
     929          10 :     CHECK(layout_descriptor->IsSlowLayout());
     930           5 :   }
     931           5 : }
     932             : 
     933             : 
     934       25880 : 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         485 :   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           5 :   Handle<JSObject> object = factory->NewJSObjectFromMap(map, TENURED);
     959             : 
     960             :   Address fake_address = static_cast<Address>(~kHeapObjectTagMask);
     961           5 :   HeapObject fake_object = HeapObject::FromAddress(fake_address);
     962           5 :   CHECK(fake_object->IsHeapObject());
     963             : 
     964             :   uint64_t boom_value = bit_cast<uint64_t>(fake_object);
     965         480 :   for (int i = 0; i < kPropsCount; i++) {
     966         480 :     FieldIndex index = FieldIndex::ForDescriptor(*map, i);
     967         480 :     CHECK(map->IsUnboxedDoubleField(index));
     968             :     object->RawFastDoublePropertyAsBitsAtPut(index, boom_value);
     969             :   }
     970           5 :   CHECK(object->HasFastProperties());
     971           5 :   CHECK(!object->map()->HasFastPointerLayout());
     972             : 
     973             :   Handle<Map> normalized_map =
     974           5 :       Map::Normalize(isolate, map, KEEP_INOBJECT_PROPERTIES, "testing");
     975           5 :   JSObject::MigrateToMap(object, normalized_map);
     976           5 :   CHECK(!object->HasFastProperties());
     977           5 :   CHECK(object->map()->HasFastPointerLayout());
     978             : 
     979             :   // Trigger GCs and heap verification.
     980           5 :   CcTest::CollectAllGarbage();
     981           5 : }
     982             : 
     983             : 
     984       25880 : TEST(DescriptorArrayTrimming) {
     985             :   ManualGCScope manual_gc_scope;
     986           5 :   CcTest::InitializeVM();
     987          10 :   v8::HandleScope scope(CcTest::isolate());
     988             :   Isolate* isolate = CcTest::i_isolate();
     989             : 
     990             :   const int kFieldCount = 128;
     991             :   const int kSplitFieldIndex = 32;
     992             :   const int kTrimmedLayoutDescriptorLength = 64;
     993             : 
     994           5 :   Handle<FieldType> any_type = FieldType::Any(isolate);
     995           5 :   Handle<Map> map = Map::Create(isolate, kFieldCount);
     996         165 :   for (int i = 0; i < kSplitFieldIndex; i++) {
     997             :     map = Map::CopyWithField(isolate, map, MakeName("prop", i), any_type, NONE,
     998             :                              PropertyConstness::kMutable, Representation::Smi(),
     999         320 :                              INSERT_TRANSITION)
    1000         320 :               .ToHandleChecked();
    1001             :   }
    1002             :   map = Map::CopyWithField(isolate, map, MakeName("dbl", kSplitFieldIndex),
    1003             :                            any_type, NONE, PropertyConstness::kMutable,
    1004          10 :                            Representation::Double(), INSERT_TRANSITION)
    1005          10 :             .ToHandleChecked();
    1006           5 :   CHECK(map->layout_descriptor()->IsConsistentWithMap(*map, true));
    1007          10 :   CHECK(map->layout_descriptor()->IsSlowLayout());
    1008           5 :   CHECK(map->owns_descriptors());
    1009          10 :   CHECK_EQ(8, map->layout_descriptor()->length());
    1010             : 
    1011             :   {
    1012             :     // Add transitions to double fields.
    1013           5 :     v8::HandleScope scope(CcTest::isolate());
    1014             : 
    1015             :     Handle<Map> tmp_map = map;
    1016         480 :     for (int i = kSplitFieldIndex + 1; i < kFieldCount; i++) {
    1017             :       tmp_map = Map::CopyWithField(isolate, tmp_map, MakeName("dbl", i),
    1018             :                                    any_type, NONE, PropertyConstness::kMutable,
    1019         950 :                                    Representation::Double(), INSERT_TRANSITION)
    1020         950 :                     .ToHandleChecked();
    1021         475 :       CHECK(tmp_map->layout_descriptor()->IsConsistentWithMap(*tmp_map, true));
    1022             :     }
    1023             :     // Check that descriptors are shared.
    1024           5 :     CHECK(tmp_map->owns_descriptors());
    1025          15 :     CHECK_EQ(map->instance_descriptors(), tmp_map->instance_descriptors());
    1026          15 :     CHECK_EQ(map->layout_descriptor(), tmp_map->layout_descriptor());
    1027             :   }
    1028          10 :   CHECK(map->layout_descriptor()->IsSlowLayout());
    1029          10 :   CHECK_EQ(16, map->layout_descriptor()->length());
    1030             : 
    1031             :   // The unused tail of the layout descriptor is now "durty" because of sharing.
    1032           5 :   CHECK(map->layout_descriptor()->IsConsistentWithMap(*map));
    1033         155 :   for (int i = kSplitFieldIndex + 1; i < kTrimmedLayoutDescriptorLength; i++) {
    1034         310 :     CHECK(!map->layout_descriptor()->IsTagged(i));
    1035             :   }
    1036          10 :   CHECK_LT(map->NumberOfOwnDescriptors(),
    1037             :            map->instance_descriptors()->number_of_descriptors());
    1038             : 
    1039             :   // Call GC that should trim both |map|'s descriptor array and layout
    1040             :   // descriptor.
    1041           5 :   CcTest::CollectAllGarbage();
    1042             : 
    1043             :   // The unused tail of the layout descriptor is now "clean" again.
    1044           5 :   CHECK(map->layout_descriptor()->IsConsistentWithMap(*map, true));
    1045           5 :   CHECK(map->owns_descriptors());
    1046          10 :   CHECK_EQ(map->NumberOfOwnDescriptors(),
    1047             :            map->instance_descriptors()->number_of_descriptors());
    1048          10 :   CHECK(map->layout_descriptor()->IsSlowLayout());
    1049          10 :   CHECK_EQ(8, map->layout_descriptor()->length());
    1050             : 
    1051             :   {
    1052             :     // Add transitions to tagged fields.
    1053           5 :     v8::HandleScope scope(CcTest::isolate());
    1054             : 
    1055             :     Handle<Map> tmp_map = map;
    1056         475 :     for (int i = kSplitFieldIndex + 1; i < kFieldCount - 1; i++) {
    1057             :       tmp_map = Map::CopyWithField(isolate, tmp_map, MakeName("tagged", i),
    1058             :                                    any_type, NONE, PropertyConstness::kMutable,
    1059         940 :                                    Representation::Tagged(), INSERT_TRANSITION)
    1060         940 :                     .ToHandleChecked();
    1061         470 :       CHECK(tmp_map->layout_descriptor()->IsConsistentWithMap(*tmp_map, true));
    1062             :     }
    1063             :     tmp_map = Map::CopyWithField(isolate, tmp_map, MakeString("dbl"), any_type,
    1064             :                                  NONE, PropertyConstness::kMutable,
    1065           5 :                                  Representation::Double(), INSERT_TRANSITION)
    1066          10 :                   .ToHandleChecked();
    1067           5 :     CHECK(tmp_map->layout_descriptor()->IsConsistentWithMap(*tmp_map, true));
    1068             :     // Check that descriptors are shared.
    1069           5 :     CHECK(tmp_map->owns_descriptors());
    1070          15 :     CHECK_EQ(map->instance_descriptors(), tmp_map->instance_descriptors());
    1071             :   }
    1072          10 :   CHECK(map->layout_descriptor()->IsSlowLayout());
    1073           5 : }
    1074             : 
    1075             : 
    1076       25880 : TEST(DoScavenge) {
    1077           5 :   CcTest::InitializeVM();
    1078           5 :   v8::HandleScope scope(CcTest::isolate());
    1079             :   Isolate* isolate = CcTest::i_isolate();
    1080             :   Factory* factory = isolate->factory();
    1081             : 
    1082             :   // The plan: create |obj| with double field in new space, do scanvenge so
    1083             :   // that |obj| is moved to old space, construct a double value that looks like
    1084             :   // a pointer to "from space" pointer. Do scavenge one more time and ensure
    1085             :   // that it didn't crash or corrupt the double value stored in the object.
    1086             : 
    1087           5 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    1088           5 :   Handle<Map> map = Map::Create(isolate, 10);
    1089             :   map = Map::CopyWithField(isolate, map, MakeName("prop", 0), any_type, NONE,
    1090             :                            PropertyConstness::kMutable,
    1091          10 :                            Representation::Double(), INSERT_TRANSITION)
    1092          10 :             .ToHandleChecked();
    1093             : 
    1094             :   // Create object in new space.
    1095           5 :   Handle<JSObject> obj = factory->NewJSObjectFromMap(map, NOT_TENURED);
    1096             : 
    1097           5 :   Handle<HeapNumber> heap_number = factory->NewHeapNumber(42.5);
    1098          10 :   WriteToField(*obj, 0, *heap_number);
    1099             : 
    1100             :   {
    1101             :     // Ensure the object is properly set up.
    1102           5 :     FieldIndex field_index = FieldIndex::ForDescriptor(*map, 0);
    1103          10 :     CHECK(field_index.is_inobject() && field_index.is_double());
    1104           5 :     CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
    1105           5 :     CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
    1106             :   }
    1107           5 :   CHECK(isolate->heap()->new_space()->Contains(*obj));
    1108             : 
    1109             :   // Do scavenge so that |obj| is moved to survivor space.
    1110           5 :   CcTest::CollectGarbage(i::NEW_SPACE);
    1111             : 
    1112             :   // Create temp object in the new space.
    1113           5 :   Handle<JSArray> temp = factory->NewJSArray(0, PACKED_ELEMENTS);
    1114           5 :   CHECK(isolate->heap()->new_space()->Contains(*temp));
    1115             : 
    1116             :   // Construct a double value that looks like a pointer to the new space object
    1117             :   // and store it into the obj.
    1118           5 :   Address fake_object = temp->ptr() + kSystemPointerSize;
    1119             :   double boom_value = bit_cast<double>(fake_object);
    1120             : 
    1121           5 :   FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0);
    1122           5 :   auto boom_number = factory->NewMutableHeapNumber(boom_value);
    1123          10 :   obj->FastPropertyAtPut(field_index, *boom_number);
    1124             : 
    1125             :   // Now |obj| moves to old gen and it has a double field that looks like
    1126             :   // a pointer to a from semi-space.
    1127           5 :   CcTest::CollectGarbage(i::NEW_SPACE);
    1128             : 
    1129           5 :   CHECK(isolate->heap()->old_space()->Contains(*obj));
    1130             : 
    1131           5 :   CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
    1132           5 : }
    1133             : 
    1134             : 
    1135       25880 : TEST(DoScavengeWithIncrementalWriteBarrier) {
    1136           5 :   if (FLAG_never_compact || !FLAG_incremental_marking) return;
    1137             :   ManualGCScope manual_gc_scope;
    1138           5 :   CcTest::InitializeVM();
    1139          10 :   v8::HandleScope scope(CcTest::isolate());
    1140             :   Isolate* isolate = CcTest::i_isolate();
    1141             :   Factory* factory = isolate->factory();
    1142           5 :   Heap* heap = CcTest::heap();
    1143             :   PagedSpace* old_space = heap->old_space();
    1144             : 
    1145             :   // The plan: create |obj_value| in old space and ensure that it is allocated
    1146             :   // on evacuation candidate page, create |obj| with double and tagged fields
    1147             :   // in new space and write |obj_value| to tagged field of |obj|, do two
    1148             :   // scavenges to promote |obj| to old space, a GC in old space and ensure that
    1149             :   // the tagged value was properly updated after candidates evacuation.
    1150             : 
    1151           5 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    1152           5 :   Handle<Map> map = Map::Create(isolate, 10);
    1153             :   map = Map::CopyWithField(isolate, map, MakeName("prop", 0), any_type, NONE,
    1154             :                            PropertyConstness::kMutable,
    1155          10 :                            Representation::Double(), INSERT_TRANSITION)
    1156          10 :             .ToHandleChecked();
    1157             :   map = Map::CopyWithField(isolate, map, MakeName("prop", 1), any_type, NONE,
    1158             :                            PropertyConstness::kMutable,
    1159          10 :                            Representation::Tagged(), INSERT_TRANSITION)
    1160          10 :             .ToHandleChecked();
    1161             : 
    1162             :   // Create |obj_value| in old space.
    1163             :   Handle<HeapObject> obj_value;
    1164             :   Page* ec_page;
    1165             :   {
    1166             :     AlwaysAllocateScope always_allocate(isolate);
    1167             :     // Make sure |obj_value| is placed on an old-space evacuation candidate.
    1168           5 :     heap::SimulateFullSpace(old_space);
    1169           5 :     obj_value = factory->NewJSArray(32 * KB, HOLEY_ELEMENTS, TENURED);
    1170             :     ec_page = Page::FromHeapObject(*obj_value);
    1171             :   }
    1172             : 
    1173             :   // Create object in new space.
    1174           5 :   Handle<JSObject> obj = factory->NewJSObjectFromMap(map, NOT_TENURED);
    1175             : 
    1176           5 :   Handle<HeapNumber> heap_number = factory->NewHeapNumber(42.5);
    1177          10 :   WriteToField(*obj, 0, *heap_number);
    1178          10 :   WriteToField(*obj, 1, *obj_value);
    1179             : 
    1180             :   {
    1181             :     // Ensure the object is properly set up.
    1182           5 :     FieldIndex field_index = FieldIndex::ForDescriptor(*map, 0);
    1183          10 :     CHECK(field_index.is_inobject() && field_index.is_double());
    1184           5 :     CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
    1185           5 :     CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
    1186             : 
    1187           5 :     field_index = FieldIndex::ForDescriptor(*map, 1);
    1188          10 :     CHECK(field_index.is_inobject() && !field_index.is_double());
    1189           5 :     CHECK(!map->IsUnboxedDoubleField(field_index));
    1190             :   }
    1191           5 :   CHECK(isolate->heap()->new_space()->Contains(*obj));
    1192             : 
    1193             :   // Heap is ready, force |ec_page| to become an evacuation candidate and
    1194             :   // simulate incremental marking.
    1195           5 :   FLAG_stress_compaction = true;
    1196           5 :   FLAG_manual_evacuation_candidates_selection = true;
    1197           5 :   heap::ForceEvacuationCandidate(ec_page);
    1198           5 :   heap::SimulateIncrementalMarking(heap);
    1199             :   // Disable stress compaction mode in order to let GC do scavenge.
    1200           5 :   FLAG_stress_compaction = false;
    1201             : 
    1202             :   // Check that everything is ready for triggering incremental write barrier
    1203             :   // during scavenge (i.e. that |obj| is black and incremental marking is
    1204             :   // in compacting mode and |obj_value|'s page is an evacuation candidate).
    1205             :   IncrementalMarking* marking = heap->incremental_marking();
    1206           5 :   CHECK(marking->IsCompacting());
    1207             :   IncrementalMarking::MarkingState* marking_state =
    1208             :       heap->incremental_marking()->marking_state();
    1209           5 :   CHECK(marking_state->IsBlack(*obj));
    1210           5 :   CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
    1211             : 
    1212             :   // Trigger GCs so that |obj| moves to old gen.
    1213           5 :   CcTest::CollectGarbage(i::NEW_SPACE);  // in survivor space now
    1214           5 :   CcTest::CollectGarbage(i::NEW_SPACE);  // in old gen now
    1215             : 
    1216           5 :   CHECK(isolate->heap()->old_space()->Contains(*obj));
    1217           5 :   CHECK(isolate->heap()->old_space()->Contains(*obj_value));
    1218           5 :   CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
    1219             : 
    1220           5 :   CcTest::CollectGarbage(i::OLD_SPACE);
    1221             : 
    1222             :   // |obj_value| must be evacuated.
    1223           5 :   CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
    1224             : 
    1225           5 :   FieldIndex field_index = FieldIndex::ForDescriptor(*map, 1);
    1226          15 :   CHECK_EQ(*obj_value, obj->RawFastPropertyAt(field_index));
    1227             : }
    1228             : 
    1229             : 
    1230          75 : static void TestLayoutDescriptorHelper(Isolate* isolate,
    1231             :                                        int inobject_properties,
    1232             :                                        Handle<DescriptorArray> descriptors,
    1233             :                                        int number_of_descriptors) {
    1234          75 :   Handle<Map> map = Map::Create(isolate, inobject_properties);
    1235             : 
    1236             :   Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
    1237          75 :       isolate, map, descriptors, descriptors->number_of_descriptors());
    1238             :   InitializeVerifiedMapDescriptors(isolate, *map, *descriptors,
    1239          75 :                                    *layout_descriptor);
    1240             : 
    1241          75 :   LayoutDescriptorHelper helper(*map);
    1242             :   bool all_fields_tagged = true;
    1243             : 
    1244             :   int instance_size = map->instance_size();
    1245             : 
    1246          75 :   int end_offset = instance_size * 2;
    1247             :   int first_non_tagged_field_offset = end_offset;
    1248        7275 :   for (int i = 0; i < number_of_descriptors; i++) {
    1249        7200 :     PropertyDetails details = descriptors->GetDetails(i);
    1250       11445 :     if (details.location() != kField) continue;
    1251        6600 :     FieldIndex index = FieldIndex::ForDescriptor(*map, i);
    1252        6600 :     if (!index.is_inobject()) continue;
    1253        2955 :     all_fields_tagged &= !details.representation().IsDouble();
    1254        2955 :     bool expected_tagged = !index.is_double();
    1255        2955 :     if (!expected_tagged) {
    1256             :       first_non_tagged_field_offset =
    1257             :           Min(first_non_tagged_field_offset, index.offset());
    1258             :     }
    1259             : 
    1260             :     int end_of_region_offset;
    1261        2955 :     CHECK_EQ(expected_tagged, helper.IsTagged(index.offset()));
    1262        2955 :     CHECK_EQ(expected_tagged, helper.IsTagged(index.offset(), instance_size,
    1263             :                                               &end_of_region_offset));
    1264        2955 :     CHECK_GT(end_of_region_offset, 0);
    1265        2955 :     CHECK_EQ(end_of_region_offset % kTaggedSize, 0);
    1266        2955 :     CHECK(end_of_region_offset <= instance_size);
    1267             : 
    1268       74865 :     for (int offset = index.offset(); offset < end_of_region_offset;
    1269             :          offset += kTaggedSize) {
    1270       74865 :       CHECK_EQ(expected_tagged, helper.IsTagged(index.offset()));
    1271             :     }
    1272        2955 :     if (end_of_region_offset < instance_size) {
    1273         875 :       CHECK_EQ(!expected_tagged, helper.IsTagged(end_of_region_offset));
    1274             :     } else {
    1275        2080 :       CHECK(helper.IsTagged(end_of_region_offset));
    1276             :     }
    1277             :   }
    1278             : 
    1279         225 :   for (int offset = 0; offset < JSObject::kHeaderSize; offset += kTaggedSize) {
    1280             :     // Header queries
    1281         225 :     CHECK(helper.IsTagged(offset));
    1282             :     int end_of_region_offset;
    1283         225 :     CHECK(helper.IsTagged(offset, end_offset, &end_of_region_offset));
    1284         225 :     CHECK_EQ(first_non_tagged_field_offset, end_of_region_offset);
    1285             : 
    1286             :     // Out of bounds queries
    1287         225 :     CHECK(helper.IsTagged(offset + instance_size));
    1288             :   }
    1289             : 
    1290          75 :   CHECK_EQ(all_fields_tagged, helper.all_fields_tagged());
    1291          75 : }
    1292             : 
    1293             : 
    1294       25880 : TEST(LayoutDescriptorHelperMixed) {
    1295           5 :   CcTest::InitializeVM();
    1296             :   Isolate* isolate = CcTest::i_isolate();
    1297           5 :   v8::HandleScope scope(CcTest::isolate());
    1298             : 
    1299             :   Handle<LayoutDescriptor> layout_descriptor;
    1300             :   const int kPropsCount = kBitsInSmiLayout * 3;
    1301             :   TestPropertyKind props[kPropsCount];
    1302         485 :   for (int i = 0; i < kPropsCount; i++) {
    1303         480 :     props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
    1304             :   }
    1305             :   Handle<DescriptorArray> descriptors =
    1306           5 :       CreateDescriptorArray(isolate, props, kPropsCount);
    1307             : 
    1308           5 :   TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
    1309             : 
    1310           5 :   TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
    1311             : 
    1312             :   TestLayoutDescriptorHelper(isolate, kBitsInSmiLayout, descriptors,
    1313           5 :                              kPropsCount);
    1314             : 
    1315             :   TestLayoutDescriptorHelper(isolate, kBitsInSmiLayout * 2, descriptors,
    1316           5 :                              kPropsCount);
    1317             : 
    1318           5 :   TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
    1319           5 : }
    1320             : 
    1321             : 
    1322       25880 : TEST(LayoutDescriptorHelperAllTagged) {
    1323           5 :   CcTest::InitializeVM();
    1324             :   Isolate* isolate = CcTest::i_isolate();
    1325           5 :   v8::HandleScope scope(CcTest::isolate());
    1326             : 
    1327             :   Handle<LayoutDescriptor> layout_descriptor;
    1328             :   const int kPropsCount = kBitsInSmiLayout * 3;
    1329             :   TestPropertyKind props[kPropsCount];
    1330         485 :   for (int i = 0; i < kPropsCount; i++) {
    1331         480 :     props[i] = PROP_TAGGED;
    1332             :   }
    1333             :   Handle<DescriptorArray> descriptors =
    1334           5 :       CreateDescriptorArray(isolate, props, kPropsCount);
    1335             : 
    1336           5 :   TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
    1337             : 
    1338           5 :   TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
    1339             : 
    1340             :   TestLayoutDescriptorHelper(isolate, kBitsInSmiLayout, descriptors,
    1341           5 :                              kPropsCount);
    1342             : 
    1343             :   TestLayoutDescriptorHelper(isolate, kBitsInSmiLayout * 2, descriptors,
    1344           5 :                              kPropsCount);
    1345             : 
    1346           5 :   TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
    1347           5 : }
    1348             : 
    1349             : 
    1350       25880 : TEST(LayoutDescriptorHelperAllDoubles) {
    1351           5 :   CcTest::InitializeVM();
    1352             :   Isolate* isolate = CcTest::i_isolate();
    1353           5 :   v8::HandleScope scope(CcTest::isolate());
    1354             : 
    1355             :   Handle<LayoutDescriptor> layout_descriptor;
    1356             :   const int kPropsCount = kBitsInSmiLayout * 3;
    1357             :   TestPropertyKind props[kPropsCount];
    1358         485 :   for (int i = 0; i < kPropsCount; i++) {
    1359         480 :     props[i] = PROP_DOUBLE;
    1360             :   }
    1361             :   Handle<DescriptorArray> descriptors =
    1362           5 :       CreateDescriptorArray(isolate, props, kPropsCount);
    1363             : 
    1364           5 :   TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
    1365             : 
    1366           5 :   TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
    1367             : 
    1368             :   TestLayoutDescriptorHelper(isolate, kBitsInSmiLayout, descriptors,
    1369           5 :                              kPropsCount);
    1370             : 
    1371             :   TestLayoutDescriptorHelper(isolate, kBitsInSmiLayout * 2, descriptors,
    1372           5 :                              kPropsCount);
    1373             : 
    1374           5 :   TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
    1375           5 : }
    1376             : 
    1377             : 
    1378       25880 : TEST(LayoutDescriptorSharing) {
    1379           5 :   CcTest::InitializeVM();
    1380           5 :   v8::HandleScope scope(CcTest::isolate());
    1381             :   Isolate* isolate = CcTest::i_isolate();
    1382           5 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    1383             : 
    1384             :   Handle<Map> split_map;
    1385             :   {
    1386           5 :     Handle<Map> map = Map::Create(isolate, 64);
    1387         165 :     for (int i = 0; i < 32; i++) {
    1388         160 :       Handle<String> name = MakeName("prop", i);
    1389             :       map = Map::CopyWithField(isolate, map, name, any_type, NONE,
    1390             :                                PropertyConstness::kMutable,
    1391         160 :                                Representation::Smi(), INSERT_TRANSITION)
    1392         320 :                 .ToHandleChecked();
    1393             :     }
    1394             :     split_map = Map::CopyWithField(isolate, map, MakeString("dbl"), any_type,
    1395             :                                    NONE, PropertyConstness::kMutable,
    1396           5 :                                    Representation::Double(), INSERT_TRANSITION)
    1397          10 :                     .ToHandleChecked();
    1398             :   }
    1399             :   Handle<LayoutDescriptor> split_layout_descriptor(
    1400          10 :       split_map->layout_descriptor(), isolate);
    1401           5 :   CHECK(split_layout_descriptor->IsConsistentWithMap(*split_map, true));
    1402          10 :   CHECK(split_layout_descriptor->IsSlowLayout());
    1403           5 :   CHECK(split_map->owns_descriptors());
    1404             : 
    1405             :   Handle<Map> map1 =
    1406             :       Map::CopyWithField(isolate, split_map, MakeString("foo"), any_type, NONE,
    1407             :                          PropertyConstness::kMutable, Representation::Double(),
    1408           5 :                          INSERT_TRANSITION)
    1409          10 :           .ToHandleChecked();
    1410           5 :   CHECK(!split_map->owns_descriptors());
    1411          15 :   CHECK_EQ(*split_layout_descriptor, split_map->layout_descriptor());
    1412             : 
    1413             :   // Layout descriptors should be shared with |split_map|.
    1414           5 :   CHECK(map1->owns_descriptors());
    1415          15 :   CHECK_EQ(*split_layout_descriptor, map1->layout_descriptor());
    1416           5 :   CHECK(map1->layout_descriptor()->IsConsistentWithMap(*map1, true));
    1417             : 
    1418             :   Handle<Map> map2 =
    1419             :       Map::CopyWithField(isolate, split_map, MakeString("bar"), any_type, NONE,
    1420             :                          PropertyConstness::kMutable, Representation::Tagged(),
    1421           5 :                          INSERT_TRANSITION)
    1422          10 :           .ToHandleChecked();
    1423             : 
    1424             :   // Layout descriptors should not be shared with |split_map|.
    1425           5 :   CHECK(map2->owns_descriptors());
    1426          15 :   CHECK_NE(*split_layout_descriptor, map2->layout_descriptor());
    1427           5 :   CHECK(map2->layout_descriptor()->IsConsistentWithMap(*map2, true));
    1428           5 : }
    1429             : 
    1430             : 
    1431           5 : static void TestWriteBarrier(Handle<Map> map, Handle<Map> new_map,
    1432             :                              int tagged_descriptor, int double_descriptor,
    1433             :                              bool check_tagged_value = true) {
    1434           5 :   FLAG_stress_compaction = true;
    1435           5 :   FLAG_manual_evacuation_candidates_selection = true;
    1436             :   Isolate* isolate = CcTest::i_isolate();
    1437             :   Factory* factory = isolate->factory();
    1438           5 :   Heap* heap = CcTest::heap();
    1439             :   PagedSpace* old_space = heap->old_space();
    1440             : 
    1441             :   // The plan: create |obj| by |map| in old space, create |obj_value| in
    1442             :   // new space and ensure that write barrier is triggered when |obj_value| is
    1443             :   // written to property |tagged_descriptor| of |obj|.
    1444             :   // Then migrate object to |new_map| and set proper value for property
    1445             :   // |double_descriptor|. Call GC and ensure that it did not crash during
    1446             :   // store buffer entries updating.
    1447             : 
    1448             :   Handle<JSObject> obj;
    1449             :   Handle<HeapObject> obj_value;
    1450             :   {
    1451             :     AlwaysAllocateScope always_allocate(isolate);
    1452           5 :     obj = factory->NewJSObjectFromMap(map, TENURED);
    1453           5 :     CHECK(old_space->Contains(*obj));
    1454             : 
    1455           5 :     obj_value = factory->NewHeapNumber(0.);
    1456             :   }
    1457             : 
    1458           5 :   CHECK(Heap::InYoungGeneration(*obj_value));
    1459             : 
    1460             :   {
    1461           5 :     FieldIndex index = FieldIndex::ForDescriptor(*map, tagged_descriptor);
    1462             :     const int n = 153;
    1463         770 :     for (int i = 0; i < n; i++) {
    1464        1530 :       obj->FastPropertyAtPut(index, *obj_value);
    1465             :     }
    1466             :   }
    1467             : 
    1468             :   // Migrate |obj| to |new_map| which should shift fields and put the
    1469             :   // |boom_value| to the slot that was earlier recorded by write barrier.
    1470           5 :   JSObject::MigrateToMap(obj, new_map);
    1471             : 
    1472           5 :   Address fake_object = obj_value->ptr() + kTaggedSize;
    1473             :   uint64_t boom_value = bit_cast<uint64_t>(fake_object);
    1474             : 
    1475             :   FieldIndex double_field_index =
    1476           5 :       FieldIndex::ForDescriptor(*new_map, double_descriptor);
    1477           5 :   CHECK(obj->IsUnboxedDoubleField(double_field_index));
    1478             :   obj->RawFastDoublePropertyAsBitsAtPut(double_field_index, boom_value);
    1479             : 
    1480             :   // Trigger GC to evacuate all candidates.
    1481           5 :   CcTest::CollectGarbage(NEW_SPACE);
    1482             : 
    1483           5 :   if (check_tagged_value) {
    1484             :     FieldIndex tagged_field_index =
    1485           5 :         FieldIndex::ForDescriptor(*new_map, tagged_descriptor);
    1486          15 :     CHECK_EQ(*obj_value, obj->RawFastPropertyAt(tagged_field_index));
    1487             :   }
    1488           5 :   CHECK_EQ(boom_value, obj->RawFastDoublePropertyAsBitsAt(double_field_index));
    1489           5 : }
    1490             : 
    1491             : 
    1492           5 : static void TestIncrementalWriteBarrier(Handle<Map> map, Handle<Map> new_map,
    1493             :                                         int tagged_descriptor,
    1494             :                                         int double_descriptor,
    1495             :                                         bool check_tagged_value = true) {
    1496           5 :   if (FLAG_never_compact || !FLAG_incremental_marking) return;
    1497             :   ManualGCScope manual_gc_scope;
    1498           5 :   FLAG_manual_evacuation_candidates_selection = true;
    1499             :   Isolate* isolate = CcTest::i_isolate();
    1500             :   Factory* factory = isolate->factory();
    1501           5 :   Heap* heap = CcTest::heap();
    1502             :   PagedSpace* old_space = heap->old_space();
    1503             : 
    1504             :   // The plan: create |obj| by |map| in old space, create |obj_value| in
    1505             :   // old space and ensure it end up in evacuation candidate page. Start
    1506             :   // incremental marking and ensure that incremental write barrier is triggered
    1507             :   // when |obj_value| is written to property |tagged_descriptor| of |obj|.
    1508             :   // Then migrate object to |new_map| and set proper value for property
    1509             :   // |double_descriptor|. Call GC and ensure that it did not crash during
    1510             :   // slots buffer entries updating.
    1511             : 
    1512             :   Handle<JSObject> obj;
    1513             :   Handle<HeapObject> obj_value;
    1514             :   Page* ec_page;
    1515             :   {
    1516             :     AlwaysAllocateScope always_allocate(isolate);
    1517           5 :     obj = factory->NewJSObjectFromMap(map, TENURED);
    1518           5 :     CHECK(old_space->Contains(*obj));
    1519             : 
    1520             :     // Make sure |obj_value| is placed on an old-space evacuation candidate.
    1521           5 :     heap::SimulateFullSpace(old_space);
    1522           5 :     obj_value = factory->NewJSArray(32 * KB, HOLEY_ELEMENTS, TENURED);
    1523             :     ec_page = Page::FromHeapObject(*obj_value);
    1524           5 :     CHECK_NE(ec_page, Page::FromHeapObject(*obj));
    1525             :   }
    1526             : 
    1527             :   // Heap is ready, force |ec_page| to become an evacuation candidate and
    1528             :   // simulate incremental marking.
    1529           5 :   heap::ForceEvacuationCandidate(ec_page);
    1530           5 :   heap::SimulateIncrementalMarking(heap);
    1531             : 
    1532             :   // Check that everything is ready for triggering incremental write barrier
    1533             :   // (i.e. that both |obj| and |obj_value| are black and the marking phase is
    1534             :   // still active and |obj_value|'s page is indeed an evacuation candidate).
    1535             :   IncrementalMarking* marking = heap->incremental_marking();
    1536           5 :   CHECK(marking->IsMarking());
    1537             :   IncrementalMarking::MarkingState* marking_state = marking->marking_state();
    1538           5 :   CHECK(marking_state->IsBlack(*obj));
    1539           5 :   CHECK(marking_state->IsBlack(*obj_value));
    1540           5 :   CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
    1541             : 
    1542             :   // Trigger incremental write barrier, which should add a slot to remembered
    1543             :   // set.
    1544             :   {
    1545           5 :     FieldIndex index = FieldIndex::ForDescriptor(*map, tagged_descriptor);
    1546          10 :     obj->FastPropertyAtPut(index, *obj_value);
    1547             :   }
    1548             : 
    1549             :   // Migrate |obj| to |new_map| which should shift fields and put the
    1550             :   // |boom_value| to the slot that was earlier recorded by incremental write
    1551             :   // barrier.
    1552           5 :   JSObject::MigrateToMap(obj, new_map);
    1553             : 
    1554             :   uint64_t boom_value = UINT64_C(0xBAAD0176A37C28E1);
    1555             : 
    1556             :   FieldIndex double_field_index =
    1557           5 :       FieldIndex::ForDescriptor(*new_map, double_descriptor);
    1558           5 :   CHECK(obj->IsUnboxedDoubleField(double_field_index));
    1559             :   obj->RawFastDoublePropertyAsBitsAtPut(double_field_index, boom_value);
    1560             : 
    1561             :   // Trigger GC to evacuate all candidates.
    1562           5 :   CcTest::CollectGarbage(OLD_SPACE);
    1563             : 
    1564             :   // Ensure that the values are still there and correct.
    1565           5 :   CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
    1566             : 
    1567           5 :   if (check_tagged_value) {
    1568             :     FieldIndex tagged_field_index =
    1569           5 :         FieldIndex::ForDescriptor(*new_map, tagged_descriptor);
    1570          15 :     CHECK_EQ(*obj_value, obj->RawFastPropertyAt(tagged_field_index));
    1571             :   }
    1572           5 :   CHECK_EQ(boom_value, obj->RawFastDoublePropertyAsBitsAt(double_field_index));
    1573             : }
    1574             : 
    1575             : enum OldToWriteBarrierKind {
    1576             :   OLD_TO_OLD_WRITE_BARRIER,
    1577             :   OLD_TO_NEW_WRITE_BARRIER
    1578             : };
    1579          10 : static void TestWriteBarrierObjectShiftFieldsRight(
    1580             :     OldToWriteBarrierKind write_barrier_kind) {
    1581             :   ManualGCScope manual_gc_scope;
    1582          10 :   CcTest::InitializeVM();
    1583             :   Isolate* isolate = CcTest::i_isolate();
    1584          20 :   v8::HandleScope scope(CcTest::isolate());
    1585             : 
    1586          10 :   Handle<FieldType> any_type = FieldType::Any(isolate);
    1587             : 
    1588             :   CompileRun("function func() { return 1; }");
    1589             : 
    1590          10 :   Handle<JSObject> func = GetObject("func");
    1591             : 
    1592          10 :   Handle<Map> map = Map::Create(isolate, 10);
    1593             :   map = Map::CopyWithConstant(isolate, map, MakeName("prop", 0), func, NONE,
    1594          20 :                               INSERT_TRANSITION)
    1595          20 :             .ToHandleChecked();
    1596             :   map = Map::CopyWithField(isolate, map, MakeName("prop", 1), any_type, NONE,
    1597             :                            PropertyConstness::kMutable,
    1598          20 :                            Representation::Double(), INSERT_TRANSITION)
    1599          20 :             .ToHandleChecked();
    1600             :   map = Map::CopyWithField(isolate, map, MakeName("prop", 2), any_type, NONE,
    1601             :                            PropertyConstness::kMutable,
    1602          20 :                            Representation::Tagged(), INSERT_TRANSITION)
    1603          20 :             .ToHandleChecked();
    1604             : 
    1605             :   // Shift fields right by turning constant property to a field.
    1606             :   Handle<Map> new_map = Map::ReconfigureProperty(
    1607          10 :       isolate, map, 0, kData, NONE, Representation::Tagged(), any_type);
    1608             : 
    1609          10 :   if (write_barrier_kind == OLD_TO_NEW_WRITE_BARRIER) {
    1610           5 :     TestWriteBarrier(map, new_map, 2, 1);
    1611             :   } else {
    1612           5 :     CHECK_EQ(OLD_TO_OLD_WRITE_BARRIER, write_barrier_kind);
    1613           5 :     TestIncrementalWriteBarrier(map, new_map, 2, 1);
    1614             :   }
    1615          10 : }
    1616             : 
    1617       25880 : TEST(WriteBarrierObjectShiftFieldsRight) {
    1618           5 :   TestWriteBarrierObjectShiftFieldsRight(OLD_TO_NEW_WRITE_BARRIER);
    1619           5 : }
    1620             : 
    1621             : 
    1622       25880 : TEST(IncrementalWriteBarrierObjectShiftFieldsRight) {
    1623           5 :   TestWriteBarrierObjectShiftFieldsRight(OLD_TO_OLD_WRITE_BARRIER);
    1624           5 : }
    1625             : 
    1626             : 
    1627             : // TODO(ishell): add respective tests for property kind reconfiguring from
    1628             : // accessor field to double, once accessor fields are supported by
    1629             : // Map::ReconfigureProperty().
    1630             : 
    1631             : 
    1632             : // TODO(ishell): add respective tests for fast property removal case once
    1633             : // Map::ReconfigureProperty() supports that.
    1634             : 
    1635             : #endif
    1636             : 
    1637             : }  // namespace test_unboxed_doubles
    1638             : }  // namespace internal
    1639       77625 : }  // namespace v8

Generated by: LCOV version 1.10