| 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 |