| 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" | |
| 8 #include "execution.h" | 7 #include "execution.h" |
| 9 #include "factory.h" | 8 #include "factory.h" |
| 10 #include "macro-assembler.h" | 9 #include "macro-assembler.h" |
| 11 #include "global-handles.h" | 10 #include "global-handles.h" |
| 12 #include "stub-cache.h" | |
| 13 #include "cctest.h" | 11 #include "cctest.h" |
| 14 | 12 |
| 15 using namespace v8::internal; | 13 using namespace v8::internal; |
| 16 | 14 |
| 17 static v8::Persistent<v8::Context> env; | 15 static v8::Persistent<v8::Context> env; |
| 18 | 16 |
| 19 static void InitializeVM() { | 17 static void InitializeVM() { |
| 20 if (env.IsEmpty()) env = v8::Context::New(); | 18 if (env.IsEmpty()) env = v8::Context::New(); |
| 21 v8::HandleScope scope; | 19 v8::HandleScope scope; |
| 22 env->Enter(); | 20 env->Enter(); |
| (...skipping 1216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1239 | 1237 |
| 1240 TEST(TestSizeOfObjectsVsHeapIteratorPrecision) { | 1238 TEST(TestSizeOfObjectsVsHeapIteratorPrecision) { |
| 1241 InitializeVM(); | 1239 InitializeVM(); |
| 1242 HEAP->EnsureHeapIsIterable(); | 1240 HEAP->EnsureHeapIsIterable(); |
| 1243 intptr_t size_of_objects_1 = HEAP->SizeOfObjects(); | 1241 intptr_t size_of_objects_1 = HEAP->SizeOfObjects(); |
| 1244 HeapIterator iterator; | 1242 HeapIterator iterator; |
| 1245 intptr_t size_of_objects_2 = 0; | 1243 intptr_t size_of_objects_2 = 0; |
| 1246 for (HeapObject* obj = iterator.next(); | 1244 for (HeapObject* obj = iterator.next(); |
| 1247 obj != NULL; | 1245 obj != NULL; |
| 1248 obj = iterator.next()) { | 1246 obj = iterator.next()) { |
| 1249 if (!obj->IsFreeSpace()) { | 1247 size_of_objects_2 += obj->Size(); |
| 1250 size_of_objects_2 += obj->Size(); | |
| 1251 } | |
| 1252 } | 1248 } |
| 1253 // Delta must be within 5% of the larger result. | 1249 // Delta must be within 5% of the larger result. |
| 1254 // TODO(gc): Tighten this up by distinguishing between byte | 1250 // TODO(gc): Tighten this up by distinguishing between byte |
| 1255 // arrays that are real and those that merely mark free space | 1251 // arrays that are real and those that merely mark free space |
| 1256 // on the heap. | 1252 // on the heap. |
| 1257 if (size_of_objects_1 > size_of_objects_2) { | 1253 if (size_of_objects_1 > size_of_objects_2) { |
| 1258 intptr_t delta = size_of_objects_1 - size_of_objects_2; | 1254 intptr_t delta = size_of_objects_1 - size_of_objects_2; |
| 1259 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " | 1255 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " |
| 1260 "Iterator: %" V8_PTR_PREFIX "d, " | 1256 "Iterator: %" V8_PTR_PREFIX "d, " |
| 1261 "delta: %" V8_PTR_PREFIX "d\n", | 1257 "delta: %" V8_PTR_PREFIX "d\n", |
| 1262 size_of_objects_1, size_of_objects_2, delta); | 1258 size_of_objects_1, size_of_objects_2, delta); |
| 1263 CHECK_GT(size_of_objects_1 / 20, delta); | 1259 CHECK_GT(size_of_objects_1 / 20, delta); |
| 1264 } else { | 1260 } else { |
| 1265 intptr_t delta = size_of_objects_2 - size_of_objects_1; | 1261 intptr_t delta = size_of_objects_2 - size_of_objects_1; |
| 1266 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " | 1262 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " |
| 1267 "Iterator: %" V8_PTR_PREFIX "d, " | 1263 "Iterator: %" V8_PTR_PREFIX "d, " |
| 1268 "delta: %" V8_PTR_PREFIX "d\n", | 1264 "delta: %" V8_PTR_PREFIX "d\n", |
| 1269 size_of_objects_1, size_of_objects_2, delta); | 1265 size_of_objects_1, size_of_objects_2, delta); |
| 1270 CHECK_GT(size_of_objects_2 / 20, delta); | 1266 CHECK_GT(size_of_objects_2 / 20, delta); |
| 1271 } | 1267 } |
| 1272 } | 1268 } |
| 1273 | 1269 |
| 1274 | 1270 |
| 1275 static void FillUpNewSpace(NewSpace* new_space) { | 1271 static void FillUpNewSpace(NewSpace* new_space) { |
| 1276 // Fill up new space to the point that it is completely full. Make sure | 1272 // Fill up new space to the point that it is completely full. Make sure |
| 1277 // that the scavenger does not undo the filling. | 1273 // that the scavenger does not undo the filling. |
| 1278 v8::HandleScope scope; | 1274 v8::HandleScope scope; |
| 1279 AlwaysAllocateScope always_allocate; | 1275 AlwaysAllocateScope always_allocate; |
| 1276 LinearAllocationScope allocate_linearly; |
| 1280 intptr_t available = new_space->EffectiveCapacity() - new_space->Size(); | 1277 intptr_t available = new_space->EffectiveCapacity() - new_space->Size(); |
| 1281 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1; | 1278 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1; |
| 1282 for (intptr_t i = 0; i < number_of_fillers; i++) { | 1279 for (intptr_t i = 0; i < number_of_fillers; i++) { |
| 1283 CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED))); | 1280 CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED))); |
| 1284 } | 1281 } |
| 1285 } | 1282 } |
| 1286 | 1283 |
| 1287 | 1284 |
| 1288 TEST(GrowAndShrinkNewSpace) { | 1285 TEST(GrowAndShrinkNewSpace) { |
| 1289 InitializeVM(); | 1286 InitializeVM(); |
| (...skipping 634 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1924 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation"); | 1921 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation"); |
| 1925 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages()); | 1922 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages()); |
| 1926 | 1923 |
| 1927 // Triggering subsequent GCs should cause at least half of the pages | 1924 // Triggering subsequent GCs should cause at least half of the pages |
| 1928 // to be released to the OS after at most two cycles. | 1925 // to be released to the OS after at most two cycles. |
| 1929 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1"); | 1926 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1"); |
| 1930 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages()); | 1927 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages()); |
| 1931 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2"); | 1928 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2"); |
| 1932 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2); | 1929 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2); |
| 1933 | 1930 |
| 1934 // Triggering a last-resort GC should cause all pages to be released to the | 1931 // Triggering a last-resort GC should cause all pages to be released |
| 1935 // OS so that other processes can seize the memory. If we get a failure here | 1932 // to the OS so that other processes can seize the memory. |
| 1936 // where there are 2 pages left instead of 1, then we should increase the | |
| 1937 // size of the first page a little in SizeOfFirstPage in spaces.cc. The | |
| 1938 // first page should be small in order to reduce memory used when the VM | |
| 1939 // boots, but if the 20 small arrays don't fit on the first page then that's | |
| 1940 // an indication that it is too small. | |
| 1941 HEAP->CollectAllAvailableGarbage("triggered really hard"); | 1933 HEAP->CollectAllAvailableGarbage("triggered really hard"); |
| 1942 CHECK_EQ(1, old_pointer_space->CountTotalPages()); | 1934 CHECK_EQ(1, old_pointer_space->CountTotalPages()); |
| 1943 } | 1935 } |
| 1944 | 1936 |
| 1945 | 1937 |
| 1946 TEST(Regress2237) { | 1938 TEST(Regress2237) { |
| 1947 InitializeVM(); | 1939 InitializeVM(); |
| 1948 v8::HandleScope scope; | 1940 v8::HandleScope scope; |
| 1949 Handle<String> slice(HEAP->empty_string()); | 1941 Handle<String> slice(HEAP->empty_string()); |
| 1950 | 1942 |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2239 // External source is being retained by the stack trace. | 2231 // External source is being retained by the stack trace. |
| 2240 CHECK(!resource->IsDisposed()); | 2232 CHECK(!resource->IsDisposed()); |
| 2241 | 2233 |
| 2242 CompileRun("error.stack; error.stack;"); | 2234 CompileRun("error.stack; error.stack;"); |
| 2243 HEAP->CollectAllAvailableGarbage(); | 2235 HEAP->CollectAllAvailableGarbage(); |
| 2244 // External source has been released. | 2236 // External source has been released. |
| 2245 CHECK(resource->IsDisposed()); | 2237 CHECK(resource->IsDisposed()); |
| 2246 | 2238 |
| 2247 delete resource; | 2239 delete resource; |
| 2248 } | 2240 } |
| 2249 | |
| 2250 | |
| 2251 TEST(Regression144230) { | |
| 2252 InitializeVM(); | |
| 2253 v8::HandleScope scope; | |
| 2254 | |
| 2255 // First make sure that the uninitialized CallIC stub is on a single page | |
| 2256 // that will later be selected as an evacuation candidate. | |
| 2257 { | |
| 2258 v8::HandleScope inner_scope; | |
| 2259 AlwaysAllocateScope always_allocate; | |
| 2260 SimulateFullSpace(HEAP->code_space()); | |
| 2261 ISOLATE->stub_cache()->ComputeCallInitialize(9, RelocInfo::CODE_TARGET); | |
| 2262 } | |
| 2263 | |
| 2264 // Second compile a CallIC and execute it once so that it gets patched to | |
| 2265 // the pre-monomorphic stub. These code objects are on yet another page. | |
| 2266 { | |
| 2267 v8::HandleScope inner_scope; | |
| 2268 AlwaysAllocateScope always_allocate; | |
| 2269 SimulateFullSpace(HEAP->code_space()); | |
| 2270 CompileRun("var o = { f:function(a,b,c,d,e,f,g,h,i) {}};" | |
| 2271 "function call() { o.f(1,2,3,4,5,6,7,8,9); };" | |
| 2272 "call();"); | |
| 2273 } | |
| 2274 | |
| 2275 // Third we fill up the last page of the code space so that it does not get | |
| 2276 // chosen as an evacuation candidate. | |
| 2277 { | |
| 2278 v8::HandleScope inner_scope; | |
| 2279 AlwaysAllocateScope always_allocate; | |
| 2280 CompileRun("for (var i = 0; i < 2000; i++) {" | |
| 2281 " eval('function f' + i + '() { return ' + i +'; };' +" | |
| 2282 " 'f' + i + '();');" | |
| 2283 "}"); | |
| 2284 } | |
| 2285 HEAP->CollectAllGarbage(Heap::kNoGCFlags); | |
| 2286 | |
| 2287 // Fourth is the tricky part. Make sure the code containing the CallIC is | |
| 2288 // visited first without clearing the IC. The shared function info is then | |
| 2289 // visited later, causing the CallIC to be cleared. | |
| 2290 Handle<String> name = FACTORY->LookupAsciiSymbol("call"); | |
| 2291 Handle<GlobalObject> global(ISOLATE->context()->global_object()); | |
| 2292 MaybeObject* maybe_call = global->GetProperty(*name); | |
| 2293 JSFunction* call = JSFunction::cast(maybe_call->ToObjectChecked()); | |
| 2294 USE(global->SetProperty(*name, Smi::FromInt(0), NONE, kNonStrictMode)); | |
| 2295 ISOLATE->compilation_cache()->Clear(); | |
| 2296 call->shared()->set_ic_age(HEAP->global_ic_age() + 1); | |
| 2297 Handle<Object> call_code(call->code()); | |
| 2298 Handle<Object> call_function(call); | |
| 2299 | |
| 2300 // Now we are ready to mess up the heap. | |
| 2301 HEAP->CollectAllGarbage(Heap::kReduceMemoryFootprintMask); | |
| 2302 | |
| 2303 // Either heap verification caught the problem already or we go kaboom once | |
| 2304 // the CallIC is executed the next time. | |
| 2305 USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode)); | |
| 2306 CompileRun("call();"); | |
| 2307 } | |
| OLD | NEW |