Line data Source code
1 : // Copyright 2018 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/api-inl.h"
6 : #include "src/assembler-inl.h"
7 : #include "src/heap/factory.h"
8 : #include "src/isolate.h"
9 : #include "src/objects/smi.h"
10 : #include "test/cctest/cctest.h"
11 : #include "test/cctest/heap/heap-tester.h"
12 : #include "test/cctest/heap/heap-utils.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 : namespace heap {
17 :
18 50 : Handle<FeedbackVector> CreateFeedbackVectorForTest(
19 : v8::Isolate* isolate, Factory* factory,
20 : PretenureFlag pretenure_flag = NOT_TENURED) {
21 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22 : v8::Local<v8::Script> script =
23 : v8::Script::Compile(isolate->GetCurrentContext(),
24 : v8::String::NewFromUtf8(isolate, "function foo() {}",
25 : v8::NewStringType::kNormal)
26 100 : .ToLocalChecked())
27 50 : .ToLocalChecked();
28 : Handle<Object> obj = v8::Utils::OpenHandle(*script);
29 : Handle<SharedFunctionInfo> shared_function =
30 100 : Handle<SharedFunctionInfo>(JSFunction::cast(*obj)->shared(), i_isolate);
31 : Handle<FeedbackVector> fv =
32 50 : factory->NewFeedbackVector(shared_function, pretenure_flag);
33 50 : return fv;
34 : }
35 :
36 28342 : TEST(WeakReferencesBasic) {
37 5 : CcTest::InitializeVM();
38 : Isolate* isolate = CcTest::i_isolate();
39 : Factory* factory = isolate->factory();
40 : HandleScope outer_scope(isolate);
41 :
42 : Handle<FeedbackVector> fv =
43 5 : CreateFeedbackVectorForTest(CcTest::isolate(), factory);
44 5 : CHECK(Heap::InNewSpace(*fv));
45 :
46 5 : MaybeObject code_object = fv->optimized_code_weak_or_smi();
47 5 : CHECK(code_object->IsSmi());
48 5 : CcTest::CollectAllGarbage();
49 5 : CHECK(Heap::InNewSpace(*fv));
50 10 : CHECK_EQ(code_object, fv->optimized_code_weak_or_smi());
51 :
52 : {
53 : HandleScope inner_scope(isolate);
54 :
55 : // Create a new Code.
56 20 : Assembler assm(AssemblerOptions{});
57 5 : assm.nop(); // supported on all architectures
58 5 : CodeDesc desc;
59 5 : assm.GetCode(isolate, &desc);
60 : Handle<Code> code =
61 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
62 10 : CHECK(code->IsCode());
63 :
64 10 : fv->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*code));
65 5 : HeapObject code_heap_object;
66 5 : CHECK(fv->optimized_code_weak_or_smi()->GetHeapObjectIfWeak(
67 : &code_heap_object));
68 10 : CHECK_EQ(*code, code_heap_object);
69 :
70 5 : CcTest::CollectAllGarbage();
71 :
72 5 : CHECK(fv->optimized_code_weak_or_smi()->GetHeapObjectIfWeak(
73 : &code_heap_object));
74 10 : CHECK_EQ(*code, code_heap_object);
75 : } // code will go out of scope.
76 :
77 5 : CcTest::CollectAllGarbage();
78 5 : CHECK(fv->optimized_code_weak_or_smi()->IsCleared());
79 5 : }
80 :
81 28342 : TEST(WeakReferencesOldToOld) {
82 : // Like WeakReferencesBasic, but the updated weak slot is in the old space,
83 : // and referring to an old space object.
84 : ManualGCScope manual_gc_scope;
85 5 : FLAG_manual_evacuation_candidates_selection = true;
86 5 : CcTest::InitializeVM();
87 : Isolate* isolate = CcTest::i_isolate();
88 : Factory* factory = isolate->factory();
89 15 : Heap* heap = isolate->heap();
90 :
91 : HandleScope outer_scope(isolate);
92 : Handle<FeedbackVector> fv =
93 5 : CreateFeedbackVectorForTest(CcTest::isolate(), factory, TENURED);
94 5 : CHECK(heap->InOldSpace(*fv));
95 :
96 : // Create a new FixedArray which the FeedbackVector will point to.
97 5 : Handle<FixedArray> fixed_array = factory->NewFixedArray(1, TENURED);
98 5 : CHECK(heap->InOldSpace(*fixed_array));
99 10 : fv->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*fixed_array));
100 :
101 : Page* page_before_gc = Page::FromHeapObject(*fixed_array);
102 5 : heap::ForceEvacuationCandidate(page_before_gc);
103 5 : CcTest::CollectAllGarbage();
104 5 : CHECK(heap->InOldSpace(*fixed_array));
105 :
106 5 : HeapObject heap_object;
107 5 : CHECK(fv->optimized_code_weak_or_smi()->GetHeapObjectIfWeak(&heap_object));
108 10 : CHECK_EQ(heap_object, *fixed_array);
109 5 : }
110 :
111 28342 : TEST(WeakReferencesOldToNew) {
112 : // Like WeakReferencesBasic, but the updated weak slot is in the old space,
113 : // and referring to an new space object.
114 5 : CcTest::InitializeVM();
115 : Isolate* isolate = CcTest::i_isolate();
116 : Factory* factory = isolate->factory();
117 5 : Heap* heap = isolate->heap();
118 :
119 : HandleScope outer_scope(isolate);
120 : Handle<FeedbackVector> fv =
121 5 : CreateFeedbackVectorForTest(CcTest::isolate(), factory, TENURED);
122 5 : CHECK(heap->InOldSpace(*fv));
123 :
124 : // Create a new FixedArray which the FeedbackVector will point to.
125 5 : Handle<FixedArray> fixed_array = factory->NewFixedArray(1);
126 5 : CHECK(Heap::InNewSpace(*fixed_array));
127 10 : fv->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*fixed_array));
128 :
129 5 : CcTest::CollectAllGarbage();
130 :
131 5 : HeapObject heap_object;
132 5 : CHECK(fv->optimized_code_weak_or_smi()->GetHeapObjectIfWeak(&heap_object));
133 10 : CHECK_EQ(heap_object, *fixed_array);
134 5 : }
135 :
136 28342 : TEST(WeakReferencesOldToNewScavenged) {
137 : // Like WeakReferencesBasic, but the updated weak slot is in the old space,
138 : // and referring to an new space object, which is then scavenged.
139 5 : CcTest::InitializeVM();
140 : Isolate* isolate = CcTest::i_isolate();
141 : Factory* factory = isolate->factory();
142 5 : Heap* heap = isolate->heap();
143 :
144 : HandleScope outer_scope(isolate);
145 : Handle<FeedbackVector> fv =
146 5 : CreateFeedbackVectorForTest(CcTest::isolate(), factory, TENURED);
147 5 : CHECK(heap->InOldSpace(*fv));
148 :
149 : // Create a new FixedArray which the FeedbackVector will point to.
150 5 : Handle<FixedArray> fixed_array = factory->NewFixedArray(1);
151 5 : CHECK(Heap::InNewSpace(*fixed_array));
152 10 : fv->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*fixed_array));
153 :
154 5 : CcTest::CollectGarbage(NEW_SPACE);
155 :
156 5 : HeapObject heap_object;
157 5 : CHECK(fv->optimized_code_weak_or_smi()->GetHeapObjectIfWeak(&heap_object));
158 10 : CHECK_EQ(heap_object, *fixed_array);
159 5 : }
160 :
161 28342 : TEST(WeakReferencesOldToCleared) {
162 : // Like WeakReferencesBasic, but the updated weak slot is in the old space,
163 : // and is cleared.
164 : ManualGCScope manual_gc_scope;
165 5 : FLAG_manual_evacuation_candidates_selection = true;
166 5 : CcTest::InitializeVM();
167 : Isolate* isolate = CcTest::i_isolate();
168 : Factory* factory = isolate->factory();
169 5 : Heap* heap = isolate->heap();
170 :
171 : HandleScope outer_scope(isolate);
172 : Handle<FeedbackVector> fv =
173 5 : CreateFeedbackVectorForTest(CcTest::isolate(), factory, TENURED);
174 5 : CHECK(heap->InOldSpace(*fv));
175 : fv->set_optimized_code_weak_or_smi(
176 10 : HeapObjectReference::ClearedValue(isolate));
177 :
178 5 : CcTest::CollectAllGarbage();
179 5 : CHECK(fv->optimized_code_weak_or_smi()->IsCleared());
180 5 : }
181 :
182 28342 : TEST(ObjectMovesBeforeClearingWeakField) {
183 5 : if (!FLAG_incremental_marking) {
184 0 : return;
185 : }
186 : ManualGCScope manual_gc_scope;
187 5 : CcTest::InitializeVM();
188 : Isolate* isolate = CcTest::i_isolate();
189 : Factory* factory = isolate->factory();
190 5 : Heap* heap = isolate->heap();
191 :
192 : HandleScope outer_scope(isolate);
193 : Handle<FeedbackVector> fv =
194 5 : CreateFeedbackVectorForTest(CcTest::isolate(), factory);
195 5 : CHECK(Heap::InNewSpace(*fv));
196 5 : FeedbackVector fv_location = *fv;
197 : {
198 : HandleScope inner_scope(isolate);
199 : // Create a new FixedArray which the FeedbackVector will point to.
200 5 : Handle<FixedArray> fixed_array = factory->NewFixedArray(1);
201 5 : CHECK(Heap::InNewSpace(*fixed_array));
202 10 : fv->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*fixed_array));
203 : // inner_scope will go out of scope, so when marking the next time,
204 : // *fixed_array will stay white.
205 : }
206 :
207 : // Do marking steps; this will store *fv into the list for later processing
208 : // (since it points to a white object).
209 5 : SimulateIncrementalMarking(heap, true);
210 :
211 : // Scavenger will move *fv.
212 5 : CcTest::CollectGarbage(NEW_SPACE);
213 5 : FeedbackVector new_fv_location = *fv;
214 5 : CHECK_NE(fv_location, new_fv_location);
215 5 : CHECK(fv->optimized_code_weak_or_smi()->IsWeak());
216 :
217 : // Now we try to clear *fv.
218 5 : CcTest::CollectAllGarbage();
219 5 : CHECK(fv->optimized_code_weak_or_smi()->IsCleared());
220 : }
221 :
222 28342 : TEST(ObjectWithWeakFieldDies) {
223 5 : if (!FLAG_incremental_marking) {
224 5 : return;
225 : }
226 : ManualGCScope manual_gc_scope;
227 5 : CcTest::InitializeVM();
228 : Isolate* isolate = CcTest::i_isolate();
229 : Factory* factory = isolate->factory();
230 5 : Heap* heap = isolate->heap();
231 :
232 : {
233 : HandleScope outer_scope(isolate);
234 : Handle<FeedbackVector> fv =
235 5 : CreateFeedbackVectorForTest(CcTest::isolate(), factory);
236 5 : CHECK(Heap::InNewSpace(*fv));
237 : {
238 : HandleScope inner_scope(isolate);
239 : // Create a new FixedArray which the FeedbackVector will point to.
240 5 : Handle<FixedArray> fixed_array = factory->NewFixedArray(1);
241 5 : CHECK(Heap::InNewSpace(*fixed_array));
242 : fv->set_optimized_code_weak_or_smi(
243 10 : HeapObjectReference::Weak(*fixed_array));
244 : // inner_scope will go out of scope, so when marking the next time,
245 : // *fixed_array will stay white.
246 : }
247 :
248 : // Do marking steps; this will store *fv into the list for later processing
249 : // (since it points to a white object).
250 5 : SimulateIncrementalMarking(heap, true);
251 : } // outer_scope goes out of scope
252 :
253 : // fv will die
254 5 : CcTest::CollectGarbage(NEW_SPACE);
255 :
256 : // This used to crash when processing the dead weak reference.
257 5 : CcTest::CollectAllGarbage();
258 : }
259 :
260 28342 : TEST(ObjectWithWeakReferencePromoted) {
261 5 : CcTest::InitializeVM();
262 : Isolate* isolate = CcTest::i_isolate();
263 : Factory* factory = isolate->factory();
264 10 : Heap* heap = isolate->heap();
265 :
266 : HandleScope outer_scope(isolate);
267 : Handle<FeedbackVector> fv =
268 5 : CreateFeedbackVectorForTest(CcTest::isolate(), factory);
269 5 : CHECK(Heap::InNewSpace(*fv));
270 :
271 : // Create a new FixedArray which the FeedbackVector will point to.
272 5 : Handle<FixedArray> fixed_array = factory->NewFixedArray(1);
273 5 : CHECK(Heap::InNewSpace(*fixed_array));
274 10 : fv->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*fixed_array));
275 :
276 5 : CcTest::CollectGarbage(NEW_SPACE);
277 5 : CcTest::CollectGarbage(NEW_SPACE);
278 5 : CHECK(heap->InOldSpace(*fv));
279 5 : CHECK(heap->InOldSpace(*fixed_array));
280 :
281 5 : HeapObject heap_object;
282 5 : CHECK(fv->optimized_code_weak_or_smi()->GetHeapObjectIfWeak(&heap_object));
283 10 : CHECK_EQ(heap_object, *fixed_array);
284 5 : }
285 :
286 28342 : TEST(ObjectWithClearedWeakReferencePromoted) {
287 5 : CcTest::InitializeVM();
288 : Isolate* isolate = CcTest::i_isolate();
289 : Factory* factory = isolate->factory();
290 5 : Heap* heap = isolate->heap();
291 :
292 : HandleScope outer_scope(isolate);
293 : Handle<FeedbackVector> fv =
294 5 : CreateFeedbackVectorForTest(CcTest::isolate(), factory);
295 5 : CHECK(Heap::InNewSpace(*fv));
296 :
297 : fv->set_optimized_code_weak_or_smi(
298 10 : HeapObjectReference::ClearedValue(isolate));
299 :
300 5 : CcTest::CollectGarbage(NEW_SPACE);
301 5 : CHECK(Heap::InNewSpace(*fv));
302 5 : CHECK(fv->optimized_code_weak_or_smi()->IsCleared());
303 :
304 5 : CcTest::CollectGarbage(NEW_SPACE);
305 5 : CHECK(heap->InOldSpace(*fv));
306 5 : CHECK(fv->optimized_code_weak_or_smi()->IsCleared());
307 :
308 5 : CcTest::CollectAllGarbage();
309 5 : CHECK(fv->optimized_code_weak_or_smi()->IsCleared());
310 5 : }
311 :
312 28342 : TEST(WeakReferenceWriteBarrier) {
313 5 : if (!FLAG_incremental_marking) {
314 5 : return;
315 : }
316 :
317 : ManualGCScope manual_gc_scope;
318 5 : CcTest::InitializeVM();
319 : Isolate* isolate = CcTest::i_isolate();
320 : Factory* factory = isolate->factory();
321 5 : Heap* heap = isolate->heap();
322 :
323 : HandleScope outer_scope(isolate);
324 : Handle<FeedbackVector> fv =
325 5 : CreateFeedbackVectorForTest(CcTest::isolate(), factory);
326 5 : CHECK(Heap::InNewSpace(*fv));
327 :
328 : {
329 : HandleScope inner_scope(isolate);
330 :
331 : // Create a new FixedArray which the FeedbackVector will point to.
332 5 : Handle<FixedArray> fixed_array1 = factory->NewFixedArray(1);
333 5 : CHECK(Heap::InNewSpace(*fixed_array1));
334 : fv->set_optimized_code_weak_or_smi(
335 10 : HeapObjectReference::Weak(*fixed_array1));
336 :
337 5 : SimulateIncrementalMarking(heap, true);
338 :
339 5 : Handle<FixedArray> fixed_array2 = factory->NewFixedArray(1);
340 5 : CHECK(Heap::InNewSpace(*fixed_array2));
341 : // This write will trigger the write barrier.
342 : fv->set_optimized_code_weak_or_smi(
343 10 : HeapObjectReference::Weak(*fixed_array2));
344 : }
345 :
346 5 : CcTest::CollectAllGarbage();
347 :
348 : // Check that the write barrier treated the weak reference as strong.
349 5 : CHECK(fv->optimized_code_weak_or_smi()->IsWeak());
350 : }
351 :
352 28342 : TEST(EmptyWeakArray) {
353 5 : CcTest::InitializeVM();
354 : Isolate* isolate = CcTest::i_isolate();
355 : Factory* factory = isolate->factory();
356 : HandleScope outer_scope(isolate);
357 :
358 : Handle<WeakFixedArray> array = factory->empty_weak_fixed_array();
359 10 : CHECK(array->IsWeakFixedArray());
360 10 : CHECK(!array->IsFixedArray());
361 5 : CHECK_EQ(array->length(), 0);
362 5 : }
363 :
364 28342 : TEST(WeakArraysBasic) {
365 : ManualGCScope manual_gc_scope;
366 5 : CcTest::InitializeVM();
367 : Isolate* isolate = CcTest::i_isolate();
368 : Factory* factory = isolate->factory();
369 10 : Heap* heap = isolate->heap();
370 : HandleScope outer_scope(isolate);
371 :
372 : const int length = 4;
373 5 : Handle<WeakFixedArray> array = factory->NewWeakFixedArray(length);
374 10 : CHECK(array->IsWeakFixedArray());
375 10 : CHECK(!array->IsFixedArray());
376 5 : CHECK_EQ(array->length(), length);
377 5 : CHECK(Heap::InNewSpace(*array));
378 :
379 20 : for (int i = 0; i < length; ++i) {
380 20 : HeapObject heap_object;
381 20 : CHECK(array->Get(i)->GetHeapObjectIfStrong(&heap_object));
382 40 : CHECK_EQ(heap_object, ReadOnlyRoots(heap).undefined_value());
383 : }
384 :
385 : Handle<HeapObject> saved;
386 : {
387 : HandleScope inner_scope(isolate);
388 5 : Handle<FixedArray> index0 = factory->NewFixedArray(1);
389 : index0->set(0, Smi::FromInt(2016));
390 5 : Handle<FixedArray> index1 = factory->NewFixedArray(1);
391 : index1->set(0, Smi::FromInt(2017));
392 :
393 5 : Handle<FixedArray> index2 = factory->NewFixedArray(1);
394 : index2->set(0, Smi::FromInt(2018));
395 5 : Handle<FixedArray> index3 = factory->NewFixedArray(1);
396 : index3->set(0, Smi::FromInt(2019));
397 :
398 10 : array->Set(0, HeapObjectReference::Weak(*index0));
399 10 : array->Set(1, HeapObjectReference::Weak(*index1));
400 10 : array->Set(2, HeapObjectReference::Strong(*index2));
401 10 : array->Set(3, HeapObjectReference::Weak(*index3));
402 5 : saved = inner_scope.CloseAndEscape(index1);
403 : } // inner_scope goes out of scope.
404 :
405 : // The references are only cleared by the mark-compact (scavenger treats weak
406 : // references as strong). Thus we need to GC until the array reaches old
407 : // space.
408 :
409 : // TODO(marja): update this when/if we do handle weak references in the new
410 : // space.
411 5 : CcTest::CollectGarbage(NEW_SPACE);
412 5 : HeapObject heap_object;
413 5 : CHECK(array->Get(0)->GetHeapObjectIfWeak(&heap_object));
414 5 : CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2016);
415 5 : CHECK(array->Get(1)->GetHeapObjectIfWeak(&heap_object));
416 5 : CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2017);
417 5 : CHECK(array->Get(2)->GetHeapObjectIfStrong(&heap_object));
418 5 : CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2018);
419 5 : CHECK(array->Get(3)->GetHeapObjectIfWeak(&heap_object));
420 5 : CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2019);
421 :
422 5 : CcTest::CollectAllGarbage();
423 5 : CHECK(heap->InOldSpace(*array));
424 10 : CHECK(array->Get(0)->IsCleared());
425 5 : CHECK(array->Get(1)->GetHeapObjectIfWeak(&heap_object));
426 5 : CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2017);
427 5 : CHECK(array->Get(2)->GetHeapObjectIfStrong(&heap_object));
428 5 : CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2018);
429 10 : CHECK(array->Get(3)->IsCleared());
430 5 : }
431 :
432 28342 : TEST(WeakArrayListBasic) {
433 : ManualGCScope manual_gc_scope;
434 5 : CcTest::InitializeVM();
435 : Isolate* isolate = CcTest::i_isolate();
436 : Factory* factory = isolate->factory();
437 10 : Heap* heap = isolate->heap();
438 : HandleScope outer_scope(isolate);
439 :
440 : Handle<WeakArrayList> array(ReadOnlyRoots(heap).empty_weak_array_list(),
441 : isolate);
442 10 : CHECK(array->IsWeakArrayList());
443 10 : CHECK(!array->IsFixedArray());
444 10 : CHECK(!array->IsWeakFixedArray());
445 5 : CHECK_EQ(array->length(), 0);
446 :
447 5 : Handle<FixedArray> index2 = factory->NewFixedArray(1);
448 : index2->set(0, Smi::FromInt(2017));
449 :
450 : Handle<HeapObject> saved;
451 : {
452 : HandleScope inner_scope(isolate);
453 5 : Handle<FixedArray> index0 = factory->NewFixedArray(1);
454 : index0->set(0, Smi::FromInt(2016));
455 5 : Handle<FixedArray> index4 = factory->NewFixedArray(1);
456 : index4->set(0, Smi::FromInt(2018));
457 5 : Handle<FixedArray> index6 = factory->NewFixedArray(1);
458 : index6->set(0, Smi::FromInt(2019));
459 :
460 : array = WeakArrayList::AddToEnd(isolate, array,
461 5 : MaybeObjectHandle::Weak(index0));
462 : array = WeakArrayList::AddToEnd(
463 5 : isolate, array, MaybeObjectHandle(Smi::FromInt(1), isolate));
464 5 : CHECK_EQ(array->length(), 2);
465 :
466 : array = WeakArrayList::AddToEnd(isolate, array,
467 5 : MaybeObjectHandle::Weak(index2));
468 : array = WeakArrayList::AddToEnd(
469 5 : isolate, array, MaybeObjectHandle(Smi::FromInt(3), isolate));
470 5 : CHECK_EQ(array->length(), 4);
471 :
472 : array = WeakArrayList::AddToEnd(isolate, array,
473 5 : MaybeObjectHandle::Weak(index4));
474 : array = WeakArrayList::AddToEnd(
475 5 : isolate, array, MaybeObjectHandle(Smi::FromInt(5), isolate));
476 5 : CHECK_EQ(array->length(), 6);
477 :
478 : array = WeakArrayList::AddToEnd(isolate, array,
479 5 : MaybeObjectHandle::Weak(index6));
480 : array = WeakArrayList::AddToEnd(
481 5 : isolate, array, MaybeObjectHandle(Smi::FromInt(7), isolate));
482 5 : CHECK_EQ(array->length(), 8);
483 :
484 5 : CHECK(Heap::InNewSpace(*array));
485 :
486 15 : CHECK_EQ(array->Get(0), HeapObjectReference::Weak(*index0));
487 10 : CHECK_EQ(array->Get(1).ToSmi().value(), 1);
488 :
489 15 : CHECK_EQ(array->Get(2), HeapObjectReference::Weak(*index2));
490 10 : CHECK_EQ(array->Get(3).ToSmi().value(), 3);
491 :
492 15 : CHECK_EQ(array->Get(4), HeapObjectReference::Weak(*index4));
493 10 : CHECK_EQ(array->Get(5).ToSmi().value(), 5);
494 :
495 15 : CHECK_EQ(array->Get(6), HeapObjectReference::Weak(*index6));
496 5 : array = inner_scope.CloseAndEscape(array);
497 : } // inner_scope goes out of scope.
498 :
499 : // The references are only cleared by the mark-compact (scavenger treats weak
500 : // references as strong). Thus we need to GC until the array reaches old
501 : // space.
502 :
503 : // TODO(marja): update this when/if we do handle weak references in the new
504 : // space.
505 5 : CcTest::CollectGarbage(NEW_SPACE);
506 5 : HeapObject heap_object;
507 5 : CHECK_EQ(array->length(), 8);
508 5 : CHECK(array->Get(0)->GetHeapObjectIfWeak(&heap_object));
509 5 : CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2016);
510 10 : CHECK_EQ(array->Get(1).ToSmi().value(), 1);
511 :
512 5 : CHECK(array->Get(2)->GetHeapObjectIfWeak(&heap_object));
513 5 : CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2017);
514 10 : CHECK_EQ(array->Get(3).ToSmi().value(), 3);
515 :
516 5 : CHECK(array->Get(4)->GetHeapObjectIfWeak(&heap_object));
517 5 : CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2018);
518 10 : CHECK_EQ(array->Get(5).ToSmi().value(), 5);
519 :
520 5 : CHECK(array->Get(6)->GetHeapObjectIfWeak(&heap_object));
521 5 : CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2019);
522 10 : CHECK_EQ(array->Get(7).ToSmi().value(), 7);
523 :
524 5 : CcTest::CollectAllGarbage();
525 5 : CHECK(heap->InOldSpace(*array));
526 5 : CHECK_EQ(array->length(), 8);
527 10 : CHECK(array->Get(0)->IsCleared());
528 10 : CHECK_EQ(array->Get(1).ToSmi().value(), 1);
529 :
530 5 : CHECK(array->Get(2)->GetHeapObjectIfWeak(&heap_object));
531 5 : CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2017);
532 10 : CHECK_EQ(array->Get(3).ToSmi().value(), 3);
533 :
534 10 : CHECK(array->Get(4)->IsCleared());
535 10 : CHECK_EQ(array->Get(5).ToSmi().value(), 5);
536 :
537 10 : CHECK(array->Get(6)->IsCleared());
538 10 : CHECK_EQ(array->Get(7).ToSmi().value(), 7);
539 5 : }
540 :
541 28342 : TEST(WeakArrayListRemove) {
542 : ManualGCScope manual_gc_scope;
543 5 : CcTest::InitializeVM();
544 : Isolate* isolate = CcTest::i_isolate();
545 : Factory* factory = isolate->factory();
546 5 : Heap* heap = isolate->heap();
547 : HandleScope outer_scope(isolate);
548 :
549 : Handle<WeakArrayList> array(ReadOnlyRoots(heap).empty_weak_array_list(),
550 : isolate);
551 :
552 5 : Handle<FixedArray> elem0 = factory->NewFixedArray(1);
553 5 : Handle<FixedArray> elem1 = factory->NewFixedArray(1);
554 5 : Handle<FixedArray> elem2 = factory->NewFixedArray(1);
555 :
556 : array =
557 5 : WeakArrayList::AddToEnd(isolate, array, MaybeObjectHandle::Weak(elem0));
558 : array =
559 5 : WeakArrayList::AddToEnd(isolate, array, MaybeObjectHandle::Weak(elem1));
560 : array =
561 5 : WeakArrayList::AddToEnd(isolate, array, MaybeObjectHandle::Weak(elem2));
562 :
563 5 : CHECK_EQ(array->length(), 3);
564 15 : CHECK_EQ(array->Get(0), HeapObjectReference::Weak(*elem0));
565 15 : CHECK_EQ(array->Get(1), HeapObjectReference::Weak(*elem1));
566 15 : CHECK_EQ(array->Get(2), HeapObjectReference::Weak(*elem2));
567 :
568 10 : CHECK(array->RemoveOne(MaybeObjectHandle::Weak(elem1)));
569 :
570 5 : CHECK_EQ(array->length(), 2);
571 15 : CHECK_EQ(array->Get(0), HeapObjectReference::Weak(*elem0));
572 15 : CHECK_EQ(array->Get(1), HeapObjectReference::Weak(*elem2));
573 :
574 10 : CHECK(!array->RemoveOne(MaybeObjectHandle::Weak(elem1)));
575 :
576 5 : CHECK_EQ(array->length(), 2);
577 15 : CHECK_EQ(array->Get(0), HeapObjectReference::Weak(*elem0));
578 15 : CHECK_EQ(array->Get(1), HeapObjectReference::Weak(*elem2));
579 :
580 10 : CHECK(array->RemoveOne(MaybeObjectHandle::Weak(elem0)));
581 :
582 5 : CHECK_EQ(array->length(), 1);
583 15 : CHECK_EQ(array->Get(0), HeapObjectReference::Weak(*elem2));
584 :
585 10 : CHECK(array->RemoveOne(MaybeObjectHandle::Weak(elem2)));
586 :
587 5 : CHECK_EQ(array->length(), 0);
588 5 : }
589 :
590 28342 : TEST(Regress7768) {
591 5 : i::FLAG_allow_natives_syntax = true;
592 5 : i::FLAG_turbo_inlining = false;
593 5 : if (!FLAG_incremental_marking) {
594 0 : return;
595 : }
596 : ManualGCScope manual_gc_scope;
597 5 : CcTest::InitializeVM();
598 10 : LocalContext context;
599 : Isolate* isolate = CcTest::i_isolate();
600 5 : Heap* heap = isolate->heap();
601 : HandleScope outer_scope(isolate);
602 : // Create an optimized code which will contain a weak reference to another
603 : // function ("f"). The weak reference is the only reference to the function.
604 : CompileRun(
605 : "function myfunc(f) { f(); } "
606 : "(function wrapper() { "
607 : " function f() {}; myfunc(f); myfunc(f); "
608 : " %OptimizeFunctionOnNextCall(myfunc); myfunc(f); "
609 : " %ClearFunctionFeedback(wrapper);"
610 : "})(); "
611 : "%ClearFunctionFeedback(myfunc);");
612 :
613 : // Do marking steps; this will store the objects pointed by myfunc for later
614 : // processing.
615 5 : SimulateIncrementalMarking(heap, true);
616 :
617 : // Deoptimize the code; now the pointers inside it will be replaced with
618 : // undefined, and the weak_objects_in_code is the only place pointing to the
619 : // function f.
620 : CompileRun("%DeoptimizeFunction(myfunc);");
621 :
622 : // The object pointed to by the weak reference won't be scavenged.
623 5 : CcTest::CollectGarbage(NEW_SPACE);
624 :
625 : // Make sure the memory where it's stored is invalidated, so that we'll crash
626 : // if we try to access it.
627 5 : HeapTester::UncommitFromSpace(heap);
628 :
629 : // This used to crash when processing the dead weak reference.
630 5 : CcTest::CollectAllGarbage();
631 : }
632 :
633 28342 : TEST(PrototypeUsersBasic) {
634 5 : CcTest::InitializeVM();
635 5 : LocalContext context;
636 : Isolate* isolate = CcTest::i_isolate();
637 : Factory* factory = isolate->factory();
638 5 : Heap* heap = isolate->heap();
639 : HandleScope outer_scope(isolate);
640 :
641 : Handle<WeakArrayList> array(ReadOnlyRoots(heap).empty_weak_array_list(),
642 : isolate);
643 :
644 : // Add some objects into the array.
645 5 : int index = -1;
646 : {
647 5 : Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
648 5 : array = PrototypeUsers::Add(isolate, array, map, &index);
649 10 : CHECK_EQ(array->length(), index + 1);
650 : }
651 5 : CHECK_EQ(index, 1);
652 :
653 : int empty_index = index;
654 5 : PrototypeUsers::MarkSlotEmpty(*array, empty_index);
655 :
656 : // Even though we have an empty slot, we still add to the end.
657 5 : int last_index = index;
658 : int old_capacity = array->capacity();
659 20 : while (!array->IsFull()) {
660 10 : Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
661 10 : array = PrototypeUsers::Add(isolate, array, map, &index);
662 10 : CHECK_EQ(index, last_index + 1);
663 20 : CHECK_EQ(array->length(), index + 1);
664 10 : last_index = index;
665 : }
666 :
667 : // The next addition will fill the empty slot.
668 : {
669 5 : Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
670 5 : array = PrototypeUsers::Add(isolate, array, map, &index);
671 : }
672 5 : CHECK_EQ(index, empty_index);
673 :
674 : // The next addition will make the arrow grow again.
675 : {
676 5 : Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
677 5 : array = PrototypeUsers::Add(isolate, array, map, &index);
678 10 : CHECK_EQ(array->length(), index + 1);
679 5 : last_index = index;
680 : }
681 5 : CHECK_GT(array->capacity(), old_capacity);
682 :
683 : // Make multiple slots empty.
684 : int empty_index1 = 1;
685 : int empty_index2 = 2;
686 5 : PrototypeUsers::MarkSlotEmpty(*array, empty_index1);
687 5 : PrototypeUsers::MarkSlotEmpty(*array, empty_index2);
688 :
689 : // Fill the array (still adding to the end)
690 : old_capacity = array->capacity();
691 20 : while (!array->IsFull()) {
692 10 : Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
693 10 : array = PrototypeUsers::Add(isolate, array, map, &index);
694 10 : CHECK_EQ(index, last_index + 1);
695 20 : CHECK_EQ(array->length(), index + 1);
696 10 : last_index = index;
697 : }
698 :
699 : // Make sure we use the empty slots in (reverse) order.
700 : {
701 5 : Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
702 5 : array = PrototypeUsers::Add(isolate, array, map, &index);
703 : }
704 5 : CHECK_EQ(index, empty_index2);
705 :
706 : {
707 5 : Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
708 5 : array = PrototypeUsers::Add(isolate, array, map, &index);
709 : }
710 10 : CHECK_EQ(index, empty_index1);
711 5 : }
712 :
713 : namespace {
714 :
715 : HeapObject saved_heap_object;
716 :
717 5 : static void TestCompactCallback(HeapObject value, int old_index,
718 : int new_index) {
719 5 : saved_heap_object = value;
720 5 : CHECK_EQ(old_index, 2);
721 5 : CHECK_EQ(new_index, 1);
722 5 : }
723 :
724 : } // namespace
725 :
726 28342 : TEST(PrototypeUsersCompacted) {
727 : ManualGCScope manual_gc_scope;
728 5 : CcTest::InitializeVM();
729 10 : LocalContext context;
730 : Isolate* isolate = CcTest::i_isolate();
731 : Factory* factory = isolate->factory();
732 5 : Heap* heap = isolate->heap();
733 : HandleScope outer_scope(isolate);
734 :
735 : Handle<WeakArrayList> array(ReadOnlyRoots(heap).empty_weak_array_list(),
736 : isolate);
737 :
738 : // Add some objects into the array.
739 5 : int index = -1;
740 : Handle<Map> map_cleared_by_user =
741 5 : factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
742 5 : array = PrototypeUsers::Add(isolate, array, map_cleared_by_user, &index);
743 5 : CHECK_EQ(index, 1);
744 5 : Handle<Map> live_map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
745 5 : array = PrototypeUsers::Add(isolate, array, live_map, &index);
746 5 : CHECK_EQ(index, 2);
747 : {
748 : HandleScope inner_scope(isolate);
749 : Handle<Map> soon_dead_map =
750 5 : factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
751 5 : array = PrototypeUsers::Add(isolate, array, soon_dead_map, &index);
752 5 : CHECK_EQ(index, 3);
753 :
754 5 : array = inner_scope.CloseAndEscape(array);
755 : }
756 :
757 5 : PrototypeUsers::MarkSlotEmpty(*array, 1);
758 5 : CcTest::CollectAllGarbage();
759 10 : CHECK(array->Get(3)->IsCleared());
760 :
761 5 : CHECK_EQ(array->length(), 3 + PrototypeUsers::kFirstIndex);
762 : WeakArrayList new_array =
763 5 : PrototypeUsers::Compact(array, heap, TestCompactCallback);
764 5 : CHECK_EQ(new_array->length(), 1 + PrototypeUsers::kFirstIndex);
765 10 : CHECK_EQ(saved_heap_object, *live_map);
766 5 : }
767 :
768 : } // namespace heap
769 : } // namespace internal
770 85011 : } // namespace v8
|