Mercurial > hg > Members > kono > jpf-core
comparison src/main/gov/nasa/jpf/vm/GenericHeap.java @ 0:61d41facf527
initial v8 import (history reset)
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Fri, 23 Jan 2015 10:14:01 -0800 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:61d41facf527 |
---|---|
1 /* | |
2 * Copyright (C) 2014, United States Government, as represented by the | |
3 * Administrator of the National Aeronautics and Space Administration. | |
4 * All rights reserved. | |
5 * | |
6 * The Java Pathfinder core (jpf-core) platform is licensed under the | |
7 * Apache License, Version 2.0 (the "License"); you may not use this file except | |
8 * in compliance with the License. You may obtain a copy of the License at | |
9 * | |
10 * http://www.apache.org/licenses/LICENSE-2.0. | |
11 * | |
12 * Unless required by applicable law or agreed to in writing, software | |
13 * distributed under the License is distributed on an "AS IS" BASIS, | |
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 * See the License for the specific language governing permissions and | |
16 * limitations under the License. | |
17 */ | |
18 | |
19 package gov.nasa.jpf.vm; | |
20 | |
21 import java.util.ArrayList; | |
22 import java.util.HashMap; | |
23 import java.util.Iterator; | |
24 import java.util.Map; | |
25 | |
26 import gov.nasa.jpf.Config; | |
27 import gov.nasa.jpf.JPFException; | |
28 import gov.nasa.jpf.util.ArrayObjectQueue; | |
29 import gov.nasa.jpf.util.IntTable; | |
30 import gov.nasa.jpf.util.IntVector; | |
31 import gov.nasa.jpf.util.ObjectQueue; | |
32 import gov.nasa.jpf.util.Processor; | |
33 | |
34 /** | |
35 * this is an abstract root for Heap implementations, providing a standard | |
36 * mark&sweep collector, change attribute management, and generic pinDownList, | |
37 * weakReference and internString handling | |
38 * | |
39 * The concrete Heap implementors have to provide the ElementInfo collection | |
40 * and associated getters, allocators and iterators | |
41 */ | |
42 public abstract class GenericHeap implements Heap, Iterable<ElementInfo> { | |
43 | |
44 static abstract class GenericHeapMemento implements Memento<Heap> { | |
45 // those can be simply copied | |
46 int attributes; | |
47 IntVector pinDownList; | |
48 Map<Integer,IntTable<String>> internStringsMap; | |
49 | |
50 protected GenericHeapMemento (GenericHeap heap){ | |
51 // these are copy-on-first-write, so we don't have to clone | |
52 pinDownList = heap.pinDownList; | |
53 internStringsMap = heap.internStringsMap; | |
54 attributes = heap.attributes & ATTR_STORE_MASK; | |
55 | |
56 heap.setStored(); | |
57 } | |
58 | |
59 @Override | |
60 public Heap restore (Heap inSitu) { | |
61 GenericHeap heap = (GenericHeap) inSitu; | |
62 heap.pinDownList = pinDownList; | |
63 heap.internStringsMap = internStringsMap; | |
64 heap.attributes = attributes; | |
65 heap.liveBitValue = false; // always start with false after a restore | |
66 return inSitu; | |
67 } | |
68 } | |
69 | |
70 | |
71 protected class ElementInfoMarker implements Processor<ElementInfo>{ | |
72 @Override | |
73 public void process (ElementInfo ei) { | |
74 ei.markRecursive( GenericHeap.this); // this might in turn call queueMark | |
75 } | |
76 } | |
77 | |
78 protected VM vm; | |
79 | |
80 // list of pinned down references (this is only efficient for a small number of objects) | |
81 // this is copy-on-first-write | |
82 protected IntVector pinDownList; | |
83 | |
84 // interned Strings | |
85 // this is copy-on-first-write, it is created on demand upon adding the first interned string, | |
86 // and it includes IntTable per process. | |
87 protected Map<Integer,IntTable<String>> internStringsMap; | |
88 | |
89 // the usual drill - the lower 2 bytes are sticky, the upper two ones | |
90 // hold change status and transient (transition local) flags | |
91 protected int attributes; | |
92 | |
93 static final int ATTR_GC = 0x0001; | |
94 static final int ATTR_OUT_OF_MEMORY = 0x0002; | |
95 static final int ATTR_RUN_FINALIZER = 0x0004; | |
96 | |
97 static final int ATTR_ELEMENTS_CHANGED = 0x10000; | |
98 static final int ATTR_PINDOWN_CHANGED = 0x20000; | |
99 static final int ATTR_INTERN_CHANGED = 0x40000; | |
100 static final int ATTR_ATTRIBUTE_CHANGED = 0x80000; | |
101 | |
102 // masks and sets | |
103 static final int ATTR_STORE_MASK = 0x0000ffff; | |
104 static final int ATTR_ANY_CHANGED = (ATTR_ELEMENTS_CHANGED | ATTR_PINDOWN_CHANGED | ATTR_INTERN_CHANGED | ATTR_ATTRIBUTE_CHANGED); | |
105 | |
106 | |
107 //--- these objects are only used during gc | |
108 | |
109 // used to keep track of marked WeakRefs that might have to be updated (no need to restore, only transient use during gc) | |
110 protected ArrayList<ElementInfo> weakRefs; | |
111 | |
112 protected ObjectQueue<ElementInfo> markQueue = new ArrayObjectQueue<ElementInfo>(); | |
113 | |
114 // this is set to false upon backtrack/restore | |
115 protected boolean liveBitValue; | |
116 | |
117 protected ElementInfoMarker elementInfoMarker = new ElementInfoMarker(); | |
118 | |
119 // the number of live objects | |
120 // <2do> currently only defined after gc | |
121 protected int nLiveObjects; | |
122 | |
123 //--- constructors | |
124 | |
125 public GenericHeap (Config config, KernelState ks){ | |
126 vm = VM.getVM(); | |
127 | |
128 pinDownList = new IntVector(256); | |
129 attributes |= ATTR_PINDOWN_CHANGED; // no need to clone on next add | |
130 | |
131 if (config.getBoolean("vm.finalize", true)){ | |
132 attributes |= ATTR_RUN_FINALIZER; | |
133 } | |
134 | |
135 if (config.getBoolean("vm.sweep",true)){ | |
136 attributes |= ATTR_GC; | |
137 } | |
138 } | |
139 | |
140 | |
141 protected DynamicElementInfo createElementInfo (int objref, ClassInfo ci, Fields f, Monitor m, ThreadInfo ti){ | |
142 return new DynamicElementInfo( objref,ci,f,m,ti); | |
143 } | |
144 | |
145 //--- pinDown handling | |
146 protected void addToPinDownList (int objref){ | |
147 if ((attributes & ATTR_PINDOWN_CHANGED) == 0) { | |
148 pinDownList = pinDownList.clone(); | |
149 attributes |= ATTR_PINDOWN_CHANGED; | |
150 } | |
151 pinDownList.add(objref); | |
152 } | |
153 | |
154 protected void removeFromPinDownList (int objref){ | |
155 if ((attributes & ATTR_PINDOWN_CHANGED) == 0) { | |
156 pinDownList = pinDownList.clone(); | |
157 attributes |= ATTR_PINDOWN_CHANGED; | |
158 } | |
159 pinDownList.removeFirst(objref); | |
160 } | |
161 | |
162 @Override | |
163 public void registerPinDown(int objref){ | |
164 ElementInfo ei = getModifiable(objref); | |
165 if (ei != null) { | |
166 if (ei.incPinDown()){ | |
167 addToPinDownList(objref); | |
168 } | |
169 } else { | |
170 throw new JPFException("pinDown reference not a live object: " + objref); | |
171 } | |
172 } | |
173 | |
174 @Override | |
175 public void releasePinDown(int objref){ | |
176 ElementInfo ei = getModifiable(objref); | |
177 if (ei != null) { | |
178 if (ei.decPinDown()){ | |
179 removeFromPinDownList(objref); | |
180 } | |
181 } else { | |
182 throw new JPFException("pinDown reference not a live object: " + objref); | |
183 } | |
184 } | |
185 void markPinDownList (){ | |
186 if (pinDownList != null){ | |
187 int len = pinDownList.size(); | |
188 for (int i=0; i<len; i++){ | |
189 int objref = pinDownList.get(i); | |
190 queueMark(objref); | |
191 } | |
192 } | |
193 } | |
194 | |
195 //--- weak reference handling | |
196 | |
197 @Override | |
198 public void registerWeakReference (ElementInfo ei) { | |
199 if (weakRefs == null) { | |
200 weakRefs = new ArrayList<ElementInfo>(); | |
201 } | |
202 | |
203 weakRefs.add(ei); | |
204 } | |
205 | |
206 /** | |
207 * reset all weak references that now point to collected objects to 'null' | |
208 * NOTE: this implementation requires our own Reference/WeakReference implementation, to | |
209 * make sure the 'ref' field is the first one | |
210 */ | |
211 protected void cleanupWeakRefs () { | |
212 if (weakRefs != null) { | |
213 for (ElementInfo ei : weakRefs) { | |
214 Fields f = ei.getFields(); | |
215 int ref = f.getIntValue(0); // watch out, the 0 only works with our own WeakReference impl | |
216 if (ref != MJIEnv.NULL) { | |
217 ElementInfo refEi = get(ref); | |
218 if ((refEi == null) || (refEi.isNull())) { | |
219 ei = ei.getModifiableInstance(); | |
220 // we need to make sure the Fields are properly state managed | |
221 ei.setReferenceField(ei.getFieldInfo(0), MJIEnv.NULL); | |
222 } | |
223 } | |
224 } | |
225 | |
226 weakRefs = null; | |
227 } | |
228 } | |
229 | |
230 // NOTE - this is where to assert if this index isn't occupied yet, since only concrete classes know | |
231 // if there can be collisions, and how elements are stored | |
232 | |
233 protected abstract AllocationContext getSUTAllocationContext (ClassInfo ci, ThreadInfo ti); | |
234 protected abstract AllocationContext getSystemAllocationContext (ClassInfo ci, ThreadInfo ti, int anchor); | |
235 | |
236 /** | |
237 * this is called for newXX(..) allocations that are SUT thread specific, i.e. in response to | |
238 * a explicit NEW or xNEWARRAY instruction that should take the allocating thread into account | |
239 */ | |
240 protected abstract int getNewElementInfoIndex (AllocationContext ctx); | |
241 | |
242 //--- allocators | |
243 | |
244 protected ElementInfo createObject (ClassInfo ci, ThreadInfo ti, int objref) { | |
245 // create the thing itself | |
246 Fields f = ci.createInstanceFields(); | |
247 Monitor m = new Monitor(); | |
248 ElementInfo ei = createElementInfo( objref, ci, f, m, ti); | |
249 | |
250 set(objref, ei); | |
251 | |
252 attributes |= ATTR_ELEMENTS_CHANGED; | |
253 | |
254 // and do the default (const) field initialization | |
255 ci.initializeInstanceData(ei, ti); | |
256 | |
257 vm.notifyObjectCreated(ti, ei); | |
258 | |
259 // note that we don't return -1 if 'outOfMemory' (which is handled in | |
260 // the NEWxx bytecode) because our allocs are used from within the | |
261 // exception handling of the resulting OutOfMemoryError (and we would | |
262 // have to override it, since the VM should guarantee proper exceptions) | |
263 | |
264 return ei; | |
265 } | |
266 | |
267 @Override | |
268 public ElementInfo newObject(ClassInfo ci, ThreadInfo ti) { | |
269 AllocationContext ctx = getSUTAllocationContext( ci, ti); | |
270 int index = getNewElementInfoIndex( ctx); | |
271 ElementInfo ei = createObject( ci, ti, index); | |
272 | |
273 return ei; | |
274 } | |
275 | |
276 @Override | |
277 public ElementInfo newSystemObject (ClassInfo ci, ThreadInfo ti, int anchor) { | |
278 AllocationContext ctx = getSystemAllocationContext( ci, ti, anchor); | |
279 int index = getNewElementInfoIndex( ctx); | |
280 ElementInfo ei = createObject( ci, ti, index); | |
281 return ei; | |
282 } | |
283 | |
284 protected ElementInfo createArray (String elementType, int nElements, ClassInfo ci, ThreadInfo ti, int objref) { | |
285 | |
286 Fields f = ci.createArrayFields(ci.getName(), nElements, Types.getTypeSize(elementType), Types.isReference(elementType)); | |
287 Monitor m = new Monitor(); | |
288 DynamicElementInfo ei = createElementInfo( objref, ci, f, m, ti); | |
289 | |
290 set(objref, ei); | |
291 | |
292 attributes |= ATTR_ELEMENTS_CHANGED; | |
293 | |
294 vm.notifyObjectCreated(ti, ei); | |
295 | |
296 return ei; | |
297 } | |
298 | |
299 protected ClassInfo getArrayClassInfo (ThreadInfo ti, String elementType) { | |
300 String type = "[" + elementType; | |
301 SystemClassLoaderInfo sysCl = ti.getSystemClassLoaderInfo(); | |
302 ClassInfo ciArray = sysCl.getResolvedClassInfo(type); | |
303 | |
304 if (!ciArray.isInitialized()) { | |
305 // we do this explicitly here since there are no clinits for array classes | |
306 ciArray.registerClass(ti); | |
307 ciArray.setInitialized(); | |
308 } | |
309 | |
310 return ciArray; | |
311 } | |
312 | |
313 @Override | |
314 public ElementInfo newArray(String elementType, int nElements, ThreadInfo ti) { | |
315 // see newObject for OOM simulation | |
316 ClassInfo ci = getArrayClassInfo(ti, elementType); | |
317 AllocationContext ctx = getSUTAllocationContext( ci, ti); | |
318 | |
319 int index = getNewElementInfoIndex( ctx); | |
320 ElementInfo ei = createArray( elementType, nElements, ci, ti, index); | |
321 | |
322 return ei; | |
323 } | |
324 | |
325 @Override | |
326 public ElementInfo newSystemArray(String elementType, int nElements, ThreadInfo ti, int anchor) { | |
327 // see newObject for OOM simulation | |
328 ClassInfo ci = getArrayClassInfo(ti, elementType); | |
329 AllocationContext ctx = getSystemAllocationContext( ci, ti, anchor); | |
330 | |
331 int index = getNewElementInfoIndex( ctx); | |
332 ElementInfo ei = createArray( elementType, nElements, ci, ti, index); | |
333 | |
334 return ei; | |
335 } | |
336 | |
337 | |
338 | |
339 protected ElementInfo initializeStringObject( String str, int index, int vref) { | |
340 ElementInfo ei = getModifiable(index); | |
341 ei.setReferenceField("value", vref); | |
342 | |
343 ElementInfo eVal = getModifiable(vref); | |
344 CharArrayFields cf = (CharArrayFields)eVal.getFields(); | |
345 cf.setCharValues(str.toCharArray()); | |
346 | |
347 return ei; | |
348 } | |
349 | |
350 protected ElementInfo newString (ClassInfo ciString, ClassInfo ciChars, String str, ThreadInfo ti, AllocationContext ctx) { | |
351 | |
352 //--- the string object itself | |
353 int sRef = getNewElementInfoIndex( ctx); | |
354 createObject( ciString, ti, sRef); | |
355 | |
356 //--- its char[] array | |
357 ctx = ctx.extend(ciChars, sRef); | |
358 int vRef = getNewElementInfoIndex( ctx); | |
359 createArray( "C", str.length(), ciChars, ti, vRef); | |
360 | |
361 ElementInfo ei = initializeStringObject(str, sRef, vRef); | |
362 return ei; | |
363 } | |
364 | |
365 @Override | |
366 public ElementInfo newString(String str, ThreadInfo ti){ | |
367 if (str != null) { | |
368 SystemClassLoaderInfo sysCl = ti.getSystemClassLoaderInfo(); | |
369 ClassInfo ciString = sysCl.getStringClassInfo(); | |
370 ClassInfo ciChars = sysCl.getCharArrayClassInfo(); | |
371 | |
372 AllocationContext ctx = getSUTAllocationContext( ciString, ti); | |
373 return newString( ciString, ciChars, str, ti, ctx); | |
374 | |
375 } else { | |
376 return null; | |
377 } | |
378 } | |
379 | |
380 @Override | |
381 public ElementInfo newSystemString (String str, ThreadInfo ti, int anchor) { | |
382 if (str != null) { | |
383 SystemClassLoaderInfo sysCl = ti.getSystemClassLoaderInfo(); | |
384 ClassInfo ciString = sysCl.getStringClassInfo(); | |
385 ClassInfo ciChars = sysCl.getCharArrayClassInfo(); | |
386 | |
387 AllocationContext ctx = getSystemAllocationContext( ciString, ti, anchor); | |
388 return newString( ciString, ciChars, str, ti, ctx); | |
389 | |
390 } else { | |
391 return null; | |
392 } | |
393 } | |
394 | |
395 @Override | |
396 public ElementInfo newInternString (String str, ThreadInfo ti) { | |
397 if(internStringsMap==null) { | |
398 internStringsMap = vm.getInitialInternStringsMap(); | |
399 } | |
400 | |
401 int prcId = ti.getApplicationContext().getId(); | |
402 IntTable.Entry<String> e = internStringsMap.get(prcId).get(str); | |
403 | |
404 if (e == null){ | |
405 if (str != null) { | |
406 ElementInfo ei = newString( str, ti); | |
407 int index = ei.getObjectRef(); | |
408 | |
409 // new interned Strings are always pinned down | |
410 ei.incPinDown(); | |
411 addToPinDownList(index); | |
412 addToInternStrings(str, index, prcId); | |
413 | |
414 return ei; | |
415 | |
416 } else { | |
417 return null; | |
418 } | |
419 | |
420 } else { | |
421 return get(e.val); | |
422 } | |
423 } | |
424 | |
425 protected void addToInternStrings (String str, int objref, int prcId) { | |
426 if ((attributes & ATTR_INTERN_CHANGED) == 0){ | |
427 // shallow copy all interned strings tables | |
428 internStringsMap = new HashMap<Integer,IntTable<String>>(internStringsMap); | |
429 | |
430 // only clone the interned strings table of the current process | |
431 internStringsMap.put(prcId, internStringsMap.get(prcId).clone()); | |
432 | |
433 // just cloned, no need to clone on the next add | |
434 attributes |= ATTR_INTERN_CHANGED; | |
435 } | |
436 internStringsMap.get(prcId).add(str, objref); | |
437 } | |
438 | |
439 | |
440 @Override | |
441 public ElementInfo newSystemThrowable (ClassInfo ciThrowable, String details, int[] stackSnapshot, int causeRef, | |
442 ThreadInfo ti, int anchor) { | |
443 SystemClassLoaderInfo sysCl = ti.getSystemClassLoaderInfo(); | |
444 ClassInfo ciString = sysCl.getStringClassInfo(); | |
445 ClassInfo ciChars = sysCl.getCharArrayClassInfo(); | |
446 | |
447 //--- the Throwable object itself | |
448 AllocationContext ctx = getSystemAllocationContext( ciThrowable, ti, anchor); | |
449 int xRef = getNewElementInfoIndex( ctx); | |
450 ElementInfo eiThrowable = createObject( ciThrowable, ti, xRef); | |
451 | |
452 //--- the detailMsg field | |
453 if (details != null) { | |
454 AllocationContext ctxString = ctx.extend( ciString, xRef); | |
455 ElementInfo eiMsg = newString( ciString, ciChars, details, ti, ctxString); | |
456 eiThrowable.setReferenceField("detailMessage", eiMsg.getObjectRef()); | |
457 } | |
458 | |
459 //--- the stack snapshot field | |
460 ClassInfo ciSnap = getArrayClassInfo(ti, "I"); | |
461 AllocationContext ctxSnap = ctx.extend(ciSnap, xRef); | |
462 int snapRef = getNewElementInfoIndex( ctxSnap); | |
463 ElementInfo eiSnap = createArray( "I", stackSnapshot.length, ciSnap, ti, snapRef); | |
464 int[] snap = eiSnap.asIntArray(); | |
465 System.arraycopy( stackSnapshot, 0, snap, 0, stackSnapshot.length); | |
466 eiThrowable.setReferenceField("snapshot", snapRef); | |
467 | |
468 //--- the cause field | |
469 eiThrowable.setReferenceField("cause", (causeRef != MJIEnv.NULL)? causeRef : xRef); | |
470 | |
471 return eiThrowable; | |
472 } | |
473 | |
474 | |
475 //--- abstract accessors | |
476 | |
477 /* | |
478 * these methods abstract away the container type used in GenericHeap subclasses | |
479 */ | |
480 | |
481 /** | |
482 * internal setter used during allocation | |
483 * @param index | |
484 * @param ei | |
485 */ | |
486 protected abstract void set (int index, ElementInfo ei); | |
487 | |
488 /** | |
489 * public getter to access but not change ElementInfos | |
490 */ | |
491 @Override | |
492 public abstract ElementInfo get (int ref); | |
493 | |
494 | |
495 /** | |
496 * public getter to access modifiable ElementInfos; | |
497 */ | |
498 @Override | |
499 public abstract ElementInfo getModifiable (int ref); | |
500 | |
501 | |
502 /** | |
503 * internal remover used by generic sweep | |
504 */ | |
505 protected abstract void remove (int ref); | |
506 | |
507 | |
508 //--- iterators | |
509 | |
510 /** | |
511 * return Iterator for all non-null ElementInfo entries | |
512 */ | |
513 @Override | |
514 public abstract Iterator<ElementInfo> iterator(); | |
515 | |
516 @Override | |
517 public abstract Iterable<ElementInfo> liveObjects(); | |
518 | |
519 | |
520 //--- garbage collection | |
521 | |
522 public boolean isGcEnabled (){ | |
523 return (attributes & ATTR_GC) != 0; | |
524 } | |
525 | |
526 public void setGcEnabled (boolean doGC) { | |
527 if (doGC != isGcEnabled()) { | |
528 if (doGC) { | |
529 attributes |= ATTR_GC; | |
530 } else { | |
531 attributes &= ~ATTR_GC; | |
532 } | |
533 attributes |= ATTR_ATTRIBUTE_CHANGED; | |
534 } | |
535 } | |
536 | |
537 @Override | |
538 public void unmarkAll(){ | |
539 for (ElementInfo ei : liveObjects()){ | |
540 ei.setUnmarked(); | |
541 } | |
542 } | |
543 | |
544 /** | |
545 * add a non-null, not yet marked reference to the markQueue | |
546 * | |
547 * called from ElementInfo.markRecursive(). We don't want to expose the | |
548 * markQueue since a copying collector might not have it | |
549 */ | |
550 @Override | |
551 public void queueMark (int objref){ | |
552 if (objref == MJIEnv.NULL) { | |
553 return; | |
554 } | |
555 | |
556 ElementInfo ei = get(objref); | |
557 if (!ei.isMarked()){ // only add objects once | |
558 ei.setMarked(); | |
559 markQueue.add(ei); | |
560 } | |
561 } | |
562 | |
563 /** | |
564 * called during non-recursive phase1 marking of all objects reachable | |
565 * from static fields | |
566 * @aspects: gc | |
567 */ | |
568 @Override | |
569 public void markStaticRoot (int objref) { | |
570 if (objref != MJIEnv.NULL) { | |
571 queueMark(objref); | |
572 } | |
573 } | |
574 | |
575 /** | |
576 * called during non-recursive phase1 marking of all objects reachable | |
577 * from Thread roots | |
578 * @aspects: gc | |
579 */ | |
580 @Override | |
581 public void markThreadRoot (int objref, int tid) { | |
582 if (objref != MJIEnv.NULL) { | |
583 queueMark(objref); | |
584 } | |
585 } | |
586 | |
587 /** | |
588 * this implementation uses a generic ElementInfo iterator, it can be replaced | |
589 * with a more efficient container specific version | |
590 */ | |
591 protected void sweep () { | |
592 ThreadInfo ti = vm.getCurrentThread(); | |
593 int tid = ti.getId(); | |
594 boolean isThreadTermination = ti.isTerminated(); | |
595 int n = 0; | |
596 | |
597 if(vm.finalizersEnabled()) { | |
598 markFinalizableObjects(); | |
599 } | |
600 | |
601 // now go over all objects, purge the ones that are not live and reset attrs for rest | |
602 for (ElementInfo ei : this){ | |
603 | |
604 if (ei.isMarked()){ // live object, prepare for next transition & gc cycle | |
605 ei.setUnmarked(); | |
606 ei.setAlive(liveBitValue); | |
607 | |
608 ei.cleanUp(this, isThreadTermination, tid); | |
609 n++; | |
610 | |
611 } else { | |
612 ei.processReleaseActions(); | |
613 | |
614 vm.notifyObjectReleased(ti, ei); | |
615 remove(ei.getObjectRef()); | |
616 } | |
617 } | |
618 | |
619 nLiveObjects = n; | |
620 } | |
621 | |
622 protected void markFinalizableObjects () { | |
623 FinalizerThreadInfo tiFinalizer = vm.getFinalizerThread(); | |
624 | |
625 if (tiFinalizer != null){ | |
626 for (ElementInfo ei : this) { | |
627 if (!ei.isMarked() && ei.hasFinalizer() && !ei.isFinalized()) { | |
628 ei = tiFinalizer.getFinalizerQueuedInstance(ei); | |
629 ei.setMarked(); // make sure it's not collected before the finalizerQueue has been processed | |
630 ei.markRecursive(this); | |
631 } | |
632 } | |
633 } | |
634 } | |
635 | |
636 protected void mark () { | |
637 markQueue.clear(); | |
638 | |
639 //--- mark everything in our root set | |
640 markPinDownList(); | |
641 vm.getThreadList().markRoots(this); // mark thread stacks | |
642 vm.getClassLoaderList().markRoots(this); // mark all static references | |
643 | |
644 //--- trace all entries - this gets recursive | |
645 markQueue.process(elementInfoMarker); | |
646 } | |
647 | |
648 @Override | |
649 public void gc() { | |
650 vm.notifyGCBegin(); | |
651 | |
652 weakRefs = null; | |
653 liveBitValue = !liveBitValue; | |
654 | |
655 mark(); | |
656 | |
657 // at this point all live objects are marked | |
658 sweep(); | |
659 | |
660 cleanupWeakRefs(); // for potential nullification | |
661 | |
662 vm.processPostGcActions(); | |
663 vm.notifyGCEnd(); | |
664 } | |
665 | |
666 /** | |
667 * clean up reference values that are stored outside of reference fields | |
668 * called from KernelState to process live ElementInfos after GC has finished | |
669 * and only live objects remain in the heap. | |
670 * | |
671 * <2do> full heap enumeration is BAD - check if this can be moved into the sweep loop | |
672 */ | |
673 @Override | |
674 public void cleanUpDanglingReferences() { | |
675 ThreadInfo ti = ThreadInfo.getCurrentThread(); | |
676 int tid = ti.getId(); | |
677 boolean isThreadTermination = ti.isTerminated(); | |
678 | |
679 for (ElementInfo e : this) { | |
680 if (e != null) { | |
681 e.cleanUp(this, isThreadTermination, tid); | |
682 } | |
683 } | |
684 } | |
685 | |
686 /** | |
687 * check if object is alive. This is here and not in ElementInfo | |
688 * because we might own the liveness bit. In fact, the generic | |
689 * implementation uses bit-toggle to avoid iteration over all live | |
690 * objects at the end of GC | |
691 */ | |
692 @Override | |
693 public boolean isAlive (ElementInfo ei){ | |
694 return (ei == null || ei.isMarkedOrAlive(liveBitValue)); | |
695 } | |
696 | |
697 //--- state management | |
698 | |
699 // since we can't provide generic implementations, we force concrete subclasses to | |
700 // handle volatile information | |
701 | |
702 @Override | |
703 public abstract void resetVolatiles(); | |
704 | |
705 @Override | |
706 public abstract void restoreVolatiles(); | |
707 | |
708 @Override | |
709 public boolean hasChanged() { | |
710 return (attributes & ATTR_ANY_CHANGED) != 0; | |
711 } | |
712 | |
713 @Override | |
714 public void markChanged(int objref) { | |
715 attributes |= ATTR_ELEMENTS_CHANGED; | |
716 } | |
717 | |
718 public void setStored() { | |
719 attributes &= ~ATTR_ANY_CHANGED; | |
720 } | |
721 | |
722 @Override | |
723 public abstract Memento<Heap> getMemento(MementoFactory factory); | |
724 | |
725 @Override | |
726 public abstract Memento<Heap> getMemento(); | |
727 | |
728 | |
729 //--- out of memory simulation | |
730 | |
731 @Override | |
732 public boolean isOutOfMemory() { | |
733 return (attributes & ATTR_OUT_OF_MEMORY) != 0; | |
734 } | |
735 | |
736 @Override | |
737 public void setOutOfMemory(boolean isOutOfMemory) { | |
738 if (isOutOfMemory != isOutOfMemory()) { | |
739 if (isOutOfMemory) { | |
740 attributes |= ATTR_OUT_OF_MEMORY; | |
741 } else { | |
742 attributes &= ~ATTR_OUT_OF_MEMORY; | |
743 } | |
744 attributes |= ATTR_ATTRIBUTE_CHANGED; | |
745 } | |
746 } | |
747 | |
748 | |
749 | |
750 //--- debugging | |
751 | |
752 @Override | |
753 public void checkConsistency(boolean isStateStore) { | |
754 for (ElementInfo ei : this){ | |
755 ei.checkConsistency(); | |
756 } | |
757 } | |
758 } |