v8  3.25.30(node0.11.13)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
test-global-handles.cc
Go to the documentation of this file.
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // 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 "global-handles.h"
29 
30 #include "cctest.h"
31 
32 using namespace v8::internal;
33 using v8::UniqueId;
34 
35 
36 static List<Object*> skippable_objects;
37 static List<Object*> can_skip_called_objects;
38 
39 
40 static bool CanSkipCallback(Heap* heap, Object** pointer) {
41  can_skip_called_objects.Add(*pointer);
42  return skippable_objects.Contains(*pointer);
43 }
44 
45 
46 static void ResetCanSkipData() {
47  skippable_objects.Clear();
48  can_skip_called_objects.Clear();
49 }
50 
51 
53  public:
54  TestRetainedObjectInfo() : has_been_disposed_(false) {}
55 
56  bool has_been_disposed() { return has_been_disposed_; }
57 
58  virtual void Dispose() {
59  ASSERT(!has_been_disposed_);
60  has_been_disposed_ = true;
61  }
62 
63  virtual bool IsEquivalent(v8::RetainedObjectInfo* other) {
64  return other == this;
65  }
66 
67  virtual intptr_t GetHash() { return 0; }
68 
69  virtual const char* GetLabel() { return "whatever"; }
70 
71  private:
72  bool has_been_disposed_;
73 };
74 
75 
76 class TestObjectVisitor : public ObjectVisitor {
77  public:
78  virtual void VisitPointers(Object** start, Object** end) {
79  for (Object** o = start; o != end; ++o)
80  visited.Add(*o);
81  }
82 
84 };
85 
86 
87 TEST(IterateObjectGroupsOldApi) {
89  GlobalHandles* global_handles = CcTest::i_isolate()->global_handles();
90  Heap* heap = CcTest::heap();
91  v8::HandleScope handle_scope(CcTest::isolate());
92 
93  Handle<Object> g1s1 =
94  global_handles->Create(heap->AllocateFixedArray(1)->ToObjectChecked());
95  Handle<Object> g1s2 =
96  global_handles->Create(heap->AllocateFixedArray(1)->ToObjectChecked());
97 
98  Handle<Object> g2s1 =
99  global_handles->Create(heap->AllocateFixedArray(1)->ToObjectChecked());
100  Handle<Object> g2s2 =
101  global_handles->Create(heap->AllocateFixedArray(1)->ToObjectChecked());
102 
103  TestRetainedObjectInfo info1;
104  TestRetainedObjectInfo info2;
105  {
106  Object** g1_objects[] = { g1s1.location(), g1s2.location() };
107  Object** g2_objects[] = { g2s1.location(), g2s2.location() };
108 
109  global_handles->AddObjectGroup(g1_objects, 2, &info1);
110  global_handles->AddObjectGroup(g2_objects, 2, &info2);
111  }
112 
113  // Iterate the object groups. First skip all.
114  {
115  ResetCanSkipData();
116  skippable_objects.Add(*g1s1.location());
117  skippable_objects.Add(*g1s2.location());
118  skippable_objects.Add(*g2s1.location());
119  skippable_objects.Add(*g2s2.location());
120  TestObjectVisitor visitor;
121  global_handles->IterateObjectGroups(&visitor, &CanSkipCallback);
122 
123  // CanSkipCallback was called for all objects.
124  ASSERT(can_skip_called_objects.length() == 4);
125  ASSERT(can_skip_called_objects.Contains(*g1s1.location()));
126  ASSERT(can_skip_called_objects.Contains(*g1s2.location()));
127  ASSERT(can_skip_called_objects.Contains(*g2s1.location()));
128  ASSERT(can_skip_called_objects.Contains(*g2s2.location()));
129 
130  // Nothing was visited.
131  ASSERT(visitor.visited.length() == 0);
132  ASSERT(!info1.has_been_disposed());
133  ASSERT(!info2.has_been_disposed());
134  }
135 
136  // Iterate again, now only skip the second object group.
137  {
138  ResetCanSkipData();
139  // The first grough should still be visited, since only one object is
140  // skipped.
141  skippable_objects.Add(*g1s1.location());
142  skippable_objects.Add(*g2s1.location());
143  skippable_objects.Add(*g2s2.location());
144  TestObjectVisitor visitor;
145  global_handles->IterateObjectGroups(&visitor, &CanSkipCallback);
146 
147  // CanSkipCallback was called for all objects.
148  ASSERT(can_skip_called_objects.length() == 3 ||
149  can_skip_called_objects.length() == 4);
150  ASSERT(can_skip_called_objects.Contains(*g1s2.location()));
151  ASSERT(can_skip_called_objects.Contains(*g2s1.location()));
152  ASSERT(can_skip_called_objects.Contains(*g2s2.location()));
153 
154  // The first group was visited.
155  ASSERT(visitor.visited.length() == 2);
156  ASSERT(visitor.visited.Contains(*g1s1.location()));
157  ASSERT(visitor.visited.Contains(*g1s2.location()));
158  ASSERT(info1.has_been_disposed());
159  ASSERT(!info2.has_been_disposed());
160  }
161 
162  // Iterate again, don't skip anything.
163  {
164  ResetCanSkipData();
165  TestObjectVisitor visitor;
166  global_handles->IterateObjectGroups(&visitor, &CanSkipCallback);
167 
168  // CanSkipCallback was called for all objects.
169  ASSERT(can_skip_called_objects.length() == 1);
170  ASSERT(can_skip_called_objects.Contains(*g2s1.location()) ||
171  can_skip_called_objects.Contains(*g2s2.location()));
172 
173  // The second group was visited.
174  ASSERT(visitor.visited.length() == 2);
175  ASSERT(visitor.visited.Contains(*g2s1.location()));
176  ASSERT(visitor.visited.Contains(*g2s2.location()));
177  ASSERT(info2.has_been_disposed());
178  }
179 }
180 
181 
182 TEST(IterateObjectGroups) {
184  GlobalHandles* global_handles = CcTest::i_isolate()->global_handles();
185  Heap* heap = CcTest::heap();
186 
187  v8::HandleScope handle_scope(CcTest::isolate());
188 
189  Handle<Object> g1s1 =
190  global_handles->Create(heap->AllocateFixedArray(1)->ToObjectChecked());
191  Handle<Object> g1s2 =
192  global_handles->Create(heap->AllocateFixedArray(1)->ToObjectChecked());
193 
194  Handle<Object> g2s1 =
195  global_handles->Create(heap->AllocateFixedArray(1)->ToObjectChecked());
196  Handle<Object> g2s2 =
197  global_handles->Create(heap->AllocateFixedArray(1)->ToObjectChecked());
198 
199  TestRetainedObjectInfo info1;
200  TestRetainedObjectInfo info2;
201  global_handles->SetObjectGroupId(g2s1.location(), UniqueId(2));
202  global_handles->SetObjectGroupId(g2s2.location(), UniqueId(2));
203  global_handles->SetRetainedObjectInfo(UniqueId(2), &info2);
204  global_handles->SetObjectGroupId(g1s1.location(), UniqueId(1));
205  global_handles->SetObjectGroupId(g1s2.location(), UniqueId(1));
206  global_handles->SetRetainedObjectInfo(UniqueId(1), &info1);
207 
208  // Iterate the object groups. First skip all.
209  {
210  ResetCanSkipData();
211  skippable_objects.Add(*g1s1.location());
212  skippable_objects.Add(*g1s2.location());
213  skippable_objects.Add(*g2s1.location());
214  skippable_objects.Add(*g2s2.location());
215  TestObjectVisitor visitor;
216  global_handles->IterateObjectGroups(&visitor, &CanSkipCallback);
217 
218  // CanSkipCallback was called for all objects.
219  ASSERT(can_skip_called_objects.length() == 4);
220  ASSERT(can_skip_called_objects.Contains(*g1s1.location()));
221  ASSERT(can_skip_called_objects.Contains(*g1s2.location()));
222  ASSERT(can_skip_called_objects.Contains(*g2s1.location()));
223  ASSERT(can_skip_called_objects.Contains(*g2s2.location()));
224 
225  // Nothing was visited.
226  ASSERT(visitor.visited.length() == 0);
227  ASSERT(!info1.has_been_disposed());
228  ASSERT(!info2.has_been_disposed());
229  }
230 
231  // Iterate again, now only skip the second object group.
232  {
233  ResetCanSkipData();
234  // The first grough should still be visited, since only one object is
235  // skipped.
236  skippable_objects.Add(*g1s1.location());
237  skippable_objects.Add(*g2s1.location());
238  skippable_objects.Add(*g2s2.location());
239  TestObjectVisitor visitor;
240  global_handles->IterateObjectGroups(&visitor, &CanSkipCallback);
241 
242  // CanSkipCallback was called for all objects.
243  ASSERT(can_skip_called_objects.length() == 3 ||
244  can_skip_called_objects.length() == 4);
245  ASSERT(can_skip_called_objects.Contains(*g1s2.location()));
246  ASSERT(can_skip_called_objects.Contains(*g2s1.location()));
247  ASSERT(can_skip_called_objects.Contains(*g2s2.location()));
248 
249  // The first group was visited.
250  ASSERT(visitor.visited.length() == 2);
251  ASSERT(visitor.visited.Contains(*g1s1.location()));
252  ASSERT(visitor.visited.Contains(*g1s2.location()));
253  ASSERT(info1.has_been_disposed());
254  ASSERT(!info2.has_been_disposed());
255  }
256 
257  // Iterate again, don't skip anything.
258  {
259  ResetCanSkipData();
260  TestObjectVisitor visitor;
261  global_handles->IterateObjectGroups(&visitor, &CanSkipCallback);
262 
263  // CanSkipCallback was called for all objects.
264  ASSERT(can_skip_called_objects.length() == 1);
265  ASSERT(can_skip_called_objects.Contains(*g2s1.location()) ||
266  can_skip_called_objects.Contains(*g2s2.location()));
267 
268  // The second group was visited.
269  ASSERT(visitor.visited.length() == 2);
270  ASSERT(visitor.visited.Contains(*g2s1.location()));
271  ASSERT(visitor.visited.Contains(*g2s2.location()));
272  ASSERT(info2.has_been_disposed());
273  }
274 }
275 
276 
277 TEST(ImplicitReferences) {
279  GlobalHandles* global_handles = CcTest::i_isolate()->global_handles();
280  Heap* heap = CcTest::heap();
281 
282  v8::HandleScope handle_scope(CcTest::isolate());
283 
284  Handle<Object> g1s1 =
285  global_handles->Create(heap->AllocateFixedArray(1)->ToObjectChecked());
286  Handle<Object> g1c1 =
287  global_handles->Create(heap->AllocateFixedArray(1)->ToObjectChecked());
288  Handle<Object> g1c2 =
289  global_handles->Create(heap->AllocateFixedArray(1)->ToObjectChecked());
290 
291 
292  Handle<Object> g2s1 =
293  global_handles->Create(heap->AllocateFixedArray(1)->ToObjectChecked());
294  Handle<Object> g2s2 =
295  global_handles->Create(heap->AllocateFixedArray(1)->ToObjectChecked());
296  Handle<Object> g2c1 =
297  global_handles->Create(heap->AllocateFixedArray(1)->ToObjectChecked());
298 
299  global_handles->SetObjectGroupId(g1s1.location(), UniqueId(1));
300  global_handles->SetObjectGroupId(g2s1.location(), UniqueId(2));
301  global_handles->SetObjectGroupId(g2s2.location(), UniqueId(2));
302  global_handles->SetReferenceFromGroup(UniqueId(1), g1c1.location());
303  global_handles->SetReferenceFromGroup(UniqueId(1), g1c2.location());
304  global_handles->SetReferenceFromGroup(UniqueId(2), g2c1.location());
305 
306  List<ImplicitRefGroup*>* implicit_refs =
307  global_handles->implicit_ref_groups();
308  USE(implicit_refs);
309  ASSERT(implicit_refs->length() == 2);
310  ASSERT(implicit_refs->at(0)->parent ==
311  reinterpret_cast<HeapObject**>(g1s1.location()));
312  ASSERT(implicit_refs->at(0)->length == 2);
313  ASSERT(implicit_refs->at(0)->children[0] == g1c1.location());
314  ASSERT(implicit_refs->at(0)->children[1] == g1c2.location());
315  ASSERT(implicit_refs->at(1)->parent ==
316  reinterpret_cast<HeapObject**>(g2s1.location()));
317  ASSERT(implicit_refs->at(1)->length == 1);
318  ASSERT(implicit_refs->at(1)->children[0] == g2c1.location());
319  global_handles->RemoveObjectGroups();
320  global_handles->RemoveImplicitRefGroups();
321 }
322 
323 
326  Isolate* isolate = CcTest::i_isolate();
327  v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
328  EternalHandles* eternal_handles = isolate->eternal_handles();
329 
330  // Create a number of handles that will not be on a block boundary
331  const int kArrayLength = 2048-1;
332  int indices[kArrayLength];
333  v8::Eternal<v8::Value> eternals[kArrayLength];
334 
335  CHECK_EQ(0, eternal_handles->NumberOfHandles());
336  for (int i = 0; i < kArrayLength; i++) {
337  indices[i] = -1;
338  HandleScope scope(isolate);
339  v8::Local<v8::Object> object = v8::Object::New(v8_isolate);
340  object->Set(i, v8::Integer::New(v8_isolate, i));
341  // Create with internal api
342  eternal_handles->Create(
343  isolate, *v8::Utils::OpenHandle(*object), &indices[i]);
344  // Create with external api
345  CHECK(eternals[i].IsEmpty());
346  eternals[i].Set(v8_isolate, object);
347  CHECK(!eternals[i].IsEmpty());
348  }
349 
350  isolate->heap()->CollectAllAvailableGarbage();
351 
352  for (int i = 0; i < kArrayLength; i++) {
353  for (int j = 0; j < 2; j++) {
354  HandleScope scope(isolate);
355  v8::Local<v8::Value> local;
356  if (j == 0) {
357  // Test internal api
358  local = v8::Utils::ToLocal(eternal_handles->Get(indices[i]));
359  } else {
360  // Test external api
361  local = eternals[i].Get(v8_isolate);
362  }
364  v8::Local<v8::Value> value = object->Get(i);
365  CHECK(value->IsInt32());
366  CHECK_EQ(i, value->Int32Value());
367  }
368  }
369 
370  CHECK_EQ(2*kArrayLength, eternal_handles->NumberOfHandles());
371 
372  // Create an eternal via the constructor
373  {
374  HandleScope scope(isolate);
375  v8::Local<v8::Object> object = v8::Object::New(v8_isolate);
376  v8::Eternal<v8::Object> eternal(v8_isolate, object);
377  CHECK(!eternal.IsEmpty());
378  CHECK(object == eternal.Get(v8_isolate));
379  }
380 
381  CHECK_EQ(2*kArrayLength + 1, eternal_handles->NumberOfHandles());
382 }
List< ImplicitRefGroup * > * implicit_ref_groups()
#define CHECK_EQ(expected, value)
Definition: checks.h:252
bool Contains(const T &elm) const
Definition: list-inl.h:196
virtual void VisitPointers(Object **start, Object **end)
T & at(int i) const
Definition: list.h:90
void SetReferenceFromGroup(UniqueId id, Object **child)
#define ASSERT(condition)
Definition: checks.h:329
void Create(Isolate *isolate, Object *object, int *index)
static i::Heap * heap()
Definition: cctest.h:106
static Local< Integer > New(Isolate *isolate, int32_t value)
Definition: api.cc:6233
#define CHECK(condition)
Definition: checks.h:75
V8_INLINE void Set(Isolate *isolate, Local< S > handle)
void AddObjectGroup(Object ***handles, size_t length, v8::RetainedObjectInfo *info)
virtual bool IsEquivalent(v8::RetainedObjectInfo *other)
List< Object * > visited
Handle< Object > Create(Object *value)
void CollectAllAvailableGarbage(const char *gc_reason=NULL)
Definition: heap.cc:743
EternalHandles * eternal_handles()
Definition: isolate.h:920
GlobalHandles * global_handles()
Definition: isolate.h:918
static V8_INLINE Handle< T > Cast(Handle< S > that)
Definition: v8.h:297
static i::Isolate * i_isolate()
Definition: cctest.h:102
static v8::internal::Handle< To > OpenHandle(v8::Local< From > handle)
Definition: api.h:308
static Local< Context > ToLocal(v8::internal::Handle< v8::internal::Context > obj)
static Local< Object > New(Isolate *isolate)
Definition: api.cc:5589
virtual intptr_t GetHash()
bool IterateObjectGroups(ObjectVisitor *v, WeakSlotCallbackWithHeap can_skip)
void SetRetainedObjectInfo(UniqueId id, RetainedObjectInfo *info)
static void InitializeVM()
Definition: cctest.h:116
Handle< Object > Get(int index)
virtual const char * GetLabel()
void SetObjectGroupId(Object **handle, UniqueId id)
void USE(T)
Definition: globals.h:341
MUST_USE_RESULT MaybeObject * AllocateFixedArray(int length, PretenureFlag pretenure=NOT_TENURED)
Definition: heap.cc:5297
V8_INLINE bool IsEmpty()
Definition: v8.h:435
void Add(const T &element, AllocationPolicy allocator=AllocationPolicy())
Definition: list-inl.h:39
V8_INLINE Local< T > Get(Isolate *isolate)
Definition: v8.h:5751
Definition: v8.h:124
static v8::Isolate * isolate()
Definition: cctest.h:96