1 31 package org.jruby.runtime; 32 33 import org.jruby.RubyModule; 34 import org.jruby.RubyProc; 35 import org.jruby.runtime.builtin.IRubyObject; 36 import org.jruby.util.WeakIdentityHashMap; 37 38 import java.lang.ref.ReferenceQueue ; 39 import java.lang.ref.WeakReference ; 40 import java.util.ArrayList ; 41 import java.util.HashMap ; 42 import java.util.Iterator ; 43 import java.util.List ; 44 import java.util.Map ; 45 46 54 public class ObjectSpace { 55 private ReferenceQueue deadReferences = new ReferenceQueue (); 56 private WeakReferenceListNode top; 57 58 private ReferenceQueue deadIdentityReferences = new ReferenceQueue (); 59 private final Map identities = new HashMap(); 60 private final Map identitiesByObject = new WeakIdentityHashMap(); 61 62 private long maxId = 4; 64 public long idOf(IRubyObject rubyObject) { 65 synchronized (identities) { 66 Long longId = (Long ) identitiesByObject.get(rubyObject); 67 if (longId == null) { 68 longId = createId(rubyObject); 69 } 70 return longId.longValue(); 71 } 72 } 73 74 private Long createId(IRubyObject object) { 75 cleanIdentities(); 76 maxId += 2; Long longMaxId = new Long (maxId); 78 identities.put(longMaxId, new IdReference(object, maxId, deadIdentityReferences)); 79 identitiesByObject.put(object, longMaxId); 80 return longMaxId; 81 } 82 83 public IRubyObject id2ref(long id) { 84 synchronized (identities) { 85 cleanIdentities(); 86 IdReference reference = (IdReference) identities.get(new Long (id)); 87 if (reference == null) 88 return null; 89 return (IRubyObject) reference.get(); 90 } 91 } 92 93 private void cleanIdentities() { 94 IdReference ref; 95 while ((ref = (IdReference) deadIdentityReferences.poll()) != null) 96 identities.remove(new Long (ref.id())); 97 } 98 99 private Map finalizers = new HashMap(); 100 private Map weakRefs = new HashMap(); 101 private List finalizersToRun = new ArrayList (); 102 private Thread finalizerThread = new FinalizerThread(); 103 104 { 105 finalizerThread.start(); 106 } 107 108 private class FinalizerThread extends Thread { 109 public FinalizerThread() { 110 super("Ruby Finalizer Thread"); 111 setDaemon(true); 112 } 113 public void run() { 114 while(true) { 115 try { 116 synchronized(finalizersToRun) { 117 while(finalizersToRun.isEmpty()) { 118 try { 119 finalizersToRun.wait(); 120 } catch(InterruptedException e) { 121 } 122 } 123 while(!finalizersToRun.isEmpty()) { 124 ((Runnable )finalizersToRun.remove(0)).run(); 125 } 126 finalizersToRun.notify(); 127 } 128 } catch(Exception e) { 129 } 131 } 132 } 133 } 134 135 136 private class FinalizerEntry implements Runnable { 137 private long id; 138 private RubyProc proc; 139 private IRubyObject fid; 140 public FinalizerEntry(IRubyObject obj, long id, RubyProc proc) { 141 this.id = id; 142 this.proc = proc; 143 this.fid = proc.getRuntime().newFixnum(id); 144 synchronized(ObjectSpace.this) { 145 FinalizerWeakReferenceListNode node = new FinalizerWeakReferenceListNode(obj,deadReferences,top,this); 146 Long key = new Long (id); 147 List refl = (List )weakRefs.get(key); 148 if(null == refl) { 149 refl = new ArrayList (); 150 weakRefs.put(key,refl); 151 } 152 refl.add(node); 153 top = node; 154 } 155 } 156 157 public void finalize(FinalizerWeakReferenceListNode obj) { 158 synchronized(ObjectSpace.this) { 159 List refl = (List )weakRefs.get(new Long (id)); 160 refl.remove(obj); 161 obj.setRan(); 162 } 163 _finalize(); 164 } 165 166 public void _finalize() { 167 synchronized(finalizersToRun) { 168 finalizersToRun.add(this); 169 finalizersToRun.notifyAll(); 170 } 171 } 172 173 public void run() { 174 proc.call(new IRubyObject[]{fid}); 175 } 176 } 177 178 public void finishFinalizers() { 179 for(Iterator iter = finalizers.keySet().iterator();iter.hasNext();) { 180 Object key = iter.next(); 181 for(Iterator iter2 = ((List )finalizers.get(key)).iterator();iter2.hasNext();) { 182 ((FinalizerEntry)iter2.next())._finalize(); 183 } 184 } 185 synchronized(finalizersToRun) { 186 while(!finalizersToRun.isEmpty()) { 187 finalizersToRun.notify(); 188 try { 189 finalizersToRun.wait(); 190 } catch (InterruptedException e) { 191 Thread.currentThread().interrupt(); 192 } 193 } 194 } 195 } 196 197 public synchronized void addFinalizer(IRubyObject obj, long id, RubyProc proc) { 198 List fins = (List )finalizers.get(new Long (id)); 199 if(fins == null) { 200 fins = new ArrayList (); 201 finalizers.put(new Long (id),fins); 202 } 203 fins.add(new FinalizerEntry(obj,id,proc)); 204 } 205 206 public synchronized void removeFinalizers(long id) { 207 finalizers.remove(new Long (id)); 208 List refl = (List )weakRefs.get(new Long (id)); 209 if(null != refl) { 210 for(Iterator iter = refl.iterator();iter.hasNext();) { 211 ((FinalizerWeakReferenceListNode)(iter.next())).setRan(); 212 } 213 } 214 weakRefs.remove(new Long (id)); 215 } 216 217 public synchronized void add(IRubyObject object) { 218 cleanup(); 219 top = new WeakReferenceListNode(object, deadReferences, top); 220 } 221 222 public synchronized Iterator iterator(RubyModule rubyClass) { 223 final List objList = new ArrayList (); 224 WeakReferenceListNode current = top; 225 while (current != null) { 226 IRubyObject obj = (IRubyObject)current.get(); 227 if (obj != null && obj.isKindOf(rubyClass)) { 228 objList.add(current); 229 } 230 231 current = current.next; 232 } 233 234 return new Iterator () { 235 private Iterator iter = objList.iterator(); 236 237 public boolean hasNext() { 238 throw new UnsupportedOperationException (); 239 } 240 241 public Object next() { 242 Object obj = null; 243 while (iter.hasNext()) { 244 WeakReferenceListNode node = (WeakReferenceListNode)iter.next(); 245 246 if(node instanceof FinalizerWeakReferenceListNode) { 247 continue; 248 } 249 250 obj = node.get(); 251 252 if (obj != null) break; 253 } 254 return obj; 255 } 256 257 public void remove() { 258 throw new UnsupportedOperationException (); 259 } 260 }; 261 } 262 263 private synchronized void cleanup() { 264 WeakReferenceListNode reference; 265 while ((reference = (WeakReferenceListNode)deadReferences.poll()) != null) { 266 reference.remove(); 267 } 268 } 269 270 private class WeakReferenceListNode extends WeakReference { 271 public WeakReferenceListNode prev; 272 public WeakReferenceListNode next; 273 public WeakReferenceListNode(Object ref, ReferenceQueue queue, WeakReferenceListNode next) { 274 super(ref, queue); 275 276 this.next = next; 277 if (next != null) { 278 next.prev = this; 279 } 280 } 281 282 public void remove() { 283 synchronized (ObjectSpace.this) { 284 if (prev != null) { 285 prev.next = next; 286 } 287 if (next != null) { 288 next.prev = prev; 289 } 290 } 291 } 292 } 293 294 private class FinalizerWeakReferenceListNode extends WeakReferenceListNode { 295 private FinalizerEntry entry; 296 private boolean ran = false; 297 public FinalizerWeakReferenceListNode(Object ref, ReferenceQueue queue, WeakReferenceListNode next, FinalizerEntry entry) { 298 super(ref, queue, next); 299 this.entry = entry; 300 } 301 public void remove() { 302 super.remove(); 303 if(!ran) { 304 entry.finalize(this); 305 } 306 } 307 public void setRan() { 308 this.ran = true; 309 } 310 } 311 312 private static class IdReference extends WeakReference { 313 private final long id; 314 315 public IdReference(IRubyObject object, long id, ReferenceQueue queue) { 316 super(object, queue); 317 this.id = id; 318 } 319 320 public long id() { 321 return id; 322 } 323 } 324 } 325 | Popular Tags |