OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 4474 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4485 BailoutId id = BailoutId(i); | 4485 BailoutId id = BailoutId(i); |
4486 SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, lit, id); | 4486 SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, lit, id); |
4487 } | 4487 } |
4488 | 4488 |
4489 // Trigger a GC to flush out the bug. | 4489 // Trigger a GC to flush out the bug. |
4490 heap->CollectGarbage(i::OLD_SPACE, "fire in the hole"); | 4490 heap->CollectGarbage(i::OLD_SPACE, "fire in the hole"); |
4491 boomer->Print(); | 4491 boomer->Print(); |
4492 } | 4492 } |
4493 | 4493 |
4494 | 4494 |
| 4495 TEST(OptimizedCodeMapReuseEntries) { |
| 4496 i::FLAG_flush_optimized_code_cache = false; |
| 4497 i::FLAG_allow_natives_syntax = true; |
| 4498 // BUG(v8:4598): Since TurboFan doesn't treat maps in code weakly, we can't |
| 4499 // run this test. |
| 4500 if (i::FLAG_turbo) return; |
| 4501 CcTest::InitializeVM(); |
| 4502 v8::Isolate* v8_isolate = CcTest::isolate(); |
| 4503 Isolate* isolate = CcTest::i_isolate(); |
| 4504 Heap* heap = isolate->heap(); |
| 4505 HandleScope scope(isolate); |
| 4506 |
| 4507 // Create 3 contexts, allow the 2nd one to be disposed, and verify that |
| 4508 // a 4th context will re-use the weak slots in the optimized code map |
| 4509 // to hold data, rather than expanding the map. |
| 4510 v8::Local<v8::Context> c1 = v8::Context::New(v8_isolate); |
| 4511 const char* source = "function foo(x) { var l = [1]; return x+l[0]; }"; |
| 4512 v8::ScriptCompiler::Source script_source( |
| 4513 v8::String::NewFromUtf8(v8_isolate, source, v8::NewStringType::kNormal) |
| 4514 .ToLocalChecked()); |
| 4515 v8::Local<v8::UnboundScript> indep = |
| 4516 v8::ScriptCompiler::CompileUnboundScript(v8_isolate, &script_source) |
| 4517 .ToLocalChecked(); |
| 4518 const char* toplevel = "foo(3); %OptimizeFunctionOnNextCall(foo); foo(3);"; |
| 4519 // Perfrom one initial GC to enable code flushing. |
| 4520 heap->CollectAllGarbage(); |
| 4521 |
| 4522 c1->Enter(); |
| 4523 indep->BindToCurrentContext()->Run(c1).ToLocalChecked(); |
| 4524 CompileRun(toplevel); |
| 4525 |
| 4526 Handle<SharedFunctionInfo> shared; |
| 4527 Handle<JSFunction> foo = Handle<JSFunction>::cast( |
| 4528 v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast( |
| 4529 CcTest::global()->Get(c1, v8_str("foo")).ToLocalChecked()))); |
| 4530 CHECK(foo->shared()->is_compiled()); |
| 4531 shared = handle(foo->shared()); |
| 4532 c1->Exit(); |
| 4533 |
| 4534 { |
| 4535 HandleScope scope(isolate); |
| 4536 v8::Local<v8::Context> c2 = v8::Context::New(v8_isolate); |
| 4537 c2->Enter(); |
| 4538 indep->BindToCurrentContext()->Run(c2).ToLocalChecked(); |
| 4539 CompileRun(toplevel); |
| 4540 c2->Exit(); |
| 4541 } |
| 4542 |
| 4543 { |
| 4544 HandleScope scope(isolate); |
| 4545 v8::Local<v8::Context> c3 = v8::Context::New(v8_isolate); |
| 4546 c3->Enter(); |
| 4547 indep->BindToCurrentContext()->Run(c3).ToLocalChecked(); |
| 4548 CompileRun(toplevel); |
| 4549 c3->Exit(); |
| 4550 |
| 4551 // Now, collect garbage. Context c2 should have no roots to it, and it's |
| 4552 // entry in the optimized code map should be free for a new context. |
| 4553 for (int i = 0; i < 4; i++) { |
| 4554 heap->CollectAllGarbage(); |
| 4555 } |
| 4556 |
| 4557 Handle<FixedArray> optimized_code_map = |
| 4558 handle(shared->optimized_code_map()); |
| 4559 // There should be 3 entries in the map. |
| 4560 CHECK_EQ( |
| 4561 3, ((optimized_code_map->length() - SharedFunctionInfo::kEntriesStart) / |
| 4562 SharedFunctionInfo::kEntryLength)); |
| 4563 // But one of them (formerly for c2) should be cleared. |
| 4564 int cleared_count = 0; |
| 4565 for (int i = SharedFunctionInfo::kEntriesStart; |
| 4566 i < optimized_code_map->length(); |
| 4567 i += SharedFunctionInfo::kEntryLength) { |
| 4568 cleared_count += |
| 4569 WeakCell::cast( |
| 4570 optimized_code_map->get(i + SharedFunctionInfo::kContextOffset)) |
| 4571 ->cleared() |
| 4572 ? 1 |
| 4573 : 0; |
| 4574 } |
| 4575 CHECK_EQ(1, cleared_count); |
| 4576 |
| 4577 // Verify that a new context uses the cleared entry rather than creating a |
| 4578 // new |
| 4579 // optimized code map array. |
| 4580 v8::Local<v8::Context> c4 = v8::Context::New(v8_isolate); |
| 4581 c4->Enter(); |
| 4582 indep->BindToCurrentContext()->Run(c4).ToLocalChecked(); |
| 4583 CompileRun(toplevel); |
| 4584 c4->Exit(); |
| 4585 CHECK_EQ(*optimized_code_map, shared->optimized_code_map()); |
| 4586 |
| 4587 // Now each entry is in use. |
| 4588 cleared_count = 0; |
| 4589 for (int i = SharedFunctionInfo::kEntriesStart; |
| 4590 i < optimized_code_map->length(); |
| 4591 i += SharedFunctionInfo::kEntryLength) { |
| 4592 cleared_count += |
| 4593 WeakCell::cast( |
| 4594 optimized_code_map->get(i + SharedFunctionInfo::kContextOffset)) |
| 4595 ->cleared() |
| 4596 ? 1 |
| 4597 : 0; |
| 4598 } |
| 4599 CHECK_EQ(0, cleared_count); |
| 4600 } |
| 4601 } |
| 4602 |
| 4603 |
4495 TEST(Regress513496) { | 4604 TEST(Regress513496) { |
4496 i::FLAG_flush_optimized_code_cache = false; | 4605 i::FLAG_flush_optimized_code_cache = false; |
4497 i::FLAG_allow_natives_syntax = true; | 4606 i::FLAG_allow_natives_syntax = true; |
4498 CcTest::InitializeVM(); | 4607 CcTest::InitializeVM(); |
4499 Isolate* isolate = CcTest::i_isolate(); | 4608 Isolate* isolate = CcTest::i_isolate(); |
4500 Heap* heap = isolate->heap(); | 4609 Heap* heap = isolate->heap(); |
4501 HandleScope scope(isolate); | 4610 HandleScope scope(isolate); |
4502 | 4611 |
4503 // Perfrom one initial GC to enable code flushing. | 4612 // Perfrom one initial GC to enable code flushing. |
4504 CcTest::heap()->CollectAllGarbage(); | 4613 CcTest::heap()->CollectAllGarbage(); |
(...skipping 1936 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6441 isolate->IncrementJsCallsFromApiCounter(); | 6550 isolate->IncrementJsCallsFromApiCounter(); |
6442 isolate->IncrementJsCallsFromApiCounter(); | 6551 isolate->IncrementJsCallsFromApiCounter(); |
6443 isolate->IncrementJsCallsFromApiCounter(); | 6552 isolate->IncrementJsCallsFromApiCounter(); |
6444 calls_per_ms = memory_reducer->SampleAndGetJsCallsPerMs(4); | 6553 calls_per_ms = memory_reducer->SampleAndGetJsCallsPerMs(4); |
6445 CheckDoubleEquals(2, calls_per_ms); | 6554 CheckDoubleEquals(2, calls_per_ms); |
6446 } | 6555 } |
6447 | 6556 |
6448 | 6557 |
6449 } // namespace internal | 6558 } // namespace internal |
6450 } // namespace v8 | 6559 } // namespace v8 |
OLD | NEW |