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