001 // MemoryArea.java, created by wbeebee 002 // Copyright (C) 2001 Wes Beebee <wbeebee@mit.edu> 003 // Licensed under the terms of the GNU GPL; see COPYING for details. 004 package javax.realtime; 005 006 import java.lang.reflect.Array; 007 import java.lang.reflect.Constructor; 008 import java.lang.reflect.InvocationTargetException; 009 010 /** 011 * @author Wes Beebee <<a href="mailto:wbeebee@mit.edu">wbeebee@mit.edu</a>> 012 */ 013 014 /** <code>MemoryArea</code> is the abstract base class of all classes dealing 015 * with the representations of allocatable memory areas, including the 016 * immortal memory area, physical memory and scoped memory areas. 017 */ 018 public abstract class MemoryArea { 019 020 /** The size of this MemoryArea. */ 021 protected long size; 022 023 /** The size of the consumed memory */ 024 // Size is somewhat inaccurate 025 protected long memoryConsumed; 026 027 /** Indicates whether this is a ScopedMemory. */ 028 boolean scoped; 029 030 /** Indicates whether this is a HeapMemory. */ 031 boolean heap; 032 033 /** Indicates whether this is a NullMemoryArea. */ 034 protected boolean nullMem; 035 036 /** Every MemoryArea has a unique ID. */ 037 protected int id; 038 039 /** The run() method of this object is called whenever enter() is called. */ 040 protected Runnable logic; 041 042 /** This is used to create the unique ID. */ 043 private static int num = 0; 044 045 /** Indicates whether this memoryArea refers to a constant or not. 046 * This is set by the compiler. 047 */ 048 boolean constant; 049 050 /** The shadow of <code>this</code>. */ 051 MemoryArea shadow; 052 053 abstract protected void initNative(long sizeInBytes); 054 055 /** Create an instance of <code>MemoryArea</code>. 056 * 057 * @param sizeInBytes The size of <code>MemoryArea</code> to allocate, in bytes. 058 */ 059 protected MemoryArea(long sizeInBytes) { 060 size = sizeInBytes; 061 preSetup(); 062 initNative(sizeInBytes); 063 postSetup(); 064 } 065 066 protected void preSetup() { 067 scoped = false; 068 heap = false; 069 id = num++; 070 constant = false; 071 nullMem = false; 072 } 073 074 protected void postSetup() { 075 (shadow = shadow()).shadow = shadow; 076 registerFinal(); 077 } 078 079 // Do we really need this abstract method? 080 // protected abstract void initNative(long sizeInBytes); 081 082 /** Create an instance of <code>MemoryArea</code>. 083 * 084 * @param sizeInBytes The size of <code>MemoryArea</code> to allocate, in bytes. 085 * @param logic The <code>run()</code> method of this object will be called 086 * whenever <code>enter()</code> is called. 087 */ 088 protected MemoryArea(long sizeInBytes, Runnable logic) { 089 this(sizeInBytes); 090 this.logic = logic; 091 } 092 093 /** Create an instance of <code>MemoryArea</code>. 094 * 095 * @param size A <code>SizeEstimator</code> object which indicates the amount 096 * of memory required by this <code>MemoryArea</code>. 097 */ 098 protected MemoryArea(SizeEstimator size) { 099 this(size.getEstimate()); 100 } 101 102 /** Create an instance of <code>MemoryArea</code>. 103 * 104 * @param size A <code>SizeEstimator</code> object which indicates the amount 105 * of memory required by this <code>MemoryArea</code>. 106 * @param logic The <code>run()</code> method of this object will be called 107 * whenever <code>enter()</code> is called. 108 */ 109 protected MemoryArea(SizeEstimator size, 110 Runnable logic) { 111 this(size); 112 this.logic = logic; 113 } 114 115 /** Associate this memory area to the current real-time thread for the 116 * duration of the execution of the <code>run()</code> method of the 117 * <code>java.lang.Runnable</code> passed at construction time. During 118 * this bound period of execution, all objects are allocated from the 119 * memory area until another one takes effect, or the <code>enter()</code> 120 * method is exited. A runtime exception is thrown if this method is 121 * called from thread other than a <code>RealtimeThread</code> or 122 * <code>NoHeapRealtimeThrea</code>. 123 * 124 * @throws java.lang.IllegalArgumentException Thrown if no <code>Runnable</code> 125 * was passed in the constructor. 126 */ 127 public void enter() { 128 enter(this.logic); 129 } 130 131 /** Associate this memory area to the current real-time thread for the 132 * duration of the execution of the <code>run()</code> method of the 133 * <code>java.lang.Runnable</code> passed at construction time. During 134 * this bound period of execution, all objects are allocated from the 135 * memory area until another one takes effect, or the <code>enter()</code> 136 * method is exited. A runtime exception is thrown if this method is 137 * called from thread other than a <code>RealtimeThread</code> or 138 * <code>NoHeapRealtimeThrea</code>. 139 * 140 * @param logic The <code>Runnable</code> object whose <code>run()</code> 141 * method should be invoked. 142 */ 143 public void enter(Runnable logic) { 144 RealtimeThread.checkInit(); 145 RealtimeThread current = RealtimeThread.currentRealtimeThread(); 146 MemoryArea oldMem = current.memoryArea(); 147 current.enter(shadow, this); 148 try { 149 logic.run(); 150 } catch (Throwable e) { 151 try { 152 e.memoryArea = getMemoryArea(e); 153 oldMem.checkAccess(e); 154 } catch (Exception checkException) { 155 current.exitMem(); 156 throw new ThrowBoundaryError("An exception occurred that was " + 157 "allocated in an inner scope that " + 158 "just exited."); 159 } 160 current.exitMem(); 161 throw new ThrowBoundaryError(e.toString()); 162 } 163 current.exitMem(); 164 } 165 166 /** Execute the <code>run()</code> method from the <code>logic</code> parameter 167 * using this memory area as the current allocation context. If the memory 168 * area is a scoped memory type, this method behaves as if it had moved the 169 * allocation context up the scope stack to the occurrence of the memory area. 170 * If the memory area is heap or immortal memory, this method behaves as if 171 * the <code>run()</code> method were running in that memory type with an 172 * empty scope stack. 173 * 174 * @param logic The runnable object whose <code>run()</code> method should be 175 * executed. 176 * @throws IllegalStateException A non-realtime thread attempted to enter the 177 * memory area. 178 * @throws InaccessibleAreaException The memory area is not in the thread's 179 * scope stack. 180 */ 181 public void executeInArea(Runnable logic) 182 throws InaccessibleAreaException { 183 enter(logic); // In our system, this is a subset of enter for all practical purposes... 184 } 185 186 /** Gets the <code>MemoryArea</code> in which the given object is located. 187 * 188 * @return The current instance of <code>MemoryArea</code> of the object. 189 */ 190 public static MemoryArea getMemoryArea(Object object) { 191 if (object == null) { 192 return ImmortalMemory.instance(); 193 } 194 MemoryArea mem = object.memoryArea; 195 if (mem == null) { // Native methods return objects 196 // allocated out of the current scope. 197 return RealtimeThread.currentRealtimeThread().memoryArea(); 198 } 199 if (mem.constant) { 200 // Constants are allocated out of ImmortalMemory 201 // Also, static objects before RTJ is setup... 202 return ImmortalMemory.instance(); 203 } 204 return mem; 205 } 206 207 /** An exact count, in bytes, of the all of the memory currently used by the 208 * system for the allocated objects. 209 * 210 * @return The amount of memory consumed. 211 */ 212 public long memoryConsumed() { 213 return memoryConsumed; 214 } 215 216 /** An approximation to the total amount of memory currently available for 217 * future allocated objects, measured in bytes. 218 * 219 * @return The amount of remaining memory in bytes. 220 */ 221 public long memoryRemaining() { 222 return size() - memoryConsumed(); 223 } 224 225 protected native Object newArray(RealtimeThread rt, 226 Class type, 227 int number); 228 protected native Object newArray(RealtimeThread rt, 229 Class type, int[] dimensions); 230 231 /** Allocate an array of the given type in this memory area. 232 * 233 * @param type The class of the elements of the new array. 234 * @param number The number of elements in the new array. 235 * @throws java.lang.IllegalAccessException The class or initializer is 236 * inaccessible. 237 * @throws java.lang.InstantiationException The array cannot be instantiated. 238 * @throws OutOfMemoryError Space in the memory area is exhaused. 239 */ 240 public Object newArray(final Class type, final int number) 241 throws IllegalAccessException, InstantiationException, 242 OutOfMemoryError { 243 RealtimeThread.checkInit(); 244 RealtimeThread rt = RealtimeThread.currentRealtimeThread(); 245 if (number<0) throw new NegativeArraySizeException(); 246 247 rt.memoryArea().checkNewInstance(shadow); 248 Object o; 249 (o = newArray(rt, type, number)).memoryArea = shadow; 250 return o; 251 } 252 253 static Class[] nullClassArr = null; 254 static Object[] nullObjArr = null; 255 256 /** Allocate an object in this memory area. 257 * 258 * @param type The class of which to create a new instance. 259 * @throws java.lang.IllegalAccessException The class or initializer is 260 * inaccessible. 261 * @throws java.lang.InstantiationException The specified class object 262 * could not be instantiated. 263 * Possible causes are: it is an 264 * interface; it is abstract; it 265 * is an array, or an exception 266 * was thrown by the constructor. 267 * @throws OutOfMemoryError Space in the memory area is exhaused. 268 */ 269 270 public Object newInstance(Class type) 271 throws IllegalAccessException, InstantiationException, OutOfMemoryError { 272 if (nullClassArr == null) { 273 nullClassArr = new Class[0]; 274 nullObjArr = new Object[0]; 275 nullClassArr.memoryArea = HeapMemory.instance(); 276 nullObjArr.memoryArea = HeapMemory.instance(); 277 } 278 if (nullClassArr.memoryArea.heap&&(!RealtimeThread.RTJ_init_in_progress)) { 279 final ImmortalMemory im = ImmortalMemory.instance(); 280 nullClassArr = (Class[])im.newArray(Class.class, 0); 281 nullObjArr = (Object[])im.newArray(Object.class, 0); 282 } 283 return newInstance(type, nullClassArr, nullObjArr); 284 } 285 286 /** Allocate an object in this memory area. */ 287 public Object newInstance(final Class type, 288 final Class[] parameterTypes, 289 final Object[] parameters) 290 throws IllegalAccessException, InstantiationException, OutOfMemoryError { 291 Constructor c; 292 try { 293 // Type.getConstructor doesn't allocate any that needs deallocation 294 c = type.getConstructor(parameterTypes); 295 } catch (Exception e) { 296 throw new InstantiationException(e.toString()); 297 } 298 299 return newInstance(c, parameters); 300 } 301 302 /** Allocate an object in this memory area. 303 * 304 * @throws java.lang.IllegalAccessException The class or initializer is 305 * inaccessible. 306 * @throws java.lang.InstantiationException The specified class object 307 * could not be instantianted. 308 * Possible causes are: it is an 309 * interface, it is abstract, it 310 * is an array, or an exception 311 * was thrown by the constructor. 312 * @throws OutOfMemoryError Space in the memory area is exhaused. 313 */ 314 public Object newInstance(Constructor c, Object[] args) 315 throws IllegalAccessException, InstantiationException, 316 OutOfMemoryError { 317 try { 318 RealtimeThread.checkInit(); 319 RealtimeThread rt = RealtimeThread.currentRealtimeThread(); 320 rt.memoryArea().checkNewInstance(shadow); 321 Object o; 322 try { 323 o = newInstance(rt, c, args); 324 } catch (InvocationTargetException e) { 325 throw new InstantiationException(e.getMessage()); 326 } 327 o.memoryArea = shadow; 328 return o; 329 } catch (IllegalAssignmentError e) { 330 throw new IllegalAccessException(e.toString()); 331 } 332 } 333 334 /** Query the size of the memory area. The returned value is the 335 * current size. Current size may be larger than initial size for 336 * those areas that are allowed to grow. 337 */ 338 public long size() { 339 return size; 340 } 341 342 343 // METHODS NOT IN SPECS 344 345 protected native Object newInstance(RealtimeThread rt, 346 Constructor constructor, 347 Object[] parameters) 348 throws InvocationTargetException; 349 350 351 /** Explicitly unsafe way to get by without polluting the previous scope with a Runnable */ 352 static void startMem(MemoryArea mem) { 353 RealtimeThread rt = RealtimeThread.currentRealtimeThread(); 354 rt.checkDepth++; 355 rt.enter(mem.shadow, mem); 356 } 357 358 static void stopMem() { 359 RealtimeThread rt = RealtimeThread.currentRealtimeThread(); 360 if ((--rt.checkDepth)<0) { 361 NoHeapRealtimeThread.print("Error: stopMem>startMem\n"); 362 System.exit(-1); 363 } 364 rt.exitMem(); 365 } 366 367 368 protected MemoryArea(long minimum, long maximum) { 369 size = maximum; 370 preSetup(); 371 /* Sub-class will do postSetup */ 372 } 373 374 protected native void enterMemBlock(RealtimeThread rt, MemAreaStack mas); 375 protected native void exitMemBlock(RealtimeThread rt, MemAreaStack mas); 376 protected native void throwIllegalAssignmentError(Object obj, 377 MemoryArea ma) 378 throws IllegalAssignmentError; 379 380 /** */ 381 382 protected native MemoryArea shadow(); 383 384 /** */ 385 386 protected native void registerFinal(); 387 388 /** */ 389 390 public void bless(java.lang.Object obj) { 391 obj.memoryArea = shadow; 392 } 393 394 /** Create a new array, allocated out of this MemoryArea. 395 */ 396 397 public Object newArray(final Class type, 398 final int[] dimensions) 399 throws IllegalAccessException, OutOfMemoryError 400 { 401 RealtimeThread.checkInit(); 402 RealtimeThread rt = RealtimeThread.currentRealtimeThread(); 403 for (int i = 0; i<dimensions.length; i++) { 404 if (dimensions[i]<0) { 405 throw new NegativeArraySizeException(); 406 } 407 } 408 rt.memoryArea().checkNewInstance(shadow); 409 Object o; 410 (o = newArray(rt, type, dimensions)).memoryArea = shadow; 411 return o; 412 } 413 414 /** Check to see if this object can be accessed from this MemoryArea 415 */ 416 417 public void checkAccess(Object obj) { 418 if ((obj != null) && (obj.memoryArea != null) && 419 obj.memoryArea.scoped) { 420 throwIllegalAssignmentError(obj, obj.memoryArea); 421 } 422 } 423 424 /** Check access restrictions for a newInstance 425 */ 426 427 public void checkNewInstance(MemoryArea mem) { 428 if (mem.scoped) { 429 throw new IllegalAssignmentError("Illegal assignment during new instance!"); 430 } 431 } 432 433 /** Get the outerScope of this MemoryArea, for non-ScopedMemory's, 434 * this defaults to null. 435 */ 436 437 public MemoryArea getOuterScope() { 438 return null; 439 } 440 441 /** Output a helpful string describing this MemoryArea. 442 */ 443 444 public String toString() { 445 return String.valueOf(id); 446 } 447 }