Merge remote-tracking branch 'origin/v0.10'
[platform/upstream/nodejs.git] / deps / v8 / test / cctest / test-global-handles.cc
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
52 class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
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
83   List<Object*> visited;
84 };
85
86
87 TEST(IterateObjectGroupsOldApi) {
88   CcTest::InitializeVM();
89   GlobalHandles* global_handles = Isolate::Current()->global_handles();
90
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) {
183   CcTest::InitializeVM();
184   GlobalHandles* global_handles = Isolate::Current()->global_handles();
185
186   v8::HandleScope handle_scope(CcTest::isolate());
187
188   Handle<Object> g1s1 =
189       global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
190   Handle<Object> g1s2 =
191       global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
192
193   Handle<Object> g2s1 =
194       global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
195   Handle<Object> g2s2 =
196     global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
197
198   TestRetainedObjectInfo info1;
199   TestRetainedObjectInfo info2;
200   global_handles->SetObjectGroupId(g2s1.location(), UniqueId(2));
201   global_handles->SetObjectGroupId(g2s2.location(), UniqueId(2));
202   global_handles->SetRetainedObjectInfo(UniqueId(2), &info2);
203   global_handles->SetObjectGroupId(g1s1.location(), UniqueId(1));
204   global_handles->SetObjectGroupId(g1s2.location(), UniqueId(1));
205   global_handles->SetRetainedObjectInfo(UniqueId(1), &info1);
206
207   // Iterate the object groups. First skip all.
208   {
209     ResetCanSkipData();
210     skippable_objects.Add(*g1s1.location());
211     skippable_objects.Add(*g1s2.location());
212     skippable_objects.Add(*g2s1.location());
213     skippable_objects.Add(*g2s2.location());
214     TestObjectVisitor visitor;
215     global_handles->IterateObjectGroups(&visitor, &CanSkipCallback);
216
217     // CanSkipCallback was called for all objects.
218     ASSERT(can_skip_called_objects.length() == 4);
219     ASSERT(can_skip_called_objects.Contains(*g1s1.location()));
220     ASSERT(can_skip_called_objects.Contains(*g1s2.location()));
221     ASSERT(can_skip_called_objects.Contains(*g2s1.location()));
222     ASSERT(can_skip_called_objects.Contains(*g2s2.location()));
223
224     // Nothing was visited.
225     ASSERT(visitor.visited.length() == 0);
226     ASSERT(!info1.has_been_disposed());
227     ASSERT(!info2.has_been_disposed());
228   }
229
230   // Iterate again, now only skip the second object group.
231   {
232     ResetCanSkipData();
233     // The first grough should still be visited, since only one object is
234     // skipped.
235     skippable_objects.Add(*g1s1.location());
236     skippable_objects.Add(*g2s1.location());
237     skippable_objects.Add(*g2s2.location());
238     TestObjectVisitor visitor;
239     global_handles->IterateObjectGroups(&visitor, &CanSkipCallback);
240
241     // CanSkipCallback was called for all objects.
242     ASSERT(can_skip_called_objects.length() == 3 ||
243            can_skip_called_objects.length() == 4);
244     ASSERT(can_skip_called_objects.Contains(*g1s2.location()));
245     ASSERT(can_skip_called_objects.Contains(*g2s1.location()));
246     ASSERT(can_skip_called_objects.Contains(*g2s2.location()));
247
248     // The first group was visited.
249     ASSERT(visitor.visited.length() == 2);
250     ASSERT(visitor.visited.Contains(*g1s1.location()));
251     ASSERT(visitor.visited.Contains(*g1s2.location()));
252     ASSERT(info1.has_been_disposed());
253     ASSERT(!info2.has_been_disposed());
254   }
255
256   // Iterate again, don't skip anything.
257   {
258     ResetCanSkipData();
259     TestObjectVisitor visitor;
260     global_handles->IterateObjectGroups(&visitor, &CanSkipCallback);
261
262     // CanSkipCallback was called for all objects.
263     ASSERT(can_skip_called_objects.length() == 1);
264     ASSERT(can_skip_called_objects.Contains(*g2s1.location()) ||
265            can_skip_called_objects.Contains(*g2s2.location()));
266
267     // The second group was visited.
268     ASSERT(visitor.visited.length() == 2);
269     ASSERT(visitor.visited.Contains(*g2s1.location()));
270     ASSERT(visitor.visited.Contains(*g2s2.location()));
271     ASSERT(info2.has_been_disposed());
272   }
273 }
274
275
276 TEST(ImplicitReferences) {
277   CcTest::InitializeVM();
278   GlobalHandles* global_handles = Isolate::Current()->global_handles();
279
280   v8::HandleScope handle_scope(CcTest::isolate());
281
282   Handle<Object> g1s1 =
283       global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
284   Handle<Object> g1c1 =
285       global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
286   Handle<Object> g1c2 =
287       global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
288
289
290   Handle<Object> g2s1 =
291       global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
292   Handle<Object> g2s2 =
293     global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
294   Handle<Object> g2c1 =
295     global_handles->Create(HEAP->AllocateFixedArray(1)->ToObjectChecked());
296
297   global_handles->SetObjectGroupId(g1s1.location(), UniqueId(1));
298   global_handles->SetObjectGroupId(g2s1.location(), UniqueId(2));
299   global_handles->SetObjectGroupId(g2s2.location(), UniqueId(2));
300   global_handles->SetReferenceFromGroup(UniqueId(1), g1c1.location());
301   global_handles->SetReferenceFromGroup(UniqueId(1), g1c2.location());
302   global_handles->SetReferenceFromGroup(UniqueId(2), g2c1.location());
303
304   List<ImplicitRefGroup*>* implicit_refs =
305       global_handles->implicit_ref_groups();
306   USE(implicit_refs);
307   ASSERT(implicit_refs->length() == 2);
308   ASSERT(implicit_refs->at(0)->parent ==
309          reinterpret_cast<HeapObject**>(g1s1.location()));
310   ASSERT(implicit_refs->at(0)->length == 2);
311   ASSERT(implicit_refs->at(0)->children[0] == g1c1.location());
312   ASSERT(implicit_refs->at(0)->children[1] == g1c2.location());
313   ASSERT(implicit_refs->at(1)->parent ==
314          reinterpret_cast<HeapObject**>(g2s1.location()));
315   ASSERT(implicit_refs->at(1)->length == 1);
316   ASSERT(implicit_refs->at(1)->children[0] == g2c1.location());
317 }