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