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 }