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 4278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4289 CompileRun("function g() { return 2 }" | 4289 CompileRun("function g() { return 2 }" |
4290 "g(); %OptimizeFunctionOnNextCall(g); g();"); | 4290 "g(); %OptimizeFunctionOnNextCall(g); g();"); |
4291 | 4291 |
4292 Handle<JSFunction> g = Handle<JSFunction>::cast( | 4292 Handle<JSFunction> g = Handle<JSFunction>::cast( |
4293 v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast( | 4293 v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast( |
4294 CcTest::global()->Get(env.local(), v8_str("g")).ToLocalChecked()))); | 4294 CcTest::global()->Get(env.local(), v8_str("g")).ToLocalChecked()))); |
4295 code = inner_scope.CloseAndEscape(handle(g->code(), isolate)); | 4295 code = inner_scope.CloseAndEscape(handle(g->code(), isolate)); |
4296 if (!code->is_optimized_code()) return; | 4296 if (!code->is_optimized_code()) return; |
4297 } | 4297 } |
4298 | 4298 |
| 4299 Handle<TypeFeedbackVector> vector = |
| 4300 TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata())); |
| 4301 Handle<LiteralsArray> lit = |
| 4302 LiteralsArray::New(isolate, vector, shared->num_literals()); |
4299 Handle<Context> context(isolate->context()); | 4303 Handle<Context> context(isolate->context()); |
4300 | 4304 |
4301 // Add the new code several times to the optimized code map and also set an | 4305 // Add the new code several times to the optimized code map and also set an |
4302 // allocation timeout so that expanding the code map will trigger a GC. | 4306 // allocation timeout so that expanding the code map will trigger a GC. |
4303 heap->set_allocation_timeout(5); | 4307 heap->set_allocation_timeout(5); |
4304 FLAG_gc_interval = 1000; | 4308 FLAG_gc_interval = 1000; |
4305 for (int i = 0; i < 10; ++i) { | 4309 for (int i = 0; i < 10; ++i) { |
4306 BailoutId id = BailoutId(i); | 4310 BailoutId id = BailoutId(i); |
4307 SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, id); | 4311 SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, lit, id); |
4308 } | 4312 } |
4309 } | 4313 } |
4310 #endif // DEBUG | 4314 #endif // DEBUG |
4311 | 4315 |
| 4316 |
| 4317 TEST(Regress514122) { |
| 4318 if (!i::FLAG_incremental_marking) return; |
| 4319 i::FLAG_allow_natives_syntax = true; |
| 4320 CcTest::InitializeVM(); |
| 4321 Isolate* isolate = CcTest::i_isolate(); |
| 4322 LocalContext env; |
| 4323 Heap* heap = isolate->heap(); |
| 4324 HandleScope scope(isolate); |
| 4325 |
| 4326 // Perfrom one initial GC to enable code flushing. |
| 4327 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); |
| 4328 |
| 4329 // Prepare function whose optimized code map we can use. |
| 4330 Handle<SharedFunctionInfo> shared; |
| 4331 { |
| 4332 HandleScope inner_scope(isolate); |
| 4333 CompileRun("function f() { return 1 }" |
| 4334 "f(); %OptimizeFunctionOnNextCall(f); f();"); |
| 4335 |
| 4336 Handle<JSFunction> f = Handle<JSFunction>::cast( |
| 4337 v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast( |
| 4338 CcTest::global()->Get(env.local(), v8_str("f")).ToLocalChecked()))); |
| 4339 shared = inner_scope.CloseAndEscape(handle(f->shared(), isolate)); |
| 4340 CompileRun("f = null"); |
| 4341 } |
| 4342 |
| 4343 // Prepare optimized code that we can use. |
| 4344 Handle<Code> code; |
| 4345 { |
| 4346 HandleScope inner_scope(isolate); |
| 4347 CompileRun("function g() { return 2 }" |
| 4348 "g(); %OptimizeFunctionOnNextCall(g); g();"); |
| 4349 |
| 4350 Handle<JSFunction> g = Handle<JSFunction>::cast( |
| 4351 v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast( |
| 4352 CcTest::global()->Get(env.local(), v8_str("g")).ToLocalChecked()))); |
| 4353 code = inner_scope.CloseAndEscape(handle(g->code(), isolate)); |
| 4354 if (!code->is_optimized_code()) return; |
| 4355 } |
| 4356 |
| 4357 Handle<TypeFeedbackVector> vector = |
| 4358 TypeFeedbackVector::New(isolate, handle(shared->feedback_metadata())); |
| 4359 Handle<LiteralsArray> lit = |
| 4360 LiteralsArray::New(isolate, vector, shared->num_literals(), TENURED); |
| 4361 Handle<Context> context(isolate->context()); |
| 4362 |
| 4363 // Add the code several times to the optimized code map. |
| 4364 for (int i = 0; i < 3; ++i) { |
| 4365 HandleScope inner_scope(isolate); |
| 4366 BailoutId id = BailoutId(i); |
| 4367 SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, lit, id); |
| 4368 } |
| 4369 shared->optimized_code_map()->Print(); |
| 4370 |
| 4371 // Add the code with a literals array to be evacuated. |
| 4372 Page* evac_page; |
| 4373 { |
| 4374 HandleScope inner_scope(isolate); |
| 4375 AlwaysAllocateScope always_allocate(isolate); |
| 4376 // Make sure literal is placed on an old-space evacuation candidate. |
| 4377 heap::SimulateFullSpace(heap->old_space()); |
| 4378 |
| 4379 // Make sure there the number of literals is > 0. |
| 4380 Handle<LiteralsArray> lit = LiteralsArray::New(isolate, vector, 23); |
| 4381 |
| 4382 evac_page = Page::FromAddress(lit->address()); |
| 4383 BailoutId id = BailoutId(100); |
| 4384 SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, lit, id); |
| 4385 } |
| 4386 |
| 4387 // Heap is ready, force {lit_page} to become an evacuation candidate and |
| 4388 // simulate incremental marking to enqueue optimized code map. |
| 4389 FLAG_manual_evacuation_candidates_selection = true; |
| 4390 heap::ForceEvacuationCandidate(evac_page); |
| 4391 heap::SimulateIncrementalMarking(heap); |
| 4392 |
| 4393 // No matter whether reachable or not, {boomer} is doomed. |
| 4394 Handle<Object> boomer(shared->optimized_code_map(), isolate); |
| 4395 |
| 4396 // Add the code several times to the optimized code map. This will leave old |
| 4397 // copies of the optimized code map unreachable but still marked. |
| 4398 for (int i = 3; i < 6; ++i) { |
| 4399 HandleScope inner_scope(isolate); |
| 4400 BailoutId id = BailoutId(i); |
| 4401 SharedFunctionInfo::AddToOptimizedCodeMap(shared, context, code, lit, id); |
| 4402 } |
| 4403 |
| 4404 // Trigger a GC to flush out the bug. |
| 4405 CcTest::CollectGarbage(i::OLD_SPACE); |
| 4406 boomer->Print(); |
| 4407 } |
| 4408 |
| 4409 |
| 4410 TEST(OptimizedCodeMapReuseEntries) { |
| 4411 i::FLAG_allow_natives_syntax = true; |
| 4412 // BUG(v8:4598): Since TurboFan doesn't treat maps in code weakly, we can't |
| 4413 // run this test. |
| 4414 if (i::FLAG_turbo) return; |
| 4415 CcTest::InitializeVM(); |
| 4416 v8::Isolate* v8_isolate = CcTest::isolate(); |
| 4417 Isolate* isolate = CcTest::i_isolate(); |
| 4418 HandleScope scope(isolate); |
| 4419 |
| 4420 // Create 3 contexts, allow the 2nd one to be disposed, and verify that |
| 4421 // a 4th context will re-use the weak slots in the optimized code map |
| 4422 // to hold data, rather than expanding the map. |
| 4423 v8::Local<v8::Context> c1 = v8::Context::New(v8_isolate); |
| 4424 const char* source = "function foo(x) { var l = [1]; return x+l[0]; }"; |
| 4425 v8::ScriptCompiler::Source script_source( |
| 4426 v8::String::NewFromUtf8(v8_isolate, source, v8::NewStringType::kNormal) |
| 4427 .ToLocalChecked()); |
| 4428 v8::Local<v8::UnboundScript> indep = |
| 4429 v8::ScriptCompiler::CompileUnboundScript(v8_isolate, &script_source) |
| 4430 .ToLocalChecked(); |
| 4431 const char* toplevel = "foo(3); %OptimizeFunctionOnNextCall(foo); foo(3);"; |
| 4432 // Perfrom one initial GC to enable code flushing. |
| 4433 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); |
| 4434 |
| 4435 c1->Enter(); |
| 4436 indep->BindToCurrentContext()->Run(c1).ToLocalChecked(); |
| 4437 CompileRun(toplevel); |
| 4438 |
| 4439 Handle<SharedFunctionInfo> shared; |
| 4440 Handle<JSFunction> foo = Handle<JSFunction>::cast( |
| 4441 v8::Utils::OpenHandle(*v8::Local<v8::Function>::Cast( |
| 4442 CcTest::global()->Get(c1, v8_str("foo")).ToLocalChecked()))); |
| 4443 CHECK(foo->shared()->is_compiled()); |
| 4444 shared = handle(foo->shared()); |
| 4445 c1->Exit(); |
| 4446 |
| 4447 { |
| 4448 HandleScope scope(isolate); |
| 4449 v8::Local<v8::Context> c2 = v8::Context::New(v8_isolate); |
| 4450 c2->Enter(); |
| 4451 indep->BindToCurrentContext()->Run(c2).ToLocalChecked(); |
| 4452 CompileRun(toplevel); |
| 4453 c2->Exit(); |
| 4454 } |
| 4455 |
| 4456 { |
| 4457 HandleScope scope(isolate); |
| 4458 v8::Local<v8::Context> c3 = v8::Context::New(v8_isolate); |
| 4459 c3->Enter(); |
| 4460 indep->BindToCurrentContext()->Run(c3).ToLocalChecked(); |
| 4461 CompileRun(toplevel); |
| 4462 c3->Exit(); |
| 4463 |
| 4464 // Now, collect garbage. Context c2 should have no roots to it, and it's |
| 4465 // entry in the optimized code map should be free for a new context. |
| 4466 for (int i = 0; i < 4; i++) { |
| 4467 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); |
| 4468 } |
| 4469 |
| 4470 Handle<FixedArray> optimized_code_map = |
| 4471 handle(shared->optimized_code_map()); |
| 4472 // There should be 3 entries in the map. |
| 4473 CHECK_EQ( |
| 4474 3, ((optimized_code_map->length() - SharedFunctionInfo::kEntriesStart) / |
| 4475 SharedFunctionInfo::kEntryLength)); |
| 4476 // But one of them (formerly for c2) should be cleared. |
| 4477 int cleared_count = 0; |
| 4478 for (int i = SharedFunctionInfo::kEntriesStart; |
| 4479 i < optimized_code_map->length(); |
| 4480 i += SharedFunctionInfo::kEntryLength) { |
| 4481 cleared_count += |
| 4482 WeakCell::cast( |
| 4483 optimized_code_map->get(i + SharedFunctionInfo::kContextOffset)) |
| 4484 ->cleared() |
| 4485 ? 1 |
| 4486 : 0; |
| 4487 } |
| 4488 CHECK_EQ(1, cleared_count); |
| 4489 |
| 4490 // Verify that a new context uses the cleared entry rather than creating a |
| 4491 // new |
| 4492 // optimized code map array. |
| 4493 v8::Local<v8::Context> c4 = v8::Context::New(v8_isolate); |
| 4494 c4->Enter(); |
| 4495 indep->BindToCurrentContext()->Run(c4).ToLocalChecked(); |
| 4496 CompileRun(toplevel); |
| 4497 c4->Exit(); |
| 4498 CHECK_EQ(*optimized_code_map, shared->optimized_code_map()); |
| 4499 |
| 4500 // Now each entry is in use. |
| 4501 cleared_count = 0; |
| 4502 for (int i = SharedFunctionInfo::kEntriesStart; |
| 4503 i < optimized_code_map->length(); |
| 4504 i += SharedFunctionInfo::kEntryLength) { |
| 4505 cleared_count += |
| 4506 WeakCell::cast( |
| 4507 optimized_code_map->get(i + SharedFunctionInfo::kContextOffset)) |
| 4508 ->cleared() |
| 4509 ? 1 |
| 4510 : 0; |
| 4511 } |
| 4512 CHECK_EQ(0, cleared_count); |
| 4513 } |
| 4514 } |
| 4515 |
| 4516 |
4312 TEST(Regress513496) { | 4517 TEST(Regress513496) { |
4313 i::FLAG_allow_natives_syntax = true; | 4518 i::FLAG_allow_natives_syntax = true; |
4314 CcTest::InitializeVM(); | 4519 CcTest::InitializeVM(); |
4315 Isolate* isolate = CcTest::i_isolate(); | 4520 Isolate* isolate = CcTest::i_isolate(); |
4316 HandleScope scope(isolate); | 4521 HandleScope scope(isolate); |
4317 | 4522 |
4318 // Perfrom one initial GC to enable code flushing. | 4523 // Perfrom one initial GC to enable code flushing. |
4319 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); | 4524 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); |
4320 | 4525 |
4321 // Prepare an optimized closure with containing an inlined function. Then age | 4526 // Prepare an optimized closure with containing an inlined function. Then age |
(...skipping 25 matching lines...) Expand all Loading... |
4347 Handle<JSFunction> f = Handle<JSFunction>::cast(v8::Utils::OpenHandle( | 4552 Handle<JSFunction> f = Handle<JSFunction>::cast(v8::Utils::OpenHandle( |
4348 *v8::Local<v8::Function>::Cast(CcTest::global() | 4553 *v8::Local<v8::Function>::Cast(CcTest::global() |
4349 ->Get(context.local(), v8_str("f")) | 4554 ->Get(context.local(), v8_str("f")) |
4350 .ToLocalChecked()))); | 4555 .ToLocalChecked()))); |
4351 CHECK(f->is_compiled()); | 4556 CHECK(f->is_compiled()); |
4352 shared = inner_scope.CloseAndEscape(handle(f->shared(), isolate)); | 4557 shared = inner_scope.CloseAndEscape(handle(f->shared(), isolate)); |
4353 CompileRun("f = null"); | 4558 CompileRun("f = null"); |
4354 } | 4559 } |
4355 | 4560 |
4356 // Lookup the optimized code and keep it alive. | 4561 // Lookup the optimized code and keep it alive. |
4357 Code* result = shared->SearchOptimizedCodeMap( | 4562 CodeAndLiterals result = shared->SearchOptimizedCodeMap( |
4358 isolate->context()->native_context(), BailoutId::None()); | 4563 isolate->context()->native_context(), BailoutId::None()); |
4359 Handle<Code> optimized_code(result, isolate); | 4564 Handle<Code> optimized_code(result.code, isolate); |
4360 | 4565 |
4361 // Finish a full GC cycle so that the unoptimized code of 'g' is flushed even | 4566 // Finish a full GC cycle so that the unoptimized code of 'g' is flushed even |
4362 // though the optimized code for 'f' is reachable via the optimized code map. | 4567 // though the optimized code for 'f' is reachable via the optimized code map. |
4363 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); | 4568 CcTest::CollectAllGarbage(i::Heap::kFinalizeIncrementalMarkingMask); |
4364 | 4569 |
4365 // Make a new closure that will get code installed from the code map. | 4570 // Make a new closure that will get code installed from the code map. |
4366 // Unoptimized code is missing and the deoptimizer will go ballistic. | 4571 // Unoptimized code is missing and the deoptimizer will go ballistic. |
4367 CompileRun("var h = mkClosure(); h('bozo');"); | 4572 CompileRun("var h = mkClosure(); h('bozo');"); |
4368 } | 4573 } |
4369 | 4574 |
(...skipping 2500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6870 double deadline = heap->MonotonicallyIncreasingTimeInMs() + 1; | 7075 double deadline = heap->MonotonicallyIncreasingTimeInMs() + 1; |
6871 marking->AdvanceIncrementalMarking( | 7076 marking->AdvanceIncrementalMarking( |
6872 deadline, IncrementalMarking::GC_VIA_STACK_GUARD, | 7077 deadline, IncrementalMarking::GC_VIA_STACK_GUARD, |
6873 IncrementalMarking::FORCE_COMPLETION, StepOrigin::kV8); | 7078 IncrementalMarking::FORCE_COMPLETION, StepOrigin::kV8); |
6874 } | 7079 } |
6875 DCHECK(marking->IsStopped()); | 7080 DCHECK(marking->IsStopped()); |
6876 } | 7081 } |
6877 | 7082 |
6878 } // namespace internal | 7083 } // namespace internal |
6879 } // namespace v8 | 7084 } // namespace v8 |
OLD | NEW |