fdcac3af355067c2d1e5945ef39e83cdec439692
[platform/upstream/nodejs.git] / deps / v8 / test / cctest / test-unboxed-doubles.cc
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/compilation-cache.h"
11 #include "src/execution.h"
12 #include "src/factory.h"
13 #include "src/global-handles.h"
14 #include "src/ic/ic.h"
15 #include "src/macro-assembler.h"
16 #include "test/cctest/cctest.h"
17
18 using namespace v8::base;
19 using namespace v8::internal;
20
21 #if (V8_DOUBLE_FIELDS_UNBOXING)
22
23
24 //
25 // Helper functions.
26 //
27
28
29 static void InitializeVerifiedMapDescriptors(
30     Map* map, DescriptorArray* descriptors,
31     LayoutDescriptor* layout_descriptor) {
32   map->InitializeDescriptors(descriptors, layout_descriptor);
33   CHECK(layout_descriptor->IsConsistentWithMap(map));
34 }
35
36
37 static Handle<String> MakeString(const char* str) {
38   Isolate* isolate = CcTest::i_isolate();
39   Factory* factory = isolate->factory();
40   return factory->InternalizeUtf8String(str);
41 }
42
43
44 static Handle<String> MakeName(const char* str, int suffix) {
45   EmbeddedVector<char, 128> buffer;
46   SNPrintF(buffer, "%s%d", str, suffix);
47   return MakeString(buffer.start());
48 }
49
50
51 static double GetDoubleFieldValue(JSObject* obj, FieldIndex field_index) {
52   if (obj->IsUnboxedDoubleField(field_index)) {
53     return obj->RawFastDoublePropertyAt(field_index);
54   } else {
55     Object* value = obj->RawFastPropertyAt(field_index);
56     DCHECK(value->IsMutableHeapNumber());
57     return HeapNumber::cast(value)->value();
58   }
59 }
60
61 const int kNumberOfBits = 32;
62
63
64 enum TestPropertyKind {
65   PROP_CONSTANT,
66   PROP_SMI,
67   PROP_DOUBLE,
68   PROP_TAGGED,
69   PROP_KIND_NUMBER
70 };
71
72 static Representation representations[PROP_KIND_NUMBER] = {
73     Representation::None(), Representation::Smi(), Representation::Double(),
74     Representation::Tagged()};
75
76
77 static Handle<DescriptorArray> CreateDescriptorArray(Isolate* isolate,
78                                                      TestPropertyKind* props,
79                                                      int kPropsCount) {
80   Factory* factory = isolate->factory();
81
82   Handle<String> func_name = factory->InternalizeUtf8String("func");
83   Handle<JSFunction> func = factory->NewFunction(func_name);
84
85   Handle<DescriptorArray> descriptors =
86       DescriptorArray::Allocate(isolate, 0, kPropsCount);
87
88   int next_field_offset = 0;
89   for (int i = 0; i < kPropsCount; i++) {
90     EmbeddedVector<char, 64> buffer;
91     SNPrintF(buffer, "prop%d", i);
92     Handle<String> name = factory->InternalizeUtf8String(buffer.start());
93
94     TestPropertyKind kind = props[i];
95
96     if (kind == PROP_CONSTANT) {
97       DataConstantDescriptor d(name, func, NONE);
98       descriptors->Append(&d);
99
100     } else {
101       DataDescriptor f(name, next_field_offset, NONE, representations[kind]);
102       next_field_offset += f.GetDetails().field_width_in_words();
103       descriptors->Append(&f);
104     }
105   }
106   return descriptors;
107 }
108
109
110 TEST(LayoutDescriptorBasicFast) {
111   CcTest::InitializeVM();
112   v8::HandleScope scope(CcTest::isolate());
113
114   LayoutDescriptor* layout_desc = LayoutDescriptor::FastPointerLayout();
115
116   CHECK(!layout_desc->IsSlowLayout());
117   CHECK(layout_desc->IsFastPointerLayout());
118   CHECK_EQ(kSmiValueSize, layout_desc->capacity());
119
120   for (int i = 0; i < kSmiValueSize + 13; i++) {
121     CHECK_EQ(true, layout_desc->IsTagged(i));
122   }
123   CHECK_EQ(true, layout_desc->IsTagged(-1));
124   CHECK_EQ(true, layout_desc->IsTagged(-12347));
125   CHECK_EQ(true, layout_desc->IsTagged(15635));
126   CHECK(layout_desc->IsFastPointerLayout());
127
128   for (int i = 0; i < kSmiValueSize; i++) {
129     layout_desc = layout_desc->SetTaggedForTesting(i, false);
130     CHECK_EQ(false, layout_desc->IsTagged(i));
131     layout_desc = layout_desc->SetTaggedForTesting(i, true);
132     CHECK_EQ(true, layout_desc->IsTagged(i));
133   }
134   CHECK(layout_desc->IsFastPointerLayout());
135
136   int sequence_length;
137   CHECK_EQ(true, layout_desc->IsTagged(0, std::numeric_limits<int>::max(),
138                                        &sequence_length));
139   CHECK_EQ(std::numeric_limits<int>::max(), sequence_length);
140
141   CHECK_EQ(true, layout_desc->IsTagged(0, 7, &sequence_length));
142   CHECK_EQ(7, sequence_length);
143 }
144
145
146 TEST(LayoutDescriptorBasicSlow) {
147   CcTest::InitializeVM();
148   Isolate* isolate = CcTest::i_isolate();
149   v8::HandleScope scope(CcTest::isolate());
150
151   Handle<LayoutDescriptor> layout_descriptor;
152   const int kPropsCount = kSmiValueSize * 3;
153   TestPropertyKind props[kPropsCount];
154   for (int i = 0; i < kPropsCount; i++) {
155     // All properties tagged.
156     props[i] = PROP_TAGGED;
157   }
158
159   {
160     Handle<DescriptorArray> descriptors =
161         CreateDescriptorArray(isolate, props, kPropsCount);
162
163     Handle<Map> map = Map::Create(isolate, kPropsCount);
164
165     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
166     CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
167     CHECK_EQ(kSmiValueSize, layout_descriptor->capacity());
168     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
169   }
170
171   props[0] = PROP_DOUBLE;
172   props[kPropsCount - 1] = PROP_DOUBLE;
173
174   Handle<DescriptorArray> descriptors =
175       CreateDescriptorArray(isolate, props, kPropsCount);
176
177   {
178     int inobject_properties = kPropsCount - 1;
179     Handle<Map> map = Map::Create(isolate, inobject_properties);
180
181     // Should be fast as the only double property is the first one.
182     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
183     CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
184     CHECK(!layout_descriptor->IsSlowLayout());
185     CHECK(!layout_descriptor->IsFastPointerLayout());
186
187     CHECK_EQ(false, layout_descriptor->IsTagged(0));
188     for (int i = 1; i < kPropsCount; i++) {
189       CHECK_EQ(true, layout_descriptor->IsTagged(i));
190     }
191     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
192   }
193
194   {
195     int inobject_properties = kPropsCount;
196     Handle<Map> map = Map::Create(isolate, inobject_properties);
197
198     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
199     CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
200     CHECK(layout_descriptor->IsSlowLayout());
201     CHECK(!layout_descriptor->IsFastPointerLayout());
202     CHECK(layout_descriptor->capacity() > kSmiValueSize);
203
204     CHECK_EQ(false, layout_descriptor->IsTagged(0));
205     CHECK_EQ(false, layout_descriptor->IsTagged(kPropsCount - 1));
206     for (int i = 1; i < kPropsCount - 1; i++) {
207       CHECK_EQ(true, layout_descriptor->IsTagged(i));
208     }
209
210     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
211
212     // Here we have truly slow layout descriptor, so play with the bits.
213     CHECK_EQ(true, layout_descriptor->IsTagged(-1));
214     CHECK_EQ(true, layout_descriptor->IsTagged(-12347));
215     CHECK_EQ(true, layout_descriptor->IsTagged(15635));
216
217     LayoutDescriptor* layout_desc = *layout_descriptor;
218     // Play with the bits but leave it in consistent state with map at the end.
219     for (int i = 1; i < kPropsCount - 1; i++) {
220       layout_desc = layout_desc->SetTaggedForTesting(i, false);
221       CHECK_EQ(false, layout_desc->IsTagged(i));
222       layout_desc = layout_desc->SetTaggedForTesting(i, true);
223       CHECK_EQ(true, layout_desc->IsTagged(i));
224     }
225     CHECK(layout_desc->IsSlowLayout());
226     CHECK(!layout_desc->IsFastPointerLayout());
227     CHECK(layout_descriptor->IsConsistentWithMap(*map));
228   }
229 }
230
231
232 static void TestLayoutDescriptorQueries(int layout_descriptor_length,
233                                         int* bit_flip_positions,
234                                         int max_sequence_length) {
235   Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::NewForTesting(
236       CcTest::i_isolate(), layout_descriptor_length);
237   layout_descriptor_length = layout_descriptor->capacity();
238   LayoutDescriptor* layout_desc = *layout_descriptor;
239
240   {
241     // Fill in the layout descriptor.
242     int cur_bit_flip_index = 0;
243     bool tagged = true;
244     for (int i = 0; i < layout_descriptor_length; i++) {
245       if (i == bit_flip_positions[cur_bit_flip_index]) {
246         tagged = !tagged;
247         ++cur_bit_flip_index;
248         CHECK(i < bit_flip_positions[cur_bit_flip_index]);  // check test data
249       }
250       layout_desc = layout_desc->SetTaggedForTesting(i, tagged);
251     }
252   }
253
254   if (layout_desc->IsFastPointerLayout()) {
255     return;
256   }
257
258   {
259     // Check queries.
260     int cur_bit_flip_index = 0;
261     bool tagged = true;
262     for (int i = 0; i < layout_descriptor_length; i++) {
263       if (i == bit_flip_positions[cur_bit_flip_index]) {
264         tagged = !tagged;
265         ++cur_bit_flip_index;
266       }
267       CHECK_EQ(tagged, layout_desc->IsTagged(i));
268
269       int next_bit_flip_position = bit_flip_positions[cur_bit_flip_index];
270       int expected_sequence_length;
271       if (next_bit_flip_position < layout_desc->capacity()) {
272         expected_sequence_length = next_bit_flip_position - i;
273       } else {
274         expected_sequence_length = tagged ? std::numeric_limits<int>::max()
275                                           : (layout_desc->capacity() - i);
276       }
277       expected_sequence_length =
278           Min(expected_sequence_length, max_sequence_length);
279       int sequence_length;
280       CHECK_EQ(tagged,
281                layout_desc->IsTagged(i, max_sequence_length, &sequence_length));
282       CHECK(sequence_length > 0);
283
284       CHECK_EQ(expected_sequence_length, sequence_length);
285     }
286
287     int sequence_length;
288     CHECK_EQ(true,
289              layout_desc->IsTagged(layout_descriptor_length,
290                                    max_sequence_length, &sequence_length));
291     CHECK_EQ(max_sequence_length, sequence_length);
292   }
293 }
294
295
296 static void TestLayoutDescriptorQueriesFast(int max_sequence_length) {
297   {
298     LayoutDescriptor* layout_desc = LayoutDescriptor::FastPointerLayout();
299     int sequence_length;
300     for (int i = 0; i < kNumberOfBits; i++) {
301       CHECK_EQ(true,
302                layout_desc->IsTagged(i, max_sequence_length, &sequence_length));
303       CHECK(sequence_length > 0);
304       CHECK_EQ(max_sequence_length, sequence_length);
305     }
306   }
307
308   {
309     int bit_flip_positions[] = {1000};
310     TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
311                                 max_sequence_length);
312   }
313
314   {
315     int bit_flip_positions[] = {0, 1000};
316     TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
317                                 max_sequence_length);
318   }
319
320   {
321     int bit_flip_positions[kNumberOfBits + 1];
322     for (int i = 0; i <= kNumberOfBits; i++) {
323       bit_flip_positions[i] = i;
324     }
325     TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
326                                 max_sequence_length);
327   }
328
329   {
330     int bit_flip_positions[] = {3, 7, 8, 10, 15, 21, 30, 1000};
331     TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
332                                 max_sequence_length);
333   }
334
335   {
336     int bit_flip_positions[] = {0,  1,  2,  3,  5,  7,  9,
337                                 12, 15, 18, 22, 26, 29, 1000};
338     TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
339                                 max_sequence_length);
340   }
341 }
342
343
344 TEST(LayoutDescriptorQueriesFastLimited7) {
345   CcTest::InitializeVM();
346   v8::HandleScope scope(CcTest::isolate());
347
348   TestLayoutDescriptorQueriesFast(7);
349 }
350
351
352 TEST(LayoutDescriptorQueriesFastLimited13) {
353   CcTest::InitializeVM();
354   v8::HandleScope scope(CcTest::isolate());
355
356   TestLayoutDescriptorQueriesFast(13);
357 }
358
359
360 TEST(LayoutDescriptorQueriesFastUnlimited) {
361   CcTest::InitializeVM();
362   v8::HandleScope scope(CcTest::isolate());
363
364   TestLayoutDescriptorQueriesFast(std::numeric_limits<int>::max());
365 }
366
367
368 static void TestLayoutDescriptorQueriesSlow(int max_sequence_length) {
369   {
370     int bit_flip_positions[] = {10000};
371     TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
372                                 max_sequence_length);
373   }
374
375   {
376     int bit_flip_positions[] = {0, 10000};
377     TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
378                                 max_sequence_length);
379   }
380
381   {
382     int bit_flip_positions[kMaxNumberOfDescriptors + 1];
383     for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
384       bit_flip_positions[i] = i;
385     }
386     bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
387     TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
388                                 max_sequence_length);
389   }
390
391   {
392     int bit_flip_positions[] = {3,  7,  8,  10, 15,  21,   30,
393                                 37, 54, 80, 99, 383, 10000};
394     TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
395                                 max_sequence_length);
396   }
397
398   {
399     int bit_flip_positions[] = {0,   10,  20,  30,  50,  70,  90,
400                                 120, 150, 180, 220, 260, 290, 10000};
401     TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
402                                 max_sequence_length);
403   }
404
405   {
406     int bit_flip_positions[kMaxNumberOfDescriptors + 1];
407     int cur = 0;
408     for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
409       bit_flip_positions[i] = cur;
410       cur = (cur + 1) * 2;
411     }
412     CHECK(cur < 10000);
413     bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
414     TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
415                                 max_sequence_length);
416   }
417
418   {
419     int bit_flip_positions[kMaxNumberOfDescriptors + 1];
420     int cur = 3;
421     for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
422       bit_flip_positions[i] = cur;
423       cur = (cur + 1) * 2;
424     }
425     CHECK(cur < 10000);
426     bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
427     TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
428                                 max_sequence_length);
429   }
430 }
431
432
433 TEST(LayoutDescriptorQueriesSlowLimited7) {
434   CcTest::InitializeVM();
435   v8::HandleScope scope(CcTest::isolate());
436
437   TestLayoutDescriptorQueriesSlow(7);
438 }
439
440
441 TEST(LayoutDescriptorQueriesSlowLimited13) {
442   CcTest::InitializeVM();
443   v8::HandleScope scope(CcTest::isolate());
444
445   TestLayoutDescriptorQueriesSlow(13);
446 }
447
448
449 TEST(LayoutDescriptorQueriesSlowLimited42) {
450   CcTest::InitializeVM();
451   v8::HandleScope scope(CcTest::isolate());
452
453   TestLayoutDescriptorQueriesSlow(42);
454 }
455
456
457 TEST(LayoutDescriptorQueriesSlowUnlimited) {
458   CcTest::InitializeVM();
459   v8::HandleScope scope(CcTest::isolate());
460
461   TestLayoutDescriptorQueriesSlow(std::numeric_limits<int>::max());
462 }
463
464
465 TEST(LayoutDescriptorCreateNewFast) {
466   CcTest::InitializeVM();
467   Isolate* isolate = CcTest::i_isolate();
468   v8::HandleScope scope(CcTest::isolate());
469
470   Handle<LayoutDescriptor> layout_descriptor;
471   TestPropertyKind props[] = {
472       PROP_CONSTANT,
473       PROP_TAGGED,  // field #0
474       PROP_CONSTANT,
475       PROP_DOUBLE,  // field #1
476       PROP_CONSTANT,
477       PROP_TAGGED,  // field #2
478       PROP_CONSTANT,
479   };
480   const int kPropsCount = arraysize(props);
481
482   Handle<DescriptorArray> descriptors =
483       CreateDescriptorArray(isolate, props, kPropsCount);
484
485   {
486     Handle<Map> map = Map::Create(isolate, 0);
487     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
488     CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
489     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
490   }
491
492   {
493     Handle<Map> map = Map::Create(isolate, 1);
494     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
495     CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
496     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
497   }
498
499   {
500     Handle<Map> map = Map::Create(isolate, 2);
501     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
502     CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
503     CHECK(!layout_descriptor->IsSlowLayout());
504     CHECK_EQ(true, layout_descriptor->IsTagged(0));
505     CHECK_EQ(false, layout_descriptor->IsTagged(1));
506     CHECK_EQ(true, layout_descriptor->IsTagged(2));
507     CHECK_EQ(true, layout_descriptor->IsTagged(125));
508     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
509   }
510 }
511
512
513 TEST(LayoutDescriptorCreateNewSlow) {
514   CcTest::InitializeVM();
515   Isolate* isolate = CcTest::i_isolate();
516   v8::HandleScope scope(CcTest::isolate());
517
518   Handle<LayoutDescriptor> layout_descriptor;
519   const int kPropsCount = kSmiValueSize * 3;
520   TestPropertyKind props[kPropsCount];
521   for (int i = 0; i < kPropsCount; i++) {
522     props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
523   }
524
525   Handle<DescriptorArray> descriptors =
526       CreateDescriptorArray(isolate, props, kPropsCount);
527
528   {
529     Handle<Map> map = Map::Create(isolate, 0);
530     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
531     CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
532     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
533   }
534
535   {
536     Handle<Map> map = Map::Create(isolate, 1);
537     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
538     CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
539     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
540   }
541
542   {
543     Handle<Map> map = Map::Create(isolate, 2);
544     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
545     CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
546     CHECK(!layout_descriptor->IsSlowLayout());
547     CHECK_EQ(true, layout_descriptor->IsTagged(0));
548     CHECK_EQ(false, layout_descriptor->IsTagged(1));
549     CHECK_EQ(true, layout_descriptor->IsTagged(2));
550     CHECK_EQ(true, layout_descriptor->IsTagged(125));
551     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
552   }
553
554   {
555     int inobject_properties = kPropsCount / 2;
556     Handle<Map> map = Map::Create(isolate, inobject_properties);
557     layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
558     CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
559     CHECK(layout_descriptor->IsSlowLayout());
560     for (int i = 0; i < inobject_properties; i++) {
561       // PROP_DOUBLE has index 1 among DATA properties.
562       const bool tagged = (i % (PROP_KIND_NUMBER - 1)) != 1;
563       CHECK_EQ(tagged, layout_descriptor->IsTagged(i));
564     }
565     // Every property after inobject_properties must be tagged.
566     for (int i = inobject_properties; i < kPropsCount; i++) {
567       CHECK_EQ(true, layout_descriptor->IsTagged(i));
568     }
569     InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
570
571     // Now test LayoutDescriptor::cast_gc_safe().
572     Handle<LayoutDescriptor> layout_descriptor_copy =
573         LayoutDescriptor::New(map, descriptors, kPropsCount);
574
575     LayoutDescriptor* layout_desc = *layout_descriptor;
576     CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
577     CHECK_EQ(layout_desc, LayoutDescriptor::cast_gc_safe(layout_desc));
578     CHECK(layout_descriptor->IsFixedTypedArrayBase());
579     // Now make it look like a forwarding pointer to layout_descriptor_copy.
580     MapWord map_word = layout_desc->map_word();
581     CHECK(!map_word.IsForwardingAddress());
582     layout_desc->set_map_word(
583         MapWord::FromForwardingAddress(*layout_descriptor_copy));
584     CHECK(layout_desc->map_word().IsForwardingAddress());
585     CHECK_EQ(*layout_descriptor_copy,
586              LayoutDescriptor::cast_gc_safe(layout_desc));
587
588     // Restore it back.
589     layout_desc->set_map_word(map_word);
590     CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
591   }
592 }
593
594
595 static Handle<LayoutDescriptor> TestLayoutDescriptorAppend(
596     Isolate* isolate, int inobject_properties, TestPropertyKind* props,
597     int kPropsCount) {
598   Factory* factory = isolate->factory();
599
600   Handle<String> func_name = factory->InternalizeUtf8String("func");
601   Handle<JSFunction> func = factory->NewFunction(func_name);
602
603   Handle<DescriptorArray> descriptors =
604       DescriptorArray::Allocate(isolate, 0, kPropsCount);
605
606   Handle<Map> map = Map::Create(isolate, inobject_properties);
607   map->InitializeDescriptors(*descriptors,
608                              LayoutDescriptor::FastPointerLayout());
609
610   int next_field_offset = 0;
611   for (int i = 0; i < kPropsCount; i++) {
612     EmbeddedVector<char, 64> buffer;
613     SNPrintF(buffer, "prop%d", i);
614     Handle<String> name = factory->InternalizeUtf8String(buffer.start());
615
616     Handle<LayoutDescriptor> layout_descriptor;
617     TestPropertyKind kind = props[i];
618     if (kind == PROP_CONSTANT) {
619       DataConstantDescriptor d(name, func, NONE);
620       layout_descriptor = LayoutDescriptor::ShareAppend(map, d.GetDetails());
621       descriptors->Append(&d);
622
623     } else {
624       DataDescriptor f(name, next_field_offset, NONE, representations[kind]);
625       int field_width_in_words = f.GetDetails().field_width_in_words();
626       next_field_offset += field_width_in_words;
627       layout_descriptor = LayoutDescriptor::ShareAppend(map, f.GetDetails());
628       descriptors->Append(&f);
629
630       int field_index = f.GetDetails().field_index();
631       bool is_inobject = field_index < map->inobject_properties();
632       for (int bit = 0; bit < field_width_in_words; bit++) {
633         CHECK_EQ(is_inobject && (kind == PROP_DOUBLE),
634                  !layout_descriptor->IsTagged(field_index + bit));
635       }
636       CHECK(layout_descriptor->IsTagged(next_field_offset));
637     }
638     map->InitializeDescriptors(*descriptors, *layout_descriptor);
639   }
640   Handle<LayoutDescriptor> layout_descriptor(map->layout_descriptor(), isolate);
641   CHECK(layout_descriptor->IsConsistentWithMap(*map));
642   return layout_descriptor;
643 }
644
645
646 TEST(LayoutDescriptorAppend) {
647   CcTest::InitializeVM();
648   Isolate* isolate = CcTest::i_isolate();
649   v8::HandleScope scope(CcTest::isolate());
650
651   Handle<LayoutDescriptor> layout_descriptor;
652   const int kPropsCount = kSmiValueSize * 3;
653   TestPropertyKind props[kPropsCount];
654   for (int i = 0; i < kPropsCount; i++) {
655     props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
656   }
657
658   layout_descriptor =
659       TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount);
660   CHECK(!layout_descriptor->IsSlowLayout());
661
662   layout_descriptor =
663       TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
664   CHECK(!layout_descriptor->IsSlowLayout());
665
666   layout_descriptor =
667       TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount);
668   CHECK(!layout_descriptor->IsSlowLayout());
669
670   layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2,
671                                                  props, kPropsCount);
672   CHECK(layout_descriptor->IsSlowLayout());
673
674   layout_descriptor =
675       TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
676   CHECK(layout_descriptor->IsSlowLayout());
677 }
678
679
680 TEST(LayoutDescriptorAppendAllDoubles) {
681   CcTest::InitializeVM();
682   Isolate* isolate = CcTest::i_isolate();
683   v8::HandleScope scope(CcTest::isolate());
684
685   Handle<LayoutDescriptor> layout_descriptor;
686   const int kPropsCount = kSmiValueSize * 3;
687   TestPropertyKind props[kPropsCount];
688   for (int i = 0; i < kPropsCount; i++) {
689     props[i] = PROP_DOUBLE;
690   }
691
692   layout_descriptor =
693       TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount);
694   CHECK(!layout_descriptor->IsSlowLayout());
695
696   layout_descriptor =
697       TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
698   CHECK(!layout_descriptor->IsSlowLayout());
699
700   layout_descriptor =
701       TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount);
702   CHECK(!layout_descriptor->IsSlowLayout());
703
704   layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize + 1,
705                                                  props, kPropsCount);
706   CHECK(layout_descriptor->IsSlowLayout());
707
708   layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2,
709                                                  props, kPropsCount);
710   CHECK(layout_descriptor->IsSlowLayout());
711
712   layout_descriptor =
713       TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
714   CHECK(layout_descriptor->IsSlowLayout());
715
716   {
717     // Ensure layout descriptor switches into slow mode at the right moment.
718     layout_descriptor =
719         TestLayoutDescriptorAppend(isolate, kPropsCount, props, kSmiValueSize);
720     CHECK(!layout_descriptor->IsSlowLayout());
721
722     layout_descriptor = TestLayoutDescriptorAppend(isolate, kPropsCount, props,
723                                                    kSmiValueSize + 1);
724     CHECK(layout_descriptor->IsSlowLayout());
725   }
726 }
727
728
729 static Handle<LayoutDescriptor> TestLayoutDescriptorAppendIfFastOrUseFull(
730     Isolate* isolate, int inobject_properties,
731     Handle<DescriptorArray> descriptors, int number_of_descriptors) {
732   Handle<Map> map = Map::Create(isolate, inobject_properties);
733
734   Handle<LayoutDescriptor> full_layout_descriptor = LayoutDescriptor::New(
735       map, descriptors, descriptors->number_of_descriptors());
736
737   int nof = 0;
738   bool switched_to_slow_mode = false;
739
740   for (int i = 0; i < number_of_descriptors; i++) {
741     PropertyDetails details = descriptors->GetDetails(i);
742
743     // This method calls LayoutDescriptor::AppendIfFastOrUseFull() internally
744     // and does all the required map-descriptors related book keeping.
745     map = Map::CopyInstallDescriptorsForTesting(map, i, descriptors,
746                                                 full_layout_descriptor);
747
748     LayoutDescriptor* layout_desc = map->layout_descriptor();
749
750     if (layout_desc->IsSlowLayout()) {
751       switched_to_slow_mode = true;
752       CHECK_EQ(*full_layout_descriptor, layout_desc);
753     } else {
754       CHECK(!switched_to_slow_mode);
755       if (details.type() == DATA) {
756         nof++;
757         int field_index = details.field_index();
758         int field_width_in_words = details.field_width_in_words();
759
760         bool is_inobject = field_index < map->inobject_properties();
761         for (int bit = 0; bit < field_width_in_words; bit++) {
762           CHECK_EQ(is_inobject && details.representation().IsDouble(),
763                    !layout_desc->IsTagged(field_index + bit));
764         }
765         CHECK(layout_desc->IsTagged(field_index + field_width_in_words));
766       }
767     }
768     CHECK(map->layout_descriptor()->IsConsistentWithMap(*map));
769   }
770
771   Handle<LayoutDescriptor> layout_descriptor(map->GetLayoutDescriptor(),
772                                              isolate);
773   CHECK(layout_descriptor->IsConsistentWithMap(*map));
774   return layout_descriptor;
775 }
776
777
778 TEST(LayoutDescriptorAppendIfFastOrUseFull) {
779   CcTest::InitializeVM();
780   Isolate* isolate = CcTest::i_isolate();
781   v8::HandleScope scope(CcTest::isolate());
782
783   Handle<LayoutDescriptor> layout_descriptor;
784   const int kPropsCount = kSmiValueSize * 3;
785   TestPropertyKind props[kPropsCount];
786   for (int i = 0; i < kPropsCount; i++) {
787     props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
788   }
789   Handle<DescriptorArray> descriptors =
790       CreateDescriptorArray(isolate, props, kPropsCount);
791
792   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
793       isolate, 0, descriptors, kPropsCount);
794   CHECK(!layout_descriptor->IsSlowLayout());
795
796   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
797       isolate, 13, descriptors, kPropsCount);
798   CHECK(!layout_descriptor->IsSlowLayout());
799
800   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
801       isolate, kSmiValueSize, descriptors, kPropsCount);
802   CHECK(!layout_descriptor->IsSlowLayout());
803
804   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
805       isolate, kSmiValueSize * 2, descriptors, kPropsCount);
806   CHECK(layout_descriptor->IsSlowLayout());
807
808   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
809       isolate, kPropsCount, descriptors, kPropsCount);
810   CHECK(layout_descriptor->IsSlowLayout());
811 }
812
813
814 TEST(LayoutDescriptorAppendIfFastOrUseFullAllDoubles) {
815   CcTest::InitializeVM();
816   Isolate* isolate = CcTest::i_isolate();
817   v8::HandleScope scope(CcTest::isolate());
818
819   Handle<LayoutDescriptor> layout_descriptor;
820   const int kPropsCount = kSmiValueSize * 3;
821   TestPropertyKind props[kPropsCount];
822   for (int i = 0; i < kPropsCount; i++) {
823     props[i] = PROP_DOUBLE;
824   }
825   Handle<DescriptorArray> descriptors =
826       CreateDescriptorArray(isolate, props, kPropsCount);
827
828   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
829       isolate, 0, descriptors, kPropsCount);
830   CHECK(!layout_descriptor->IsSlowLayout());
831
832   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
833       isolate, 13, descriptors, kPropsCount);
834   CHECK(!layout_descriptor->IsSlowLayout());
835
836   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
837       isolate, kSmiValueSize, descriptors, kPropsCount);
838   CHECK(!layout_descriptor->IsSlowLayout());
839
840   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
841       isolate, kSmiValueSize + 1, descriptors, kPropsCount);
842   CHECK(layout_descriptor->IsSlowLayout());
843
844   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
845       isolate, kSmiValueSize * 2, descriptors, kPropsCount);
846   CHECK(layout_descriptor->IsSlowLayout());
847
848   layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
849       isolate, kPropsCount, descriptors, kPropsCount);
850   CHECK(layout_descriptor->IsSlowLayout());
851
852   {
853     // Ensure layout descriptor switches into slow mode at the right moment.
854     layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
855         isolate, kPropsCount, descriptors, kSmiValueSize);
856     CHECK(!layout_descriptor->IsSlowLayout());
857
858     layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
859         isolate, kPropsCount, descriptors, kSmiValueSize + 1);
860     CHECK(layout_descriptor->IsSlowLayout());
861   }
862 }
863
864
865 TEST(Regress436816) {
866   CcTest::InitializeVM();
867   Isolate* isolate = CcTest::i_isolate();
868   Factory* factory = isolate->factory();
869   v8::HandleScope scope(CcTest::isolate());
870
871   const int kPropsCount = kSmiValueSize * 3;
872   TestPropertyKind props[kPropsCount];
873   for (int i = 0; i < kPropsCount; i++) {
874     props[i] = PROP_DOUBLE;
875   }
876   Handle<DescriptorArray> descriptors =
877       CreateDescriptorArray(isolate, props, kPropsCount);
878
879   Handle<Map> map = Map::Create(isolate, kPropsCount);
880   Handle<LayoutDescriptor> layout_descriptor =
881       LayoutDescriptor::New(map, descriptors, kPropsCount);
882   map->InitializeDescriptors(*descriptors, *layout_descriptor);
883
884   Handle<JSObject> object = factory->NewJSObjectFromMap(map, TENURED);
885
886   Address fake_address = reinterpret_cast<Address>(~kHeapObjectTagMask);
887   HeapObject* fake_object = HeapObject::FromAddress(fake_address);
888   CHECK(fake_object->IsHeapObject());
889
890   double boom_value = bit_cast<double>(fake_object);
891   for (int i = 0; i < kPropsCount; i++) {
892     FieldIndex index = FieldIndex::ForDescriptor(*map, i);
893     CHECK(map->IsUnboxedDoubleField(index));
894     object->RawFastDoublePropertyAtPut(index, boom_value);
895   }
896   CHECK(object->HasFastProperties());
897   CHECK(!object->map()->HasFastPointerLayout());
898
899   Handle<Map> normalized_map =
900       Map::Normalize(map, KEEP_INOBJECT_PROPERTIES, "testing");
901   JSObject::MigrateToMap(object, normalized_map);
902   CHECK(!object->HasFastProperties());
903   CHECK(object->map()->HasFastPointerLayout());
904
905   // Trigger GCs and heap verification.
906   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
907 }
908
909
910 TEST(DoScavenge) {
911   CcTest::InitializeVM();
912   Isolate* isolate = CcTest::i_isolate();
913   Factory* factory = isolate->factory();
914   v8::HandleScope scope(CcTest::isolate());
915
916   CompileRun(
917       "function A() {"
918       "  this.x = 42.5;"
919       "  this.o = {};"
920       "};"
921       "var o = new A();");
922
923   Handle<String> obj_name = factory->InternalizeUtf8String("o");
924
925   Handle<Object> obj_value =
926       Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked();
927   CHECK(obj_value->IsJSObject());
928   Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
929
930   {
931     // Ensure the object is properly set up.
932     Map* map = obj->map();
933     DescriptorArray* descriptors = map->instance_descriptors();
934     CHECK(map->NumberOfOwnDescriptors() == 2);
935     CHECK(descriptors->GetDetails(0).representation().IsDouble());
936     CHECK(descriptors->GetDetails(1).representation().IsHeapObject());
937     FieldIndex field_index = FieldIndex::ForDescriptor(map, 0);
938     CHECK(field_index.is_inobject() && field_index.is_double());
939     CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
940     CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
941   }
942   CHECK(isolate->heap()->new_space()->Contains(*obj));
943
944   // Trigger GCs so that the newly allocated object moves to old gen.
945   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
946
947   // Create temp object in the new space.
948   Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED);
949   CHECK(isolate->heap()->new_space()->Contains(*temp));
950
951   // Construct a double value that looks like a pointer to the new space object
952   // and store it into the obj.
953   Address fake_object = reinterpret_cast<Address>(*temp) + kPointerSize;
954   double boom_value = bit_cast<double>(fake_object);
955
956   FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0);
957   Handle<HeapNumber> boom_number = factory->NewHeapNumber(boom_value, MUTABLE);
958   obj->FastPropertyAtPut(field_index, *boom_number);
959
960   // Now the object moves to old gen and it has a double field that looks like
961   // a pointer to a from semi-space.
962   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
963
964   CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
965
966   CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
967 }
968
969
970 static void TestLayoutDescriptorHelper(Isolate* isolate,
971                                        int inobject_properties,
972                                        Handle<DescriptorArray> descriptors,
973                                        int number_of_descriptors) {
974   Handle<Map> map = Map::Create(isolate, inobject_properties);
975
976   Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
977       map, descriptors, descriptors->number_of_descriptors());
978   InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
979
980   LayoutDescriptorHelper helper(*map);
981   bool all_fields_tagged = true;
982
983   int instance_size = map->instance_size();
984
985   int end_offset = instance_size * 2;
986   int first_non_tagged_field_offset = end_offset;
987   for (int i = 0; i < number_of_descriptors; i++) {
988     PropertyDetails details = descriptors->GetDetails(i);
989     if (details.type() != DATA) continue;
990     FieldIndex index = FieldIndex::ForDescriptor(*map, i);
991     if (!index.is_inobject()) continue;
992     all_fields_tagged &= !details.representation().IsDouble();
993     bool expected_tagged = !index.is_double();
994     if (!expected_tagged) {
995       first_non_tagged_field_offset =
996           Min(first_non_tagged_field_offset, index.offset());
997     }
998
999     int end_of_region_offset;
1000     CHECK_EQ(expected_tagged, helper.IsTagged(index.offset()));
1001     CHECK_EQ(expected_tagged, helper.IsTagged(index.offset(), instance_size,
1002                                               &end_of_region_offset));
1003     CHECK(end_of_region_offset > 0);
1004     CHECK(end_of_region_offset % kPointerSize == 0);
1005     CHECK(end_of_region_offset <= instance_size);
1006
1007     for (int offset = index.offset(); offset < end_of_region_offset;
1008          offset += kPointerSize) {
1009       CHECK_EQ(expected_tagged, helper.IsTagged(index.offset()));
1010     }
1011     if (end_of_region_offset < instance_size) {
1012       CHECK_EQ(!expected_tagged, helper.IsTagged(end_of_region_offset));
1013     } else {
1014       CHECK_EQ(true, helper.IsTagged(end_of_region_offset));
1015     }
1016   }
1017
1018   for (int offset = 0; offset < JSObject::kHeaderSize; offset += kPointerSize) {
1019     // Header queries
1020     CHECK_EQ(true, helper.IsTagged(offset));
1021     int end_of_region_offset;
1022     CHECK_EQ(true, helper.IsTagged(offset, end_offset, &end_of_region_offset));
1023     CHECK_EQ(first_non_tagged_field_offset, end_of_region_offset);
1024
1025     // Out of bounds queries
1026     CHECK_EQ(true, helper.IsTagged(offset + instance_size));
1027   }
1028
1029   CHECK_EQ(all_fields_tagged, helper.all_fields_tagged());
1030 }
1031
1032
1033 TEST(LayoutDescriptorHelperMixed) {
1034   CcTest::InitializeVM();
1035   Isolate* isolate = CcTest::i_isolate();
1036   v8::HandleScope scope(CcTest::isolate());
1037
1038   Handle<LayoutDescriptor> layout_descriptor;
1039   const int kPropsCount = kSmiValueSize * 3;
1040   TestPropertyKind props[kPropsCount];
1041   for (int i = 0; i < kPropsCount; i++) {
1042     props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
1043   }
1044   Handle<DescriptorArray> descriptors =
1045       CreateDescriptorArray(isolate, props, kPropsCount);
1046
1047   TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
1048
1049   TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
1050
1051   TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
1052
1053   TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
1054                              kPropsCount);
1055
1056   TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
1057 }
1058
1059
1060 TEST(LayoutDescriptorHelperAllTagged) {
1061   CcTest::InitializeVM();
1062   Isolate* isolate = CcTest::i_isolate();
1063   v8::HandleScope scope(CcTest::isolate());
1064
1065   Handle<LayoutDescriptor> layout_descriptor;
1066   const int kPropsCount = kSmiValueSize * 3;
1067   TestPropertyKind props[kPropsCount];
1068   for (int i = 0; i < kPropsCount; i++) {
1069     props[i] = PROP_TAGGED;
1070   }
1071   Handle<DescriptorArray> descriptors =
1072       CreateDescriptorArray(isolate, props, kPropsCount);
1073
1074   TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
1075
1076   TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
1077
1078   TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
1079
1080   TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
1081                              kPropsCount);
1082
1083   TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
1084 }
1085
1086
1087 TEST(LayoutDescriptorHelperAllDoubles) {
1088   CcTest::InitializeVM();
1089   Isolate* isolate = CcTest::i_isolate();
1090   v8::HandleScope scope(CcTest::isolate());
1091
1092   Handle<LayoutDescriptor> layout_descriptor;
1093   const int kPropsCount = kSmiValueSize * 3;
1094   TestPropertyKind props[kPropsCount];
1095   for (int i = 0; i < kPropsCount; i++) {
1096     props[i] = PROP_DOUBLE;
1097   }
1098   Handle<DescriptorArray> descriptors =
1099       CreateDescriptorArray(isolate, props, kPropsCount);
1100
1101   TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
1102
1103   TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
1104
1105   TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
1106
1107   TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
1108                              kPropsCount);
1109
1110   TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
1111 }
1112
1113
1114 TEST(LayoutDescriptorSharing) {
1115   CcTest::InitializeVM();
1116   v8::HandleScope scope(CcTest::isolate());
1117   Isolate* isolate = CcTest::i_isolate();
1118   Handle<HeapType> any_type = HeapType::Any(isolate);
1119
1120   Handle<Map> split_map;
1121   {
1122     Handle<Map> map = Map::Create(isolate, 64);
1123     for (int i = 0; i < 32; i++) {
1124       Handle<String> name = MakeName("prop", i);
1125       map = Map::CopyWithField(map, name, any_type, NONE, Representation::Smi(),
1126                                INSERT_TRANSITION).ToHandleChecked();
1127     }
1128     split_map = Map::CopyWithField(map, MakeString("dbl"), any_type, NONE,
1129                                    Representation::Double(),
1130                                    INSERT_TRANSITION).ToHandleChecked();
1131   }
1132   Handle<LayoutDescriptor> split_layout_descriptor(
1133       split_map->layout_descriptor(), isolate);
1134   CHECK(split_layout_descriptor->IsConsistentWithMap(*split_map));
1135   CHECK(split_layout_descriptor->IsSlowLayout());
1136   CHECK(split_map->owns_descriptors());
1137
1138   Handle<Map> map1 = Map::CopyWithField(split_map, MakeString("foo"), any_type,
1139                                         NONE, Representation::Double(),
1140                                         INSERT_TRANSITION).ToHandleChecked();
1141   CHECK(!split_map->owns_descriptors());
1142   CHECK_EQ(*split_layout_descriptor, split_map->layout_descriptor());
1143
1144   // Layout descriptors should be shared with |split_map|.
1145   CHECK(map1->owns_descriptors());
1146   CHECK_EQ(*split_layout_descriptor, map1->layout_descriptor());
1147   CHECK(map1->layout_descriptor()->IsConsistentWithMap(*map1));
1148
1149   Handle<Map> map2 = Map::CopyWithField(split_map, MakeString("bar"), any_type,
1150                                         NONE, Representation::Tagged(),
1151                                         INSERT_TRANSITION).ToHandleChecked();
1152
1153   // Layout descriptors should not be shared with |split_map|.
1154   CHECK(map2->owns_descriptors());
1155   CHECK_NE(*split_layout_descriptor, map2->layout_descriptor());
1156   CHECK(map2->layout_descriptor()->IsConsistentWithMap(*map2));
1157 }
1158
1159
1160 TEST(StoreBufferScanOnScavenge) {
1161   CcTest::InitializeVM();
1162   Isolate* isolate = CcTest::i_isolate();
1163   Factory* factory = isolate->factory();
1164   v8::HandleScope scope(CcTest::isolate());
1165
1166   CompileRun(
1167       "function A() {"
1168       "  this.x = 42.5;"
1169       "  this.o = {};"
1170       "};"
1171       "var o = new A();");
1172
1173   Handle<String> obj_name = factory->InternalizeUtf8String("o");
1174
1175   Handle<Object> obj_value =
1176       Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked();
1177   CHECK(obj_value->IsJSObject());
1178   Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
1179
1180   {
1181     // Ensure the object is properly set up.
1182     Map* map = obj->map();
1183     DescriptorArray* descriptors = map->instance_descriptors();
1184     CHECK(map->NumberOfOwnDescriptors() == 2);
1185     CHECK(descriptors->GetDetails(0).representation().IsDouble());
1186     CHECK(descriptors->GetDetails(1).representation().IsHeapObject());
1187     FieldIndex field_index = FieldIndex::ForDescriptor(map, 0);
1188     CHECK(field_index.is_inobject() && field_index.is_double());
1189     CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
1190     CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
1191   }
1192   CHECK(isolate->heap()->new_space()->Contains(*obj));
1193
1194   // Trigger GCs so that the newly allocated object moves to old gen.
1195   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
1196   CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
1197
1198   CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
1199
1200   // Create temp object in the new space.
1201   Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED);
1202   CHECK(isolate->heap()->new_space()->Contains(*temp));
1203
1204   // Construct a double value that looks like a pointer to the new space object
1205   // and store it into the obj.
1206   Address fake_object = reinterpret_cast<Address>(*temp) + kPointerSize;
1207   double boom_value = bit_cast<double>(fake_object);
1208
1209   FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0);
1210   Handle<HeapNumber> boom_number = factory->NewHeapNumber(boom_value, MUTABLE);
1211   obj->FastPropertyAtPut(field_index, *boom_number);
1212
1213   // Enforce scan on scavenge for the obj's page.
1214   MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
1215   chunk->set_scan_on_scavenge(true);
1216
1217   // Trigger GCs and force evacuation. Should not crash there.
1218   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
1219
1220   CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
1221 }
1222
1223
1224 static int LenFromSize(int size) {
1225   return (size - FixedArray::kHeaderSize) / kPointerSize;
1226 }
1227
1228
1229 TEST(WriteBarriersInCopyJSObject) {
1230   FLAG_max_semi_space_size = 1;  // Ensure new space is not growing.
1231   CcTest::InitializeVM();
1232   Isolate* isolate = CcTest::i_isolate();
1233   TestHeap* heap = CcTest::test_heap();
1234
1235   v8::HandleScope scope(CcTest::isolate());
1236
1237   // The plan: create JSObject which contains unboxed double value that looks
1238   // like a reference to an object in new space.
1239   // Then clone this object (forcing it to go into old space) and check
1240   // that the value of the unboxed double property of the cloned object has
1241   // was not corrupted by GC.
1242
1243   // Step 1: prepare a map for the object. We add unboxed double property to it.
1244   // Create a map with single inobject property.
1245   Handle<Map> my_map = Map::Create(isolate, 1);
1246   Handle<String> name = isolate->factory()->InternalizeUtf8String("foo");
1247   my_map = Map::CopyWithField(my_map, name, HeapType::Any(isolate), NONE,
1248                               Representation::Double(),
1249                               INSERT_TRANSITION).ToHandleChecked();
1250   my_map->set_pre_allocated_property_fields(1);
1251   int n_properties = my_map->InitialPropertiesLength();
1252   CHECK_GE(n_properties, 0);
1253
1254   int object_size = my_map->instance_size();
1255
1256   // Step 2: allocate a lot of objects so to almost fill new space: we need
1257   // just enough room to allocate JSObject and thus fill the newspace.
1258
1259   int allocation_amount =
1260       Min(FixedArray::kMaxSize, Page::kMaxRegularHeapObjectSize + kPointerSize);
1261   int allocation_len = LenFromSize(allocation_amount);
1262   NewSpace* new_space = heap->new_space();
1263   Address* top_addr = new_space->allocation_top_address();
1264   Address* limit_addr = new_space->allocation_limit_address();
1265   while ((*limit_addr - *top_addr) > allocation_amount) {
1266     CHECK(!heap->always_allocate());
1267     Object* array = heap->AllocateFixedArray(allocation_len).ToObjectChecked();
1268     CHECK(new_space->Contains(array));
1269   }
1270
1271   // Step 3: now allocate fixed array and JSObject to fill the whole new space.
1272   int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
1273   int fixed_array_len = LenFromSize(to_fill);
1274   CHECK(fixed_array_len < FixedArray::kMaxLength);
1275
1276   CHECK(!heap->always_allocate());
1277   Object* array = heap->AllocateFixedArray(fixed_array_len).ToObjectChecked();
1278   CHECK(new_space->Contains(array));
1279
1280   Object* object = heap->AllocateJSObjectFromMap(*my_map).ToObjectChecked();
1281   CHECK(new_space->Contains(object));
1282   JSObject* jsobject = JSObject::cast(object);
1283   CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
1284   CHECK_EQ(0, jsobject->properties()->length());
1285
1286   // Construct a double value that looks like a pointer to the new space object
1287   // and store it into the obj.
1288   Address fake_object = reinterpret_cast<Address>(array) + kPointerSize;
1289   double boom_value = bit_cast<double>(fake_object);
1290   FieldIndex index = FieldIndex::ForDescriptor(*my_map, 0);
1291   jsobject->RawFastDoublePropertyAtPut(index, boom_value);
1292
1293   CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
1294
1295   // Step 4: clone jsobject, but force always allocate first to create a clone
1296   // in old pointer space.
1297   AlwaysAllocateScope aa_scope(isolate);
1298   Object* clone_obj = heap->CopyJSObject(jsobject).ToObjectChecked();
1299   Handle<JSObject> clone(JSObject::cast(clone_obj));
1300   CHECK(heap->old_pointer_space()->Contains(clone->address()));
1301
1302   CcTest::heap()->CollectGarbage(NEW_SPACE, "boom");
1303
1304   // The value in cloned object should not be corrupted by GC.
1305   CHECK_EQ(boom_value, clone->RawFastDoublePropertyAt(index));
1306 }
1307
1308 #endif