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
}
#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);
}
#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;
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();");
+}