blob: 48610b09acf78e8781ee07580f4c02531e50eb94 [file] [log] [blame]
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001// Copyright 2012 the V8 project authors. All rights reserved.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000030#ifdef __linux__
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34#include <unistd.h>
35#include <errno.h>
36#endif
37
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000038#include "v8.h"
39
40#include "global-handles.h"
41#include "snapshot.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000042#include "cctest.h"
43
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000044using namespace v8::internal;
45
46static v8::Persistent<v8::Context> env;
47
48static void InitializeVM() {
49 if (env.IsEmpty()) env = v8::Context::New();
50 v8::HandleScope scope;
51 env->Enter();
52}
53
54
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000055TEST(MarkingDeque) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000056 int mem_size = 20 * kPointerSize;
57 byte* mem = NewArray<byte>(20*kPointerSize);
58 Address low = reinterpret_cast<Address>(mem);
59 Address high = low + mem_size;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000060 MarkingDeque s;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000061 s.Initialize(low, high);
62
63 Address address = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000064 while (!s.IsFull()) {
65 s.PushBlack(HeapObject::FromAddress(address));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000066 address += kPointerSize;
67 }
68
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000069 while (!s.IsEmpty()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000070 Address value = s.Pop()->address();
71 address -= kPointerSize;
72 CHECK_EQ(address, value);
73 }
74
75 CHECK_EQ(NULL, address);
76 DeleteArray(mem);
77}
78
79
80TEST(Promotion) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000081 // This test requires compaction. If compaction is turned off, we
82 // skip the entire test.
83 if (FLAG_never_compact) return;
84
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000085 // Ensure that we get a compacting collection so that objects are promoted
86 // from new space.
87 FLAG_gc_global = true;
88 FLAG_always_compact = true;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000089 HEAP->ConfigureHeap(2*256*KB, 8*MB, 8*MB);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000090
91 InitializeVM();
92
93 v8::HandleScope sc;
94
95 // Allocate a fixed array in the new space.
kasperl@chromium.orge959c182009-07-27 08:59:04 +000096 int array_size =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000097 (Page::kMaxNonCodeHeapObjectSize - FixedArray::kHeaderSize) /
ager@chromium.org5aa501c2009-06-23 07:57:28 +000098 (kPointerSize * 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000099 Object* obj = HEAP->AllocateFixedArray(array_size)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000100
101 Handle<FixedArray> array(FixedArray::cast(obj));
102
103 // Array should be in the new space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000104 CHECK(HEAP->InSpace(*array, NEW_SPACE));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000105
106 // Call the m-c collector, so array becomes an old object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000107 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000108
109 // Array now sits in the old space
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000110 CHECK(HEAP->InSpace(*array, OLD_POINTER_SPACE));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000111}
112
113
114TEST(NoPromotion) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000115 HEAP->ConfigureHeap(2*256*KB, 8*MB, 8*MB);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000116
117 // Test the situation that some objects in new space are promoted to
118 // the old space
119 InitializeVM();
120
121 v8::HandleScope sc;
122
123 // Do a mark compact GC to shrink the heap.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000124 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000125
126 // Allocate a big Fixed array in the new space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000127 int max_size =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000128 Min(Page::kMaxNonCodeHeapObjectSize, HEAP->MaxObjectSizeInNewSpace());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000129
130 int length = (max_size - FixedArray::kHeaderSize) / (2*kPointerSize);
131 Object* obj = i::Isolate::Current()->heap()->AllocateFixedArray(length)->
132 ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000133
134 Handle<FixedArray> array(FixedArray::cast(obj));
135
136 // Array still stays in the new space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 CHECK(HEAP->InSpace(*array, NEW_SPACE));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000138
139 // Allocate objects in the old space until out of memory.
140 FixedArray* host = *array;
141 while (true) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000142 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000143 { MaybeObject* maybe_obj = HEAP->AllocateFixedArray(100, TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 if (!maybe_obj->ToObject(&obj)) break;
145 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000146
147 host->set(0, obj);
148 host = FixedArray::cast(obj);
149 }
150
151 // Call mark compact GC, and it should pass.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000152 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000153}
154
155
156TEST(MarkCompactCollector) {
157 InitializeVM();
158
159 v8::HandleScope sc;
160 // call mark-compact when heap is empty
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000161 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000162
163 // keep allocating garbage in new space until it fails
164 const int ARRAY_SIZE = 100;
165 Object* array;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000166 MaybeObject* maybe_array;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000167 do {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000168 maybe_array = HEAP->AllocateFixedArray(ARRAY_SIZE);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 } while (maybe_array->ToObject(&array));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000170 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000171
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000172 array = HEAP->AllocateFixedArray(ARRAY_SIZE)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000173
174 // keep allocating maps until it fails
175 Object* mapp;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000176 MaybeObject* maybe_mapp;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000177 do {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000178 maybe_mapp = HEAP->AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000179 } while (maybe_mapp->ToObject(&mapp));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000180 HEAP->CollectGarbage(MAP_SPACE);
181 mapp = HEAP->AllocateMap(JS_OBJECT_TYPE,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000182 JSObject::kHeaderSize)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000183
184 // allocate a garbage
lrn@chromium.org303ada72010-10-27 09:33:13 +0000185 String* func_name =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000186 String::cast(HEAP->LookupUtf8Symbol("theFunction")->ToObjectChecked());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000187 SharedFunctionInfo* function_share = SharedFunctionInfo::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000188 HEAP->AllocateSharedFunctionInfo(func_name)->ToObjectChecked());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000189 JSFunction* function = JSFunction::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000190 HEAP->AllocateFunction(*Isolate::Current()->function_map(),
lrn@chromium.org303ada72010-10-27 09:33:13 +0000191 function_share,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000192 HEAP->undefined_value())->ToObjectChecked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000193 Map* initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 Map::cast(HEAP->AllocateMap(JS_OBJECT_TYPE,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000195 JSObject::kHeaderSize)->ToObjectChecked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000196 function->set_initial_map(initial_map);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000197 Isolate::Current()->context()->global_object()->SetProperty(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000198 func_name, function, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000199
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000200 JSObject* obj = JSObject::cast(
201 HEAP->AllocateJSObject(function)->ToObjectChecked());
202 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000203
lrn@chromium.org303ada72010-10-27 09:33:13 +0000204 func_name =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000205 String::cast(HEAP->LookupUtf8Symbol("theFunction")->ToObjectChecked());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000206 CHECK(Isolate::Current()->context()->global_object()->
207 HasLocalProperty(func_name));
208 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000209 GetProperty(func_name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000210 CHECK(func_value->IsJSFunction());
211 function = JSFunction::cast(func_value);
212
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000213 obj = JSObject::cast(HEAP->AllocateJSObject(function)->ToObjectChecked());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000214 String* obj_name =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000215 String::cast(HEAP->LookupUtf8Symbol("theObject")->ToObjectChecked());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000216 Isolate::Current()->context()->global_object()->SetProperty(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000217 obj_name, obj, NONE, kNonStrictMode)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000218 String* prop_name =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000219 String::cast(HEAP->LookupUtf8Symbol("theSlot")->ToObjectChecked());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000220 obj->SetProperty(prop_name,
221 Smi::FromInt(23),
222 NONE,
223 kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000224
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000225 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000226
lrn@chromium.org303ada72010-10-27 09:33:13 +0000227 obj_name =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000228 String::cast(HEAP->LookupUtf8Symbol("theObject")->ToObjectChecked());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000229 CHECK(Isolate::Current()->context()->global_object()->
230 HasLocalProperty(obj_name));
231 CHECK(Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000232 GetProperty(obj_name)->ToObjectChecked()->IsJSObject());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000233 obj = JSObject::cast(Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000234 GetProperty(obj_name)->ToObjectChecked());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000235 prop_name =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000236 String::cast(HEAP->LookupUtf8Symbol("theSlot")->ToObjectChecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000237 CHECK(obj->GetProperty(prop_name) == Smi::FromInt(23));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000238}
239
240
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000241// TODO(1600): compaction of map space is temporary removed from GC.
242#if 0
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000243static Handle<Map> CreateMap() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000244 return FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000245}
246
247
248TEST(MapCompact) {
249 FLAG_max_map_space_pages = 16;
250 InitializeVM();
251
252 {
253 v8::HandleScope sc;
254 // keep allocating maps while pointers are still encodable and thus
255 // mark compact is permitted.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000256 Handle<JSObject> root = FACTORY->NewJSObjectFromMap(CreateMap());
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000257 do {
258 Handle<Map> map = CreateMap();
259 map->set_prototype(*root);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000260 root = FACTORY->NewJSObjectFromMap(map);
261 } while (HEAP->map_space()->MapPointersEncodable());
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000262 }
263 // Now, as we don't have any handles to just allocated maps, we should
264 // be able to trigger map compaction.
265 // To give an additional chance to fail, try to force compaction which
266 // should be impossible right now.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000267 HEAP->CollectAllGarbage(Heap::kForceCompactionMask);
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000268 // And now map pointers should be encodable again.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000269 CHECK(HEAP->map_space()->MapPointersEncodable());
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000270}
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000271#endif
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000272
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000273static int gc_starts = 0;
274static int gc_ends = 0;
275
276static void GCPrologueCallbackFunc() {
277 CHECK(gc_starts == gc_ends);
278 gc_starts++;
279}
280
281
282static void GCEpilogueCallbackFunc() {
283 CHECK(gc_starts == gc_ends + 1);
284 gc_ends++;
285}
286
287
288TEST(GCCallback) {
289 InitializeVM();
290
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000291 HEAP->SetGlobalGCPrologueCallback(&GCPrologueCallbackFunc);
292 HEAP->SetGlobalGCEpilogueCallback(&GCEpilogueCallbackFunc);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000293
294 // Scavenge does not call GC callback functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000295 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000296
297 CHECK_EQ(0, gc_starts);
298 CHECK_EQ(gc_ends, gc_starts);
299
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000300 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000301 CHECK_EQ(1, gc_starts);
302 CHECK_EQ(gc_ends, gc_starts);
303}
304
305
306static int NumberOfWeakCalls = 0;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000307static void WeakPointerCallback(v8::Isolate* isolate,
308 v8::Persistent<v8::Value> handle,
309 void* id) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000310 ASSERT(id == reinterpret_cast<void*>(1234));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000311 NumberOfWeakCalls++;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000312 handle.Dispose(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000313}
314
315TEST(ObjectGroups) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000316 FLAG_incremental_marking = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000317 InitializeVM();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000318 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000319
320 NumberOfWeakCalls = 0;
321 v8::HandleScope handle_scope;
322
323 Handle<Object> g1s1 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000325 Handle<Object> g1s2 =
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000326 global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000327 Handle<Object> g1c1 =
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000328 global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000329 global_handles->MakeWeak(g1s1.location(),
330 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000331 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000332 &WeakPointerCallback);
333 global_handles->MakeWeak(g1s2.location(),
334 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000335 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000336 &WeakPointerCallback);
337 global_handles->MakeWeak(g1c1.location(),
338 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000339 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 &WeakPointerCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000341
342 Handle<Object> g2s1 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000343 global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000344 Handle<Object> g2s2 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000345 global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000346 Handle<Object> g2c1 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000347 global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
348 global_handles->MakeWeak(g2s1.location(),
349 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000350 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000351 &WeakPointerCallback);
352 global_handles->MakeWeak(g2s2.location(),
353 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000354 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000355 &WeakPointerCallback);
356 global_handles->MakeWeak(g2c1.location(),
357 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000358 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000359 &WeakPointerCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 Handle<Object> root = global_handles->Create(*g1s1); // make a root.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000362
363 // Connect group 1 and 2, make a cycle.
364 Handle<FixedArray>::cast(g1s2)->set(0, *g2s2);
365 Handle<FixedArray>::cast(g2s1)->set(0, *g1s1);
366
ager@chromium.org8bb60582008-12-11 12:02:20 +0000367 {
368 Object** g1_objects[] = { g1s1.location(), g1s2.location() };
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000369 Object** g1_children[] = { g1c1.location() };
ager@chromium.org8bb60582008-12-11 12:02:20 +0000370 Object** g2_objects[] = { g2s1.location(), g2s2.location() };
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000371 Object** g2_children[] = { g2c1.location() };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000372 global_handles->AddObjectGroup(g1_objects, 2, NULL);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000373 global_handles->AddImplicitReferences(
374 Handle<HeapObject>::cast(g1s1).location(), g1_children, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000375 global_handles->AddObjectGroup(g2_objects, 2, NULL);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000376 global_handles->AddImplicitReferences(
377 Handle<HeapObject>::cast(g2s2).location(), g2_children, 1);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000378 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000379 // Do a full GC
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000380 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000381
382 // All object should be alive.
383 CHECK_EQ(0, NumberOfWeakCalls);
384
385 // Weaken the root.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000386 global_handles->MakeWeak(root.location(),
387 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000388 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000389 &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000390 // But make children strong roots---all the objects (except for children)
391 // should be collectable now.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000392 global_handles->ClearWeakness(g1c1.location());
393 global_handles->ClearWeakness(g2c1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000394
395 // Groups are deleted, rebuild groups.
ager@chromium.org8bb60582008-12-11 12:02:20 +0000396 {
397 Object** g1_objects[] = { g1s1.location(), g1s2.location() };
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000398 Object** g1_children[] = { g1c1.location() };
ager@chromium.org8bb60582008-12-11 12:02:20 +0000399 Object** g2_objects[] = { g2s1.location(), g2s2.location() };
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000400 Object** g2_children[] = { g2c1.location() };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000401 global_handles->AddObjectGroup(g1_objects, 2, NULL);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000402 global_handles->AddImplicitReferences(
403 Handle<HeapObject>::cast(g1s1).location(), g1_children, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000404 global_handles->AddObjectGroup(g2_objects, 2, NULL);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000405 global_handles->AddImplicitReferences(
406 Handle<HeapObject>::cast(g2s2).location(), g2_children, 1);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000407 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000408
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000409 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000410
411 // All objects should be gone. 5 global handles in total.
412 CHECK_EQ(5, NumberOfWeakCalls);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000413
414 // And now make children weak again and collect them.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 global_handles->MakeWeak(g1c1.location(),
416 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000417 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 &WeakPointerCallback);
419 global_handles->MakeWeak(g2c1.location(),
420 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000421 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000422 &WeakPointerCallback);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000423
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000424 HEAP->CollectGarbage(OLD_POINTER_SPACE);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000425 CHECK_EQ(7, NumberOfWeakCalls);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000426}
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000427
428
429class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
430 public:
431 TestRetainedObjectInfo() : has_been_disposed_(false) {}
432
433 bool has_been_disposed() { return has_been_disposed_; }
434
435 virtual void Dispose() {
436 ASSERT(!has_been_disposed_);
437 has_been_disposed_ = true;
438 }
439
440 virtual bool IsEquivalent(v8::RetainedObjectInfo* other) {
441 return other == this;
442 }
443
444 virtual intptr_t GetHash() { return 0; }
445
446 virtual const char* GetLabel() { return "whatever"; }
447
448 private:
449 bool has_been_disposed_;
450};
451
452
453TEST(EmptyObjectGroups) {
454 InitializeVM();
455 GlobalHandles* global_handles = Isolate::Current()->global_handles();
456
457 v8::HandleScope handle_scope;
458
459 Handle<Object> object =
460 global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
461
462 TestRetainedObjectInfo info;
463 global_handles->AddObjectGroup(NULL, 0, &info);
464 ASSERT(info.has_been_disposed());
465
466 global_handles->AddImplicitReferences(
467 Handle<HeapObject>::cast(object).location(), NULL, 0);
468}
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000469
470
471// Here is a memory use test that uses /proc, and is therefore Linux-only. We
472// do not care how much memory the simulator uses, since it is only there for
473// debugging purposes.
474#if defined(__linux__) && !defined(USE_SIMULATOR)
475
476
477static uintptr_t ReadLong(char* buffer, intptr_t* position, int base) {
478 char* end_address = buffer + *position;
479 uintptr_t result = strtoul(buffer + *position, &end_address, base);
480 CHECK(result != ULONG_MAX || errno != ERANGE);
481 CHECK(end_address > buffer + *position);
482 *position = end_address - buffer;
483 return result;
484}
485
486
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000487// The memory use computed this way is not entirely accurate and depends on
488// the way malloc allocates memory. That's why the memory use may seem to
489// increase even though the sum of the allocated object sizes decreases. It
490// also means that the memory use depends on the kernel and stdlib.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000491static intptr_t MemoryInUse() {
492 intptr_t memory_use = 0;
493
494 int fd = open("/proc/self/maps", O_RDONLY);
495 if (fd < 0) return -1;
496
497 const int kBufSize = 10000;
498 char buffer[kBufSize];
499 int length = read(fd, buffer, kBufSize);
500 intptr_t line_start = 0;
501 CHECK_LT(length, kBufSize); // Make the buffer bigger.
502 CHECK_GT(length, 0); // We have to find some data in the file.
503 while (line_start < length) {
504 if (buffer[line_start] == '\n') {
505 line_start++;
506 continue;
507 }
508 intptr_t position = line_start;
509 uintptr_t start = ReadLong(buffer, &position, 16);
510 CHECK_EQ(buffer[position++], '-');
511 uintptr_t end = ReadLong(buffer, &position, 16);
512 CHECK_EQ(buffer[position++], ' ');
513 CHECK(buffer[position] == '-' || buffer[position] == 'r');
514 bool read_permission = (buffer[position++] == 'r');
515 CHECK(buffer[position] == '-' || buffer[position] == 'w');
516 bool write_permission = (buffer[position++] == 'w');
517 CHECK(buffer[position] == '-' || buffer[position] == 'x');
518 bool execute_permission = (buffer[position++] == 'x');
519 CHECK(buffer[position] == '-' || buffer[position] == 'p');
520 bool private_mapping = (buffer[position++] == 'p');
521 CHECK_EQ(buffer[position++], ' ');
522 uintptr_t offset = ReadLong(buffer, &position, 16);
523 USE(offset);
524 CHECK_EQ(buffer[position++], ' ');
525 uintptr_t major = ReadLong(buffer, &position, 16);
526 USE(major);
527 CHECK_EQ(buffer[position++], ':');
528 uintptr_t minor = ReadLong(buffer, &position, 16);
529 USE(minor);
530 CHECK_EQ(buffer[position++], ' ');
531 uintptr_t inode = ReadLong(buffer, &position, 10);
532 while (position < length && buffer[position] != '\n') position++;
533 if ((read_permission || write_permission || execute_permission) &&
534 private_mapping && inode == 0) {
535 memory_use += (end - start);
536 }
537
538 line_start = position;
539 }
540 close(fd);
541 return memory_use;
542}
543
544
545TEST(BootUpMemoryUse) {
546 intptr_t initial_memory = MemoryInUse();
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000547 // Avoid flakiness.
548 FLAG_crankshaft = false;
549 FLAG_parallel_recompilation = false;
550
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000551 // Only Linux has the proc filesystem and only if it is mapped. If it's not
552 // there we just skip the test.
553 if (initial_memory >= 0) {
554 InitializeVM();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000555 intptr_t delta = MemoryInUse() - initial_memory;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000556 printf("delta: %" V8_PTR_PREFIX "d kB\n", delta / 1024);
557 if (sizeof(initial_memory) == 8) { // 64-bit.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000558 if (v8::internal::Snapshot::IsEnabled()) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000559 CHECK_LE(delta, 3700 * 1024);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000560 } else {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000561 CHECK_LE(delta, 4200 * 1024);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000562 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000563 } else { // 32-bit.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000564 if (v8::internal::Snapshot::IsEnabled()) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000565 CHECK_LE(delta, 2600 * 1024);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000566 } else {
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +0000567 CHECK_LE(delta, 3100 * 1024);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000568 }
569 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000570 }
571}
572
573#endif // __linux__ and !USE_SIMULATOR