OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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" |
(...skipping 766 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
777 DeleteArray(non_ascii); | 777 DeleteArray(non_ascii); |
778 DeleteArray(ascii); | 778 DeleteArray(ascii); |
779 } | 779 } |
780 } | 780 } |
781 | 781 |
782 | 782 |
783 static int ObjectsFoundInHeap(Handle<Object> objs[], int size) { | 783 static int ObjectsFoundInHeap(Handle<Object> objs[], int size) { |
784 // Count the number of objects found in the heap. | 784 // Count the number of objects found in the heap. |
785 int found_count = 0; | 785 int found_count = 0; |
786 HeapIterator iterator; | 786 HeapIterator iterator; |
787 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { | 787 for (HeapObject* obj = iterator.Next(); obj != NULL; obj = iterator.Next()) { |
788 for (int i = 0; i < size; i++) { | 788 for (int i = 0; i < size; i++) { |
789 if (*objs[i] == obj) { | 789 if (*objs[i] == obj) { |
790 found_count++; | 790 found_count++; |
791 } | 791 } |
792 } | 792 } |
793 } | 793 } |
794 return found_count; | 794 return found_count; |
795 } | 795 } |
796 | 796 |
797 | 797 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
850 static int LenFromSize(int size) { | 850 static int LenFromSize(int size) { |
851 return (size - FixedArray::kHeaderSize) / kPointerSize; | 851 return (size - FixedArray::kHeaderSize) / kPointerSize; |
852 } | 852 } |
853 | 853 |
854 | 854 |
855 TEST(Regression39128) { | 855 TEST(Regression39128) { |
856 // Test case for crbug.com/39128. | 856 // Test case for crbug.com/39128. |
857 InitializeVM(); | 857 InitializeVM(); |
858 | 858 |
859 // Increase the chance of 'bump-the-pointer' allocation in old space. | 859 // Increase the chance of 'bump-the-pointer' allocation in old space. |
860 bool force_compaction = true; | 860 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
861 Heap::CollectAllGarbage(force_compaction); | |
862 | 861 |
863 v8::HandleScope scope; | 862 v8::HandleScope scope; |
864 | 863 |
865 // The plan: create JSObject which references objects in new space. | 864 // The plan: create JSObject which references objects in new space. |
866 // Then clone this object (forcing it to go into old space) and check | 865 // Then clone this object (forcing it to go into old space) and check |
867 // that region dirty marks are updated correctly. | 866 // that region dirty marks are updated correctly. |
868 | 867 |
869 // Step 1: prepare a map for the object. We add 1 inobject property to it. | 868 // Step 1: prepare a map for the object. We add 1 inobject property to it. |
870 Handle<JSFunction> object_ctor(Top::global_context()->object_function()); | 869 Handle<JSFunction> object_ctor(Top::global_context()->object_function()); |
871 CHECK(object_ctor->has_initial_map()); | 870 CHECK(object_ctor->has_initial_map()); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
946 CompileRun(source); | 945 CompileRun(source); |
947 } | 946 } |
948 | 947 |
949 // Check function is compiled. | 948 // Check function is compiled. |
950 Object* func_value = | 949 Object* func_value = |
951 Top::context()->global()->GetProperty(*foo_name)->ToObjectChecked(); | 950 Top::context()->global()->GetProperty(*foo_name)->ToObjectChecked(); |
952 CHECK(func_value->IsJSFunction()); | 951 CHECK(func_value->IsJSFunction()); |
953 Handle<JSFunction> function(JSFunction::cast(func_value)); | 952 Handle<JSFunction> function(JSFunction::cast(func_value)); |
954 CHECK(function->shared()->is_compiled()); | 953 CHECK(function->shared()->is_compiled()); |
955 | 954 |
956 Heap::CollectAllGarbage(true); | 955 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
957 Heap::CollectAllGarbage(true); | 956 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
958 | 957 |
959 CHECK(function->shared()->is_compiled()); | 958 CHECK(function->shared()->is_compiled()); |
960 | 959 |
961 Heap::CollectAllGarbage(true); | 960 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
962 Heap::CollectAllGarbage(true); | 961 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
963 Heap::CollectAllGarbage(true); | 962 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
964 Heap::CollectAllGarbage(true); | 963 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
965 Heap::CollectAllGarbage(true); | 964 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
966 Heap::CollectAllGarbage(true); | 965 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
967 | 966 |
968 // foo should no longer be in the compilation cache | 967 // foo should no longer be in the compilation cache |
969 CHECK(!function->shared()->is_compiled() || function->IsOptimized()); | 968 CHECK(!function->shared()->is_compiled() || function->IsOptimized()); |
970 CHECK(!function->is_compiled() || function->IsOptimized()); | 969 CHECK(!function->is_compiled() || function->IsOptimized()); |
971 // Call foo to get it recompiled. | 970 // Call foo to get it recompiled. |
972 CompileRun("foo()"); | 971 CompileRun("foo()"); |
973 CHECK(function->shared()->is_compiled()); | 972 CHECK(function->shared()->is_compiled()); |
974 CHECK(function->is_compiled()); | 973 CHECK(function->is_compiled()); |
975 } | 974 } |
976 | 975 |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1043 // Remove function f1, and | 1042 // Remove function f1, and |
1044 CompileRun("f1=null"); | 1043 CompileRun("f1=null"); |
1045 | 1044 |
1046 // Scavenge treats these references as strong. | 1045 // Scavenge treats these references as strong. |
1047 for (int j = 0; j < 10; j++) { | 1046 for (int j = 0; j < 10; j++) { |
1048 Heap::PerformScavenge(); | 1047 Heap::PerformScavenge(); |
1049 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i])); | 1048 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i])); |
1050 } | 1049 } |
1051 | 1050 |
1052 // Mark compact handles the weak references. | 1051 // Mark compact handles the weak references. |
1053 Heap::CollectAllGarbage(true); | 1052 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
1054 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); | 1053 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); |
1055 | 1054 |
1056 // Get rid of f3 and f5 in the same way. | 1055 // Get rid of f3 and f5 in the same way. |
1057 CompileRun("f3=null"); | 1056 CompileRun("f3=null"); |
1058 for (int j = 0; j < 10; j++) { | 1057 for (int j = 0; j < 10; j++) { |
1059 Heap::PerformScavenge(); | 1058 Heap::PerformScavenge(); |
1060 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); | 1059 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); |
1061 } | 1060 } |
1062 Heap::CollectAllGarbage(true); | 1061 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
1063 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); | 1062 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); |
1064 CompileRun("f5=null"); | 1063 CompileRun("f5=null"); |
1065 for (int j = 0; j < 10; j++) { | 1064 for (int j = 0; j < 10; j++) { |
1066 Heap::PerformScavenge(); | 1065 Heap::PerformScavenge(); |
1067 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); | 1066 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); |
1068 } | 1067 } |
1069 Heap::CollectAllGarbage(true); | 1068 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
1070 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i])); | 1069 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i])); |
1071 | 1070 |
1072 ctx[i]->Exit(); | 1071 ctx[i]->Exit(); |
1073 } | 1072 } |
1074 | 1073 |
1075 // Force compilation cache cleanup. | 1074 // Force compilation cache cleanup. |
1076 Heap::CollectAllGarbage(true); | 1075 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
1077 | 1076 |
1078 // Dispose the global contexts one by one. | 1077 // Dispose the global contexts one by one. |
1079 for (int i = 0; i < kNumTestContexts; i++) { | 1078 for (int i = 0; i < kNumTestContexts; i++) { |
1080 ctx[i].Dispose(); | 1079 ctx[i].Dispose(); |
1081 ctx[i].Clear(); | 1080 ctx[i].Clear(); |
1082 | 1081 |
1083 // Scavenge treats these references as strong. | 1082 // Scavenge treats these references as strong. |
1084 for (int j = 0; j < 10; j++) { | 1083 for (int j = 0; j < 10; j++) { |
1085 Heap::PerformScavenge(); | 1084 Heap::PerformScavenge(); |
1086 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts()); | 1085 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts()); |
1087 } | 1086 } |
1088 | 1087 |
1089 // Mark compact handles the weak references. | 1088 // Mark compact handles the weak references. |
1090 Heap::CollectAllGarbage(true); | 1089 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
1091 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts()); | 1090 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts()); |
1092 } | 1091 } |
1093 | 1092 |
1094 CHECK_EQ(0, CountGlobalContexts()); | 1093 CHECK_EQ(0, CountGlobalContexts()); |
1095 } | 1094 } |
1096 | 1095 |
1097 | 1096 |
1098 // Count the number of global contexts in the weak list of global contexts | 1097 // Count the number of global contexts in the weak list of global contexts |
1099 // causing a GC after the specified number of elements. | 1098 // causing a GC after the specified number of elements. |
1100 static int CountGlobalContextsWithGC(int n) { | 1099 static int CountGlobalContextsWithGC(int n) { |
1101 int count = 0; | 1100 int count = 0; |
1102 Handle<Object> object(Heap::global_contexts_list()); | 1101 Handle<Object> object(Heap::global_contexts_list()); |
1103 while (!object->IsUndefined()) { | 1102 while (!object->IsUndefined()) { |
1104 count++; | 1103 count++; |
1105 if (count == n) Heap::CollectAllGarbage(true); | 1104 if (count == n) Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
1106 object = | 1105 object = |
1107 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK)); | 1106 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK)); |
1108 } | 1107 } |
1109 return count; | 1108 return count; |
1110 } | 1109 } |
1111 | 1110 |
1112 | 1111 |
1113 // Count the number of user functions in the weak list of optimized | 1112 // Count the number of user functions in the weak list of optimized |
1114 // functions attached to a global context causing a GC after the | 1113 // functions attached to a global context causing a GC after the |
1115 // specified number of elements. | 1114 // specified number of elements. |
1116 static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context, | 1115 static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context, |
1117 int n) { | 1116 int n) { |
1118 int count = 0; | 1117 int count = 0; |
1119 Handle<Context> icontext = v8::Utils::OpenHandle(*context); | 1118 Handle<Context> icontext = v8::Utils::OpenHandle(*context); |
1120 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST)); | 1119 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST)); |
1121 while (object->IsJSFunction() && | 1120 while (object->IsJSFunction() && |
1122 !Handle<JSFunction>::cast(object)->IsBuiltin()) { | 1121 !Handle<JSFunction>::cast(object)->IsBuiltin()) { |
1123 count++; | 1122 count++; |
1124 if (count == n) Heap::CollectAllGarbage(true); | 1123 if (count == n) Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
1125 object = Handle<Object>( | 1124 object = Handle<Object>( |
1126 Object::cast(JSFunction::cast(*object)->next_function_link())); | 1125 Object::cast(JSFunction::cast(*object)->next_function_link())); |
1127 } | 1126 } |
1128 return count; | 1127 return count; |
1129 } | 1128 } |
1130 | 1129 |
1131 | 1130 |
1132 TEST(TestInternalWeakListsTraverseWithGC) { | 1131 TEST(TestInternalWeakListsTraverseWithGC) { |
1133 static const int kNumTestContexts = 10; | 1132 static const int kNumTestContexts = 10; |
1134 | 1133 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1172 CompileRun("f5()"); | 1171 CompileRun("f5()"); |
1173 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0])); | 1172 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0])); |
1174 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4)); | 1173 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4)); |
1175 | 1174 |
1176 ctx[0]->Exit(); | 1175 ctx[0]->Exit(); |
1177 } | 1176 } |
1178 | 1177 |
1179 | 1178 |
1180 TEST(TestSizeOfObjectsVsHeapIteratorPrecision) { | 1179 TEST(TestSizeOfObjectsVsHeapIteratorPrecision) { |
1181 InitializeVM(); | 1180 InitializeVM(); |
| 1181 Heap::EnsureHeapIsIterable(); |
1182 intptr_t size_of_objects_1 = Heap::SizeOfObjects(); | 1182 intptr_t size_of_objects_1 = Heap::SizeOfObjects(); |
1183 HeapIterator iterator(HeapIterator::kFilterFreeListNodes); | 1183 HeapIterator iterator; |
1184 intptr_t size_of_objects_2 = 0; | 1184 intptr_t size_of_objects_2 = 0; |
1185 for (HeapObject* obj = iterator.next(); | 1185 for (HeapObject* obj = iterator.Next(); |
1186 obj != NULL; | 1186 obj != NULL; |
1187 obj = iterator.next()) { | 1187 obj = iterator.Next()) { |
1188 size_of_objects_2 += obj->Size(); | 1188 size_of_objects_2 += obj->Size(); |
1189 } | 1189 } |
1190 // Delta must be within 1% of the larger result. | 1190 // Delta must be within 5% of the larger result. |
| 1191 // TODO(gc): Tighten this up by distinguishing between byte |
| 1192 // arrays that are real and those that merely mark free space |
| 1193 // on the heap. |
1191 if (size_of_objects_1 > size_of_objects_2) { | 1194 if (size_of_objects_1 > size_of_objects_2) { |
1192 intptr_t delta = size_of_objects_1 - size_of_objects_2; | 1195 intptr_t delta = size_of_objects_1 - size_of_objects_2; |
1193 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " | 1196 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " |
1194 "Iterator: %" V8_PTR_PREFIX "d, " | 1197 "Iterator: %" V8_PTR_PREFIX "d, " |
1195 "delta: %" V8_PTR_PREFIX "d\n", | 1198 "delta: %" V8_PTR_PREFIX "d\n", |
1196 size_of_objects_1, size_of_objects_2, delta); | 1199 size_of_objects_1, size_of_objects_2, delta); |
1197 CHECK_GT(size_of_objects_1 / 100, delta); | 1200 CHECK_GT(size_of_objects_1 / 20, delta); |
1198 } else { | 1201 } else { |
1199 intptr_t delta = size_of_objects_2 - size_of_objects_1; | 1202 intptr_t delta = size_of_objects_2 - size_of_objects_1; |
1200 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " | 1203 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " |
1201 "Iterator: %" V8_PTR_PREFIX "d, " | 1204 "Iterator: %" V8_PTR_PREFIX "d, " |
1202 "delta: %" V8_PTR_PREFIX "d\n", | 1205 "delta: %" V8_PTR_PREFIX "d\n", |
1203 size_of_objects_1, size_of_objects_2, delta); | 1206 size_of_objects_1, size_of_objects_2, delta); |
1204 CHECK_GT(size_of_objects_2 / 100, delta); | 1207 CHECK_GT(size_of_objects_2 / 20, delta); |
1205 } | 1208 } |
1206 } | 1209 } |
1207 | 1210 |
1208 | 1211 |
1209 class HeapIteratorTestHelper { | 1212 class HeapIteratorTestHelper { |
1210 public: | 1213 public: |
1211 HeapIteratorTestHelper(Object* a, Object* b) | 1214 HeapIteratorTestHelper(Object* a, Object* b) |
1212 : a_(a), b_(b), a_found_(false), b_found_(false) {} | 1215 : a_(a), b_(b), a_found_(false), b_found_(false) {} |
1213 bool a_found() { return a_found_; } | 1216 bool a_found() { return a_found_; } |
1214 bool b_found() { return b_found_; } | 1217 bool b_found() { return b_found_; } |
1215 void IterateHeap(HeapIterator::HeapObjectsFiltering mode) { | 1218 void IterateHeap() { |
1216 HeapIterator iterator(mode); | 1219 HeapIterator iterator; |
1217 for (HeapObject* obj = iterator.next(); | 1220 for (HeapObject* obj = iterator.Next(); |
1218 obj != NULL; | 1221 obj != NULL; |
1219 obj = iterator.next()) { | 1222 obj = iterator.Next()) { |
1220 if (obj == a_) | 1223 if (obj == a_) |
1221 a_found_ = true; | 1224 a_found_ = true; |
1222 else if (obj == b_) | 1225 else if (obj == b_) |
1223 b_found_ = true; | 1226 b_found_ = true; |
1224 } | 1227 } |
1225 } | 1228 } |
1226 private: | 1229 private: |
1227 Object* a_; | 1230 Object* a_; |
1228 Object* b_; | 1231 Object* b_; |
1229 bool a_found_; | 1232 bool a_found_; |
1230 bool b_found_; | 1233 bool b_found_; |
1231 }; | 1234 }; |
1232 | 1235 |
1233 TEST(HeapIteratorFilterUnreachable) { | |
1234 InitializeVM(); | |
1235 v8::HandleScope scope; | |
1236 CompileRun("a = {}; b = {};"); | |
1237 v8::Handle<Object> a(Top::context()->global()->GetProperty( | |
1238 *Factory::LookupAsciiSymbol("a"))->ToObjectChecked()); | |
1239 v8::Handle<Object> b(Top::context()->global()->GetProperty( | |
1240 *Factory::LookupAsciiSymbol("b"))->ToObjectChecked()); | |
1241 CHECK_NE(*a, *b); | |
1242 { | |
1243 HeapIteratorTestHelper helper(*a, *b); | |
1244 helper.IterateHeap(HeapIterator::kFilterUnreachable); | |
1245 CHECK(helper.a_found()); | |
1246 CHECK(helper.b_found()); | |
1247 } | |
1248 CHECK(Top::context()->global()->DeleteProperty( | |
1249 *Factory::LookupAsciiSymbol("a"), JSObject::FORCE_DELETION)); | |
1250 // We ensure that GC will not happen, so our raw pointer stays valid. | |
1251 AssertNoAllocation no_alloc; | |
1252 Object* a_saved = *a; | |
1253 a.Clear(); | |
1254 // Verify that "a" object still resides in the heap... | |
1255 { | |
1256 HeapIteratorTestHelper helper(a_saved, *b); | |
1257 helper.IterateHeap(HeapIterator::kNoFiltering); | |
1258 CHECK(helper.a_found()); | |
1259 CHECK(helper.b_found()); | |
1260 } | |
1261 // ...but is now unreachable. | |
1262 { | |
1263 HeapIteratorTestHelper helper(a_saved, *b); | |
1264 helper.IterateHeap(HeapIterator::kFilterUnreachable); | |
1265 CHECK(!helper.a_found()); | |
1266 CHECK(helper.b_found()); | |
1267 } | |
1268 } | |
OLD | NEW |