Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(90)

Side by Side Diff: test/cctest/test-unboxed-doubles.cc

Issue 1039733003: This fixes missing incremental write barrier issue when double fields unboxing is enabled. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/heap/spaces.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 the V8 project authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stdlib.h> 5 #include <stdlib.h>
6 #include <utility> 6 #include <utility>
7 7
8 #include "src/v8.h" 8 #include "src/v8.h"
9 9
10 #include "src/compilation-cache.h" 10 #include "src/compilation-cache.h"
11 #include "src/execution.h" 11 #include "src/execution.h"
12 #include "src/factory.h" 12 #include "src/factory.h"
13 #include "src/global-handles.h" 13 #include "src/global-handles.h"
14 #include "src/ic/ic.h" 14 #include "src/ic/ic.h"
15 #include "src/macro-assembler.h" 15 #include "src/macro-assembler.h"
16 #include "test/cctest/cctest.h" 16 #include "test/cctest/cctest.h"
17 17
18 using namespace v8::base; 18 using namespace v8::base;
19 using namespace v8::internal; 19 using namespace v8::internal;
20 20
21 #if (V8_DOUBLE_FIELDS_UNBOXING) 21 #if V8_DOUBLE_FIELDS_UNBOXING
22 22
23 23
24 // 24 //
25 // Helper functions. 25 // Helper functions.
26 // 26 //
27 27
28 28
29 static void InitializeVerifiedMapDescriptors( 29 static void InitializeVerifiedMapDescriptors(
30 Map* map, DescriptorArray* descriptors, 30 Map* map, DescriptorArray* descriptors,
31 LayoutDescriptor* layout_descriptor) { 31 LayoutDescriptor* layout_descriptor) {
(...skipping 870 matching lines...) Expand 10 before | Expand all | Expand 10 after
902 CHECK(!object->HasFastProperties()); 902 CHECK(!object->HasFastProperties());
903 CHECK(object->map()->HasFastPointerLayout()); 903 CHECK(object->map()->HasFastPointerLayout());
904 904
905 // Trigger GCs and heap verification. 905 // Trigger GCs and heap verification.
906 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); 906 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
907 } 907 }
908 908
909 909
910 TEST(DoScavenge) { 910 TEST(DoScavenge) {
911 CcTest::InitializeVM(); 911 CcTest::InitializeVM();
912 v8::HandleScope scope(CcTest::isolate());
912 Isolate* isolate = CcTest::i_isolate(); 913 Isolate* isolate = CcTest::i_isolate();
913 Factory* factory = isolate->factory(); 914 Factory* factory = isolate->factory();
914 v8::HandleScope scope(CcTest::isolate());
915 915
916 CompileRun( 916 // The plan: create |obj| with double field in new space, do scanvenge so
917 "function A() {" 917 // that |obj| is moved to old space, construct a double value that looks like
918 " this.x = 42.5;" 918 // a pointer to "from space" pointer. Do scavenge one more time and ensure
919 " this.o = {};" 919 // that it didn't crash or corrupt the double value stored in the object.
920 "};"
921 "var o = new A();");
922 920
923 Handle<String> obj_name = factory->InternalizeUtf8String("o"); 921 Handle<HeapType> any_type = HeapType::Any(isolate);
922 Handle<Map> map = Map::Create(isolate, 10);
923 map = Map::CopyWithField(map, MakeName("prop", 0), any_type, NONE,
924 Representation::Double(),
925 INSERT_TRANSITION).ToHandleChecked();
924 926
925 Handle<Object> obj_value = 927 // Create object in new space.
926 Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked(); 928 Handle<JSObject> obj = factory->NewJSObjectFromMap(map, NOT_TENURED, false);
927 CHECK(obj_value->IsJSObject()); 929
928 Handle<JSObject> obj = Handle<JSObject>::cast(obj_value); 930 Handle<HeapNumber> heap_number = factory->NewHeapNumber(42.5);
931 obj->WriteToField(0, *heap_number);
929 932
930 { 933 {
931 // Ensure the object is properly set up. 934 // Ensure the object is properly set up.
932 Map* map = obj->map(); 935 FieldIndex field_index = FieldIndex::ForDescriptor(*map, 0);
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()); 936 CHECK(field_index.is_inobject() && field_index.is_double());
939 CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index)); 937 CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
940 CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index)); 938 CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
941 } 939 }
942 CHECK(isolate->heap()->new_space()->Contains(*obj)); 940 CHECK(isolate->heap()->new_space()->Contains(*obj));
943 941
944 // Trigger GCs so that the newly allocated object moves to old gen. 942 // Do scavenge so that |obj| is moved to survivor space.
945 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 943 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
946 944
947 // Create temp object in the new space. 945 // Create temp object in the new space.
948 Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED); 946 Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED);
949 CHECK(isolate->heap()->new_space()->Contains(*temp)); 947 CHECK(isolate->heap()->new_space()->Contains(*temp));
950 948
951 // Construct a double value that looks like a pointer to the new space object 949 // Construct a double value that looks like a pointer to the new space object
952 // and store it into the obj. 950 // and store it into the obj.
953 Address fake_object = reinterpret_cast<Address>(*temp) + kPointerSize; 951 Address fake_object = reinterpret_cast<Address>(*temp) + kPointerSize;
954 double boom_value = bit_cast<double>(fake_object); 952 double boom_value = bit_cast<double>(fake_object);
955 953
956 FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0); 954 FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0);
957 Handle<HeapNumber> boom_number = factory->NewHeapNumber(boom_value, MUTABLE); 955 Handle<HeapNumber> boom_number = factory->NewHeapNumber(boom_value, MUTABLE);
958 obj->FastPropertyAtPut(field_index, *boom_number); 956 obj->FastPropertyAtPut(field_index, *boom_number);
959 957
960 // Now the object moves to old gen and it has a double field that looks like 958 // Now |obj| moves to old gen and it has a double field that looks like
961 // a pointer to a from semi-space. 959 // a pointer to a from semi-space.
962 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 960 CcTest::heap()->CollectGarbage(i::NEW_SPACE, "boom");
963 961
964 CHECK(isolate->heap()->old_pointer_space()->Contains(*obj)); 962 CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
965 963
966 CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index)); 964 CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
967 } 965 }
968 966
969 967
968 TEST(DoScavengeWithIncrementalWriteBarrier) {
969 if (FLAG_never_compact || !FLAG_incremental_marking) return;
970 CcTest::InitializeVM();
971 v8::HandleScope scope(CcTest::isolate());
972 Isolate* isolate = CcTest::i_isolate();
973 Factory* factory = isolate->factory();
974 Heap* heap = CcTest::heap();
975 PagedSpace* old_pointer_space = heap->old_pointer_space();
976
977 // The plan: create |obj_value| in old space and ensure that it is allocated
978 // on evacuation candidate page, create |obj| with double and tagged fields
979 // in new space and write |obj_value| to tagged field of |obj|, do two
980 // scavenges to promote |obj| to old space, a GC in old space and ensure that
981 // the tagged value was properly updated after candidates evacuation.
982
983 Handle<HeapType> any_type = HeapType::Any(isolate);
984 Handle<Map> map = Map::Create(isolate, 10);
985 map = Map::CopyWithField(map, MakeName("prop", 0), any_type, NONE,
986 Representation::Double(),
987 INSERT_TRANSITION).ToHandleChecked();
988 map = Map::CopyWithField(map, MakeName("prop", 1), any_type, NONE,
989 Representation::Tagged(),
990 INSERT_TRANSITION).ToHandleChecked();
991
992 // Create |obj_value| in old space.
993 Handle<HeapObject> obj_value;
994 Page* ec_page;
995 {
996 AlwaysAllocateScope always_allocate(isolate);
997 // Make sure |obj_value| is placed on an old-space evacuation candidate.
998 SimulateFullSpace(old_pointer_space);
999 obj_value = factory->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
1000 ec_page = Page::FromAddress(obj_value->address());
1001 }
1002
1003 // Create object in new space.
1004 Handle<JSObject> obj = factory->NewJSObjectFromMap(map, NOT_TENURED, false);
1005
1006 Handle<HeapNumber> heap_number = factory->NewHeapNumber(42.5);
1007 obj->WriteToField(0, *heap_number);
1008 obj->WriteToField(1, *obj_value);
1009
1010 {
1011 // Ensure the object is properly set up.
1012 FieldIndex field_index = FieldIndex::ForDescriptor(*map, 0);
1013 CHECK(field_index.is_inobject() && field_index.is_double());
1014 CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
1015 CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
1016
1017 field_index = FieldIndex::ForDescriptor(*map, 1);
1018 CHECK(field_index.is_inobject() && !field_index.is_double());
1019 CHECK(!map->IsUnboxedDoubleField(field_index));
1020 }
1021 CHECK(isolate->heap()->new_space()->Contains(*obj));
1022
1023 // Heap is ready, force |ec_page| to become an evacuation candidate and
1024 // simulate incremental marking.
1025 FLAG_stress_compaction = true;
1026 FLAG_manual_evacuation_candidates_selection = true;
1027 ec_page->SetFlag(MemoryChunk::FORCE_EVACUATION_CANDIDATE_FOR_TESTING);
1028 SimulateIncrementalMarking(heap);
1029 // Disable stress compaction mode in order to let GC do scavenge.
1030 FLAG_stress_compaction = false;
1031
1032 // Check that everything is ready for triggering incremental write barrier
1033 // during scavenge (i.e. that |obj| is black and incremental marking is
1034 // in compacting mode and |obj_value|'s page is an evacuation candidate).
1035 IncrementalMarking* marking = heap->incremental_marking();
1036 CHECK(marking->IsCompacting());
1037 CHECK(Marking::IsBlack(Marking::MarkBitFrom(*obj)));
1038 CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
1039
1040 // Trigger GCs so that |obj| moves to old gen.
1041 heap->CollectGarbage(i::NEW_SPACE); // in survivor space now
1042 heap->CollectGarbage(i::NEW_SPACE); // in old gen now
1043
1044 CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
1045 CHECK(isolate->heap()->old_pointer_space()->Contains(*obj_value));
1046 CHECK(MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
1047
1048 heap->CollectGarbage(i::OLD_POINTER_SPACE, "boom");
1049
1050 // |obj_value| must be evacuated.
1051 CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(*obj_value));
1052
1053 FieldIndex field_index = FieldIndex::ForDescriptor(*map, 1);
1054 CHECK_EQ(*obj_value, obj->RawFastPropertyAt(field_index));
1055 }
1056
1057
970 static void TestLayoutDescriptorHelper(Isolate* isolate, 1058 static void TestLayoutDescriptorHelper(Isolate* isolate,
971 int inobject_properties, 1059 int inobject_properties,
972 Handle<DescriptorArray> descriptors, 1060 Handle<DescriptorArray> descriptors,
973 int number_of_descriptors) { 1061 int number_of_descriptors) {
974 Handle<Map> map = Map::Create(isolate, inobject_properties); 1062 Handle<Map> map = Map::Create(isolate, inobject_properties);
975 1063
976 Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New( 1064 Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
977 map, descriptors, descriptors->number_of_descriptors()); 1065 map, descriptors, descriptors->number_of_descriptors());
978 InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor); 1066 InitializeVerifiedMapDescriptors(*map, *descriptors, *layout_descriptor);
979 1067
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
1156 CHECK(map2->layout_descriptor()->IsConsistentWithMap(*map2)); 1244 CHECK(map2->layout_descriptor()->IsConsistentWithMap(*map2));
1157 } 1245 }
1158 1246
1159 1247
1160 TEST(StoreBufferScanOnScavenge) { 1248 TEST(StoreBufferScanOnScavenge) {
1161 CcTest::InitializeVM(); 1249 CcTest::InitializeVM();
1162 Isolate* isolate = CcTest::i_isolate(); 1250 Isolate* isolate = CcTest::i_isolate();
1163 Factory* factory = isolate->factory(); 1251 Factory* factory = isolate->factory();
1164 v8::HandleScope scope(CcTest::isolate()); 1252 v8::HandleScope scope(CcTest::isolate());
1165 1253
1166 CompileRun( 1254 Handle<HeapType> any_type = HeapType::Any(isolate);
1167 "function A() {" 1255 Handle<Map> map = Map::Create(isolate, 10);
1168 " this.x = 42.5;" 1256 map = Map::CopyWithField(map, MakeName("prop", 0), any_type, NONE,
1169 " this.o = {};" 1257 Representation::Double(),
1170 "};" 1258 INSERT_TRANSITION).ToHandleChecked();
1171 "var o = new A();");
1172 1259
1173 Handle<String> obj_name = factory->InternalizeUtf8String("o"); 1260 // Create object in new space.
1261 Handle<JSObject> obj = factory->NewJSObjectFromMap(map, NOT_TENURED, false);
1174 1262
1175 Handle<Object> obj_value = 1263 Handle<HeapNumber> heap_number = factory->NewHeapNumber(42.5);
1176 Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked(); 1264 obj->WriteToField(0, *heap_number);
1177 CHECK(obj_value->IsJSObject());
1178 Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
1179 1265
1180 { 1266 {
1181 // Ensure the object is properly set up. 1267 // Ensure the object is properly set up.
1182 Map* map = obj->map();
1183 DescriptorArray* descriptors = map->instance_descriptors(); 1268 DescriptorArray* descriptors = map->instance_descriptors();
1184 CHECK(map->NumberOfOwnDescriptors() == 2);
1185 CHECK(descriptors->GetDetails(0).representation().IsDouble()); 1269 CHECK(descriptors->GetDetails(0).representation().IsDouble());
1186 CHECK(descriptors->GetDetails(1).representation().IsHeapObject()); 1270 FieldIndex field_index = FieldIndex::ForDescriptor(*map, 0);
1187 FieldIndex field_index = FieldIndex::ForDescriptor(map, 0);
1188 CHECK(field_index.is_inobject() && field_index.is_double()); 1271 CHECK(field_index.is_inobject() && field_index.is_double());
1189 CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index)); 1272 CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
1190 CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index)); 1273 CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
1191 } 1274 }
1192 CHECK(isolate->heap()->new_space()->Contains(*obj)); 1275 CHECK(isolate->heap()->new_space()->Contains(*obj));
1193 1276
1194 // Trigger GCs so that the newly allocated object moves to old gen. 1277 // Trigger GCs so that the newly allocated object moves to old gen.
1195 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now 1278 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
1196 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now 1279 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
1197 1280
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
1299 Handle<JSObject> clone(JSObject::cast(clone_obj)); 1382 Handle<JSObject> clone(JSObject::cast(clone_obj));
1300 CHECK(heap->old_pointer_space()->Contains(clone->address())); 1383 CHECK(heap->old_pointer_space()->Contains(clone->address()));
1301 1384
1302 CcTest::heap()->CollectGarbage(NEW_SPACE, "boom"); 1385 CcTest::heap()->CollectGarbage(NEW_SPACE, "boom");
1303 1386
1304 // The value in cloned object should not be corrupted by GC. 1387 // The value in cloned object should not be corrupted by GC.
1305 CHECK_EQ(boom_value, clone->RawFastDoublePropertyAt(index)); 1388 CHECK_EQ(boom_value, clone->RawFastDoublePropertyAt(index));
1306 } 1389 }
1307 1390
1308 #endif 1391 #endif
OLDNEW
« no previous file with comments | « src/heap/spaces.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698