| Index: test/cctest/test-heap.cc
|
| diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
|
| index d67f18de60cb1600aae5ccd47f76dbec499b8085..55bb466416fa352a6785cd79c757f272be04d0d1 100644
|
| --- a/test/cctest/test-heap.cc
|
| +++ b/test/cctest/test-heap.cc
|
| @@ -3752,6 +3752,102 @@ TEST(ObjectsInOptimizedCodeAreWeak) {
|
| }
|
|
|
|
|
| +
|
| +static Handle<JSFunction> OptimizeDummyFunction(const char* name) {
|
| + EmbeddedVector<char, 256> source;
|
| + OS::SNPrintF(source,
|
| + "function %s() { return 0; }"
|
| + "%s(); %s();"
|
| + "%%OptimizeFunctionOnNextCall(%s);"
|
| + "%s();", name, name, name, name, name);
|
| + CompileRun(source.start());
|
| + Handle<JSFunction> fun =
|
| + v8::Utils::OpenHandle(
|
| + *v8::Handle<v8::Function>::Cast(
|
| + CcTest::global()->Get(v8_str(name))));
|
| + return fun;
|
| +}
|
| +
|
| +
|
| +static int GetCodeChainLength(Code* code) {
|
| + int result = 0;
|
| + while (code->next_code_link()->IsCode()) {
|
| + result++;
|
| + code = Code::cast(code->next_code_link());
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +
|
| +TEST(NextCodeLinkIsWeak) {
|
| + i::FLAG_allow_natives_syntax = true;
|
| + CcTest::InitializeVM();
|
| + Isolate* isolate = CcTest::i_isolate();
|
| + v8::internal::Heap* heap = CcTest::heap();
|
| +
|
| + if (!isolate->use_crankshaft()) return;
|
| + HandleScope outer_scope(heap->isolate());
|
| + Handle<Code> code;
|
| + heap->CollectAllAvailableGarbage();
|
| + int code_chain_length_before, code_chain_length_after;
|
| + {
|
| + HandleScope scope(heap->isolate());
|
| + Handle<JSFunction> mortal = OptimizeDummyFunction("mortal");
|
| + Handle<JSFunction> immortal = OptimizeDummyFunction("immortal");
|
| + CHECK_EQ(immortal->code()->next_code_link(), mortal->code());
|
| + code_chain_length_before = GetCodeChainLength(immortal->code());
|
| + // Keep the immortal code and let the mortal code die.
|
| + code = scope.CloseAndEscape(Handle<Code>(immortal->code()));
|
| + CompileRun("mortal = null; immortal = null;");
|
| + }
|
| + heap->CollectAllAvailableGarbage();
|
| + // Now mortal code should be dead.
|
| + code_chain_length_after = GetCodeChainLength(*code);
|
| + CHECK_EQ(code_chain_length_before - 1, code_chain_length_after);
|
| +}
|
| +
|
| +
|
| +static Handle<Code> DummyOptimizedCode(Isolate* isolate) {
|
| + i::byte buffer[i::Assembler::kMinimalBufferSize];
|
| + MacroAssembler masm(isolate, buffer, sizeof(buffer));
|
| + CodeDesc desc;
|
| + masm.Prologue(BUILD_FUNCTION_FRAME);
|
| + masm.GetCode(&desc);
|
| + Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
|
| + Handle<Code> code = isolate->factory()->NewCode(
|
| + desc, Code::ComputeFlags(Code::OPTIMIZED_FUNCTION), undefined);
|
| + CHECK(code->IsCode());
|
| + return code;
|
| +}
|
| +
|
| +
|
| +TEST(NextCodeLinkIsWeak2) {
|
| + i::FLAG_allow_natives_syntax = true;
|
| + CcTest::InitializeVM();
|
| + Isolate* isolate = CcTest::i_isolate();
|
| + v8::internal::Heap* heap = CcTest::heap();
|
| +
|
| + if (!isolate->use_crankshaft()) return;
|
| + HandleScope outer_scope(heap->isolate());
|
| + heap->CollectAllAvailableGarbage();
|
| + Handle<Context> context(Context::cast(heap->native_contexts_list()), isolate);
|
| + Handle<Code> new_head;
|
| + Handle<Object> old_head(context->get(Context::OPTIMIZED_CODE_LIST), isolate);
|
| + {
|
| + HandleScope scope(heap->isolate());
|
| + Handle<Code> immortal = DummyOptimizedCode(isolate);
|
| + Handle<Code> mortal = DummyOptimizedCode(isolate);
|
| + mortal->set_next_code_link(*old_head);
|
| + immortal->set_next_code_link(*mortal);
|
| + context->set(Context::OPTIMIZED_CODE_LIST, *immortal);
|
| + new_head = scope.CloseAndEscape(immortal);
|
| + }
|
| + heap->CollectAllAvailableGarbage();
|
| + // Now mortal code should be dead.
|
| + CHECK_EQ(*old_head, new_head->next_code_link());
|
| +}
|
| +
|
| +
|
| #ifdef DEBUG
|
| TEST(AddInstructionChangesNewSpacePromotion) {
|
| i::FLAG_allow_natives_syntax = true;
|
|
|