diff options
Diffstat (limited to 'deps/v8/test/cctest/test-heap.cc')
-rw-r--r-- | deps/v8/test/cctest/test-heap.cc | 840 |
1 files changed, 534 insertions, 306 deletions
diff --git a/deps/v8/test/cctest/test-heap.cc b/deps/v8/test/cctest/test-heap.cc index 3cc61ed5f..ab000dc6a 100644 --- a/deps/v8/test/cctest/test-heap.cc +++ b/deps/v8/test/cctest/test-heap.cc @@ -28,37 +28,18 @@ #include <stdlib.h> #include <utility> -#include "v8.h" +#include "src/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" +#include "src/compilation-cache.h" +#include "src/execution.h" +#include "src/factory.h" +#include "src/global-handles.h" +#include "src/macro-assembler.h" +#include "src/stub-cache.h" +#include "test/cctest/cctest.h" using namespace v8::internal; -// Go through all incremental marking steps in one swoop. -static void SimulateIncrementalMarking() { - MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector(); - IncrementalMarking* marking = CcTest::heap()->incremental_marking(); - if (collector->IsConcurrentSweepingInProgress()) { - collector->WaitUntilSweepingCompleted(); - } - CHECK(marking->IsMarking() || marking->IsStopped()); - if (marking->IsStopped()) { - marking->Start(); - } - CHECK(marking->IsMarking()); - while (!marking->IsComplete()) { - marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD); - } - CHECK(marking->IsComplete()); -} - - static void CheckMap(Map* map, int type, int instance_size) { CHECK(map->IsHeapObject()); #ifdef DEBUG @@ -179,7 +160,8 @@ TEST(HeapObjects) { CHECK(value->IsNumber()); CHECK_EQ(Smi::kMaxValue, Handle<Smi>::cast(value)->value()); -#if !defined(V8_TARGET_ARCH_X64) && !defined(V8_TARGET_ARCH_ARM64) +#if !defined(V8_TARGET_ARCH_X64) && !defined(V8_TARGET_ARCH_ARM64) && \ + !defined(V8_TARGET_ARCH_MIPS64) // TODO(lrn): We need a NumberFromIntptr function in order to test this. value = factory->NewNumberFromInt(Smi::kMinValue - 1); CHECK(value->IsHeapNumber()); @@ -209,7 +191,9 @@ TEST(HeapObjects) { Handle<String> object_string = Handle<String>::cast(factory->Object_string()); Handle<GlobalObject> global(CcTest::i_isolate()->context()->global_object()); - CHECK(JSReceiver::HasLocalProperty(global, object_string)); + v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(global, object_string); + CHECK(maybe.has_value); + CHECK(maybe.value); // Check ToString for oddballs CheckOddball(isolate, heap->true_value(), "true"); @@ -260,18 +244,12 @@ TEST(GarbageCollection) { { HandleScope inner_scope(isolate); // Allocate a function and keep it in global object's property. - Handle<JSFunction> function = factory->NewFunctionWithPrototype( - name, factory->undefined_value()); - Handle<Map> initial_map = - factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); - function->set_initial_map(*initial_map); - JSReceiver::SetProperty(global, name, function, NONE, SLOPPY).Check(); + Handle<JSFunction> function = factory->NewFunction(name); + JSReceiver::SetProperty(global, name, function, SLOPPY).Check(); // Allocate an object. Unrooted after leaving the scope. Handle<JSObject> obj = factory->NewJSObject(function); - JSReceiver::SetProperty( - obj, prop_name, twenty_three, NONE, SLOPPY).Check(); - JSReceiver::SetProperty( - obj, prop_namex, twenty_four, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(obj, prop_name, twenty_three, SLOPPY).Check(); + JSReceiver::SetProperty(obj, prop_namex, twenty_four, SLOPPY).Check(); CHECK_EQ(Smi::FromInt(23), *Object::GetProperty(obj, prop_name).ToHandleChecked()); @@ -282,7 +260,9 @@ TEST(GarbageCollection) { heap->CollectGarbage(NEW_SPACE); // Function should be alive. - CHECK(JSReceiver::HasLocalProperty(global, name)); + v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(global, name); + CHECK(maybe.has_value); + CHECK(maybe.value); // Check function is retained. Handle<Object> func_value = Object::GetProperty(global, name).ToHandleChecked(); @@ -293,15 +273,16 @@ TEST(GarbageCollection) { HandleScope inner_scope(isolate); // Allocate another object, make it reachable from global. Handle<JSObject> obj = factory->NewJSObject(function); - JSReceiver::SetProperty(global, obj_name, obj, NONE, SLOPPY).Check(); - JSReceiver::SetProperty( - obj, prop_name, twenty_three, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(global, obj_name, obj, SLOPPY).Check(); + JSReceiver::SetProperty(obj, prop_name, twenty_three, SLOPPY).Check(); } // After gc, it should survive. heap->CollectGarbage(NEW_SPACE); - CHECK(JSReceiver::HasLocalProperty(global, obj_name)); + maybe = JSReceiver::HasOwnProperty(global, obj_name); + CHECK(maybe.has_value); + CHECK(maybe.value); Handle<Object> obj = Object::GetProperty(global, obj_name).ToHandleChecked(); CHECK(obj->IsJSObject()); @@ -623,23 +604,18 @@ TEST(FunctionAllocation) { v8::HandleScope sc(CcTest::isolate()); Handle<String> name = factory->InternalizeUtf8String("theFunction"); - Handle<JSFunction> function = factory->NewFunctionWithPrototype( - name, factory->undefined_value()); - Handle<Map> initial_map = - factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); - function->set_initial_map(*initial_map); + Handle<JSFunction> function = factory->NewFunction(name); Handle<Smi> twenty_three(Smi::FromInt(23), isolate); Handle<Smi> twenty_four(Smi::FromInt(24), isolate); Handle<String> prop_name = factory->InternalizeUtf8String("theSlot"); Handle<JSObject> obj = factory->NewJSObject(function); - JSReceiver::SetProperty(obj, prop_name, twenty_three, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(obj, prop_name, twenty_three, SLOPPY).Check(); CHECK_EQ(Smi::FromInt(23), *Object::GetProperty(obj, prop_name).ToHandleChecked()); // Check that we can add properties to function objects. - JSReceiver::SetProperty( - function, prop_name, twenty_four, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(function, prop_name, twenty_four, SLOPPY).Check(); CHECK_EQ(Smi::FromInt(24), *Object::GetProperty(function, prop_name).ToHandleChecked()); } @@ -663,55 +639,85 @@ TEST(ObjectProperties) { Handle<Smi> two(Smi::FromInt(2), isolate); // check for empty - CHECK(!JSReceiver::HasLocalProperty(obj, first)); + v8::Maybe<bool> maybe = JSReceiver::HasOwnProperty(obj, first); + CHECK(maybe.has_value); + CHECK(!maybe.value); // add first - JSReceiver::SetProperty(obj, first, one, NONE, SLOPPY).Check(); - CHECK(JSReceiver::HasLocalProperty(obj, first)); + JSReceiver::SetProperty(obj, first, one, SLOPPY).Check(); + maybe = JSReceiver::HasOwnProperty(obj, first); + CHECK(maybe.has_value); + CHECK(maybe.value); // delete first JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION).Check(); - CHECK(!JSReceiver::HasLocalProperty(obj, first)); + maybe = JSReceiver::HasOwnProperty(obj, first); + CHECK(maybe.has_value); + CHECK(!maybe.value); // add first and then second - JSReceiver::SetProperty(obj, first, one, NONE, SLOPPY).Check(); - JSReceiver::SetProperty(obj, second, two, NONE, SLOPPY).Check(); - CHECK(JSReceiver::HasLocalProperty(obj, first)); - CHECK(JSReceiver::HasLocalProperty(obj, second)); + JSReceiver::SetProperty(obj, first, one, SLOPPY).Check(); + JSReceiver::SetProperty(obj, second, two, SLOPPY).Check(); + maybe = JSReceiver::HasOwnProperty(obj, first); + CHECK(maybe.has_value); + CHECK(maybe.value); + maybe = JSReceiver::HasOwnProperty(obj, second); + CHECK(maybe.has_value); + CHECK(maybe.value); // delete first and then second JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION).Check(); - CHECK(JSReceiver::HasLocalProperty(obj, second)); + maybe = JSReceiver::HasOwnProperty(obj, second); + CHECK(maybe.has_value); + CHECK(maybe.value); JSReceiver::DeleteProperty(obj, second, JSReceiver::NORMAL_DELETION).Check(); - CHECK(!JSReceiver::HasLocalProperty(obj, first)); - CHECK(!JSReceiver::HasLocalProperty(obj, second)); + maybe = JSReceiver::HasOwnProperty(obj, first); + CHECK(maybe.has_value); + CHECK(!maybe.value); + maybe = JSReceiver::HasOwnProperty(obj, second); + CHECK(maybe.has_value); + CHECK(!maybe.value); // add first and then second - JSReceiver::SetProperty(obj, first, one, NONE, SLOPPY).Check(); - JSReceiver::SetProperty(obj, second, two, NONE, SLOPPY).Check(); - CHECK(JSReceiver::HasLocalProperty(obj, first)); - CHECK(JSReceiver::HasLocalProperty(obj, second)); + JSReceiver::SetProperty(obj, first, one, SLOPPY).Check(); + JSReceiver::SetProperty(obj, second, two, SLOPPY).Check(); + maybe = JSReceiver::HasOwnProperty(obj, first); + CHECK(maybe.has_value); + CHECK(maybe.value); + maybe = JSReceiver::HasOwnProperty(obj, second); + CHECK(maybe.has_value); + CHECK(maybe.value); // delete second and then first JSReceiver::DeleteProperty(obj, second, JSReceiver::NORMAL_DELETION).Check(); - CHECK(JSReceiver::HasLocalProperty(obj, first)); + maybe = JSReceiver::HasOwnProperty(obj, first); + CHECK(maybe.has_value); + CHECK(maybe.value); JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION).Check(); - CHECK(!JSReceiver::HasLocalProperty(obj, first)); - CHECK(!JSReceiver::HasLocalProperty(obj, second)); + maybe = JSReceiver::HasOwnProperty(obj, first); + CHECK(maybe.has_value); + CHECK(!maybe.value); + maybe = JSReceiver::HasOwnProperty(obj, second); + CHECK(maybe.has_value); + CHECK(!maybe.value); // check string and internalized string match const char* string1 = "fisk"; Handle<String> s1 = factory->NewStringFromAsciiChecked(string1); - JSReceiver::SetProperty(obj, s1, one, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(obj, s1, one, SLOPPY).Check(); Handle<String> s1_string = factory->InternalizeUtf8String(string1); - CHECK(JSReceiver::HasLocalProperty(obj, s1_string)); + maybe = JSReceiver::HasOwnProperty(obj, s1_string); + CHECK(maybe.has_value); + CHECK(maybe.value); // check internalized string and string match const char* string2 = "fugl"; Handle<String> s2_string = factory->InternalizeUtf8String(string2); - JSReceiver::SetProperty(obj, s2_string, one, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(obj, s2_string, one, SLOPPY).Check(); Handle<String> s2 = factory->NewStringFromAsciiChecked(string2); - CHECK(JSReceiver::HasLocalProperty(obj, s2)); + maybe = JSReceiver::HasOwnProperty(obj, s2); + CHECK(maybe.has_value); + CHECK(maybe.value); } @@ -722,18 +728,15 @@ TEST(JSObjectMaps) { v8::HandleScope sc(CcTest::isolate()); Handle<String> name = factory->InternalizeUtf8String("theFunction"); - Handle<JSFunction> function = factory->NewFunctionWithPrototype( - name, factory->undefined_value()); - Handle<Map> initial_map = - factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); - function->set_initial_map(*initial_map); + Handle<JSFunction> function = factory->NewFunction(name); Handle<String> prop_name = factory->InternalizeUtf8String("theSlot"); Handle<JSObject> obj = factory->NewJSObject(function); + Handle<Map> initial_map(function->initial_map()); // Set a propery Handle<Smi> twenty_three(Smi::FromInt(23), isolate); - JSReceiver::SetProperty(obj, prop_name, twenty_three, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(obj, prop_name, twenty_three, SLOPPY).Check(); CHECK_EQ(Smi::FromInt(23), *Object::GetProperty(obj, prop_name).ToHandleChecked()); @@ -811,8 +814,8 @@ TEST(JSObjectCopy) { Handle<Smi> one(Smi::FromInt(1), isolate); Handle<Smi> two(Smi::FromInt(2), isolate); - JSReceiver::SetProperty(obj, first, one, NONE, SLOPPY).Check(); - JSReceiver::SetProperty(obj, second, two, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(obj, first, one, SLOPPY).Check(); + JSReceiver::SetProperty(obj, second, two, SLOPPY).Check(); JSReceiver::SetElement(obj, 0, first, NONE, SLOPPY).Check(); JSReceiver::SetElement(obj, 1, second, NONE, SLOPPY).Check(); @@ -837,8 +840,8 @@ TEST(JSObjectCopy) { CHECK_EQ(*value1, *value2); // Flip the values. - JSReceiver::SetProperty(clone, first, two, NONE, SLOPPY).Check(); - JSReceiver::SetProperty(clone, second, one, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(clone, first, two, SLOPPY).Check(); + JSReceiver::SetProperty(clone, second, one, SLOPPY).Check(); JSReceiver::SetElement(clone, 0, second, NONE, SLOPPY).Check(); JSReceiver::SetElement(clone, 1, first, NONE, SLOPPY).Check(); @@ -901,7 +904,6 @@ TEST(StringAllocation) { static int ObjectsFoundInHeap(Heap* heap, Handle<Object> objs[], int size) { // Count the number of objects found in the heap. int found_count = 0; - heap->EnsureHeapIsIterable(); HeapIterator iterator(heap); for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { for (int i = 0; i < size; i++) { @@ -1030,7 +1032,9 @@ TEST(Regression39128) { CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length()); CHECK_EQ(0, jsobject->properties()->length()); // Create a reference to object in new space in jsobject. - jsobject->FastPropertyAtPut(-1, array); + FieldIndex index = FieldIndex::ForInObjectOffset( + JSObject::kHeaderSize - kPointerSize); + jsobject->FastPropertyAtPut(index, array); CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr)); @@ -1200,7 +1204,7 @@ TEST(TestCodeFlushingIncremental) { // Simulate several GCs that use incremental marking. const int kAgingThreshold = 6; for (int i = 0; i < kAgingThreshold; i++) { - SimulateIncrementalMarking(); + SimulateIncrementalMarking(CcTest::heap()); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); } CHECK(!function->shared()->is_compiled() || function->IsOptimized()); @@ -1214,7 +1218,7 @@ TEST(TestCodeFlushingIncremental) { // Simulate several GCs that use incremental marking but make sure // the loop breaks once the function is enqueued as a candidate. for (int i = 0; i < kAgingThreshold; i++) { - SimulateIncrementalMarking(); + SimulateIncrementalMarking(CcTest::heap()); if (!function->next_function_link()->IsUndefined()) break; CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); } @@ -1290,7 +1294,7 @@ TEST(TestCodeFlushingIncrementalScavenge) { // Simulate incremental marking so that the functions are enqueued as // code flushing candidates. Then kill one of the functions. Finally // perform a scavenge while incremental marking is still running. - SimulateIncrementalMarking(); + SimulateIncrementalMarking(CcTest::heap()); *function2.location() = NULL; CcTest::heap()->CollectGarbage(NEW_SPACE, "test scavenge while marking"); @@ -1344,7 +1348,7 @@ TEST(TestCodeFlushingIncrementalAbort) { // Simulate incremental marking so that the function is enqueued as // code flushing candidate. - SimulateIncrementalMarking(); + SimulateIncrementalMarking(heap); // Enable the debugger and add a breakpoint while incremental marking // is running so that incremental marking aborts and code flushing is @@ -1604,8 +1608,8 @@ TEST(TestSizeOfObjects) { CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector(); - if (collector->IsConcurrentSweepingInProgress()) { - collector->WaitUntilSweepingCompleted(); + if (collector->sweeping_in_progress()) { + collector->EnsureSweepingCompleted(); } int initial_size = static_cast<int>(CcTest::heap()->SizeOfObjects()); @@ -1631,8 +1635,8 @@ TEST(TestSizeOfObjects) { CHECK_EQ(initial_size, static_cast<int>(CcTest::heap()->SizeOfObjects())); // Waiting for sweeper threads should not change heap size. - if (collector->IsConcurrentSweepingInProgress()) { - collector->WaitUntilSweepingCompleted(); + if (collector->sweeping_in_progress()) { + collector->EnsureSweepingCompleted(); } CHECK_EQ(initial_size, static_cast<int>(CcTest::heap()->SizeOfObjects())); } @@ -1640,9 +1644,8 @@ TEST(TestSizeOfObjects) { TEST(TestSizeOfObjectsVsHeapIteratorPrecision) { CcTest::InitializeVM(); - CcTest::heap()->EnsureHeapIsIterable(); - intptr_t size_of_objects_1 = CcTest::heap()->SizeOfObjects(); HeapIterator iterator(CcTest::heap()); + intptr_t size_of_objects_1 = CcTest::heap()->SizeOfObjects(); intptr_t size_of_objects_2 = 0; for (HeapObject* obj = iterator.next(); obj != NULL; @@ -1811,7 +1814,7 @@ TEST(LeakNativeContextViaMap) { ctx2->Exit(); v8::Local<v8::Context>::New(isolate, ctx1)->Exit(); ctx1p.Reset(); - v8::V8::ContextDisposedNotification(); + isolate->ContextDisposedNotification(); } CcTest::heap()->CollectAllAvailableGarbage(); CHECK_EQ(2, NumberOfGlobalObjects()); @@ -1857,7 +1860,7 @@ TEST(LeakNativeContextViaFunction) { ctx2->Exit(); ctx1->Exit(); ctx1p.Reset(); - v8::V8::ContextDisposedNotification(); + isolate->ContextDisposedNotification(); } CcTest::heap()->CollectAllAvailableGarbage(); CHECK_EQ(2, NumberOfGlobalObjects()); @@ -1901,7 +1904,7 @@ TEST(LeakNativeContextViaMapKeyed) { ctx2->Exit(); ctx1->Exit(); ctx1p.Reset(); - v8::V8::ContextDisposedNotification(); + isolate->ContextDisposedNotification(); } CcTest::heap()->CollectAllAvailableGarbage(); CHECK_EQ(2, NumberOfGlobalObjects()); @@ -1949,7 +1952,7 @@ TEST(LeakNativeContextViaMapProto) { ctx2->Exit(); ctx1->Exit(); ctx1p.Reset(); - v8::V8::ContextDisposedNotification(); + isolate->ContextDisposedNotification(); } CcTest::heap()->CollectAllAvailableGarbage(); CHECK_EQ(2, NumberOfGlobalObjects()); @@ -2110,8 +2113,8 @@ TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) { // The following two calls will increment CcTest::heap()->global_ic_age(). const int kLongIdlePauseInMs = 1000; - v8::V8::ContextDisposedNotification(); - v8::V8::IdleNotification(kLongIdlePauseInMs); + CcTest::isolate()->ContextDisposedNotification(); + CcTest::isolate()->IdleNotification(kLongIdlePauseInMs); while (!marking->IsStopped() && !marking->IsComplete()) { marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD); @@ -2166,8 +2169,8 @@ TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) { // The following two calls will increment CcTest::heap()->global_ic_age(). // Since incremental marking is off, IdleNotification will do full GC. const int kLongIdlePauseInMs = 1000; - v8::V8::ContextDisposedNotification(); - v8::V8::IdleNotification(kLongIdlePauseInMs); + CcTest::isolate()->ContextDisposedNotification(); + CcTest::isolate()->IdleNotification(kLongIdlePauseInMs); CHECK_EQ(CcTest::heap()->global_ic_age(), f->shared()->ic_age()); CHECK_EQ(0, f->shared()->opt_count()); @@ -2207,100 +2210,70 @@ TEST(OptimizedAllocationAlwaysInNewSpace) { TEST(OptimizedPretenuringAllocationFolding) { i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; - i::FLAG_allocation_site_pretenuring = false; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - CcTest::heap()->SetNewSpaceHighPromotionModeActive(true); - v8::Local<v8::Value> res = CompileRun( - "function DataObject() {" - " this.a = 1.1;" - " this.b = [{}];" - " this.c = 1.2;" - " this.d = [{}];" - " this.e = 1.3;" - " this.f = [{}];" - "}" - "var number_elements = 20000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + i::SNPrintF( + source, + "var number_elements = %d;" "var elements = new Array();" "function f() {" " for (var i = 0; i < number_elements; i++) {" - " elements[i] = new DataObject();" + " elements[i] = [[{}], [1.1]];" " }" " return elements[number_elements-1]" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); - - Handle<JSObject> o = - v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); - - CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(0))); - CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(1))); - CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(2))); - CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(3))); - CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(4))); - CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(5))); -} + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated); + v8::Local<v8::Value> res = CompileRun(source.start()); -TEST(OptimizedPretenuringAllocationFoldingBlocks) { - i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; - i::FLAG_allocation_site_pretenuring = false; - CcTest::InitializeVM(); - if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; - if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; - v8::HandleScope scope(CcTest::isolate()); - CcTest::heap()->SetNewSpaceHighPromotionModeActive(true); - - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 30000;" - "var elements = new Array(number_elements);" - "function DataObject() {" - " this.a = [{}];" - " this.b = [{}];" - " this.c = 1.1;" - " this.d = 1.2;" - " this.e = [{}];" - " this.f = 1.3;" - "}" - "function f() {" - " for (var i = 0; i < number_elements; i++) {" - " elements[i] = new DataObject();" - " }" - " return elements[number_elements - 1];" - "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); + v8::Local<v8::Value> int_array = v8::Object::Cast(*res)->Get(v8_str("0")); + Handle<JSObject> int_array_handle = + v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(int_array)); + v8::Local<v8::Value> double_array = v8::Object::Cast(*res)->Get(v8_str("1")); + Handle<JSObject> double_array_handle = + v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(double_array)); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); - - CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(0))); - CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(1))); - CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(2))); - CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(3))); - CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(4))); - CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(5))); + CHECK(CcTest::heap()->InOldPointerSpace(*o)); + CHECK(CcTest::heap()->InOldPointerSpace(*int_array_handle)); + CHECK(CcTest::heap()->InOldPointerSpace(int_array_handle->elements())); + CHECK(CcTest::heap()->InOldPointerSpace(*double_array_handle)); + CHECK(CcTest::heap()->InOldDataSpace(double_array_handle->elements())); } TEST(OptimizedPretenuringObjectArrayLiterals) { i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 20000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + i::SNPrintF( + source, + "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" " for (var i = 0; i < number_elements; i++) {" @@ -2308,9 +2281,13 @@ TEST(OptimizedPretenuringObjectArrayLiterals) { " }" " return elements[number_elements - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated); + + v8::Local<v8::Value> res = CompileRun(source.start()); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); @@ -2322,14 +2299,22 @@ TEST(OptimizedPretenuringObjectArrayLiterals) { TEST(OptimizedPretenuringMixedInObjectProperties) { i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 20000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + + i::ScopedVector<char> source(1024); + i::SNPrintF( + source, + "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" " for (var i = 0; i < number_elements; i++) {" @@ -2337,34 +2322,49 @@ TEST(OptimizedPretenuringMixedInObjectProperties) { " }" " return elements[number_elements - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated); + + v8::Local<v8::Value> res = CompileRun(source.start()); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); CHECK(CcTest::heap()->InOldPointerSpace(*o)); - CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(0))); - CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(1))); + FieldIndex idx1 = FieldIndex::ForPropertyIndex(o->map(), 0); + FieldIndex idx2 = FieldIndex::ForPropertyIndex(o->map(), 1); + CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(idx1))); + CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(idx2))); - JSObject* inner_object = reinterpret_cast<JSObject*>(o->RawFastPropertyAt(0)); + JSObject* inner_object = + reinterpret_cast<JSObject*>(o->RawFastPropertyAt(idx1)); CHECK(CcTest::heap()->InOldPointerSpace(inner_object)); - CHECK(CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(0))); - CHECK(CcTest::heap()->InOldPointerSpace(inner_object->RawFastPropertyAt(1))); + CHECK(CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(idx1))); + CHECK(CcTest::heap()->InOldPointerSpace( + inner_object->RawFastPropertyAt(idx2))); } TEST(OptimizedPretenuringDoubleArrayProperties) { i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 30000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + i::SNPrintF( + source, + "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" " for (var i = 0; i < number_elements; i++) {" @@ -2372,9 +2372,13 @@ TEST(OptimizedPretenuringDoubleArrayProperties) { " }" " return elements[i - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated); + + v8::Local<v8::Value> res = CompileRun(source.start()); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); @@ -2386,14 +2390,21 @@ TEST(OptimizedPretenuringDoubleArrayProperties) { TEST(OptimizedPretenuringdoubleArrayLiterals) { i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 30000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + i::SNPrintF( + source, + "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" " for (var i = 0; i < number_elements; i++) {" @@ -2401,9 +2412,13 @@ TEST(OptimizedPretenuringdoubleArrayLiterals) { " }" " return elements[number_elements - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated); + + v8::Local<v8::Value> res = CompileRun(source.start()); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); @@ -2415,14 +2430,21 @@ TEST(OptimizedPretenuringdoubleArrayLiterals) { TEST(OptimizedPretenuringNestedMixedArrayLiterals) { i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 20000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + i::SNPrintF( + source, + "var number_elements = 100;" "var elements = new Array(number_elements);" "function f() {" " for (var i = 0; i < number_elements; i++) {" @@ -2430,10 +2452,13 @@ TEST(OptimizedPretenuringNestedMixedArrayLiterals) { " }" " return elements[number_elements - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" "f();"); + v8::Local<v8::Value> res = CompileRun(source.start()); + v8::Local<v8::Value> int_array = v8::Object::Cast(*res)->Get(v8_str("0")); Handle<JSObject> int_array_handle = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(int_array)); @@ -2453,14 +2478,21 @@ TEST(OptimizedPretenuringNestedMixedArrayLiterals) { TEST(OptimizedPretenuringNestedObjectLiterals) { i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 20000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + i::SNPrintF( + source, + "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" " for (var i = 0; i < number_elements; i++) {" @@ -2468,9 +2500,13 @@ TEST(OptimizedPretenuringNestedObjectLiterals) { " }" " return elements[number_elements - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated); + + v8::Local<v8::Value> res = CompileRun(source.start()); v8::Local<v8::Value> int_array_1 = v8::Object::Cast(*res)->Get(v8_str("0")); Handle<JSObject> int_array_handle_1 = @@ -2491,14 +2527,21 @@ TEST(OptimizedPretenuringNestedObjectLiterals) { TEST(OptimizedPretenuringNestedDoubleLiterals) { i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 20000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + i::SNPrintF( + source, + "var number_elements = %d;" "var elements = new Array(number_elements);" "function f() {" " for (var i = 0; i < number_elements; i++) {" @@ -2506,9 +2549,13 @@ TEST(OptimizedPretenuringNestedDoubleLiterals) { " }" " return elements[number_elements - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated); + + v8::Local<v8::Value> res = CompileRun(source.start()); v8::Local<v8::Value> double_array_1 = v8::Object::Cast(*res)->Get(v8_str("0")); @@ -2532,19 +2579,29 @@ TEST(OptimizedPretenuringNestedDoubleLiterals) { // Make sure pretenuring feedback is gathered for constructed objects as well // as for literals. TEST(OptimizedPretenuringConstructorCalls) { - if (!FLAG_allocation_site_pretenuring || !i::FLAG_pretenuring_call_new) { + if (!i::FLAG_pretenuring_call_new) { // FLAG_pretenuring_call_new needs to be synced with the snapshot. return; } i::FLAG_allow_natives_syntax = true; - i::FLAG_max_new_space_size = 2; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( - "var number_elements = 20000;" + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + // Call new is doing slack tracking for the first + // JSFunction::kGenerousAllocationCount allocations, and we can't find + // mementos during that time. + i::SNPrintF( + source, + "var number_elements = %d;" "var elements = new Array(number_elements);" "function foo() {" " this.a = 3;" @@ -2556,9 +2613,14 @@ TEST(OptimizedPretenuringConstructorCalls) { " }" " return elements[number_elements - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated + + JSFunction::kGenerousAllocationCount); + + v8::Local<v8::Value> res = CompileRun(source.start()); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); @@ -2567,57 +2629,77 @@ TEST(OptimizedPretenuringConstructorCalls) { } -// Test regular array literals allocation. -TEST(OptimizedAllocationArrayLiterals) { +TEST(OptimizedPretenuringCallNew) { + if (!i::FLAG_pretenuring_call_new) { + // FLAG_pretenuring_call_new needs to be synced with the snapshot. + return; + } i::FLAG_allow_natives_syntax = true; + i::FLAG_expose_gc = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - v8::Local<v8::Value> res = CompileRun( + // Grow new space unitl maximum capacity reached. + while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) { + CcTest::heap()->new_space()->Grow(); + } + + i::ScopedVector<char> source(1024); + // Call new is doing slack tracking for the first + // JSFunction::kGenerousAllocationCount allocations, and we can't find + // mementos during that time. + i::SNPrintF( + source, + "var number_elements = %d;" + "var elements = new Array(number_elements);" + "function g() { this.a = 0; }" "function f() {" - " var numbers = new Array(1, 2, 3);" - " numbers[0] = 3.14;" - " return numbers;" + " for (var i = 0; i < number_elements; i++) {" + " elements[i] = new g();" + " }" + " return elements[number_elements - 1];" "};" - "f(); f(); f();" - "%OptimizeFunctionOnNextCall(f);" - "f();"); - CHECK_EQ(static_cast<int>(3.14), - v8::Object::Cast(*res)->Get(v8_str("0"))->Int32Value()); + "f(); gc();" + "f(); f();" + "%%OptimizeFunctionOnNextCall(f);" + "f();", + AllocationSite::kPretenureMinimumCreated + + JSFunction::kGenerousAllocationCount); + + v8::Local<v8::Value> res = CompileRun(source.start()); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); - - CHECK(CcTest::heap()->InNewSpace(o->elements())); + CHECK(CcTest::heap()->InOldPointerSpace(*o)); } -// Test global pretenuring call new. -TEST(OptimizedPretenuringCallNew) { +// Test regular array literals allocation. +TEST(OptimizedAllocationArrayLiterals) { i::FLAG_allow_natives_syntax = true; - i::FLAG_allocation_site_pretenuring = false; - i::FLAG_pretenuring_call_new = true; CcTest::InitializeVM(); if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; if (i::FLAG_gc_global || i::FLAG_stress_compaction) return; v8::HandleScope scope(CcTest::isolate()); - CcTest::heap()->SetNewSpaceHighPromotionModeActive(true); - AlwaysAllocateScope always_allocate(CcTest::i_isolate()); v8::Local<v8::Value> res = CompileRun( - "function g() { this.a = 0; }" "function f() {" - " return new g();" + " var numbers = new Array(1, 2, 3);" + " numbers[0] = 3.14;" + " return numbers;" "};" "f(); f(); f();" "%OptimizeFunctionOnNextCall(f);" "f();"); + CHECK_EQ(static_cast<int>(3.14), + v8::Object::Cast(*res)->Get(v8_str("0"))->Int32Value()); Handle<JSObject> o = v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res)); - CHECK(CcTest::heap()->InOldPointerSpace(*o)); + + CHECK(CcTest::heap()->InNewSpace(o->elements())); } @@ -2641,7 +2723,7 @@ TEST(Regress1465) { AlwaysAllocateScope always_allocate(CcTest::i_isolate()); for (int i = 0; i < transitions_count; i++) { EmbeddedVector<char, 64> buffer; - OS::SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i); + SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i); CompileRun(buffer.start()); } CompileRun("var root = new F;"); @@ -2657,7 +2739,7 @@ TEST(Regress1465) { CompileRun("%DebugPrint(root);"); CHECK_EQ(transitions_count, transitions_before); - SimulateIncrementalMarking(); + SimulateIncrementalMarking(CcTest::heap()); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); // Count number of live transitions after marking. Note that one transition @@ -2673,7 +2755,7 @@ static void AddTransitions(int transitions_count) { AlwaysAllocateScope always_allocate(CcTest::i_isolate()); for (int i = 0; i < transitions_count; i++) { EmbeddedVector<char, 64> buffer; - OS::SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i); + SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i); CompileRun(buffer.start()); } } @@ -2695,8 +2777,7 @@ static void AddPropertyTo( i::FLAG_gc_interval = gc_count; i::FLAG_gc_global = true; CcTest::heap()->set_allocation_timeout(gc_count); - JSReceiver::SetProperty( - object, prop_name, twenty_three, NONE, SLOPPY).Check(); + JSReceiver::SetProperty(object, prop_name, twenty_three, SLOPPY).Check(); } @@ -2799,7 +2880,7 @@ TEST(TransitionArraySimpleToFull) { CompileRun("o = new F;" "root = new F"); root = GetByName("root"); - ASSERT(root->map()->transitions()->IsSimpleTransition()); + DCHECK(root->map()->transitions()->IsSimpleTransition()); AddPropertyTo(2, root, "happy"); // Count number of live transitions after marking. Note that one transition @@ -2823,7 +2904,7 @@ TEST(Regress2143a) { "root.foo = 0;" "root = new Object;"); - SimulateIncrementalMarking(); + SimulateIncrementalMarking(CcTest::heap()); // Compile a StoreIC that performs the prepared map transition. This // will restart incremental marking and should make sure the root is @@ -2864,7 +2945,7 @@ TEST(Regress2143b) { "root.foo = 0;" "root = new Object;"); - SimulateIncrementalMarking(); + SimulateIncrementalMarking(CcTest::heap()); // Compile an optimized LStoreNamedField that performs the prepared // map transition. This will restart incremental marking and should @@ -2920,7 +3001,8 @@ TEST(ReleaseOverReservedPages) { // Triggering one GC will cause a lot of garbage to be discovered but // even spread across all allocated pages. - heap->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation"); + heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask, + "triggered for preparation"); CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages()); // Triggering subsequent GCs should cause at least half of the pages @@ -2986,8 +3068,9 @@ TEST(PrintSharedFunctionInfo) { *v8::Handle<v8::Function>::Cast( CcTest::global()->Get(v8_str("g")))); - DisallowHeapAllocation no_allocation; - g->shared()->PrintLn(); + OFStream os(stdout); + g->shared()->Print(os); + os << endl; } #endif // OBJECT_PRINT @@ -3018,9 +3101,9 @@ TEST(Regress2211) { CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string")))); // Check size. - DescriptorArray* descriptors = internal_obj->map()->instance_descriptors(); + FieldIndex index = FieldIndex::ForDescriptor(internal_obj->map(), 0); ObjectHashTable* hashtable = ObjectHashTable::cast( - internal_obj->RawFastPropertyAt(descriptors->GetFieldIndex(0))); + internal_obj->RawFastPropertyAt(index)); // HashTable header (5) and 4 initial entries (8). CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize); } @@ -3058,18 +3141,22 @@ TEST(IncrementalMarkingClearsTypeFeedbackInfo) { Handle<FixedArray> feedback_vector(f->shared()->feedback_vector()); - CHECK_EQ(2, feedback_vector->length()); - CHECK(feedback_vector->get(0)->IsJSFunction()); - CHECK(feedback_vector->get(1)->IsJSFunction()); + int expected_length = FLAG_vector_ics ? 4 : 2; + CHECK_EQ(expected_length, feedback_vector->length()); + for (int i = 0; i < expected_length; i++) { + if ((i % 2) == 1) { + CHECK(feedback_vector->get(i)->IsJSFunction()); + } + } - SimulateIncrementalMarking(); + SimulateIncrementalMarking(CcTest::heap()); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); - CHECK_EQ(2, feedback_vector->length()); - CHECK_EQ(feedback_vector->get(0), - *TypeFeedbackInfo::UninitializedSentinel(CcTest::i_isolate())); - CHECK_EQ(feedback_vector->get(1), - *TypeFeedbackInfo::UninitializedSentinel(CcTest::i_isolate())); + CHECK_EQ(expected_length, feedback_vector->length()); + for (int i = 0; i < expected_length; i++) { + CHECK_EQ(feedback_vector->get(i), + *TypeFeedbackInfo::UninitializedSentinel(CcTest::i_isolate())); + } } @@ -3105,7 +3192,7 @@ TEST(IncrementalMarkingPreservesMonomorphicIC) { Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); CHECK(ic_before->ic_state() == MONOMORPHIC); - SimulateIncrementalMarking(); + SimulateIncrementalMarking(CcTest::heap()); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); @@ -3138,8 +3225,8 @@ TEST(IncrementalMarkingClearsMonomorphicIC) { CHECK(ic_before->ic_state() == MONOMORPHIC); // Fire context dispose notification. - v8::V8::ContextDisposedNotification(); - SimulateIncrementalMarking(); + CcTest::isolate()->ContextDisposedNotification(); + SimulateIncrementalMarking(CcTest::heap()); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); @@ -3179,8 +3266,8 @@ TEST(IncrementalMarkingClearsPolymorphicIC) { CHECK(ic_before->ic_state() == POLYMORPHIC); // Fire context dispose notification. - v8::V8::ContextDisposedNotification(); - SimulateIncrementalMarking(); + CcTest::isolate()->ContextDisposedNotification(); + SimulateIncrementalMarking(CcTest::heap()); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); @@ -3341,7 +3428,7 @@ TEST(Regress159140) { // Simulate incremental marking so that the functions are enqueued as // code flushing candidates. Then optimize one function. Finally // finish the GC to complete code flushing. - SimulateIncrementalMarking(); + SimulateIncrementalMarking(heap); CompileRun("%OptimizeFunctionOnNextCall(g); g(3);"); heap->CollectAllGarbage(Heap::kNoGCFlags); @@ -3388,7 +3475,7 @@ TEST(Regress165495) { // Simulate incremental marking so that unoptimized code is flushed // even though it still is cached in the optimized code map. - SimulateIncrementalMarking(); + SimulateIncrementalMarking(heap); heap->CollectAllGarbage(Heap::kNoGCFlags); // Make a new closure that will get code installed from the code map. @@ -3456,7 +3543,7 @@ TEST(Regress169209) { } // Simulate incremental marking and collect code flushing candidates. - SimulateIncrementalMarking(); + SimulateIncrementalMarking(heap); CHECK(shared1->code()->gc_metadata() != NULL); // Optimize function and make sure the unoptimized code is replaced. @@ -3602,7 +3689,7 @@ TEST(Regress168801) { // Simulate incremental marking so that unoptimized function is enqueued as a // candidate for code flushing. The shared function info however will not be // explicitly enqueued. - SimulateIncrementalMarking(); + SimulateIncrementalMarking(heap); // Now optimize the function so that it is taken off the candidate list. { @@ -3659,7 +3746,7 @@ TEST(Regress173458) { // Simulate incremental marking so that unoptimized function is enqueued as a // candidate for code flushing. The shared function info however will not be // explicitly enqueued. - SimulateIncrementalMarking(); + SimulateIncrementalMarking(heap); // Now enable the debugger which in turn will disable code flushing. CHECK(isolate->debug()->Load()); @@ -3688,7 +3775,7 @@ TEST(DeferredHandles) { } // An entire block of handles has been filled. // Next handle would require a new block. - ASSERT(data->next == data->limit); + DCHECK(data->next == data->limit); DeferredHandleScope deferred(isolate); DummyVisitor visitor; @@ -3709,7 +3796,7 @@ TEST(IncrementalMarkingStepMakesBigProgressWithLargeObjects) { if (marking->IsStopped()) marking->Start(); // This big step should be sufficient to mark the whole array. marking->Step(100 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD); - ASSERT(marking->IsComplete()); + DCHECK(marking->IsComplete()); } @@ -3736,10 +3823,6 @@ TEST(DisableInlineAllocation) { CcTest::heap()->DisableInlineAllocation(); CompileRun("run()"); - // Run test with inline allocation disabled and pretenuring. - CcTest::heap()->SetNewSpaceHighPromotionModeActive(true); - CompileRun("run()"); - // Run test with inline allocation re-enabled. CcTest::heap()->EnableInlineAllocation(); CompileRun("run()"); @@ -3803,7 +3886,7 @@ TEST(EnsureAllocationSiteDependentCodesProcessed) { // Now make sure that a gc should get rid of the function, even though we // still have the allocation site alive. for (int i = 0; i < 4; i++) { - heap->CollectAllGarbage(false); + heap->CollectAllGarbage(Heap::kNoGCFlags); } // The site still exists because of our global handle, but the code is no @@ -3853,7 +3936,7 @@ TEST(CellsInOptimizedCodeAreWeak) { heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); } - ASSERT(code->marked_for_deoptimization()); + DCHECK(code->marked_for_deoptimization()); } @@ -3894,7 +3977,7 @@ TEST(ObjectsInOptimizedCodeAreWeak) { heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); } - ASSERT(code->marked_for_deoptimization()); + DCHECK(code->marked_for_deoptimization()); } @@ -3911,37 +3994,41 @@ TEST(NoWeakHashTableLeakWithIncrementalMarking) { if (!isolate->use_crankshaft()) return; HandleScope outer_scope(heap->isolate()); for (int i = 0; i < 3; i++) { - SimulateIncrementalMarking(); + SimulateIncrementalMarking(heap); { LocalContext context; HandleScope scope(heap->isolate()); EmbeddedVector<char, 256> source; - OS::SNPrintF(source, - "function bar%d() {" - " return foo%d(1);" - "};" - "function foo%d(x) { with (x) { return 1 + x; } };" - "bar%d();" - "bar%d();" - "bar%d();" - "%OptimizeFunctionOnNextCall(bar%d);" - "bar%d();", i, i, i, i, i, i, i, i); + SNPrintF(source, + "function bar%d() {" + " return foo%d(1);" + "};" + "function foo%d(x) { with (x) { return 1 + x; } };" + "bar%d();" + "bar%d();" + "bar%d();" + "%%OptimizeFunctionOnNextCall(bar%d);" + "bar%d();", i, i, i, i, i, i, i, i); CompileRun(source.start()); } heap->CollectAllGarbage(i::Heap::kNoGCFlags); } - WeakHashTable* table = WeakHashTable::cast(heap->weak_object_to_code_table()); - CHECK_EQ(0, table->NumberOfElements()); + int elements = 0; + if (heap->weak_object_to_code_table()->IsHashTable()) { + WeakHashTable* t = WeakHashTable::cast(heap->weak_object_to_code_table()); + elements = t->NumberOfElements(); + } + CHECK_EQ(0, elements); } 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); + 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( @@ -3993,7 +4080,8 @@ 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.Push(isolate->factory()->undefined_value()); + masm.Drop(1); masm.GetCode(&desc); Handle<Object> undefined(isolate->heap()->undefined_value(), isolate); Handle<Code> code = isolate->factory()->NewCode( @@ -4221,7 +4309,7 @@ TEST(Regress357137) { global->Set(v8::String::NewFromUtf8(isolate, "interrupt"), v8::FunctionTemplate::New(isolate, RequestInterrupt)); v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global); - ASSERT(!context.IsEmpty()); + DCHECK(!context.IsEmpty()); v8::Context::Scope cscope(context); v8::Local<v8::Value> result = CompileRun( @@ -4246,6 +4334,7 @@ TEST(ArrayShiftSweeping) { "var tmp = new Array(100000);" "array[0] = 10;" "gc();" + "gc();" "array.shift();" "array;"); @@ -4254,6 +4343,145 @@ TEST(ArrayShiftSweeping) { CHECK(heap->InOldPointerSpace(o->elements())); CHECK(heap->InOldPointerSpace(*o)); Page* page = Page::FromAddress(o->elements()->address()); - CHECK(page->WasSwept() || + CHECK(page->parallel_sweeping() <= MemoryChunk::SWEEPING_FINALIZE || Marking::IsBlack(Marking::MarkBitFrom(o->elements()))); } + + +TEST(PromotionQueue) { + i::FLAG_expose_gc = true; + i::FLAG_max_semi_space_size = 2; + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Heap* heap = isolate->heap(); + NewSpace* new_space = heap->new_space(); + + // In this test we will try to overwrite the promotion queue which is at the + // end of to-space. To actually make that possible, we need at least two + // semi-space pages and take advantage of fragementation. + // (1) Grow semi-space to two pages. + // (2) Create a few small long living objects and call the scavenger to + // move them to the other semi-space. + // (3) Create a huge object, i.e., remainder of first semi-space page and + // create another huge object which should be of maximum allocatable memory + // size of the second semi-space page. + // (4) Call the scavenger again. + // What will happen is: the scavenger will promote the objects created in (2) + // and will create promotion queue entries at the end of the second + // semi-space page during the next scavenge when it promotes the objects to + // the old generation. The first allocation of (3) will fill up the first + // semi-space page. The second allocation in (3) will not fit into the first + // semi-space page, but it will overwrite the promotion queue which are in + // the second semi-space page. If the right guards are in place, the promotion + // queue will be evacuated in that case. + + // Grow the semi-space to two pages to make semi-space copy overwrite the + // promotion queue, which will be at the end of the second page. + intptr_t old_capacity = new_space->Capacity(); + new_space->Grow(); + CHECK(new_space->IsAtMaximumCapacity()); + CHECK(2 * old_capacity == new_space->Capacity()); + + // Call the scavenger two times to get an empty new space + heap->CollectGarbage(NEW_SPACE); + heap->CollectGarbage(NEW_SPACE); + + // First create a few objects which will survive a scavenge, and will get + // promoted to the old generation later on. These objects will create + // promotion queue entries at the end of the second semi-space page. + const int number_handles = 12; + Handle<FixedArray> handles[number_handles]; + for (int i = 0; i < number_handles; i++) { + handles[i] = isolate->factory()->NewFixedArray(1, NOT_TENURED); + } + heap->CollectGarbage(NEW_SPACE); + + // Create the first huge object which will exactly fit the first semi-space + // page. + int new_linear_size = static_cast<int>( + *heap->new_space()->allocation_limit_address() - + *heap->new_space()->allocation_top_address()); + int length = new_linear_size / kPointerSize - FixedArray::kHeaderSize; + Handle<FixedArray> first = + isolate->factory()->NewFixedArray(length, NOT_TENURED); + CHECK(heap->InNewSpace(*first)); + + // Create the second huge object of maximum allocatable second semi-space + // page size. + new_linear_size = static_cast<int>( + *heap->new_space()->allocation_limit_address() - + *heap->new_space()->allocation_top_address()); + length = Page::kMaxRegularHeapObjectSize / kPointerSize - + FixedArray::kHeaderSize; + Handle<FixedArray> second = + isolate->factory()->NewFixedArray(length, NOT_TENURED); + CHECK(heap->InNewSpace(*second)); + + // This scavenge will corrupt memory if the promotion queue is not evacuated. + heap->CollectGarbage(NEW_SPACE); +} + + +TEST(Regress388880) { + i::FLAG_expose_gc = true; + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + Isolate* isolate = CcTest::i_isolate(); + Factory* factory = isolate->factory(); + Heap* heap = isolate->heap(); + + Handle<Map> map1 = Map::Create(isolate->object_function(), 1); + Handle<Map> map2 = + Map::CopyWithField(map1, factory->NewStringFromStaticAscii("foo"), + HeapType::Any(isolate), NONE, Representation::Tagged(), + OMIT_TRANSITION).ToHandleChecked(); + + int desired_offset = Page::kPageSize - map1->instance_size(); + + // Allocate fixed array in old pointer space so, that object allocated + // afterwards would end at the end of the page. + { + SimulateFullSpace(heap->old_pointer_space()); + int padding_size = desired_offset - Page::kObjectStartOffset; + int padding_array_length = + (padding_size - FixedArray::kHeaderSize) / kPointerSize; + + Handle<FixedArray> temp2 = + factory->NewFixedArray(padding_array_length, TENURED); + Page* page = Page::FromAddress(temp2->address()); + CHECK_EQ(Page::kObjectStartOffset, page->Offset(temp2->address())); + } + + Handle<JSObject> o = factory->NewJSObjectFromMap(map1, TENURED, false); + o->set_properties(*factory->empty_fixed_array()); + + // Ensure that the object allocated where we need it. + Page* page = Page::FromAddress(o->address()); + CHECK_EQ(desired_offset, page->Offset(o->address())); + + // Now we have an object right at the end of the page. + + // Enable incremental marking to trigger actions in Heap::AdjustLiveBytes() + // that would cause crash. + IncrementalMarking* marking = CcTest::heap()->incremental_marking(); + marking->Abort(); + marking->Start(); + CHECK(marking->IsMarking()); + + // Now everything is set up for crashing in JSObject::MigrateFastToFast() + // when it calls heap->AdjustLiveBytes(...). + JSObject::MigrateToMap(o, map2); +} + + +#ifdef DEBUG +TEST(PathTracer) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + + v8::Local<v8::Value> result = CompileRun("'abc'"); + Handle<Object> o = v8::Utils::OpenHandle(*result); + CcTest::i_isolate()->heap()->TracePathToObject(*o); +} +#endif // DEBUG |