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 753 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
764 DeleteArray(non_ascii); | 764 DeleteArray(non_ascii); |
765 DeleteArray(ascii); | 765 DeleteArray(ascii); |
766 } | 766 } |
767 } | 767 } |
768 | 768 |
769 | 769 |
770 static int ObjectsFoundInHeap(Handle<Object> objs[], int size) { | 770 static int ObjectsFoundInHeap(Handle<Object> objs[], int size) { |
771 // Count the number of objects found in the heap. | 771 // Count the number of objects found in the heap. |
772 int found_count = 0; | 772 int found_count = 0; |
773 HeapIterator iterator; | 773 HeapIterator iterator; |
774 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { | 774 for (HeapObject* obj = iterator.Next(); obj != NULL; obj = iterator.Next()) { |
775 for (int i = 0; i < size; i++) { | 775 for (int i = 0; i < size; i++) { |
776 if (*objs[i] == obj) { | 776 if (*objs[i] == obj) { |
777 found_count++; | 777 found_count++; |
778 } | 778 } |
779 } | 779 } |
780 } | 780 } |
781 return found_count; | 781 return found_count; |
782 } | 782 } |
783 | 783 |
784 | 784 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
837 static int LenFromSize(int size) { | 837 static int LenFromSize(int size) { |
838 return (size - FixedArray::kHeaderSize) / kPointerSize; | 838 return (size - FixedArray::kHeaderSize) / kPointerSize; |
839 } | 839 } |
840 | 840 |
841 | 841 |
842 TEST(Regression39128) { | 842 TEST(Regression39128) { |
843 // Test case for crbug.com/39128. | 843 // Test case for crbug.com/39128. |
844 InitializeVM(); | 844 InitializeVM(); |
845 | 845 |
846 // Increase the chance of 'bump-the-pointer' allocation in old space. | 846 // Increase the chance of 'bump-the-pointer' allocation in old space. |
847 bool force_compaction = true; | 847 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
848 Heap::CollectAllGarbage(force_compaction); | |
849 | 848 |
850 v8::HandleScope scope; | 849 v8::HandleScope scope; |
851 | 850 |
852 // The plan: create JSObject which references objects in new space. | 851 // The plan: create JSObject which references objects in new space. |
853 // Then clone this object (forcing it to go into old space) and check | 852 // Then clone this object (forcing it to go into old space) and check |
854 // that region dirty marks are updated correctly. | 853 // that region dirty marks are updated correctly. |
855 | 854 |
856 // Step 1: prepare a map for the object. We add 1 inobject property to it. | 855 // Step 1: prepare a map for the object. We add 1 inobject property to it. |
857 Handle<JSFunction> object_ctor(Top::global_context()->object_function()); | 856 Handle<JSFunction> object_ctor(Top::global_context()->object_function()); |
858 CHECK(object_ctor->has_initial_map()); | 857 CHECK(object_ctor->has_initial_map()); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
933 CompileRun(source); | 932 CompileRun(source); |
934 } | 933 } |
935 | 934 |
936 // Check function is compiled. | 935 // Check function is compiled. |
937 Object* func_value = | 936 Object* func_value = |
938 Top::context()->global()->GetProperty(*foo_name)->ToObjectChecked(); | 937 Top::context()->global()->GetProperty(*foo_name)->ToObjectChecked(); |
939 CHECK(func_value->IsJSFunction()); | 938 CHECK(func_value->IsJSFunction()); |
940 Handle<JSFunction> function(JSFunction::cast(func_value)); | 939 Handle<JSFunction> function(JSFunction::cast(func_value)); |
941 CHECK(function->shared()->is_compiled()); | 940 CHECK(function->shared()->is_compiled()); |
942 | 941 |
943 Heap::CollectAllGarbage(true); | 942 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
944 Heap::CollectAllGarbage(true); | 943 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
945 | 944 |
946 CHECK(function->shared()->is_compiled()); | 945 CHECK(function->shared()->is_compiled()); |
947 | 946 |
948 Heap::CollectAllGarbage(true); | 947 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
949 Heap::CollectAllGarbage(true); | 948 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
950 Heap::CollectAllGarbage(true); | 949 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
951 Heap::CollectAllGarbage(true); | 950 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
952 Heap::CollectAllGarbage(true); | 951 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
953 Heap::CollectAllGarbage(true); | 952 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
954 | 953 |
955 // foo should no longer be in the compilation cache | 954 // foo should no longer be in the compilation cache |
956 CHECK(!function->shared()->is_compiled() || function->IsOptimized()); | 955 CHECK(!function->shared()->is_compiled() || function->IsOptimized()); |
957 CHECK(!function->is_compiled() || function->IsOptimized()); | 956 CHECK(!function->is_compiled() || function->IsOptimized()); |
958 // Call foo to get it recompiled. | 957 // Call foo to get it recompiled. |
959 CompileRun("foo()"); | 958 CompileRun("foo()"); |
960 CHECK(function->shared()->is_compiled()); | 959 CHECK(function->shared()->is_compiled()); |
961 CHECK(function->is_compiled()); | 960 CHECK(function->is_compiled()); |
962 } | 961 } |
963 | 962 |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1030 // Remove function f1, and | 1029 // Remove function f1, and |
1031 CompileRun("f1=null"); | 1030 CompileRun("f1=null"); |
1032 | 1031 |
1033 // Scavenge treats these references as strong. | 1032 // Scavenge treats these references as strong. |
1034 for (int j = 0; j < 10; j++) { | 1033 for (int j = 0; j < 10; j++) { |
1035 Heap::PerformScavenge(); | 1034 Heap::PerformScavenge(); |
1036 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i])); | 1035 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i])); |
1037 } | 1036 } |
1038 | 1037 |
1039 // Mark compact handles the weak references. | 1038 // Mark compact handles the weak references. |
1040 Heap::CollectAllGarbage(true); | 1039 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
1041 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); | 1040 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); |
1042 | 1041 |
1043 // Get rid of f3 and f5 in the same way. | 1042 // Get rid of f3 and f5 in the same way. |
1044 CompileRun("f3=null"); | 1043 CompileRun("f3=null"); |
1045 for (int j = 0; j < 10; j++) { | 1044 for (int j = 0; j < 10; j++) { |
1046 Heap::PerformScavenge(); | 1045 Heap::PerformScavenge(); |
1047 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); | 1046 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); |
1048 } | 1047 } |
1049 Heap::CollectAllGarbage(true); | 1048 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
1050 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); | 1049 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); |
1051 CompileRun("f5=null"); | 1050 CompileRun("f5=null"); |
1052 for (int j = 0; j < 10; j++) { | 1051 for (int j = 0; j < 10; j++) { |
1053 Heap::PerformScavenge(); | 1052 Heap::PerformScavenge(); |
1054 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); | 1053 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); |
1055 } | 1054 } |
1056 Heap::CollectAllGarbage(true); | 1055 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
1057 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i])); | 1056 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i])); |
1058 | 1057 |
1059 ctx[i]->Exit(); | 1058 ctx[i]->Exit(); |
1060 } | 1059 } |
1061 | 1060 |
1062 // Force compilation cache cleanup. | 1061 // Force compilation cache cleanup. |
1063 Heap::CollectAllGarbage(true); | 1062 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
1064 | 1063 |
1065 // Dispose the global contexts one by one. | 1064 // Dispose the global contexts one by one. |
1066 for (int i = 0; i < kNumTestContexts; i++) { | 1065 for (int i = 0; i < kNumTestContexts; i++) { |
1067 ctx[i].Dispose(); | 1066 ctx[i].Dispose(); |
1068 ctx[i].Clear(); | 1067 ctx[i].Clear(); |
1069 | 1068 |
1070 // Scavenge treats these references as strong. | 1069 // Scavenge treats these references as strong. |
1071 for (int j = 0; j < 10; j++) { | 1070 for (int j = 0; j < 10; j++) { |
1072 Heap::PerformScavenge(); | 1071 Heap::PerformScavenge(); |
1073 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts()); | 1072 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts()); |
1074 } | 1073 } |
1075 | 1074 |
1076 // Mark compact handles the weak references. | 1075 // Mark compact handles the weak references. |
1077 Heap::CollectAllGarbage(true); | 1076 Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
1078 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts()); | 1077 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts()); |
1079 } | 1078 } |
1080 | 1079 |
1081 CHECK_EQ(0, CountGlobalContexts()); | 1080 CHECK_EQ(0, CountGlobalContexts()); |
1082 } | 1081 } |
1083 | 1082 |
1084 | 1083 |
1085 // Count the number of global contexts in the weak list of global contexts | 1084 // Count the number of global contexts in the weak list of global contexts |
1086 // causing a GC after the specified number of elements. | 1085 // causing a GC after the specified number of elements. |
1087 static int CountGlobalContextsWithGC(int n) { | 1086 static int CountGlobalContextsWithGC(int n) { |
1088 int count = 0; | 1087 int count = 0; |
1089 Handle<Object> object(Heap::global_contexts_list()); | 1088 Handle<Object> object(Heap::global_contexts_list()); |
1090 while (!object->IsUndefined()) { | 1089 while (!object->IsUndefined()) { |
1091 count++; | 1090 count++; |
1092 if (count == n) Heap::CollectAllGarbage(true); | 1091 if (count == n) Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
1093 object = | 1092 object = |
1094 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK)); | 1093 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK)); |
1095 } | 1094 } |
1096 return count; | 1095 return count; |
1097 } | 1096 } |
1098 | 1097 |
1099 | 1098 |
1100 // Count the number of user functions in the weak list of optimized | 1099 // Count the number of user functions in the weak list of optimized |
1101 // functions attached to a global context causing a GC after the | 1100 // functions attached to a global context causing a GC after the |
1102 // specified number of elements. | 1101 // specified number of elements. |
1103 static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context, | 1102 static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context, |
1104 int n) { | 1103 int n) { |
1105 int count = 0; | 1104 int count = 0; |
1106 Handle<Context> icontext = v8::Utils::OpenHandle(*context); | 1105 Handle<Context> icontext = v8::Utils::OpenHandle(*context); |
1107 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST)); | 1106 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST)); |
1108 while (object->IsJSFunction() && | 1107 while (object->IsJSFunction() && |
1109 !Handle<JSFunction>::cast(object)->IsBuiltin()) { | 1108 !Handle<JSFunction>::cast(object)->IsBuiltin()) { |
1110 count++; | 1109 count++; |
1111 if (count == n) Heap::CollectAllGarbage(true); | 1110 if (count == n) Heap::CollectAllGarbage(Heap::kForceCompactionMask); |
1112 object = Handle<Object>( | 1111 object = Handle<Object>( |
1113 Object::cast(JSFunction::cast(*object)->next_function_link())); | 1112 Object::cast(JSFunction::cast(*object)->next_function_link())); |
1114 } | 1113 } |
1115 return count; | 1114 return count; |
1116 } | 1115 } |
1117 | 1116 |
1118 | 1117 |
1119 TEST(TestInternalWeakListsTraverseWithGC) { | 1118 TEST(TestInternalWeakListsTraverseWithGC) { |
1120 static const int kNumTestContexts = 10; | 1119 static const int kNumTestContexts = 10; |
1121 | 1120 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1159 CompileRun("f5()"); | 1158 CompileRun("f5()"); |
1160 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0])); | 1159 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0])); |
1161 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4)); | 1160 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4)); |
1162 | 1161 |
1163 ctx[0]->Exit(); | 1162 ctx[0]->Exit(); |
1164 } | 1163 } |
1165 | 1164 |
1166 | 1165 |
1167 TEST(TestSizeOfObjectsVsHeapIteratorPrecision) { | 1166 TEST(TestSizeOfObjectsVsHeapIteratorPrecision) { |
1168 InitializeVM(); | 1167 InitializeVM(); |
| 1168 Heap::EnsureHeapIsIterable(); |
1169 intptr_t size_of_objects_1 = Heap::SizeOfObjects(); | 1169 intptr_t size_of_objects_1 = Heap::SizeOfObjects(); |
1170 HeapIterator iterator(HeapIterator::kFilterFreeListNodes); | 1170 HeapIterator iterator; |
1171 intptr_t size_of_objects_2 = 0; | 1171 intptr_t size_of_objects_2 = 0; |
1172 for (HeapObject* obj = iterator.next(); | 1172 for (HeapObject* obj = iterator.Next(); |
1173 obj != NULL; | 1173 obj != NULL; |
1174 obj = iterator.next()) { | 1174 obj = iterator.Next()) { |
1175 size_of_objects_2 += obj->Size(); | 1175 size_of_objects_2 += obj->Size(); |
1176 } | 1176 } |
1177 // Delta must be within 1% of the larger result. | 1177 // Delta must be within 5% of the larger result. |
| 1178 // TODO(gc): Tighten this up by distinguishing between byte |
| 1179 // arrays that are real and those that merely mark free space |
| 1180 // on the heap. |
1178 if (size_of_objects_1 > size_of_objects_2) { | 1181 if (size_of_objects_1 > size_of_objects_2) { |
1179 intptr_t delta = size_of_objects_1 - size_of_objects_2; | 1182 intptr_t delta = size_of_objects_1 - size_of_objects_2; |
1180 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " | 1183 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " |
1181 "Iterator: %" V8_PTR_PREFIX "d, " | 1184 "Iterator: %" V8_PTR_PREFIX "d, " |
1182 "delta: %" V8_PTR_PREFIX "d\n", | 1185 "delta: %" V8_PTR_PREFIX "d\n", |
1183 size_of_objects_1, size_of_objects_2, delta); | 1186 size_of_objects_1, size_of_objects_2, delta); |
1184 CHECK_GT(size_of_objects_1 / 100, delta); | 1187 CHECK_GT(size_of_objects_1 / 20, delta); |
1185 } else { | 1188 } else { |
1186 intptr_t delta = size_of_objects_2 - size_of_objects_1; | 1189 intptr_t delta = size_of_objects_2 - size_of_objects_1; |
1187 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " | 1190 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " |
1188 "Iterator: %" V8_PTR_PREFIX "d, " | 1191 "Iterator: %" V8_PTR_PREFIX "d, " |
1189 "delta: %" V8_PTR_PREFIX "d\n", | 1192 "delta: %" V8_PTR_PREFIX "d\n", |
1190 size_of_objects_1, size_of_objects_2, delta); | 1193 size_of_objects_1, size_of_objects_2, delta); |
1191 CHECK_GT(size_of_objects_2 / 100, delta); | 1194 CHECK_GT(size_of_objects_2 / 20, delta); |
1192 } | 1195 } |
1193 } | 1196 } |
1194 | 1197 |
1195 | 1198 |
1196 class HeapIteratorTestHelper { | 1199 class HeapIteratorTestHelper { |
1197 public: | 1200 public: |
1198 HeapIteratorTestHelper(Object* a, Object* b) | 1201 HeapIteratorTestHelper(Object* a, Object* b) |
1199 : a_(a), b_(b), a_found_(false), b_found_(false) {} | 1202 : a_(a), b_(b), a_found_(false), b_found_(false) {} |
1200 bool a_found() { return a_found_; } | 1203 bool a_found() { return a_found_; } |
1201 bool b_found() { return b_found_; } | 1204 bool b_found() { return b_found_; } |
1202 void IterateHeap(HeapIterator::HeapObjectsFiltering mode) { | 1205 void IterateHeap() { |
1203 HeapIterator iterator(mode); | 1206 HeapIterator iterator; |
1204 for (HeapObject* obj = iterator.next(); | 1207 for (HeapObject* obj = iterator.Next(); |
1205 obj != NULL; | 1208 obj != NULL; |
1206 obj = iterator.next()) { | 1209 obj = iterator.Next()) { |
1207 if (obj == a_) | 1210 if (obj == a_) |
1208 a_found_ = true; | 1211 a_found_ = true; |
1209 else if (obj == b_) | 1212 else if (obj == b_) |
1210 b_found_ = true; | 1213 b_found_ = true; |
1211 } | 1214 } |
1212 } | 1215 } |
1213 private: | 1216 private: |
1214 Object* a_; | 1217 Object* a_; |
1215 Object* b_; | 1218 Object* b_; |
1216 bool a_found_; | 1219 bool a_found_; |
1217 bool b_found_; | 1220 bool b_found_; |
1218 }; | 1221 }; |
1219 | 1222 |
1220 TEST(HeapIteratorFilterUnreachable) { | |
1221 InitializeVM(); | |
1222 v8::HandleScope scope; | |
1223 CompileRun("a = {}; b = {};"); | |
1224 v8::Handle<Object> a(Top::context()->global()->GetProperty( | |
1225 *Factory::LookupAsciiSymbol("a"))->ToObjectChecked()); | |
1226 v8::Handle<Object> b(Top::context()->global()->GetProperty( | |
1227 *Factory::LookupAsciiSymbol("b"))->ToObjectChecked()); | |
1228 CHECK_NE(*a, *b); | |
1229 { | |
1230 HeapIteratorTestHelper helper(*a, *b); | |
1231 helper.IterateHeap(HeapIterator::kFilterUnreachable); | |
1232 CHECK(helper.a_found()); | |
1233 CHECK(helper.b_found()); | |
1234 } | |
1235 CHECK(Top::context()->global()->DeleteProperty( | |
1236 *Factory::LookupAsciiSymbol("a"), JSObject::FORCE_DELETION)); | |
1237 // We ensure that GC will not happen, so our raw pointer stays valid. | |
1238 AssertNoAllocation no_alloc; | |
1239 Object* a_saved = *a; | |
1240 a.Clear(); | |
1241 // Verify that "a" object still resides in the heap... | |
1242 { | |
1243 HeapIteratorTestHelper helper(a_saved, *b); | |
1244 helper.IterateHeap(HeapIterator::kNoFiltering); | |
1245 CHECK(helper.a_found()); | |
1246 CHECK(helper.b_found()); | |
1247 } | |
1248 // ...but is now unreachable. | |
1249 { | |
1250 HeapIteratorTestHelper helper(a_saved, *b); | |
1251 helper.IterateHeap(HeapIterator::kFilterUnreachable); | |
1252 CHECK(!helper.a_found()); | |
1253 CHECK(helper.b_found()); | |
1254 } | |
1255 } | |
OLD | NEW |