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