blob: 499286c46f4227c5dff3580bf5442069e7f7c00a [file] [log] [blame]
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001// Copyright 2011 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 "v8.h"
29
30#include "global-handles.h"
31#include "snapshot.h"
32#include "cctest.h"
33
34using namespace v8::internal;
35
36
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000037static Isolate* GetIsolateFrom(LocalContext* context) {
38 return reinterpret_cast<Isolate*>((*context)->GetIsolate());
39}
40
41
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000042static Handle<JSWeakMap> AllocateJSWeakMap(Isolate* isolate) {
43 Factory* factory = isolate->factory();
44 Heap* heap = isolate->heap();
45 Handle<Map> map = factory->NewMap(JS_WEAK_MAP_TYPE, JSWeakMap::kSize);
46 Handle<JSObject> weakmap_obj = factory->NewJSObjectFromMap(map);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000047 Handle<JSWeakMap> weakmap(JSWeakMap::cast(*weakmap_obj));
48 // Do not use handles for the hash table, it would make entries strong.
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000049 Object* table_obj = ObjectHashTable::Allocate(heap, 1)->ToObjectChecked();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000050 ObjectHashTable* table = ObjectHashTable::cast(table_obj);
51 weakmap->set_table(table);
52 weakmap->set_next(Smi::FromInt(0));
53 return weakmap;
54}
55
56static void PutIntoWeakMap(Handle<JSWeakMap> weakmap,
57 Handle<JSObject> key,
jkummerow@chromium.org28faa982012-04-13 09:58:30 +000058 Handle<Object> value) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000059 Handle<ObjectHashTable> table = PutIntoObjectHashTable(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000060 Handle<ObjectHashTable>(ObjectHashTable::cast(weakmap->table())),
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000061 Handle<JSObject>(JSObject::cast(*key)),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +000062 value);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000063 weakmap->set_table(*table);
64}
65
66static int NumberOfWeakCalls = 0;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000067static void WeakPointerCallback(v8::Isolate* isolate,
ulan@chromium.org57ff8812013-05-10 08:16:55 +000068 v8::Persistent<v8::Value>* handle,
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000069 void* id) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000070 ASSERT(id == reinterpret_cast<void*>(1234));
71 NumberOfWeakCalls++;
ulan@chromium.org57ff8812013-05-10 08:16:55 +000072 handle->Dispose(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000073}
74
75
76TEST(Weakness) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +000077 FLAG_incremental_marking = false;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000078 LocalContext context;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000079 Isolate* isolate = GetIsolateFrom(&context);
80 Factory* factory = isolate->factory();
81 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000082 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000083 Handle<JSWeakMap> weakmap = AllocateJSWeakMap(isolate);
84 GlobalHandles* global_handles = isolate->global_handles();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000085
86 // Keep global reference to the key.
87 Handle<Object> key;
88 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000089 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000090 Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
91 Handle<JSObject> object = factory->NewJSObjectFromMap(map);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000092 key = global_handles->Create(*object);
93 }
94 CHECK(!global_handles->IsWeak(key.location()));
95
96 // Put entry into weak map.
97 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000098 HandleScope scope(isolate);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +000099 PutIntoWeakMap(weakmap,
100 Handle<JSObject>(JSObject::cast(*key)),
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000101 Handle<Smi>(Smi::FromInt(23), isolate));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000102 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000103 CHECK_EQ(1, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000104
105 // Force a full GC.
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000106 heap->CollectAllGarbage(false);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000107 CHECK_EQ(0, NumberOfWeakCalls);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000108 CHECK_EQ(1, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
109 CHECK_EQ(
110 0, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000111
112 // Make the global reference to the key weak.
113 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000114 HandleScope scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000115 global_handles->MakeWeak(key.location(),
116 reinterpret_cast<void*>(1234),
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000117 &WeakPointerCallback,
118 NULL);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000119 }
120 CHECK(global_handles->IsWeak(key.location()));
121
122 // Force a full GC.
123 // Perform two consecutive GCs because the first one will only clear
124 // weak references whereas the second one will also clear weak maps.
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000125 heap->CollectAllGarbage(false);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000126 CHECK_EQ(1, NumberOfWeakCalls);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000127 CHECK_EQ(1, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
128 CHECK_EQ(
129 0, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000130 heap->CollectAllGarbage(false);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000131 CHECK_EQ(1, NumberOfWeakCalls);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000132 CHECK_EQ(0, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
133 CHECK_EQ(
134 1, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000135}
136
137
138TEST(Shrinking) {
139 LocalContext context;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000140 Isolate* isolate = GetIsolateFrom(&context);
141 Factory* factory = isolate->factory();
142 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000143 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000144 Handle<JSWeakMap> weakmap = AllocateJSWeakMap(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000145
146 // Check initial capacity.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000147 CHECK_EQ(32, ObjectHashTable::cast(weakmap->table())->Capacity());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000148
149 // Fill up weak map to trigger capacity change.
150 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000151 HandleScope scope(isolate);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000152 Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000153 for (int i = 0; i < 32; i++) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000154 Handle<JSObject> object = factory->NewJSObjectFromMap(map);
155 PutIntoWeakMap(weakmap, object, Handle<Smi>(Smi::FromInt(i), isolate));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000156 }
157 }
158
159 // Check increased capacity.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000160 CHECK_EQ(128, ObjectHashTable::cast(weakmap->table())->Capacity());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000161
162 // Force a full GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000163 CHECK_EQ(32, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
164 CHECK_EQ(
165 0, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000166 heap->CollectAllGarbage(false);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000167 CHECK_EQ(0, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
168 CHECK_EQ(
169 32, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000170
171 // Check shrunk capacity.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000172 CHECK_EQ(32, ObjectHashTable::cast(weakmap->table())->Capacity());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000173}
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000174
175
176// Test that weak map values on an evacuation candidate which are not reachable
177// by other paths are correctly recorded in the slots buffer.
178TEST(Regress2060a) {
179 FLAG_always_compact = true;
180 LocalContext context;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000181 Isolate* isolate = GetIsolateFrom(&context);
182 Factory* factory = isolate->factory();
183 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000184 HandleScope scope(isolate);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000185 Handle<JSFunction> function =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000186 factory->NewFunction(factory->function_string(), factory->null_value());
187 Handle<JSObject> key = factory->NewJSObject(function);
188 Handle<JSWeakMap> weakmap = AllocateJSWeakMap(isolate);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000189
190 // Start second old-space page so that values land on evacuation candidate.
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000191 Page* first_page = heap->old_pointer_space()->anchor()->next_page();
192 factory->NewFixedArray(900 * KB / kPointerSize, TENURED);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000193
194 // Fill up weak map with values on an evacuation candidate.
195 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000196 HandleScope scope(isolate);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000197 for (int i = 0; i < 32; i++) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000198 Handle<JSObject> object = factory->NewJSObject(function, TENURED);
199 CHECK(!heap->InNewSpace(object->address()));
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000200 CHECK(!first_page->Contains(object->address()));
201 PutIntoWeakMap(weakmap, key, object);
202 }
203 }
204
205 // Force compacting garbage collection.
206 CHECK(FLAG_always_compact);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000207 heap->CollectAllGarbage(Heap::kNoGCFlags);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000208}
209
210
211// Test that weak map keys on an evacuation candidate which are reachable by
212// other strong paths are correctly recorded in the slots buffer.
213TEST(Regress2060b) {
214 FLAG_always_compact = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000215#ifdef VERIFY_HEAP
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000216 FLAG_verify_heap = true;
217#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000218
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000219 LocalContext context;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000220 Isolate* isolate = GetIsolateFrom(&context);
221 Factory* factory = isolate->factory();
222 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000223 HandleScope scope(isolate);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000224 Handle<JSFunction> function =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000225 factory->NewFunction(factory->function_string(), factory->null_value());
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000226
227 // Start second old-space page so that keys land on evacuation candidate.
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000228 Page* first_page = heap->old_pointer_space()->anchor()->next_page();
229 factory->NewFixedArray(900 * KB / kPointerSize, TENURED);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000230
231 // Fill up weak map with keys on an evacuation candidate.
232 Handle<JSObject> keys[32];
233 for (int i = 0; i < 32; i++) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000234 keys[i] = factory->NewJSObject(function, TENURED);
235 CHECK(!heap->InNewSpace(keys[i]->address()));
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000236 CHECK(!first_page->Contains(keys[i]->address()));
237 }
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000238 Handle<JSWeakMap> weakmap = AllocateJSWeakMap(isolate);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000239 for (int i = 0; i < 32; i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000240 PutIntoWeakMap(weakmap,
241 keys[i],
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000242 Handle<Smi>(Smi::FromInt(i), isolate));
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000243 }
244
245 // Force compacting garbage collection. The subsequent collections are used
246 // to verify that key references were actually updated.
247 CHECK(FLAG_always_compact);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000248 heap->CollectAllGarbage(Heap::kNoGCFlags);
249 heap->CollectAllGarbage(Heap::kNoGCFlags);
250 heap->CollectAllGarbage(Heap::kNoGCFlags);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000251}