OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 | 2 |
3 #include <stdlib.h> | 3 #include <stdlib.h> |
4 | 4 |
5 #include "v8.h" | 5 #include "v8.h" |
6 | 6 |
7 #include "execution.h" | 7 #include "execution.h" |
8 #include "factory.h" | 8 #include "factory.h" |
9 #include "macro-assembler.h" | 9 #include "macro-assembler.h" |
10 #include "global-handles.h" | 10 #include "global-handles.h" |
11 #include "cctest.h" | 11 #include "cctest.h" |
(...skipping 819 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
831 delete[] str; | 831 delete[] str; |
832 | 832 |
833 // Add a Map object to look for. | 833 // Add a Map object to look for. |
834 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map()); | 834 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map()); |
835 | 835 |
836 CHECK_EQ(objs_count, next_objs_index); | 836 CHECK_EQ(objs_count, next_objs_index); |
837 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count)); | 837 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count)); |
838 } | 838 } |
839 | 839 |
840 | 840 |
841 TEST(LargeObjectSpaceContains) { | |
842 InitializeVM(); | |
843 | |
844 HEAP->CollectGarbage(NEW_SPACE); | |
845 | |
846 Address current_top = HEAP->new_space()->top(); | |
847 Page* page = Page::FromAddress(current_top); | |
848 Address current_page = page->address(); | |
849 Address next_page = current_page + Page::kPageSize; | |
850 int bytes_to_page = static_cast<int>(next_page - current_top); | |
851 if (bytes_to_page <= FixedArray::kHeaderSize) { | |
852 // Alas, need to cross another page to be able to | |
853 // put desired value. | |
854 next_page += Page::kPageSize; | |
855 bytes_to_page = static_cast<int>(next_page - current_top); | |
856 } | |
857 CHECK(bytes_to_page > FixedArray::kHeaderSize); | |
858 | |
859 intptr_t* flags_ptr = &Page::FromAddress(next_page)->flags_; | |
860 Address flags_addr = reinterpret_cast<Address>(flags_ptr); | |
861 | |
862 int bytes_to_allocate = | |
863 static_cast<int>(flags_addr - current_top) + kPointerSize; | |
864 | |
865 int n_elements = (bytes_to_allocate - FixedArray::kHeaderSize) / | |
866 kPointerSize; | |
867 CHECK_EQ(bytes_to_allocate, FixedArray::SizeFor(n_elements)); | |
868 FixedArray* array = FixedArray::cast( | |
869 HEAP->AllocateFixedArray(n_elements)->ToObjectChecked()); | |
870 | |
871 int index = n_elements - 1; | |
872 CHECK_EQ(flags_ptr, | |
873 HeapObject::RawField(array, FixedArray::OffsetOfElementAt(index))); | |
874 array->set(index, Smi::FromInt(0)); | |
875 // This chould have turned next page into LargeObjectPage: | |
876 // CHECK(Page::FromAddress(next_page)->IsLargeObjectPage()); | |
877 | |
878 HeapObject* addr = HeapObject::FromAddress(next_page + 2 * kPointerSize); | |
879 CHECK(HEAP->new_space()->Contains(addr)); | |
880 CHECK(!HEAP->lo_space()->Contains(addr)); | |
881 } | |
882 | |
883 | |
884 TEST(EmptyHandleEscapeFrom) { | 841 TEST(EmptyHandleEscapeFrom) { |
885 InitializeVM(); | 842 InitializeVM(); |
886 | 843 |
887 v8::HandleScope scope; | 844 v8::HandleScope scope; |
888 Handle<JSObject> runaway; | 845 Handle<JSObject> runaway; |
889 | 846 |
890 { | 847 { |
891 v8::HandleScope nested; | 848 v8::HandleScope nested; |
892 Handle<JSObject> empty; | 849 Handle<JSObject> empty; |
893 runaway = empty.EscapeFrom(&nested); | 850 runaway = empty.EscapeFrom(&nested); |
894 } | 851 } |
895 | 852 |
896 CHECK(runaway.is_null()); | 853 CHECK(runaway.is_null()); |
897 } | 854 } |
898 | 855 |
899 | 856 |
900 static int LenFromSize(int size) { | 857 static int LenFromSize(int size) { |
901 return (size - FixedArray::kHeaderSize) / kPointerSize; | 858 return (size - FixedArray::kHeaderSize) / kPointerSize; |
902 } | 859 } |
903 | 860 |
904 | 861 |
905 TEST(Regression39128) { | 862 TEST(Regression39128) { |
906 // Test case for crbug.com/39128. | 863 // Test case for crbug.com/39128. |
907 InitializeVM(); | 864 InitializeVM(); |
908 | 865 |
909 // Increase the chance of 'bump-the-pointer' allocation in old space. | 866 // Increase the chance of 'bump-the-pointer' allocation in old space. |
910 bool force_compaction = true; | 867 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
911 HEAP->CollectAllGarbage(force_compaction); | |
912 | 868 |
913 v8::HandleScope scope; | 869 v8::HandleScope scope; |
914 | 870 |
915 // The plan: create JSObject which references objects in new space. | 871 // The plan: create JSObject which references objects in new space. |
916 // Then clone this object (forcing it to go into old space) and check | 872 // Then clone this object (forcing it to go into old space) and check |
917 // that region dirty marks are updated correctly. | 873 // that region dirty marks are updated correctly. |
918 | 874 |
919 // Step 1: prepare a map for the object. We add 1 inobject property to it. | 875 // Step 1: prepare a map for the object. We add 1 inobject property to it. |
920 Handle<JSFunction> object_ctor( | 876 Handle<JSFunction> object_ctor( |
921 Isolate::Current()->global_context()->object_function()); | 877 Isolate::Current()->global_context()->object_function()); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
968 // in old pointer space. | 924 // in old pointer space. |
969 Address old_pointer_space_top = HEAP->old_pointer_space()->top(); | 925 Address old_pointer_space_top = HEAP->old_pointer_space()->top(); |
970 AlwaysAllocateScope aa_scope; | 926 AlwaysAllocateScope aa_scope; |
971 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked(); | 927 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked(); |
972 JSObject* clone = JSObject::cast(clone_obj); | 928 JSObject* clone = JSObject::cast(clone_obj); |
973 if (clone->address() != old_pointer_space_top) { | 929 if (clone->address() != old_pointer_space_top) { |
974 // Alas, got allocated from free list, we cannot do checks. | 930 // Alas, got allocated from free list, we cannot do checks. |
975 return; | 931 return; |
976 } | 932 } |
977 CHECK(HEAP->old_pointer_space()->Contains(clone->address())); | 933 CHECK(HEAP->old_pointer_space()->Contains(clone->address())); |
978 | |
979 // Step 5: verify validity of region dirty marks. | |
980 Address clone_addr = clone->address(); | |
981 Page* page = Page::FromAddress(clone_addr); | |
982 // Check that region covering inobject property 1 is marked dirty. | |
983 CHECK(page->IsRegionDirty(clone_addr + (object_size - kPointerSize))); | |
984 } | 934 } |
985 | 935 |
986 | 936 |
987 TEST(TestCodeFlushing) { | 937 TEST(TestCodeFlushing) { |
988 i::FLAG_allow_natives_syntax = true; | 938 i::FLAG_allow_natives_syntax = true; |
989 // If we do not flush code this test is invalid. | 939 // If we do not flush code this test is invalid. |
990 if (!FLAG_flush_code) return; | 940 if (!FLAG_flush_code) return; |
991 InitializeVM(); | 941 InitializeVM(); |
992 v8::HandleScope scope; | 942 v8::HandleScope scope; |
993 const char* source = "function foo() {" | 943 const char* source = "function foo() {" |
994 " var x = 42;" | 944 " var x = 42;" |
995 " var y = 42;" | 945 " var y = 42;" |
996 " var z = x + y;" | 946 " var z = x + y;" |
997 "};" | 947 "};" |
998 "foo()"; | 948 "foo()"; |
999 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo"); | 949 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo"); |
1000 | 950 |
1001 // This compile will add the code to the compilation cache. | 951 // This compile will add the code to the compilation cache. |
1002 { v8::HandleScope scope; | 952 { v8::HandleScope scope; |
1003 CompileRun(source); | 953 CompileRun(source); |
1004 } | 954 } |
1005 | 955 |
1006 // Check function is compiled. | 956 // Check function is compiled. |
1007 Object* func_value = Isolate::Current()->context()->global()-> | 957 Object* func_value = Isolate::Current()->context()->global()-> |
1008 GetProperty(*foo_name)->ToObjectChecked(); | 958 GetProperty(*foo_name)->ToObjectChecked(); |
1009 CHECK(func_value->IsJSFunction()); | 959 CHECK(func_value->IsJSFunction()); |
1010 Handle<JSFunction> function(JSFunction::cast(func_value)); | 960 Handle<JSFunction> function(JSFunction::cast(func_value)); |
1011 CHECK(function->shared()->is_compiled()); | 961 CHECK(function->shared()->is_compiled()); |
1012 | 962 |
1013 HEAP->CollectAllGarbage(true); | 963 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
1014 HEAP->CollectAllGarbage(true); | 964 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
1015 | 965 |
1016 CHECK(function->shared()->is_compiled()); | 966 CHECK(function->shared()->is_compiled()); |
1017 | 967 |
1018 HEAP->CollectAllGarbage(true); | 968 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
1019 HEAP->CollectAllGarbage(true); | 969 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
1020 HEAP->CollectAllGarbage(true); | 970 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
1021 HEAP->CollectAllGarbage(true); | 971 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
1022 HEAP->CollectAllGarbage(true); | 972 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
1023 HEAP->CollectAllGarbage(true); | 973 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
1024 | 974 |
1025 // foo should no longer be in the compilation cache | 975 // foo should no longer be in the compilation cache |
1026 CHECK(!function->shared()->is_compiled() || function->IsOptimized()); | 976 CHECK(!function->shared()->is_compiled() || function->IsOptimized()); |
1027 CHECK(!function->is_compiled() || function->IsOptimized()); | 977 CHECK(!function->is_compiled() || function->IsOptimized()); |
1028 // Call foo to get it recompiled. | 978 // Call foo to get it recompiled. |
1029 CompileRun("foo()"); | 979 CompileRun("foo()"); |
1030 CHECK(function->shared()->is_compiled()); | 980 CHECK(function->shared()->is_compiled()); |
1031 CHECK(function->is_compiled()); | 981 CHECK(function->is_compiled()); |
1032 } | 982 } |
1033 | 983 |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1102 // Remove function f1, and | 1052 // Remove function f1, and |
1103 CompileRun("f1=null"); | 1053 CompileRun("f1=null"); |
1104 | 1054 |
1105 // Scavenge treats these references as strong. | 1055 // Scavenge treats these references as strong. |
1106 for (int j = 0; j < 10; j++) { | 1056 for (int j = 0; j < 10; j++) { |
1107 HEAP->PerformScavenge(); | 1057 HEAP->PerformScavenge(); |
1108 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i])); | 1058 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i])); |
1109 } | 1059 } |
1110 | 1060 |
1111 // Mark compact handles the weak references. | 1061 // Mark compact handles the weak references. |
1112 HEAP->CollectAllGarbage(true); | 1062 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
1113 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); | 1063 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); |
1114 | 1064 |
1115 // Get rid of f3 and f5 in the same way. | 1065 // Get rid of f3 and f5 in the same way. |
1116 CompileRun("f3=null"); | 1066 CompileRun("f3=null"); |
1117 for (int j = 0; j < 10; j++) { | 1067 for (int j = 0; j < 10; j++) { |
1118 HEAP->PerformScavenge(); | 1068 HEAP->PerformScavenge(); |
1119 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); | 1069 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); |
1120 } | 1070 } |
1121 HEAP->CollectAllGarbage(true); | 1071 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
1122 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); | 1072 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); |
1123 CompileRun("f5=null"); | 1073 CompileRun("f5=null"); |
1124 for (int j = 0; j < 10; j++) { | 1074 for (int j = 0; j < 10; j++) { |
1125 HEAP->PerformScavenge(); | 1075 HEAP->PerformScavenge(); |
1126 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); | 1076 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); |
1127 } | 1077 } |
1128 HEAP->CollectAllGarbage(true); | 1078 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
1129 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i])); | 1079 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i])); |
1130 | 1080 |
1131 ctx[i]->Exit(); | 1081 ctx[i]->Exit(); |
1132 } | 1082 } |
1133 | 1083 |
1134 // Force compilation cache cleanup. | 1084 // Force compilation cache cleanup. |
1135 HEAP->CollectAllGarbage(true); | 1085 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
1136 | 1086 |
1137 // Dispose the global contexts one by one. | 1087 // Dispose the global contexts one by one. |
1138 for (int i = 0; i < kNumTestContexts; i++) { | 1088 for (int i = 0; i < kNumTestContexts; i++) { |
1139 ctx[i].Dispose(); | 1089 ctx[i].Dispose(); |
1140 ctx[i].Clear(); | 1090 ctx[i].Clear(); |
1141 | 1091 |
1142 // Scavenge treats these references as strong. | 1092 // Scavenge treats these references as strong. |
1143 for (int j = 0; j < 10; j++) { | 1093 for (int j = 0; j < 10; j++) { |
1144 HEAP->PerformScavenge(); | 1094 HEAP->PerformScavenge(); |
1145 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts()); | 1095 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts()); |
1146 } | 1096 } |
1147 | 1097 |
1148 // Mark compact handles the weak references. | 1098 // Mark compact handles the weak references. |
1149 HEAP->CollectAllGarbage(true); | 1099 HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
1150 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts()); | 1100 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts()); |
1151 } | 1101 } |
1152 | 1102 |
1153 CHECK_EQ(0, CountGlobalContexts()); | 1103 CHECK_EQ(0, CountGlobalContexts()); |
1154 } | 1104 } |
1155 | 1105 |
1156 | 1106 |
1157 // Count the number of global contexts in the weak list of global contexts | 1107 // Count the number of global contexts in the weak list of global contexts |
1158 // causing a GC after the specified number of elements. | 1108 // causing a GC after the specified number of elements. |
1159 static int CountGlobalContextsWithGC(int n) { | 1109 static int CountGlobalContextsWithGC(int n) { |
1160 int count = 0; | 1110 int count = 0; |
1161 Handle<Object> object(HEAP->global_contexts_list()); | 1111 Handle<Object> object(HEAP->global_contexts_list()); |
1162 while (!object->IsUndefined()) { | 1112 while (!object->IsUndefined()) { |
1163 count++; | 1113 count++; |
1164 if (count == n) HEAP->CollectAllGarbage(true); | 1114 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
1165 object = | 1115 object = |
1166 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK)); | 1116 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK)); |
1167 } | 1117 } |
1168 return count; | 1118 return count; |
1169 } | 1119 } |
1170 | 1120 |
1171 | 1121 |
1172 // Count the number of user functions in the weak list of optimized | 1122 // Count the number of user functions in the weak list of optimized |
1173 // functions attached to a global context causing a GC after the | 1123 // functions attached to a global context causing a GC after the |
1174 // specified number of elements. | 1124 // specified number of elements. |
1175 static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context, | 1125 static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context, |
1176 int n) { | 1126 int n) { |
1177 int count = 0; | 1127 int count = 0; |
1178 Handle<Context> icontext = v8::Utils::OpenHandle(*context); | 1128 Handle<Context> icontext = v8::Utils::OpenHandle(*context); |
1179 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST)); | 1129 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST)); |
1180 while (object->IsJSFunction() && | 1130 while (object->IsJSFunction() && |
1181 !Handle<JSFunction>::cast(object)->IsBuiltin()) { | 1131 !Handle<JSFunction>::cast(object)->IsBuiltin()) { |
1182 count++; | 1132 count++; |
1183 if (count == n) HEAP->CollectAllGarbage(true); | 1133 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags); |
1184 object = Handle<Object>( | 1134 object = Handle<Object>( |
1185 Object::cast(JSFunction::cast(*object)->next_function_link())); | 1135 Object::cast(JSFunction::cast(*object)->next_function_link())); |
1186 } | 1136 } |
1187 return count; | 1137 return count; |
1188 } | 1138 } |
1189 | 1139 |
1190 | 1140 |
1191 TEST(TestInternalWeakListsTraverseWithGC) { | 1141 TEST(TestInternalWeakListsTraverseWithGC) { |
1192 v8::V8::Initialize(); | 1142 v8::V8::Initialize(); |
1193 | 1143 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1233 CompileRun("f5()"); | 1183 CompileRun("f5()"); |
1234 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0])); | 1184 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0])); |
1235 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4)); | 1185 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4)); |
1236 | 1186 |
1237 ctx[0]->Exit(); | 1187 ctx[0]->Exit(); |
1238 } | 1188 } |
1239 | 1189 |
1240 | 1190 |
1241 TEST(TestSizeOfObjectsVsHeapIteratorPrecision) { | 1191 TEST(TestSizeOfObjectsVsHeapIteratorPrecision) { |
1242 InitializeVM(); | 1192 InitializeVM(); |
| 1193 HEAP->EnsureHeapIsIterable(); |
1243 intptr_t size_of_objects_1 = HEAP->SizeOfObjects(); | 1194 intptr_t size_of_objects_1 = HEAP->SizeOfObjects(); |
1244 HeapIterator iterator(HeapIterator::kFilterFreeListNodes); | 1195 HeapIterator iterator; |
1245 intptr_t size_of_objects_2 = 0; | 1196 intptr_t size_of_objects_2 = 0; |
1246 for (HeapObject* obj = iterator.next(); | 1197 for (HeapObject* obj = iterator.next(); |
1247 obj != NULL; | 1198 obj != NULL; |
1248 obj = iterator.next()) { | 1199 obj = iterator.next()) { |
1249 size_of_objects_2 += obj->Size(); | 1200 size_of_objects_2 += obj->Size(); |
1250 } | 1201 } |
1251 // Delta must be within 1% of the larger result. | 1202 // Delta must be within 5% of the larger result. |
| 1203 // TODO(gc): Tighten this up by distinguishing between byte |
| 1204 // arrays that are real and those that merely mark free space |
| 1205 // on the heap. |
1252 if (size_of_objects_1 > size_of_objects_2) { | 1206 if (size_of_objects_1 > size_of_objects_2) { |
1253 intptr_t delta = size_of_objects_1 - size_of_objects_2; | 1207 intptr_t delta = size_of_objects_1 - size_of_objects_2; |
1254 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " | 1208 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " |
1255 "Iterator: %" V8_PTR_PREFIX "d, " | 1209 "Iterator: %" V8_PTR_PREFIX "d, " |
1256 "delta: %" V8_PTR_PREFIX "d\n", | 1210 "delta: %" V8_PTR_PREFIX "d\n", |
1257 size_of_objects_1, size_of_objects_2, delta); | 1211 size_of_objects_1, size_of_objects_2, delta); |
1258 CHECK_GT(size_of_objects_1 / 100, delta); | 1212 CHECK_GT(size_of_objects_1 / 20, delta); |
1259 } else { | 1213 } else { |
1260 intptr_t delta = size_of_objects_2 - size_of_objects_1; | 1214 intptr_t delta = size_of_objects_2 - size_of_objects_1; |
1261 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " | 1215 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " |
1262 "Iterator: %" V8_PTR_PREFIX "d, " | 1216 "Iterator: %" V8_PTR_PREFIX "d, " |
1263 "delta: %" V8_PTR_PREFIX "d\n", | 1217 "delta: %" V8_PTR_PREFIX "d\n", |
1264 size_of_objects_1, size_of_objects_2, delta); | 1218 size_of_objects_1, size_of_objects_2, delta); |
1265 CHECK_GT(size_of_objects_2 / 100, delta); | 1219 CHECK_GT(size_of_objects_2 / 20, delta); |
1266 } | 1220 } |
1267 } | 1221 } |
1268 | 1222 |
1269 | 1223 |
1270 class HeapIteratorTestHelper { | 1224 class HeapIteratorTestHelper { |
1271 public: | 1225 public: |
1272 HeapIteratorTestHelper(Object* a, Object* b) | 1226 HeapIteratorTestHelper(Object* a, Object* b) |
1273 : a_(a), b_(b), a_found_(false), b_found_(false) {} | 1227 : a_(a), b_(b), a_found_(false), b_found_(false) {} |
1274 bool a_found() { return a_found_; } | 1228 bool a_found() { return a_found_; } |
1275 bool b_found() { return b_found_; } | 1229 bool b_found() { return b_found_; } |
1276 void IterateHeap(HeapIterator::HeapObjectsFiltering mode) { | 1230 void IterateHeap() { |
1277 HeapIterator iterator(mode); | 1231 HeapIterator iterator; |
1278 for (HeapObject* obj = iterator.next(); | 1232 for (HeapObject* obj = iterator.next(); |
1279 obj != NULL; | 1233 obj != NULL; |
1280 obj = iterator.next()) { | 1234 obj = iterator.next()) { |
1281 if (obj == a_) | 1235 if (obj == a_) |
1282 a_found_ = true; | 1236 a_found_ = true; |
1283 else if (obj == b_) | 1237 else if (obj == b_) |
1284 b_found_ = true; | 1238 b_found_ = true; |
1285 } | 1239 } |
1286 } | 1240 } |
1287 private: | 1241 private: |
1288 Object* a_; | 1242 Object* a_; |
1289 Object* b_; | 1243 Object* b_; |
1290 bool a_found_; | 1244 bool a_found_; |
1291 bool b_found_; | 1245 bool b_found_; |
1292 }; | 1246 }; |
1293 | |
1294 TEST(HeapIteratorFilterUnreachable) { | |
1295 InitializeVM(); | |
1296 v8::HandleScope scope; | |
1297 CompileRun("a = {}; b = {};"); | |
1298 v8::Handle<Object> a(ISOLATE->context()->global()->GetProperty( | |
1299 *FACTORY->LookupAsciiSymbol("a"))->ToObjectChecked()); | |
1300 v8::Handle<Object> b(ISOLATE->context()->global()->GetProperty( | |
1301 *FACTORY->LookupAsciiSymbol("b"))->ToObjectChecked()); | |
1302 CHECK_NE(*a, *b); | |
1303 { | |
1304 HeapIteratorTestHelper helper(*a, *b); | |
1305 helper.IterateHeap(HeapIterator::kFilterUnreachable); | |
1306 CHECK(helper.a_found()); | |
1307 CHECK(helper.b_found()); | |
1308 } | |
1309 CHECK(ISOLATE->context()->global()->DeleteProperty( | |
1310 *FACTORY->LookupAsciiSymbol("a"), JSObject::FORCE_DELETION)); | |
1311 // We ensure that GC will not happen, so our raw pointer stays valid. | |
1312 AssertNoAllocation no_alloc; | |
1313 Object* a_saved = *a; | |
1314 a.Clear(); | |
1315 // Verify that "a" object still resides in the heap... | |
1316 { | |
1317 HeapIteratorTestHelper helper(a_saved, *b); | |
1318 helper.IterateHeap(HeapIterator::kNoFiltering); | |
1319 CHECK(helper.a_found()); | |
1320 CHECK(helper.b_found()); | |
1321 } | |
1322 // ...but is now unreachable. | |
1323 { | |
1324 HeapIteratorTestHelper helper(a_saved, *b); | |
1325 helper.IterateHeap(HeapIterator::kFilterUnreachable); | |
1326 CHECK(!helper.a_found()); | |
1327 CHECK(helper.b_found()); | |
1328 } | |
1329 } | |
OLD | NEW |