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