Fix missing slot recodring during clearing of CallICs.
This fixes a rare corner case that was caused by missing recording of relocation slots when the uninitialized CallIC stub happenes to land on an evacuation candidate and the IC is cleared via the shared function. R=ulan@chromium.org BUG=chromium:144230 TEST=cctest/test-heap/Regression144230 Review URL: https://codereview.chromium.org/10963005 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12563 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
a8e502fe60
commit
84935fb23a
12
src/ic-inl.h
12
src/ic-inl.h
@ -79,6 +79,7 @@ Code* IC::GetTargetAtAddress(Address address) {
|
||||
|
||||
void IC::SetTargetAtAddress(Address address, Code* target) {
|
||||
ASSERT(target->is_inline_cache_stub() || target->is_compare_ic_stub());
|
||||
Heap* heap = target->GetHeap();
|
||||
Code* old_target = GetTargetAtAddress(address);
|
||||
#ifdef DEBUG
|
||||
// STORE_IC and KEYED_STORE_IC use Code::extra_ic_state() to mark
|
||||
@ -90,8 +91,15 @@ void IC::SetTargetAtAddress(Address address, Code* target) {
|
||||
}
|
||||
#endif
|
||||
Assembler::set_target_address_at(address, target->instruction_start());
|
||||
target->GetHeap()->incremental_marking()->RecordCodeTargetPatch(address,
|
||||
target);
|
||||
if (heap->gc_state() == Heap::MARK_COMPACT &&
|
||||
heap->mark_compact_collector()->is_compacting()) {
|
||||
Code* host = heap->isolate()->inner_pointer_to_code_cache()->
|
||||
GcSafeFindCodeForInnerPointer(address);
|
||||
RelocInfo rinfo(address, RelocInfo::CODE_TARGET, 0, host);
|
||||
heap->mark_compact_collector()->RecordRelocSlot(&rinfo, target);
|
||||
} else {
|
||||
heap->incremental_marking()->RecordCodeTargetPatch(address, target);
|
||||
}
|
||||
PostPatching(address, target, old_target);
|
||||
}
|
||||
|
||||
|
@ -4,10 +4,12 @@
|
||||
|
||||
#include "v8.h"
|
||||
|
||||
#include "compilation-cache.h"
|
||||
#include "execution.h"
|
||||
#include "factory.h"
|
||||
#include "macro-assembler.h"
|
||||
#include "global-handles.h"
|
||||
#include "stub-cache.h"
|
||||
#include "cctest.h"
|
||||
|
||||
using namespace v8::internal;
|
||||
@ -2244,3 +2246,62 @@ TEST(ReleaseStackTraceData) {
|
||||
|
||||
delete resource;
|
||||
}
|
||||
|
||||
|
||||
TEST(Regression144230) {
|
||||
InitializeVM();
|
||||
v8::HandleScope scope;
|
||||
|
||||
// First make sure that the uninitialized CallIC stub is on a single page
|
||||
// that will later be selected as an evacuation candidate.
|
||||
{
|
||||
v8::HandleScope inner_scope;
|
||||
AlwaysAllocateScope always_allocate;
|
||||
SimulateFullSpace(HEAP->code_space());
|
||||
ISOLATE->stub_cache()->ComputeCallInitialize(9, RelocInfo::CODE_TARGET);
|
||||
}
|
||||
|
||||
// Second compile a CallIC and execute it once so that it gets patched to
|
||||
// the pre-monomorphic stub. These code objects are on yet another page.
|
||||
{
|
||||
v8::HandleScope inner_scope;
|
||||
AlwaysAllocateScope always_allocate;
|
||||
SimulateFullSpace(HEAP->code_space());
|
||||
CompileRun("var o = { f:function(a,b,c,d,e,f,g,h,i) {}};"
|
||||
"function call() { o.f(1,2,3,4,5,6,7,8,9); };"
|
||||
"call();");
|
||||
}
|
||||
|
||||
// Third we fill up the last page of the code space so that it does not get
|
||||
// chosen as an evacuation candidate.
|
||||
{
|
||||
v8::HandleScope inner_scope;
|
||||
AlwaysAllocateScope always_allocate;
|
||||
CompileRun("for (var i = 0; i < 2000; i++) {"
|
||||
" eval('function f' + i + '() { return ' + i +'; };' +"
|
||||
" 'f' + i + '();');"
|
||||
"}");
|
||||
}
|
||||
HEAP->CollectAllGarbage(Heap::kNoGCFlags);
|
||||
|
||||
// Fourth is the tricky part. Make sure the code containing the CallIC is
|
||||
// visited first without clearing the IC. The shared function info is then
|
||||
// visited later, causing the CallIC to be cleared.
|
||||
Handle<String> name = FACTORY->LookupAsciiSymbol("call");
|
||||
Handle<GlobalObject> global(ISOLATE->context()->global_object());
|
||||
MaybeObject* maybe_call = global->GetProperty(*name);
|
||||
JSFunction* call = JSFunction::cast(maybe_call->ToObjectChecked());
|
||||
USE(global->SetProperty(*name, Smi::FromInt(0), NONE, kNonStrictMode));
|
||||
ISOLATE->compilation_cache()->Clear();
|
||||
call->shared()->set_ic_age(HEAP->global_ic_age() + 1);
|
||||
Handle<Object> call_code(call->code());
|
||||
Handle<Object> call_function(call);
|
||||
|
||||
// Now we are ready to mess up the heap.
|
||||
HEAP->CollectAllGarbage(Heap::kReduceMemoryFootprintMask);
|
||||
|
||||
// Either heap verification caught the problem already or we go kaboom once
|
||||
// the CallIC is executed the next time.
|
||||
USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode));
|
||||
CompileRun("call();");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user