test-mark-compact.cc revision a7e24c173cf37484693b9abb38e494fa7bd7baeb
1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Copyright 2006-2008 the V8 project authors. All rights reserved.
2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Redistribution and use in source and binary forms, with or without
3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// modification, are permitted provided that the following conditions are
4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// met:
5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Redistributions of source code must retain the above copyright
7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       notice, this list of conditions and the following disclaimer.
8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Redistributions in binary form must reproduce the above
9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       copyright notice, this list of conditions and the following
10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       disclaimer in the documentation and/or other materials provided
11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       with the distribution.
12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Neither the name of Google Inc. nor the names of its
13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       contributors may be used to endorse or promote products derived
14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       from this software without specific prior written permission.
15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <stdlib.h>
29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8.h"
31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "global-handles.h"
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "snapshot.h"
34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "top.h"
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "cctest.h"
36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing namespace v8::internal;
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic v8::Persistent<v8::Context> env;
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void InitializeVM() {
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (env.IsEmpty()) env = v8::Context::New();
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  env->Enter();
45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(MarkingStack) {
49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int mem_size = 20 * kPointerSize;
50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  byte* mem = NewArray<byte>(20*kPointerSize);
51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address low = reinterpret_cast<Address>(mem);
52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address high = low + mem_size;
53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  MarkingStack s;
54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  s.Initialize(low, high);
55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address address = NULL;
57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (!s.is_full()) {
58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    s.Push(HeapObject::FromAddress(address));
59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    address += kPointerSize;
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (!s.is_empty()) {
63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Address value = s.Pop()->address();
64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    address -= kPointerSize;
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CHECK_EQ(address, value);
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(NULL, address);
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DeleteArray(mem);
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(Promotion) {
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Test the situation that some objects in new space are promoted to the
75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // old space
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (Snapshot::IsEnabled()) return;
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Ensure that we get a compacting collection so that objects are promoted
79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // from new space.
80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  FLAG_gc_global = true;
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  FLAG_always_compact = true;
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Heap::ConfigureHeap(2*256*KB, 4*MB);
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InitializeVM();
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope sc;
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Allocate a fixed array in the new space.
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int array_size =
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      (Heap::MaxObjectSizeInPagedSpace() - FixedArray::kHeaderSize) /
91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      (kPointerSize * 4);
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Object* obj = Heap::AllocateFixedArray(array_size);
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(!obj->IsFailure());
94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<FixedArray> array(FixedArray::cast(obj));
96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Array should be in the new space.
98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Heap::InSpace(*array, NEW_SPACE));
99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call the m-c collector, so array becomes an old object.
101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Array now sits in the old space
104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Heap::InSpace(*array, OLD_POINTER_SPACE));
105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(NoPromotion) {
109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (Snapshot::IsEnabled()) return;
110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Heap::ConfigureHeap(2*256*KB, 4*MB);
111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Test the situation that some objects in new space are promoted to
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // the old space
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InitializeVM();
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope sc;
117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do a mark compact GC to shrink the heap.
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Allocate a big Fixed array in the new space.
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int size = (Heap::MaxObjectSizeInPagedSpace() - FixedArray::kHeaderSize) /
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      kPointerSize;
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Object* obj = Heap::AllocateFixedArray(size);
125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<FixedArray> array(FixedArray::cast(obj));
127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Array still stays in the new space.
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Heap::InSpace(*array, NEW_SPACE));
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Allocate objects in the old space until out of memory.
132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  FixedArray* host = *array;
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (true) {
134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Object* obj = Heap::AllocateFixedArray(100, TENURED);
135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (obj->IsFailure()) break;
136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    host->set(0, obj);
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    host = FixedArray::cast(obj);
139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call mark compact GC, and it should pass.
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // array should not be promoted because the old space is full.
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Heap::InSpace(*array, NEW_SPACE));
146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(MarkCompactCollector) {
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InitializeVM();
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope sc;
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // call mark-compact when heap is empty
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // keep allocating garbage in new space until it fails
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int ARRAY_SIZE = 100;
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Object* array;
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  do {
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    array = Heap::AllocateFixedArray(ARRAY_SIZE);
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } while (!array->IsFailure());
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Heap::CollectGarbage(0, NEW_SPACE));
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  array = Heap::AllocateFixedArray(ARRAY_SIZE);
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(!array->IsFailure());
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // keep allocating maps until it fails
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Object* mapp;
169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  do {
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    mapp = Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } while (!mapp->IsFailure());
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Heap::CollectGarbage(0, MAP_SPACE));
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  mapp = Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(!mapp->IsFailure());
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // allocate a garbage
177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  String* func_name = String::cast(Heap::LookupAsciiSymbol("theFunction"));
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  SharedFunctionInfo* function_share =
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(func_name));
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSFunction* function =
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    JSFunction::cast(Heap::AllocateFunction(*Top::function_map(),
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            function_share,
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            Heap::undefined_value()));
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Map* initial_map =
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize));
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  function->set_initial_map(initial_map);
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Top::context()->global()->SetProperty(func_name, function, NONE);
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function));
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  func_name = String::cast(Heap::LookupAsciiSymbol("theFunction"));
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Top::context()->global()->HasLocalProperty(func_name));
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Object* func_value = Top::context()->global()->GetProperty(func_name);
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(func_value->IsJSFunction());
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  function = JSFunction::cast(func_value);
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  obj = JSObject::cast(Heap::AllocateJSObject(function));
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  String* obj_name = String::cast(Heap::LookupAsciiSymbol("theObject"));
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Top::context()->global()->SetProperty(obj_name, obj, NONE);
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  obj_name = String::cast(Heap::LookupAsciiSymbol("theObject"));
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Top::context()->global()->HasLocalProperty(obj_name));
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Top::context()->global()->GetProperty(obj_name)->IsJSObject());
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  obj = JSObject::cast(Top::context()->global()->GetProperty(obj_name));
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(obj->GetProperty(prop_name) == Smi::FromInt(23));
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic int gc_starts = 0;
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic int gc_ends = 0;
217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void GCPrologueCallbackFunc() {
219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(gc_starts == gc_ends);
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  gc_starts++;
221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void GCEpilogueCallbackFunc() {
225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(gc_starts == gc_ends + 1);
226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  gc_ends++;
227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(GCCallback) {
231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InitializeVM();
232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Heap::SetGlobalGCPrologueCallback(&GCPrologueCallbackFunc);
234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Heap::SetGlobalGCEpilogueCallback(&GCEpilogueCallbackFunc);
235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Scavenge does not call GC callback functions.
237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Heap::PerformScavenge();
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(0, gc_starts);
240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(gc_ends, gc_starts);
241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(1, gc_starts);
244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(gc_ends, gc_starts);
245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic int NumberOfWeakCalls = 0;
249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void WeakPointerCallback(v8::Persistent<v8::Value> handle, void* id) {
250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  NumberOfWeakCalls++;
251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ObjectGroups) {
254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InitializeVM();
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  NumberOfWeakCalls = 0;
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope handle_scope;
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Object> g1s1 =
260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    GlobalHandles::Create(Heap::AllocateFixedArray(1));
261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Object> g1s2 =
262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    GlobalHandles::Create(Heap::AllocateFixedArray(1));
263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GlobalHandles::MakeWeak(g1s1.location(),
264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          reinterpret_cast<void*>(1234),
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          &WeakPointerCallback);
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GlobalHandles::MakeWeak(g1s2.location(),
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          reinterpret_cast<void*>(1234),
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          &WeakPointerCallback);
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Object> g2s1 =
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    GlobalHandles::Create(Heap::AllocateFixedArray(1));
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Object> g2s2 =
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    GlobalHandles::Create(Heap::AllocateFixedArray(1));
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GlobalHandles::MakeWeak(g2s1.location(),
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          reinterpret_cast<void*>(1234),
276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          &WeakPointerCallback);
277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GlobalHandles::MakeWeak(g2s2.location(),
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          reinterpret_cast<void*>(1234),
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          &WeakPointerCallback);
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<Object> root = GlobalHandles::Create(*g1s1);  // make a root.
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Connect group 1 and 2, make a cycle.
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<FixedArray>::cast(g1s2)->set(0, *g2s2);
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<FixedArray>::cast(g2s1)->set(0, *g1s1);
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  {
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Object** g1_objects[] = { g1s1.location(), g1s2.location() };
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Object** g2_objects[] = { g2s1.location(), g2s2.location() };
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    GlobalHandles::AddGroup(g1_objects, 2);
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    GlobalHandles::AddGroup(g2_objects, 2);
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do a full GC
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // All object should be alive.
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(0, NumberOfWeakCalls);
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Weaken the root.
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GlobalHandles::MakeWeak(root.location(),
301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          reinterpret_cast<void*>(1234),
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          &WeakPointerCallback);
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Groups are deleted, rebuild groups.
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  {
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Object** g1_objects[] = { g1s1.location(), g1s2.location() };
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Object** g2_objects[] = { g2s1.location(), g2s2.location() };
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    GlobalHandles::AddGroup(g1_objects, 2);
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    GlobalHandles::AddGroup(g2_objects, 2);
310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // All objects should be gone. 5 global handles in total.
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(5, NumberOfWeakCalls);
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
317