/** Prints the address of the object. */ @Override public String toString() { if (value.isNull()) { return "null"; } return value.toString(); }
@Uninterruptible public static void dumpRef(ObjectReference ref) { VM.sysWrite("REF="); if (ref.isNull()) { VM.sysWrite("NULL\n"); return; } VM.sysWrite(ref); if (!mappedVMRef(ref)) { VM.sysWrite(" (REF OUTSIDE OF HEAP OR NOT MAPPED)\n"); return; } ObjectModel.dumpHeader(ref); ObjectReference tib = ObjectReference.fromObject(ObjectModel.getTIB(ref)); if (!MemoryManager.mightBeTIB(tib)) { VM.sysWrite(" (INVALID TIB: CLASS NOT ACCESSIBLE)\n"); return; } RVMType type = Magic.getObjectType(ref.toObject()); ObjectReference itype = ObjectReference.fromObject(type); VM.sysWrite(" TYPE="); VM.sysWrite(itype); if (!validType(itype)) { VM.sysWrite(" (INVALID TYPE: CLASS NOT ACCESSIBLE)\n"); return; } VM.sysWrite(" CLASS="); VM.sysWrite(type.getDescriptor()); VM.sysWrite("\n"); }
/** * Store a value into a reference field of an object. * * @param object The object to store the field of. * @param index The field index. * @param value The value to store. */ public void storeReferenceField(ObjectReference object, int index, ObjectReference value) { int limit = ObjectModel.getRefs(object); if (Trace.isEnabled(Item.STORE) || ObjectModel.isWatched(object)) { Trace.printf( Item.STORE, "[%s].object[%d/%d] = %s", ObjectModel.getString(object), index, limit, value.toString()); } check(!object.isNull(), "Object can not be null"); check(index >= 0, "Index must be non-negative"); check(index < limit, "Index " + index + " out of bounds " + limit); Address referenceSlot = ObjectModel.getRefSlot(object, index); if (ActivePlan.constraints.needsWriteBarrier()) { context.writeBarrier(object, referenceSlot, value, null, null, Plan.AASTORE_WRITE_BARRIER); if (gcEveryWB) { gc(); } } else { referenceSlot.store(value); } }
/** * Given a slot (ie the address of an ObjectReference), ensure that the referent will not move for * the rest of the GC. This is achieved by calling the precopyObject method. * * @param slot The slot to check */ @Inline public final void processPrecopyEdge(Address slot) { ObjectReference child = slot.loadObjectReference(); if (!child.isNull()) { child = precopyObject(child); slot.store(child); } }
private static synchronized Throwable fillInStackTrace(Throwable instance) { ObjectReference.fromObject(instance) .toAddress() .add(BACKTRACE_OFFSET) .store( ObjectReference.fromObject( VmThread.getStackTrace(VmProcessor.current().getCurrentThread()))); return instance; }
/** * Store a value into the data field of an object. * * @param object The object to store the field of. * @param index The field index. * @param value The value to store. */ public void storeDataField(ObjectReference object, int index, int value) { int limit = ObjectModel.getDataCount(object); check(!object.isNull(), "Object can not be null"); check(index >= 0, "Index must be non-negative"); check(index < limit, "Index " + index + " out of bounds " + limit); Address ref = ObjectModel.getDataSlot(object, index); ref.store(value); Trace.trace(Item.STORE, "%s.[%d] = %d", object.toString(), index, value); }
/** All Scalars */ public static void scalar(Object object, TransitiveClosure trace) { Address base = Magic.objectAsAddress(object); int[] offsets = ObjectModel.getObjectType(object).asClass().getReferenceOffsets(); for (int i = 0; i < offsets.length; i++) { trace.processEdge(ObjectReference.fromObject(object), base.plus(offsets[i])); } }
/** {@inheritDoc} */ @Override public boolean isLive(ObjectReference object) { if (object.isNull()) return false; if (Space.isInSpace(SS.SS0, object)) return SS.hi ? SS.copySpace0.isLive(object) : true; if (Space.isInSpace(SS.SS1, object)) return SS.hi ? true : SS.copySpace1.isLive(object); return super.isLive(object); }
/** * Push an address onto the address stack. * * @param object the object to be pushed onto the object queue */ @Inline public final void push(ObjectReference object) { Address addr = object.toAddress(); if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!addr.isZero()); checkHeadInsert(1); uncheckedHeadInsert(addr); }
/** Reference Arrays */ public static void referenceArray(Object object, TransitiveClosure trace) { Address base = Magic.objectAsAddress(object); int length = ObjectModel.getArrayLength(object); for (int i = 0; i < length; i++) { trace.processEdge(ObjectReference.fromObject(object), base.plus(i << LOG_BYTES_IN_ADDRESS)); } }
/** * Is the specified object live? * * @param object The object. * @return True if the object is live. */ public boolean isLive(ObjectReference object) { if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Immix.immixSpace.inImmixDefragCollection()); if (object.isNull()) return false; if (Space.isInSpace(Immix.IMMIX, object)) { return Immix.immixSpace.isLive(object); } return super.isLive(object); }
/** * Pop an address from the address stack, return zero if the stack is empty. * * @return The next address in the address stack, or zero if the stack is empty */ @Inline public final ObjectReference pop() { if (checkDequeue(1)) { return uncheckedDequeue().toObjectReference(); } else { return ObjectReference.nullReference(); } }
/** * This method is the core method during the trace of the object graph. The role of this method is * to: * * <p>1. Ensure the traced object is not collected. 2. If this is the first visit to the object * enqueue it to be scanned. 3. Return the forwarded reference to the object. * * <p>In this instance, we refer objects in the mark-sweep space to the immixSpace for tracing, * and defer to the superclass for all others. * * @param object The object to be traced. * @return The new reference to the same object instance. */ @Inline public ObjectReference traceObject(ObjectReference object) { if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(Immix.immixSpace.inImmixDefragCollection()); if (object.isNull()) return object; if (Space.isInSpace(Immix.IMMIX, object)) return Immix.immixSpace.traceObject(this, object, Plan.ALLOC_DEFAULT); return super.traceObject(object); }
private static int getStackTraceDepth(Throwable instance) { return ((Object[]) ObjectReference.fromObject(instance) .toAddress() .add(BACKTRACE_OFFSET) .loadObjectReference() .toObject()) .length; }
@Override @Inline public ObjectReference traceObject(ObjectReference object) { if (object.isNull()) return object; if (Space.isInSpace(SS.SS0, object)) return SS.copySpace0.traceObject(this, object, SS.ALLOC_SS); if (Space.isInSpace(SS.SS1, object)) return SS.copySpace1.traceObject(this, object, SS.ALLOC_SS); return super.traceObject(object); }
/** * Trace a reference during GC. This involves determining which collection policy applies and * calling the appropriate <code>trace</code> method. * * @param target The object the interior edge points within. * @param slot The location of the interior edge. * @param root True if this is a root edge. */ public final void processInteriorEdge(ObjectReference target, Address slot, boolean root) { Address interiorRef = slot.loadAddress(); Offset offset = interiorRef.diff(target.toAddress()); ObjectReference newTarget = traceObject(target, root); if (VM.VERIFY_ASSERTIONS) { if (offset.sLT(Offset.zero()) || offset.sGT(Offset.fromIntSignExtend(1 << 24))) { // There is probably no object this large Log.writeln("ERROR: Suspiciously large delta to interior pointer"); Log.write(" object base = "); Log.writeln(target); Log.write(" interior reference = "); Log.writeln(interiorRef); Log.write(" delta = "); Log.writeln(offset); VM.assertions._assert(false); } } slot.store(newTarget.toAddress().plus(offset)); }
/** * Load and return the value of a reference field of an object. * * @param object The object to load the field of. * @param index The field index. */ public ObjectReference loadReferenceField(ObjectReference object, int index) { int limit = ObjectModel.getRefs(object); check(!object.isNull(), "Object can not be null"); check(index >= 0, "Index must be non-negative"); check(index < limit, "Index " + index + " out of bounds " + limit); Address referenceSlot = ObjectModel.getRefSlot(object, index); ObjectReference result; if (ActivePlan.constraints.needsReadBarrier()) { result = context.readBarrier(object, referenceSlot, null, null, Plan.AASTORE_WRITE_BARRIER); } else { result = referenceSlot.loadObjectReference(); } Trace.trace( Item.LOAD, "[%s].object[%d] returned [%s]", ObjectModel.getString(object), index, result.toString()); return result; }
static int newGlobalRef(Object referent) { if (VM.VerifyAssertions) VM._assert(MemoryManager.validRef(ObjectReference.fromObject(referent))); if (free >= JNIGlobalRefs.length()) { AddressArray newGlobalRefs = AddressArray.create(JNIGlobalRefs.length() * 2); copyAndReplaceGlobalRefs(newGlobalRefs); } JNIGlobalRefs.set(free, Magic.objectAsAddress(referent)); return -free++; }
/** * Load and return the value of a data field of an object. * * @param object The object to load the field of. * @param index The field index. */ public int loadDataField(ObjectReference object, int index) { int limit = ObjectModel.getDataCount(object); check(!object.isNull(), "Object can not be null"); check(index >= 0, "Index must be non-negative"); check(index < limit, "Index " + index + " out of bounds " + limit); Address dataSlot = ObjectModel.getDataSlot(object, index); int result = dataSlot.loadInt(); Trace.trace( Item.LOAD, "[%s].int[%d] returned [%d]", ObjectModel.getString(object), index, result); return result; }
/** * This method is the core method during the trace of the object graph. The role of this method is * to: * * <p>1. Ensure the traced object is not collected. 2. If this is the first visit to the object * enqueue it to be scanned. 3. Return the forwarded reference to the object. * * @param object The object to be traced. * @return The new reference to the same object instance. */ @Inline public ObjectReference traceObject(ObjectReference object) { if (Space.isInSpace(Plan.VM_SPACE, object)) return (Plan.SCAN_BOOT_IMAGE) ? object : Plan.vmSpace.traceObject(this, object); if (Space.isInSpace(Plan.IMMORTAL, object)) return Plan.immortalSpace.traceObject(this, object); if (Space.isInSpace(Plan.LOS, object)) return Plan.loSpace.traceObject(this, object); if (Space.isInSpace(Plan.PLOS, object)) return Plan.ploSpace.traceObject(this, object); if (Plan.USE_CODE_SPACE && Space.isInSpace(Plan.SMALL_CODE, object)) return Plan.smallCodeSpace.traceObject(this, object); if (Plan.USE_CODE_SPACE && Space.isInSpace(Plan.LARGE_CODE, object)) return Plan.largeCodeSpace.traceObject(this, object); if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(false, "No special case for space in traceObject"); return ObjectReference.nullReference(); }
private static StackTraceElement getStackTraceElement(Throwable instance, int index) { final VmStackFrame frame = (VmStackFrame) ((Object[]) ObjectReference.fromObject(instance) .toAddress() .add(BACKTRACE_OFFSET) .loadObjectReference() .toObject()) [index]; final String location = frame.getLocationInfo(); final int lineNumber = "?".equals(location) ? -1 : Integer.parseInt(location); final VmMethod method = frame.getMethod(); final VmType<?> vmClass = (method == null) ? null : method.getDeclaringClass(); final String fname = (vmClass == null) ? null : vmClass.getSourceFile(); final String cname = (vmClass == null) ? "<unknown class>" : vmClass.getName(); final String mname = (method == null) ? "<unknown method>" : method.getName(); return new StackTraceElement( cname, mname, fname, method == null || method.isNative() ? -2 : lineNumber); }
/** Fallback */ public static void fallback(Object object, TransitiveClosure trace) { ObjectReference objectRef = ObjectReference.fromObject(object); RVMType type = ObjectModel.getObjectType(objectRef.toObject()); if (type.isClassType()) { RVMClass klass = type.asClass(); int[] offsets = klass.getReferenceOffsets(); for (int i = 0; i < offsets.length; i++) { trace.processEdge(objectRef, objectRef.toAddress().plus(offsets[i])); } } else if (type.isArrayType() && type.asArray().getElementType().isReferenceType()) { for (int i = 0; i < ObjectModel.getArrayLength(objectRef.toObject()); i++) { trace.processEdge(objectRef, objectRef.toAddress().plus(i << LOG_BYTES_IN_ADDRESS)); } } }
/** All patterns bottom out here */ @Inline public static void pattern(int pattern, Object object, TransitiveClosure trace) { Address base = Magic.objectAsAddress(object).plus(FIELD_ZERO_OFFSET); if ((pattern & 1) != 0) { trace.processEdge(ObjectReference.fromObject(object), base.plus(0)); } if ((pattern & 2) != 0) { trace.processEdge(ObjectReference.fromObject(object), base.plus(1 << LOG_BYTES_IN_ADDRESS)); } if ((pattern & 4) != 0) { trace.processEdge(ObjectReference.fromObject(object), base.plus(2 << LOG_BYTES_IN_ADDRESS)); } if ((pattern & 8) != 0) { trace.processEdge(ObjectReference.fromObject(object), base.plus(3 << LOG_BYTES_IN_ADDRESS)); } if ((pattern & 16) != 0) { trace.processEdge(ObjectReference.fromObject(object), base.plus(4 << LOG_BYTES_IN_ADDRESS)); } if ((pattern & 32) != 0) { trace.processEdge(ObjectReference.fromObject(object), base.plus(5 << LOG_BYTES_IN_ADDRESS)); } }
/** Use the hash code of the underlying ObjectReference */ @Override public int hashCode() { return value.hashCode(); }
/** * Checks if a reference, its TIB pointer and type pointer are all in the heap. * * @param ref the reference to check * @return {@code true} if and only if the reference refers to a valid object */ @Uninterruptible public static boolean validObject(Object ref) { return validRef(ObjectReference.fromObject(ref)); }
/** Construct an initially null object value */ public ObjectValue() { this(ObjectReference.nullReference()); }
/** Get this value as a boolean. */ @Override public boolean getBoolValue() { return !value.isNull(); }
@Uninterruptible public static boolean validRef(ObjectReference ref) { if (ref.isNull()) return true; if (!Space.isMappedObject(ref)) { VM.sysWrite("validRef: REF outside heap, ref = "); VM.sysWrite(ref); VM.sysWrite("\n"); Space.printVMMap(); return false; } if (MOVES_OBJECTS) { /* TODO: Work out how to check if forwarded if (Plan.isForwardedOrBeingForwarded(ref)) { // TODO: actually follow forwarding pointer // (need to bound recursion when things are broken!!) return true; } */ } TIB tib = ObjectModel.getTIB(ref); Address tibAddr = Magic.objectAsAddress(tib); if (!Space.isMappedObject(ObjectReference.fromObject(tib))) { VM.sysWrite("validRef: TIB outside heap, ref = "); VM.sysWrite(ref); VM.sysWrite(" tib = "); VM.sysWrite(tibAddr); VM.sysWrite("\n"); ObjectModel.dumpHeader(ref); return false; } if (tibAddr.isZero()) { VM.sysWrite("validRef: TIB is Zero! "); VM.sysWrite(ref); VM.sysWrite("\n"); ObjectModel.dumpHeader(ref); return false; } if (tib.length() == 0) { VM.sysWrite("validRef: TIB length zero, ref = "); VM.sysWrite(ref); VM.sysWrite(" tib = "); VM.sysWrite(tibAddr); VM.sysWrite("\n"); ObjectModel.dumpHeader(ref); return false; } ObjectReference type = ObjectReference.fromObject(tib.getType()); if (!validType(type)) { VM.sysWrite("validRef: invalid TYPE, ref = "); VM.sysWrite(ref); VM.sysWrite(" tib = "); VM.sysWrite(Magic.objectAsAddress(tib)); VM.sysWrite(" type = "); VM.sysWrite(type); VM.sysWrite("\n"); ObjectModel.dumpHeader(ref); return false; } return true; } // validRef
/** Get the hash code for the given object. */ public int hash(ObjectReference object) { check(!object.isNull(), "Object can not be null"); int result = ObjectModel.getHashCode(object); Trace.trace(Item.HASH, "hash(%s) returned [%d]", ObjectModel.getString(object), result); return result; }
/** * Return true if the object resides within the nursery * * @param obj The object to be tested * @return true if the object resides within the nursery */ @Inline static boolean inNursery(ObjectReference obj) { return inNursery(obj.toAddress()); }