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.
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"
18 using namespace v8::base;
19 using namespace v8::internal;
21 #if (V8_DOUBLE_FIELDS_UNBOXING)
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));
37 static Handle<String> MakeString(const char* str) {
38 Isolate* isolate = CcTest::i_isolate();
39 Factory* factory = isolate->factory();
40 return factory->InternalizeUtf8String(str);
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());
51 static double GetDoubleFieldValue(JSObject* obj, FieldIndex field_index) {
52 if (obj->IsUnboxedDoubleField(field_index)) {
53 return obj->RawFastDoublePropertyAt(field_index);
55 Object* value = obj->RawFastPropertyAt(field_index);
56 DCHECK(value->IsMutableHeapNumber());
57 return HeapNumber::cast(value)->value();
61 const int kNumberOfBits = 32;
64 enum TestPropertyKind {
72 static Representation representations[PROP_KIND_NUMBER] = {
73 Representation::None(), Representation::Smi(), Representation::Double(),
74 Representation::Tagged()};
77 static Handle<DescriptorArray> CreateDescriptorArray(Isolate* isolate,
78 TestPropertyKind* props,
80 Factory* factory = isolate->factory();
82 Handle<String> func_name = factory->InternalizeUtf8String("func");
83 Handle<JSFunction> func = factory->NewFunction(func_name);
85 Handle<DescriptorArray> descriptors =
86 DescriptorArray::Allocate(isolate, 0, kPropsCount);
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());
94 TestPropertyKind kind = props[i];
96 if (kind == PROP_CONSTANT) {
97 DataConstantDescriptor d(name, func, NONE);
98 descriptors->Append(&d);
101 DataDescriptor f(name, next_field_offset, NONE, representations[kind]);
102 next_field_offset += f.GetDetails().field_width_in_words();
103 descriptors->Append(&f);
110 TEST(LayoutDescriptorBasicFast) {
111 CcTest::InitializeVM();
112 v8::HandleScope scope(CcTest::isolate());
114 LayoutDescriptor* layout_desc = LayoutDescriptor::FastPointerLayout();
116 CHECK(!layout_desc->IsSlowLayout());
117 CHECK(layout_desc->IsFastPointerLayout());
118 CHECK_EQ(kSmiValueSize, layout_desc->capacity());
120 for (int i = 0; i < kSmiValueSize + 13; i++) {
121 CHECK_EQ(true, layout_desc->IsTagged(i));
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());
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));
134 CHECK(layout_desc->IsFastPointerLayout());
137 CHECK_EQ(true, layout_desc->IsTagged(0, std::numeric_limits<int>::max(),
139 CHECK_EQ(std::numeric_limits<int>::max(), sequence_length);
141 CHECK_EQ(true, layout_desc->IsTagged(0, 7, &sequence_length));
142 CHECK_EQ(7, sequence_length);
146 TEST(LayoutDescriptorBasicSlow) {
147 CcTest::InitializeVM();
148 Isolate* isolate = CcTest::i_isolate();
149 v8::HandleScope scope(CcTest::isolate());
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;
160 Handle<DescriptorArray> descriptors =
161 CreateDescriptorArray(isolate, props, kPropsCount);
163 Handle<Map> map = Map::Create(isolate, kPropsCount);
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);
171 props[0] = PROP_DOUBLE;
172 props[kPropsCount - 1] = PROP_DOUBLE;
174 Handle<DescriptorArray> descriptors =
175 CreateDescriptorArray(isolate, props, kPropsCount);
178 int inobject_properties = kPropsCount - 1;
179 Handle<Map> map = Map::Create(isolate, inobject_properties);
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());
187 CHECK_EQ(false, layout_descriptor->IsTagged(0));
188 for (int i = 1; i < kPropsCount; i++) {
189 CHECK_EQ(true, layout_descriptor->IsTagged(i));
191 InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
195 int inobject_properties = kPropsCount;
196 Handle<Map> map = Map::Create(isolate, inobject_properties);
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);
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));
210 InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
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));
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));
225 CHECK(layout_desc->IsSlowLayout());
226 CHECK(!layout_desc->IsFastPointerLayout());
227 CHECK(layout_descriptor->IsConsistentWithMap(*map));
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;
241 // Fill in the layout descriptor.
242 int cur_bit_flip_index = 0;
244 for (int i = 0; i < layout_descriptor_length; i++) {
245 if (i == bit_flip_positions[cur_bit_flip_index]) {
247 ++cur_bit_flip_index;
248 CHECK(i < bit_flip_positions[cur_bit_flip_index]); // check test data
250 layout_desc = layout_desc->SetTaggedForTesting(i, tagged);
254 if (layout_desc->IsFastPointerLayout()) {
260 int cur_bit_flip_index = 0;
262 for (int i = 0; i < layout_descriptor_length; i++) {
263 if (i == bit_flip_positions[cur_bit_flip_index]) {
265 ++cur_bit_flip_index;
267 CHECK_EQ(tagged, layout_desc->IsTagged(i));
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;
274 expected_sequence_length = tagged ? std::numeric_limits<int>::max()
275 : (layout_desc->capacity() - i);
277 expected_sequence_length =
278 Min(expected_sequence_length, max_sequence_length);
281 layout_desc->IsTagged(i, max_sequence_length, &sequence_length));
282 CHECK(sequence_length > 0);
284 CHECK_EQ(expected_sequence_length, sequence_length);
289 layout_desc->IsTagged(layout_descriptor_length,
290 max_sequence_length, &sequence_length));
291 CHECK_EQ(max_sequence_length, sequence_length);
296 static void TestLayoutDescriptorQueriesFast(int max_sequence_length) {
298 LayoutDescriptor* layout_desc = LayoutDescriptor::FastPointerLayout();
300 for (int i = 0; i < kNumberOfBits; i++) {
302 layout_desc->IsTagged(i, max_sequence_length, &sequence_length));
303 CHECK(sequence_length > 0);
304 CHECK_EQ(max_sequence_length, sequence_length);
309 int bit_flip_positions[] = {1000};
310 TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
311 max_sequence_length);
315 int bit_flip_positions[] = {0, 1000};
316 TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
317 max_sequence_length);
321 int bit_flip_positions[kNumberOfBits + 1];
322 for (int i = 0; i <= kNumberOfBits; i++) {
323 bit_flip_positions[i] = i;
325 TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
326 max_sequence_length);
330 int bit_flip_positions[] = {3, 7, 8, 10, 15, 21, 30, 1000};
331 TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
332 max_sequence_length);
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);
344 TEST(LayoutDescriptorQueriesFastLimited7) {
345 CcTest::InitializeVM();
346 v8::HandleScope scope(CcTest::isolate());
348 TestLayoutDescriptorQueriesFast(7);
352 TEST(LayoutDescriptorQueriesFastLimited13) {
353 CcTest::InitializeVM();
354 v8::HandleScope scope(CcTest::isolate());
356 TestLayoutDescriptorQueriesFast(13);
360 TEST(LayoutDescriptorQueriesFastUnlimited) {
361 CcTest::InitializeVM();
362 v8::HandleScope scope(CcTest::isolate());
364 TestLayoutDescriptorQueriesFast(std::numeric_limits<int>::max());
368 static void TestLayoutDescriptorQueriesSlow(int max_sequence_length) {
370 int bit_flip_positions[] = {10000};
371 TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
372 max_sequence_length);
376 int bit_flip_positions[] = {0, 10000};
377 TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
378 max_sequence_length);
382 int bit_flip_positions[kMaxNumberOfDescriptors + 1];
383 for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
384 bit_flip_positions[i] = i;
386 bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
387 TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
388 max_sequence_length);
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);
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);
406 int bit_flip_positions[kMaxNumberOfDescriptors + 1];
408 for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
409 bit_flip_positions[i] = cur;
413 bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
414 TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
415 max_sequence_length);
419 int bit_flip_positions[kMaxNumberOfDescriptors + 1];
421 for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
422 bit_flip_positions[i] = cur;
426 bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
427 TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
428 max_sequence_length);
433 TEST(LayoutDescriptorQueriesSlowLimited7) {
434 CcTest::InitializeVM();
435 v8::HandleScope scope(CcTest::isolate());
437 TestLayoutDescriptorQueriesSlow(7);
441 TEST(LayoutDescriptorQueriesSlowLimited13) {
442 CcTest::InitializeVM();
443 v8::HandleScope scope(CcTest::isolate());
445 TestLayoutDescriptorQueriesSlow(13);
449 TEST(LayoutDescriptorQueriesSlowLimited42) {
450 CcTest::InitializeVM();
451 v8::HandleScope scope(CcTest::isolate());
453 TestLayoutDescriptorQueriesSlow(42);
457 TEST(LayoutDescriptorQueriesSlowUnlimited) {
458 CcTest::InitializeVM();
459 v8::HandleScope scope(CcTest::isolate());
461 TestLayoutDescriptorQueriesSlow(std::numeric_limits<int>::max());
465 TEST(LayoutDescriptorCreateNewFast) {
466 CcTest::InitializeVM();
467 Isolate* isolate = CcTest::i_isolate();
468 v8::HandleScope scope(CcTest::isolate());
470 Handle<LayoutDescriptor> layout_descriptor;
471 TestPropertyKind props[] = {
473 PROP_TAGGED, // field #0
475 PROP_DOUBLE, // field #1
477 PROP_TAGGED, // field #2
480 const int kPropsCount = arraysize(props);
482 Handle<DescriptorArray> descriptors =
483 CreateDescriptorArray(isolate, props, kPropsCount);
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);
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);
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);
513 TEST(LayoutDescriptorCreateNewSlow) {
514 CcTest::InitializeVM();
515 Isolate* isolate = CcTest::i_isolate();
516 v8::HandleScope scope(CcTest::isolate());
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);
525 Handle<DescriptorArray> descriptors =
526 CreateDescriptorArray(isolate, props, kPropsCount);
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);
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);
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);
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));
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));
569 InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
571 // Now test LayoutDescriptor::cast_gc_safe().
572 Handle<LayoutDescriptor> layout_descriptor_copy =
573 LayoutDescriptor::New(map, descriptors, kPropsCount);
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));
589 layout_desc->set_map_word(map_word);
590 CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
595 static Handle<LayoutDescriptor> TestLayoutDescriptorAppend(
596 Isolate* isolate, int inobject_properties, TestPropertyKind* props,
598 Factory* factory = isolate->factory();
600 Handle<String> func_name = factory->InternalizeUtf8String("func");
601 Handle<JSFunction> func = factory->NewFunction(func_name);
603 Handle<DescriptorArray> descriptors =
604 DescriptorArray::Allocate(isolate, 0, kPropsCount);
606 Handle<Map> map = Map::Create(isolate, inobject_properties);
607 map->InitializeDescriptors(*descriptors,
608 LayoutDescriptor::FastPointerLayout());
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());
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);
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);
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));
636 CHECK(layout_descriptor->IsTagged(next_field_offset));
638 map->InitializeDescriptors(*descriptors, *layout_descriptor);
640 Handle<LayoutDescriptor> layout_descriptor(map->layout_descriptor(), isolate);
641 CHECK(layout_descriptor->IsConsistentWithMap(*map));
642 return layout_descriptor;
646 TEST(LayoutDescriptorAppend) {
647 CcTest::InitializeVM();
648 Isolate* isolate = CcTest::i_isolate();
649 v8::HandleScope scope(CcTest::isolate());
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);
659 TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount);
660 CHECK(!layout_descriptor->IsSlowLayout());
663 TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
664 CHECK(!layout_descriptor->IsSlowLayout());
667 TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount);
668 CHECK(!layout_descriptor->IsSlowLayout());
670 layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2,
672 CHECK(layout_descriptor->IsSlowLayout());
675 TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
676 CHECK(layout_descriptor->IsSlowLayout());
680 TEST(LayoutDescriptorAppendAllDoubles) {
681 CcTest::InitializeVM();
682 Isolate* isolate = CcTest::i_isolate();
683 v8::HandleScope scope(CcTest::isolate());
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;
693 TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount);
694 CHECK(!layout_descriptor->IsSlowLayout());
697 TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
698 CHECK(!layout_descriptor->IsSlowLayout());
701 TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount);
702 CHECK(!layout_descriptor->IsSlowLayout());
704 layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize + 1,
706 CHECK(layout_descriptor->IsSlowLayout());
708 layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2,
710 CHECK(layout_descriptor->IsSlowLayout());
713 TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
714 CHECK(layout_descriptor->IsSlowLayout());
717 // Ensure layout descriptor switches into slow mode at the right moment.
719 TestLayoutDescriptorAppend(isolate, kPropsCount, props, kSmiValueSize);
720 CHECK(!layout_descriptor->IsSlowLayout());
722 layout_descriptor = TestLayoutDescriptorAppend(isolate, kPropsCount, props,
724 CHECK(layout_descriptor->IsSlowLayout());
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);
734 Handle<LayoutDescriptor> full_layout_descriptor = LayoutDescriptor::New(
735 map, descriptors, descriptors->number_of_descriptors());
738 bool switched_to_slow_mode = false;
740 for (int i = 0; i < number_of_descriptors; i++) {
741 PropertyDetails details = descriptors->GetDetails(i);
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);
748 LayoutDescriptor* layout_desc = map->layout_descriptor();
750 if (layout_desc->IsSlowLayout()) {
751 switched_to_slow_mode = true;
752 CHECK_EQ(*full_layout_descriptor, layout_desc);
754 CHECK(!switched_to_slow_mode);
755 if (details.type() == DATA) {
757 int field_index = details.field_index();
758 int field_width_in_words = details.field_width_in_words();
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));
765 CHECK(layout_desc->IsTagged(field_index + field_width_in_words));
768 CHECK(map->layout_descriptor()->IsConsistentWithMap(*map));
771 Handle<LayoutDescriptor> layout_descriptor(map->GetLayoutDescriptor(),
773 CHECK(layout_descriptor->IsConsistentWithMap(*map));
774 return layout_descriptor;
778 TEST(LayoutDescriptorAppendIfFastOrUseFull) {
779 CcTest::InitializeVM();
780 Isolate* isolate = CcTest::i_isolate();
781 v8::HandleScope scope(CcTest::isolate());
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);
789 Handle<DescriptorArray> descriptors =
790 CreateDescriptorArray(isolate, props, kPropsCount);
792 layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
793 isolate, 0, descriptors, kPropsCount);
794 CHECK(!layout_descriptor->IsSlowLayout());
796 layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
797 isolate, 13, descriptors, kPropsCount);
798 CHECK(!layout_descriptor->IsSlowLayout());
800 layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
801 isolate, kSmiValueSize, descriptors, kPropsCount);
802 CHECK(!layout_descriptor->IsSlowLayout());
804 layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
805 isolate, kSmiValueSize * 2, descriptors, kPropsCount);
806 CHECK(layout_descriptor->IsSlowLayout());
808 layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
809 isolate, kPropsCount, descriptors, kPropsCount);
810 CHECK(layout_descriptor->IsSlowLayout());
814 TEST(LayoutDescriptorAppendIfFastOrUseFullAllDoubles) {
815 CcTest::InitializeVM();
816 Isolate* isolate = CcTest::i_isolate();
817 v8::HandleScope scope(CcTest::isolate());
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;
825 Handle<DescriptorArray> descriptors =
826 CreateDescriptorArray(isolate, props, kPropsCount);
828 layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
829 isolate, 0, descriptors, kPropsCount);
830 CHECK(!layout_descriptor->IsSlowLayout());
832 layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
833 isolate, 13, descriptors, kPropsCount);
834 CHECK(!layout_descriptor->IsSlowLayout());
836 layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
837 isolate, kSmiValueSize, descriptors, kPropsCount);
838 CHECK(!layout_descriptor->IsSlowLayout());
840 layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
841 isolate, kSmiValueSize + 1, descriptors, kPropsCount);
842 CHECK(layout_descriptor->IsSlowLayout());
844 layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
845 isolate, kSmiValueSize * 2, descriptors, kPropsCount);
846 CHECK(layout_descriptor->IsSlowLayout());
848 layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
849 isolate, kPropsCount, descriptors, kPropsCount);
850 CHECK(layout_descriptor->IsSlowLayout());
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());
858 layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
859 isolate, kPropsCount, descriptors, kSmiValueSize + 1);
860 CHECK(layout_descriptor->IsSlowLayout());
865 TEST(Regress436816) {
866 CcTest::InitializeVM();
867 Isolate* isolate = CcTest::i_isolate();
868 Factory* factory = isolate->factory();
869 v8::HandleScope scope(CcTest::isolate());
871 const int kPropsCount = kSmiValueSize * 3;
872 TestPropertyKind props[kPropsCount];
873 for (int i = 0; i < kPropsCount; i++) {
874 props[i] = PROP_DOUBLE;
876 Handle<DescriptorArray> descriptors =
877 CreateDescriptorArray(isolate, props, kPropsCount);
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);
884 Handle<JSObject> object = factory->NewJSObjectFromMap(map, TENURED);
886 Address fake_address = reinterpret_cast<Address>(~kHeapObjectTagMask);
887 HeapObject* fake_object = HeapObject::FromAddress(fake_address);
888 CHECK(fake_object->IsHeapObject());
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);
896 CHECK(object->HasFastProperties());
897 CHECK(!object->map()->HasFastPointerLayout());
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());
905 // Trigger GCs and heap verification.
906 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
911 CcTest::InitializeVM();
912 Isolate* isolate = CcTest::i_isolate();
913 Factory* factory = isolate->factory();
914 v8::HandleScope scope(CcTest::isolate());
923 Handle<String> obj_name = factory->InternalizeUtf8String("o");
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);
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));
942 CHECK(isolate->heap()->new_space()->Contains(*obj));
944 // Trigger GCs so that the newly allocated object moves to old gen.
945 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
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));
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);
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);
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
964 CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
966 CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
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);
976 Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
977 map, descriptors, descriptors->number_of_descriptors());
978 InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
980 LayoutDescriptorHelper helper(*map);
981 bool all_fields_tagged = true;
983 int instance_size = map->instance_size();
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());
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);
1007 for (int offset = index.offset(); offset < end_of_region_offset;
1008 offset += kPointerSize) {
1009 CHECK_EQ(expected_tagged, helper.IsTagged(index.offset()));
1011 if (end_of_region_offset < instance_size) {
1012 CHECK_EQ(!expected_tagged, helper.IsTagged(end_of_region_offset));
1014 CHECK_EQ(true, helper.IsTagged(end_of_region_offset));
1018 for (int offset = 0; offset < JSObject::kHeaderSize; offset += kPointerSize) {
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);
1025 // Out of bounds queries
1026 CHECK_EQ(true, helper.IsTagged(offset + instance_size));
1029 CHECK_EQ(all_fields_tagged, helper.all_fields_tagged());
1033 TEST(LayoutDescriptorHelperMixed) {
1034 CcTest::InitializeVM();
1035 Isolate* isolate = CcTest::i_isolate();
1036 v8::HandleScope scope(CcTest::isolate());
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);
1044 Handle<DescriptorArray> descriptors =
1045 CreateDescriptorArray(isolate, props, kPropsCount);
1047 TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
1049 TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
1051 TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
1053 TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
1056 TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
1060 TEST(LayoutDescriptorHelperAllTagged) {
1061 CcTest::InitializeVM();
1062 Isolate* isolate = CcTest::i_isolate();
1063 v8::HandleScope scope(CcTest::isolate());
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;
1071 Handle<DescriptorArray> descriptors =
1072 CreateDescriptorArray(isolate, props, kPropsCount);
1074 TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
1076 TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
1078 TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
1080 TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
1083 TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
1087 TEST(LayoutDescriptorHelperAllDoubles) {
1088 CcTest::InitializeVM();
1089 Isolate* isolate = CcTest::i_isolate();
1090 v8::HandleScope scope(CcTest::isolate());
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;
1098 Handle<DescriptorArray> descriptors =
1099 CreateDescriptorArray(isolate, props, kPropsCount);
1101 TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
1103 TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
1105 TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
1107 TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
1110 TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
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);
1120 Handle<Map> split_map;
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();
1128 split_map = Map::CopyWithField(map, MakeString("dbl"), any_type, NONE,
1129 Representation::Double(),
1130 INSERT_TRANSITION).ToHandleChecked();
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());
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());
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));
1149 Handle<Map> map2 = Map::CopyWithField(split_map, MakeString("bar"), any_type,
1150 NONE, Representation::Tagged(),
1151 INSERT_TRANSITION).ToHandleChecked();
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));
1160 TEST(StoreBufferScanOnScavenge) {
1161 CcTest::InitializeVM();
1162 Isolate* isolate = CcTest::i_isolate();
1163 Factory* factory = isolate->factory();
1164 v8::HandleScope scope(CcTest::isolate());
1171 "var o = new A();");
1173 Handle<String> obj_name = factory->InternalizeUtf8String("o");
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);
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));
1192 CHECK(isolate->heap()->new_space()->Contains(*obj));
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
1198 CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
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));
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);
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);
1213 // Enforce scan on scavenge for the obj's page.
1214 MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
1215 chunk->set_scan_on_scavenge(true);
1217 // Trigger GCs and force evacuation. Should not crash there.
1218 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
1220 CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
1224 static int LenFromSize(int size) {
1225 return (size - FixedArray::kHeaderSize) / kPointerSize;
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();
1235 v8::HandleScope scope(CcTest::isolate());
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.
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);
1254 int object_size = my_map->instance_size();
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.
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));
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);
1276 CHECK(!heap->always_allocate());
1277 Object* array = heap->AllocateFixedArray(fixed_array_len).ToObjectChecked();
1278 CHECK(new_space->Contains(array));
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());
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);
1293 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
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()));
1302 CcTest::heap()->CollectGarbage(NEW_SPACE, "boom");
1304 // The value in cloned object should not be corrupted by GC.
1305 CHECK_EQ(boom_value, clone->RawFastDoublePropertyAt(index));