Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(110)

Side by Side Diff: test/cctest/heap/test-heap.cc

Issue 2674593003: [TypeFeedbackVector] Root feedback vectors at function literal site. (Closed)
Patch Set: REBASE. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 1659 matching lines...) Expand 10 before | Expand all | Expand 10 after
1670 "foo();"; 1670 "foo();";
1671 Handle<String> source = factory->InternalizeUtf8String(raw_source); 1671 Handle<String> source = factory->InternalizeUtf8String(raw_source);
1672 Handle<Context> native_context = isolate->native_context(); 1672 Handle<Context> native_context = isolate->native_context();
1673 1673
1674 { 1674 {
1675 v8::HandleScope scope(CcTest::isolate()); 1675 v8::HandleScope scope(CcTest::isolate());
1676 CompileRun(raw_source); 1676 CompileRun(raw_source);
1677 } 1677 }
1678 1678
1679 // The script should be in the cache now. 1679 // The script should be in the cache now.
1680 MaybeHandle<SharedFunctionInfo> info = compilation_cache->LookupScript( 1680 InfoVectorPair pair = compilation_cache->LookupScript(
1681 source, Handle<Object>(), 0, 0, v8::ScriptOriginOptions(true, false), 1681 source, Handle<Object>(), 0, 0, v8::ScriptOriginOptions(true, false),
1682 native_context, language_mode); 1682 native_context, language_mode);
1683 CHECK(!info.is_null()); 1683 CHECK(pair.has_info());
1684 1684
1685 // Check that the code cache entry survives at least on GC. 1685 // Check that the code cache entry survives at least on GC.
1686 // (Unless --optimize-for-size, in which case it might get collected 1686 // (Unless --optimize-for-size, in which case it might get collected
1687 // immediately.) 1687 // immediately.)
1688 if (!FLAG_optimize_for_size) { 1688 if (!FLAG_optimize_for_size) {
1689 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); 1689 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
1690 info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, 1690 pair = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0,
1691 v8::ScriptOriginOptions(true, false), 1691 v8::ScriptOriginOptions(true, false),
1692 native_context, language_mode); 1692 native_context, language_mode);
1693 CHECK(!info.is_null()); 1693 CHECK(pair.has_info());
1694 } 1694 }
1695 1695
1696 // Progress code age until it's old and ready for GC. 1696 // Progress code age until it's old and ready for GC.
1697 const int kAgingThreshold = 6; 1697 const int kAgingThreshold = 6;
1698 for (int i = 0; i < kAgingThreshold; i++) { 1698 for (int i = 0; i < kAgingThreshold; i++) {
1699 info.ToHandleChecked()->code()->MakeOlder(); 1699 pair.info()->code()->MakeOlder();
1700 if (info.ToHandleChecked()->HasBytecodeArray()) { 1700 if (pair.info()->HasBytecodeArray()) {
1701 info.ToHandleChecked()->bytecode_array()->MakeOlder(); 1701 pair.info()->bytecode_array()->MakeOlder();
1702 } 1702 }
1703 } 1703 }
1704 1704
1705 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); 1705 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
1706 // Ensure code aging cleared the entry from the cache. 1706 // Ensure code aging cleared the entry from the cache.
1707 info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, 1707 pair = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0,
1708 v8::ScriptOriginOptions(true, false), 1708 v8::ScriptOriginOptions(true, false),
1709 native_context, language_mode); 1709 native_context, language_mode);
1710 CHECK(info.is_null()); 1710 CHECK(!pair.has_info());
1711 } 1711 }
1712 1712
1713 1713
1714 static void OptimizeEmptyFunction(const char* name) { 1714 static void OptimizeEmptyFunction(const char* name) {
1715 HandleScope scope(CcTest::i_isolate()); 1715 HandleScope scope(CcTest::i_isolate());
1716 EmbeddedVector<char, 256> source; 1716 EmbeddedVector<char, 256> source;
1717 SNPrintF(source, 1717 SNPrintF(source,
1718 "function %s() { return 0; }" 1718 "function %s() { return 0; }"
1719 "%s(); %s();" 1719 "%s(); %s();"
1720 "%%OptimizeFunctionOnNextCall(%s);" 1720 "%%OptimizeFunctionOnNextCall(%s);"
(...skipping 2604 matching lines...) Expand 10 before | Expand all | Expand 10 after
4325 CompileRun("function g() { return 2 }" 4325 CompileRun("function g() { return 2 }"
4326 "g(); %OptimizeFunctionOnNextCall(g); g();"); 4326 "g(); %OptimizeFunctionOnNextCall(g); g();");
4327 4327
4328 Handle<JSFunction> g = Handle<JSFunction>::cast( 4328 Handle<JSFunction> g = Handle<JSFunction>::cast(
4329 v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast( 4329 v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
4330 CcTest::global()->Get(env.local(), v8_str("g")).ToLocalChecked()))); 4330 CcTest::global()->Get(env.local(), v8_str("g")).ToLocalChecked())));
4331 code = inner_scope.CloseAndEscape(handle(g->code(), isolate)); 4331 code = inner_scope.CloseAndEscape(handle(g->code(), isolate));
4332 if (!code->is_optimized_code()) return; 4332 if (!code->is_optimized_code()) return;
4333 } 4333 }
4334 4334
4335 Handle<TypeFeedbackVector> vector =
4336 TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata()));
4337 Handle<Context> context(isolate->context()); 4335 Handle<Context> context(isolate->context());
4338 4336
4339 // Add the new code several times to the optimized code map and also set an 4337 // Add the new code several times to the optimized code map and also set an
4340 // allocation timeout so that expanding the code map will trigger a GC. 4338 // allocation timeout so that expanding the code map will trigger a GC.
4341 heap->set_allocation_timeout(5); 4339 heap->set_allocation_timeout(5);
4342 FLAG_gc_interval = 1000; 4340 FLAG_gc_interval = 1000;
4343 for (int i = 0; i < 10; ++i) { 4341 for (int i = 0; i < 10; ++i) {
4344 BailoutId id = BailoutId(i); 4342 BailoutId id = BailoutId(i);
4345 SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, vector, 4343 SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, id);
4346 id);
4347 } 4344 }
4348 } 4345 }
4349 #endif // DEBUG 4346 #endif // DEBUG
4350 4347
4351 TEST(Regress514122) {
4352 if (!i::FLAG_incremental_marking) return;
4353 i::FLAG_allow_natives_syntax = true;
4354 CcTest::InitializeVM();
4355 Isolate* isolate = CcTest::i_isolate();
4356 LocalContext env;
4357 Heap* heap = isolate->heap();
4358 HandleScope scope(isolate);
4359
4360 // Perfrom one initial GC to enable code flushing.
4361 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
4362
4363 // Prepare function whose optimized code map we can use.
4364 Handle<SharedFunctionInfo> shared;
4365 {
4366 HandleScope inner_scope(isolate);
4367 CompileRun(
4368 "function f() { return 1 }"
4369 "f(); %OptimizeFunctionOnNextCall(f); f();");
4370
4371 Handle<JSFunction> f = Handle<JSFunction>::cast(
4372 v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
4373 CcTest::global()->Get(env.local(), v8_str("f")).ToLocalChecked())));
4374 shared = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
4375 CompileRun("f = null");
4376 }
4377
4378 // Prepare optimized code that we can use.
4379 Handle<Code> code;
4380 {
4381 HandleScope inner_scope(isolate);
4382 CompileRun(
4383 "function g() { return 2 }"
4384 "g(); %OptimizeFunctionOnNextCall(g); g();");
4385
4386 Handle<JSFunction> g = Handle<JSFunction>::cast(
4387 v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
4388 CcTest::global()->Get(env.local(), v8_str("g")).ToLocalChecked())));
4389 code = inner_scope.CloseAndEscape(handle(g->code(), isolate));
4390 if (!code->is_optimized_code()) return;
4391 }
4392
4393 Handle<TypeFeedbackVector> vector =
4394 TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata()));
4395 Handle<Context> context(isolate->context());
4396
4397 // Add the code several times to the optimized code map.
4398 for (int i = 0; i < 3; ++i) {
4399 HandleScope inner_scope(isolate);
4400 BailoutId id = BailoutId(i);
4401 SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, vector,
4402 id);
4403 }
4404 shared->optimized_code_map()->Print();
4405
4406 // Add the code with a feedback vector to be evacuated.
4407 Page* evac_page;
4408 {
4409 HandleScope inner_scope(isolate);
4410 AlwaysAllocateScope always_allocate(isolate);
4411 // Make sure literal is placed on an old-space evacuation candidate.
4412 heap::SimulateFullSpace(heap->old_space());
4413
4414 // Make sure there the number of literals is > 0.
4415 Handle<TypeFeedbackVector> vector =
4416 TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata()));
4417 evac_page = Page::FromAddress(vector->address());
4418 BailoutId id = BailoutId(100);
4419 SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, vector,
4420 id);
4421 }
4422
4423 // Heap is ready, force {lit_page} to become an evacuation candidate and
4424 // simulate incremental marking to enqueue optimized code map.
4425 FLAG_manual_evacuation_candidates_selection = true;
4426 heap::ForceEvacuationCandidate(evac_page);
4427 heap::SimulateIncrementalMarking(heap);
4428
4429 // No matter whether reachable or not, {boomer} is doomed.
4430 Handle<Object> boomer(shared->optimized_code_map(), isolate);
4431
4432 // Add the code several times to the optimized code map. This will leave old
4433 // copies of the optimized code map unreachable but still marked.
4434 for (int i = 3; i < 6; ++i) {
4435 HandleScope inner_scope(isolate);
4436 BailoutId id = BailoutId(i);
4437 SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, vector,
4438 id);
4439 }
4440
4441 // Trigger a GC to flush out the bug.
4442 CcTest::CollectGarbage(i::OLD_SPACE);
4443 boomer->Print();
4444 }
4445
4446 TEST(OptimizedCodeMapReuseEntries) {
4447 i::FLAG_allow_natives_syntax = true;
4448 // BUG(v8:4598): Since TurboFan doesn't treat maps in code weakly, we can't
4449 // run this test.
4450 if (i::FLAG_turbo) return;
4451 CcTest::InitializeVM();
4452 v8::Isolate* v8_isolate = CcTest::isolate();
4453 Isolate* isolate = CcTest::i_isolate();
4454 HandleScope scope(isolate);
4455
4456 // Create 3 contexts, allow the 2nd one to be disposed, and verify that
4457 // a 4th context will re-use the weak slots in the optimized code map
4458 // to hold data, rather than expanding the map.
4459 v8::Local<v8::Context> c1 = v8::Context::New(v8_isolate);
4460 const char* source = "function foo(x) { var l = [1]; return x+l[0]; }";
4461 v8::ScriptCompiler::Source script_source(
4462 v8::String::NewFromUtf8(v8_isolate, source, v8::NewStringType::kNormal)
4463 .ToLocalChecked());
4464 v8::Local<v8::UnboundScript> indep =
4465 v8::ScriptCompiler::CompileUnboundScript(v8_isolate, &script_source)
4466 .ToLocalChecked();
4467 const char* toplevel = "foo(3); %OptimizeFunctionOnNextCall(foo); foo(3);";
4468 // Perfrom one initial GC to enable code flushing.
4469 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
4470
4471 c1->Enter();
4472 indep->BindToCurrentContext()->Run(c1).ToLocalChecked();
4473 CompileRun(toplevel);
4474
4475 Handle<SharedFunctionInfo> shared;
4476 Handle<JSFunction> foo = Handle<JSFunction>::cast(
4477 v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast(
4478 CcTest::global()->Get(c1, v8_str("foo")).ToLocalChecked())));
4479 CHECK(foo->shared()->is_compiled());
4480 shared = handle(foo->shared());
4481 c1->Exit();
4482
4483 {
4484 HandleScope scope(isolate);
4485 v8::Local<v8::Context> c2 = v8::Context::New(v8_isolate);
4486 c2->Enter();
4487 indep->BindToCurrentContext()->Run(c2).ToLocalChecked();
4488 CompileRun(toplevel);
4489 c2->Exit();
4490 }
4491
4492 {
4493 HandleScope scope(isolate);
4494 v8::Local<v8::Context> c3 = v8::Context::New(v8_isolate);
4495 c3->Enter();
4496 indep->BindToCurrentContext()->Run(c3).ToLocalChecked();
4497 CompileRun(toplevel);
4498 c3->Exit();
4499
4500 // Now, collect garbage. Context c2 should have no roots to it, and it's
4501 // entry in the optimized code map should be free for a new context.
4502 for (int i = 0; i < 4; i++) {
4503 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
4504 }
4505
4506 Handle<FixedArray> optimized_code_map =
4507 handle(shared->optimized_code_map());
4508 // There should be 3 entries in the map.
4509 CHECK_EQ(
4510 3, ((optimized_code_map->length() - SharedFunctionInfo::kEntriesStart) /
4511 SharedFunctionInfo::kEntryLength));
4512 // But one of them (formerly for c2) should be cleared.
4513 int cleared_count = 0;
4514 for (int i = SharedFunctionInfo::kEntriesStart;
4515 i < optimized_code_map->length();
4516 i += SharedFunctionInfo::kEntryLength) {
4517 cleared_count +=
4518 WeakCell::cast(
4519 optimized_code_map->get(i + SharedFunctionInfo::kContextOffset))
4520 ->cleared()
4521 ? 1
4522 : 0;
4523 }
4524 CHECK_EQ(1, cleared_count);
4525
4526 // Verify that a new context uses the cleared entry rather than creating a
4527 // new
4528 // optimized code map array.
4529 v8::Local<v8::Context> c4 = v8::Context::New(v8_isolate);
4530 c4->Enter();
4531 indep->BindToCurrentContext()->Run(c4).ToLocalChecked();
4532 CompileRun(toplevel);
4533 c4->Exit();
4534 CHECK_EQ(*optimized_code_map, shared->optimized_code_map());
4535
4536 // Now each entry is in use.
4537 cleared_count = 0;
4538 for (int i = SharedFunctionInfo::kEntriesStart;
4539 i < optimized_code_map->length();
4540 i += SharedFunctionInfo::kEntryLength) {
4541 cleared_count +=
4542 WeakCell::cast(
4543 optimized_code_map->get(i + SharedFunctionInfo::kContextOffset))
4544 ->cleared()
4545 ? 1
4546 : 0;
4547 }
4548 CHECK_EQ(0, cleared_count);
4549 }
4550 }
4551
4552 TEST(Regress513496) { 4348 TEST(Regress513496) {
4553 i::FLAG_allow_natives_syntax = true; 4349 i::FLAG_allow_natives_syntax = true;
4554 CcTest::InitializeVM(); 4350 CcTest::InitializeVM();
4555 Isolate* isolate = CcTest::i_isolate(); 4351 Isolate* isolate = CcTest::i_isolate();
4556 HandleScope scope(isolate); 4352 HandleScope scope(isolate);
4557 4353
4558 // Perfrom one initial GC to enable code flushing. 4354 // Perfrom one initial GC to enable code flushing.
4559 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); 4355 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
4560 4356
4561 // Prepare an optimized closure with containing an inlined function. Then age 4357 // Prepare an optimized closure with containing an inlined function. Then age
(...skipping 25 matching lines...) Expand all
4587 Handle<JSFunction> f = Handle<JSFunction>::cast(v8::Utils::OpenHandle( 4383 Handle<JSFunction> f = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
4588 *v8::Local<v8::Function>::Cast(CcTest::global() 4384 *v8::Local<v8::Function>::Cast(CcTest::global()
4589 ->Get(context.local(), v8_str("f")) 4385 ->Get(context.local(), v8_str("f"))
4590 .ToLocalChecked()))); 4386 .ToLocalChecked())));
4591 CHECK(f->is_compiled()); 4387 CHECK(f->is_compiled());
4592 shared = inner_scope.CloseAndEscape(handle(f->shared(), isolate)); 4388 shared = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
4593 CompileRun("f = null"); 4389 CompileRun("f = null");
4594 } 4390 }
4595 4391
4596 // Lookup the optimized code and keep it alive. 4392 // Lookup the optimized code and keep it alive.
4597 CodeAndVector result = shared->SearchOptimizedCodeMap( 4393 Code* result = shared->SearchOptimizedCodeMap(
4598 isolate->context()->native_context(), BailoutId::None()); 4394 isolate->context()->native_context(), BailoutId::None());
4599 Handle<Code> optimized_code(result.code, isolate); 4395 Handle<Code> optimized_code(result, isolate);
4600 4396
4601 // Finish a full GC cycle so that the unoptimized code of 'g' is flushed even 4397 // Finish a full GC cycle so that the unoptimized code of 'g' is flushed even
4602 // though the optimized code for 'f' is reachable via the optimized code map. 4398 // though the optimized code for 'f' is reachable via the optimized code map.
4603 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); 4399 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask);
4604 4400
4605 // Make a new closure that will get code installed from the code map. 4401 // Make a new closure that will get code installed from the code map.
4606 // Unoptimized code is missing and the deoptimizer will go ballistic. 4402 // Unoptimized code is missing and the deoptimizer will go ballistic.
4607 CompileRun("var h = mkClosure(); h('bozo');"); 4403 CompileRun("var h = mkClosure(); h('bozo');");
4608 } 4404 }
4609 4405
(...skipping 2515 matching lines...) Expand 10 before | Expand all | Expand 10 after
7125 CHECK(!heap->code_space()->FirstPage()->Contains(code->address())); 6921 CHECK(!heap->code_space()->FirstPage()->Contains(code->address()));
7126 6922
7127 // Ensure it's not in large object space. 6923 // Ensure it's not in large object space.
7128 MemoryChunk* chunk = MemoryChunk::FromAddress(code->address()); 6924 MemoryChunk* chunk = MemoryChunk::FromAddress(code->address());
7129 CHECK(chunk->owner()->identity() != LO_SPACE); 6925 CHECK(chunk->owner()->identity() != LO_SPACE);
7130 CHECK(chunk->NeverEvacuate()); 6926 CHECK(chunk->NeverEvacuate());
7131 } 6927 }
7132 6928
7133 } // namespace internal 6929 } // namespace internal
7134 } // namespace v8 6930 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698