OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 "compilation-cache.h" | 7 #include "compilation-cache.h" |
8 #include "execution.h" | 8 #include "execution.h" |
9 #include "factory.h" | 9 #include "factory.h" |
10 #include "macro-assembler.h" | 10 #include "macro-assembler.h" |
11 #include "global-handles.h" | 11 #include "global-handles.h" |
12 #include "stub-cache.h" | 12 #include "stub-cache.h" |
13 #include "cctest.h" | 13 #include "cctest.h" |
14 | 14 |
15 using namespace v8::internal; | 15 using namespace v8::internal; |
16 | 16 |
17 static v8::Persistent<v8::Context> env; | 17 static v8::Persistent<v8::Context> env; |
18 | 18 |
19 static void InitializeVM() { | 19 static void InitializeVM() { |
20 if (env.IsEmpty()) env = v8::Context::New(); | 20 if (env.IsEmpty()) env = v8::Context::New(); |
21 v8::HandleScope scope; | 21 v8::HandleScope scope; |
22 env->Enter(); | 22 env->Enter(); |
23 } | 23 } |
24 | 24 |
25 | 25 |
26 // Go through all incremental marking steps in one swoop. | |
27 static void SimulateIncrementalMarking() { | |
28 IncrementalMarking* marking = HEAP->incremental_marking(); | |
29 CHECK(marking->IsStopped()); | |
30 marking->Start(); | |
31 CHECK(marking->IsMarking()); | |
32 while (!marking->IsComplete()) { | |
33 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD); | |
34 } | |
35 CHECK(marking->IsComplete()); | |
36 } | |
37 | |
38 | |
39 static void CheckMap(Map* map, int type, int instance_size) { | 26 static void CheckMap(Map* map, int type, int instance_size) { |
40 CHECK(map->IsHeapObject()); | 27 CHECK(map->IsHeapObject()); |
41 #ifdef DEBUG | 28 #ifdef DEBUG |
42 CHECK(HEAP->Contains(map)); | 29 CHECK(HEAP->Contains(map)); |
43 #endif | 30 #endif |
44 CHECK_EQ(HEAP->meta_map(), map->map()); | 31 CHECK_EQ(HEAP->meta_map(), map->map()); |
45 CHECK_EQ(type, map->instance_type()); | 32 CHECK_EQ(type, map->instance_type()); |
46 CHECK_EQ(instance_size, map->instance_size()); | 33 CHECK_EQ(instance_size, map->instance_size()); |
47 } | 34 } |
48 | 35 |
(...skipping 899 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
948 JSObject* clone = JSObject::cast(clone_obj); | 935 JSObject* clone = JSObject::cast(clone_obj); |
949 if (clone->address() != old_pointer_space_top) { | 936 if (clone->address() != old_pointer_space_top) { |
950 // Alas, got allocated from free list, we cannot do checks. | 937 // Alas, got allocated from free list, we cannot do checks. |
951 return; | 938 return; |
952 } | 939 } |
953 CHECK(HEAP->old_pointer_space()->Contains(clone->address())); | 940 CHECK(HEAP->old_pointer_space()->Contains(clone->address())); |
954 } | 941 } |
955 | 942 |
956 | 943 |
957 TEST(TestCodeFlushing) { | 944 TEST(TestCodeFlushing) { |
| 945 i::FLAG_allow_natives_syntax = true; |
958 // If we do not flush code this test is invalid. | 946 // If we do not flush code this test is invalid. |
959 if (!FLAG_flush_code) return; | 947 if (!FLAG_flush_code) return; |
960 i::FLAG_allow_natives_syntax = true; | |
961 InitializeVM(); | 948 InitializeVM(); |
962 v8::HandleScope scope; | 949 v8::HandleScope scope; |
963 const char* source = "function foo() {" | 950 const char* source = "function foo() {" |
964 " var x = 42;" | 951 " var x = 42;" |
965 " var y = 42;" | 952 " var y = 42;" |
966 " var z = x + y;" | 953 " var z = x + y;" |
967 "};" | 954 "};" |
968 "foo()"; | 955 "foo()"; |
969 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo"); | 956 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo"); |
970 | 957 |
971 // This compile will add the code to the compilation cache. | 958 // This compile will add the code to the compilation cache. |
972 { v8::HandleScope scope; | 959 { v8::HandleScope scope; |
973 CompileRun(source); | 960 CompileRun(source); |
974 } | 961 } |
975 | 962 |
976 // Check function is compiled. | 963 // Check function is compiled. |
977 Object* func_value = Isolate::Current()->context()->global_object()-> | 964 Object* func_value = Isolate::Current()->context()->global_object()-> |
978 GetProperty(*foo_name)->ToObjectChecked(); | 965 GetProperty(*foo_name)->ToObjectChecked(); |
979 CHECK(func_value->IsJSFunction()); | 966 CHECK(func_value->IsJSFunction()); |
980 Handle<JSFunction> function(JSFunction::cast(func_value)); | 967 Handle<JSFunction> function(JSFunction::cast(func_value)); |
981 CHECK(function->shared()->is_compiled()); | 968 CHECK(function->shared()->is_compiled()); |
982 | 969 |
983 // The code will survive at least two GCs. | 970 // TODO(1609) Currently incremental marker does not support code flushing. |
984 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | 971 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
985 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | 972 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
| 973 |
986 CHECK(function->shared()->is_compiled()); | 974 CHECK(function->shared()->is_compiled()); |
987 | 975 |
988 // Simulate several GCs that use full marking. | 976 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
989 const int kAgingThreshold = 6; | 977 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
990 for (int i = 0; i < kAgingThreshold; i++) { | 978 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
991 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); | 979 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
992 } | 980 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
| 981 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); |
993 | 982 |
994 // foo should no longer be in the compilation cache | 983 // foo should no longer be in the compilation cache |
995 CHECK(!function->shared()->is_compiled() || function->IsOptimized()); | 984 CHECK(!function->shared()->is_compiled() || function->IsOptimized()); |
996 CHECK(!function->is_compiled() || function->IsOptimized()); | 985 CHECK(!function->is_compiled() || function->IsOptimized()); |
997 // Call foo to get it recompiled. | 986 // Call foo to get it recompiled. |
998 CompileRun("foo()"); | 987 CompileRun("foo()"); |
999 CHECK(function->shared()->is_compiled()); | 988 CHECK(function->shared()->is_compiled()); |
1000 CHECK(function->is_compiled()); | 989 CHECK(function->is_compiled()); |
1001 } | 990 } |
1002 | 991 |
1003 | 992 |
1004 TEST(TestCodeFlushingIncremental) { | |
1005 // If we do not flush code this test is invalid. | |
1006 if (!FLAG_flush_code) return; | |
1007 i::FLAG_allow_natives_syntax = true; | |
1008 InitializeVM(); | |
1009 v8::HandleScope scope; | |
1010 const char* source = "function foo() {" | |
1011 " var x = 42;" | |
1012 " var y = 42;" | |
1013 " var z = x + y;" | |
1014 "};" | |
1015 "foo()"; | |
1016 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo"); | |
1017 | |
1018 // This compile will add the code to the compilation cache. | |
1019 { v8::HandleScope scope; | |
1020 CompileRun(source); | |
1021 } | |
1022 | |
1023 // Check function is compiled. | |
1024 Object* func_value = Isolate::Current()->context()->global_object()-> | |
1025 GetProperty(*foo_name)->ToObjectChecked(); | |
1026 CHECK(func_value->IsJSFunction()); | |
1027 Handle<JSFunction> function(JSFunction::cast(func_value)); | |
1028 CHECK(function->shared()->is_compiled()); | |
1029 | |
1030 // The code will survive at least two GCs. | |
1031 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | |
1032 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | |
1033 CHECK(function->shared()->is_compiled()); | |
1034 | |
1035 // Simulate several GCs that use incremental marking. | |
1036 const int kAgingThreshold = 6; | |
1037 for (int i = 0; i < kAgingThreshold; i++) { | |
1038 HEAP->incremental_marking()->Abort(); | |
1039 SimulateIncrementalMarking(); | |
1040 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | |
1041 } | |
1042 CHECK(!function->shared()->is_compiled() || function->IsOptimized()); | |
1043 CHECK(!function->is_compiled() || function->IsOptimized()); | |
1044 | |
1045 // This compile will compile the function again. | |
1046 { v8::HandleScope scope; | |
1047 CompileRun("foo();"); | |
1048 } | |
1049 | |
1050 // Simulate several GCs that use incremental marking but make sure | |
1051 // the loop breaks once the function is enqueued as a candidate. | |
1052 for (int i = 0; i < kAgingThreshold; i++) { | |
1053 HEAP->incremental_marking()->Abort(); | |
1054 SimulateIncrementalMarking(); | |
1055 if (!function->next_function_link()->IsUndefined()) break; | |
1056 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | |
1057 } | |
1058 | |
1059 // Force optimization while incremental marking is active and while | |
1060 // the function is enqueued as a candidate. | |
1061 { v8::HandleScope scope; | |
1062 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();"); | |
1063 } | |
1064 | |
1065 // Simulate one final GC to make sure the candidate queue is sane. | |
1066 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | |
1067 CHECK(function->shared()->is_compiled() || !function->IsOptimized()); | |
1068 CHECK(function->is_compiled() || !function->IsOptimized()); | |
1069 } | |
1070 | |
1071 | |
1072 TEST(TestCodeFlushingIncrementalScavenge) { | |
1073 // If we do not flush code this test is invalid. | |
1074 if (!FLAG_flush_code) return; | |
1075 i::FLAG_allow_natives_syntax = true; | |
1076 InitializeVM(); | |
1077 v8::HandleScope scope; | |
1078 const char* source = "var foo = function() {" | |
1079 " var x = 42;" | |
1080 " var y = 42;" | |
1081 " var z = x + y;" | |
1082 "};" | |
1083 "foo();" | |
1084 "var bar = function() {" | |
1085 " var x = 23;" | |
1086 "};" | |
1087 "bar();"; | |
1088 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo"); | |
1089 Handle<String> bar_name = FACTORY->LookupAsciiSymbol("bar"); | |
1090 | |
1091 // Perfrom one initial GC to enable code flushing. | |
1092 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | |
1093 | |
1094 // This compile will add the code to the compilation cache. | |
1095 { v8::HandleScope scope; | |
1096 CompileRun(source); | |
1097 } | |
1098 | |
1099 // Check functions are compiled. | |
1100 Object* func_value = Isolate::Current()->context()->global_object()-> | |
1101 GetProperty(*foo_name)->ToObjectChecked(); | |
1102 CHECK(func_value->IsJSFunction()); | |
1103 Handle<JSFunction> function(JSFunction::cast(func_value)); | |
1104 CHECK(function->shared()->is_compiled()); | |
1105 Object* func_value2 = Isolate::Current()->context()->global_object()-> | |
1106 GetProperty(*bar_name)->ToObjectChecked(); | |
1107 CHECK(func_value2->IsJSFunction()); | |
1108 Handle<JSFunction> function2(JSFunction::cast(func_value2)); | |
1109 CHECK(function2->shared()->is_compiled()); | |
1110 | |
1111 // Clear references to functions so that one of them can die. | |
1112 { v8::HandleScope scope; | |
1113 CompileRun("foo = 0; bar = 0;"); | |
1114 } | |
1115 | |
1116 // Bump the code age so that flushing is triggered while the function | |
1117 // object is still located in new-space. | |
1118 const int kAgingThreshold = 6; | |
1119 function->shared()->set_code_age(kAgingThreshold); | |
1120 function2->shared()->set_code_age(kAgingThreshold); | |
1121 | |
1122 // Simulate incremental marking so that the functions are enqueued as | |
1123 // code flushing candidates. Then kill one of the functions. Finally | |
1124 // perform a scavenge while incremental marking is still running. | |
1125 SimulateIncrementalMarking(); | |
1126 *function2.location() = NULL; | |
1127 HEAP->CollectGarbage(NEW_SPACE, "test scavenge while marking"); | |
1128 | |
1129 // Simulate one final GC to make sure the candidate queue is sane. | |
1130 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | |
1131 CHECK(!function->shared()->is_compiled() || function->IsOptimized()); | |
1132 CHECK(!function->is_compiled() || function->IsOptimized()); | |
1133 } | |
1134 | |
1135 | |
1136 // Count the number of native contexts in the weak list of native contexts. | 993 // Count the number of native contexts in the weak list of native contexts. |
1137 int CountNativeContexts() { | 994 int CountNativeContexts() { |
1138 int count = 0; | 995 int count = 0; |
1139 Object* object = HEAP->native_contexts_list(); | 996 Object* object = HEAP->native_contexts_list(); |
1140 while (!object->IsUndefined()) { | 997 while (!object->IsUndefined()) { |
1141 count++; | 998 count++; |
1142 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK); | 999 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK); |
1143 } | 1000 } |
1144 return count; | 1001 return count; |
1145 } | 1002 } |
(...skipping 757 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1903 | 1760 |
1904 CHECK(HEAP->InNewSpace(*o)); | 1761 CHECK(HEAP->InNewSpace(*o)); |
1905 } | 1762 } |
1906 | 1763 |
1907 | 1764 |
1908 static int CountMapTransitions(Map* map) { | 1765 static int CountMapTransitions(Map* map) { |
1909 return map->transitions()->number_of_transitions(); | 1766 return map->transitions()->number_of_transitions(); |
1910 } | 1767 } |
1911 | 1768 |
1912 | 1769 |
| 1770 // Go through all incremental marking steps in one swoop. |
| 1771 static void SimulateIncrementalMarking() { |
| 1772 IncrementalMarking* marking = HEAP->incremental_marking(); |
| 1773 CHECK(marking->IsStopped()); |
| 1774 marking->Start(); |
| 1775 CHECK(marking->IsMarking()); |
| 1776 while (!marking->IsComplete()) { |
| 1777 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD); |
| 1778 } |
| 1779 CHECK(marking->IsComplete()); |
| 1780 } |
| 1781 |
| 1782 |
1913 // Test that map transitions are cleared and maps are collected with | 1783 // Test that map transitions are cleared and maps are collected with |
1914 // incremental marking as well. | 1784 // incremental marking as well. |
1915 TEST(Regress1465) { | 1785 TEST(Regress1465) { |
1916 i::FLAG_allow_natives_syntax = true; | 1786 i::FLAG_allow_natives_syntax = true; |
1917 i::FLAG_trace_incremental_marking = true; | 1787 i::FLAG_trace_incremental_marking = true; |
1918 InitializeVM(); | 1788 InitializeVM(); |
1919 v8::HandleScope scope; | 1789 v8::HandleScope scope; |
1920 static const int transitions_count = 256; | 1790 static const int transitions_count = 256; |
1921 | 1791 |
1922 { | 1792 { |
(...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2434 Handle<Object> call_function(call); | 2304 Handle<Object> call_function(call); |
2435 | 2305 |
2436 // Now we are ready to mess up the heap. | 2306 // Now we are ready to mess up the heap. |
2437 HEAP->CollectAllGarbage(Heap::kReduceMemoryFootprintMask); | 2307 HEAP->CollectAllGarbage(Heap::kReduceMemoryFootprintMask); |
2438 | 2308 |
2439 // Either heap verification caught the problem already or we go kaboom once | 2309 // Either heap verification caught the problem already or we go kaboom once |
2440 // the CallIC is executed the next time. | 2310 // the CallIC is executed the next time. |
2441 USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode)); | 2311 USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode)); |
2442 CompileRun("call();"); | 2312 CompileRun("call();"); |
2443 } | 2313 } |
OLD | NEW |