Index: test/cctest/test-heap.cc |
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc |
index fcddd089aa7c2c53b5f2005a99a09ea2c5229aaa..d6285db026bba0d530576b0216ec44f506274f7c 100644 |
--- a/test/cctest/test-heap.cc |
+++ b/test/cctest/test-heap.cc |
@@ -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();"); |
+} |