/** * Change machine code that will be used by future executions of this method (ie. optimized <-> * non-optimized) * * <p>Side effect: updates JTOC or method dispatch tables ("type information blocks") for this * class and its subclasses * * @param compiledMethod new machine code */ public final synchronized void replaceCompiledMethod(CompiledMethod compiledMethod) { if (VM.VerifyAssertions) VM._assert(getDeclaringClass().isInstantiated()); // If we're replacing with a non-null compiledMethod, ensure that is still valid! if (compiledMethod != null) { synchronized (compiledMethod) { if (compiledMethod.isInvalid()) return; } } // Grab version that is being replaced CompiledMethod oldCompiledMethod = currentCompiledMethod; currentCompiledMethod = compiledMethod; // Install the new method in JTOC/TIB. If virtual, will also replace in // all subclasses that inherited the method. getDeclaringClass().updateMethod(this); // Replace constant-ified virtual method in JTOC if necessary Offset jtocOffset = getJtocOffset(); if (jtocOffset.NE(Offset.zero())) { Statics.setSlotContents(jtocOffset, getCurrentEntryCodeArray()); } // Now that we've updated the JTOC/TIB, old version is obsolete if (oldCompiledMethod != null) { CompiledMethods.setCompiledMethodObsolete(oldCompiledMethod); } }
/** Generate machine code for this method if valid machine code doesn't already exist. */ public final synchronized void compile() { if (VM.VerifyAssertions) VM._assert(getDeclaringClass().isResolved()); if (isCompiled()) return; if (VM.TraceClassLoading && VM.runningVM) VM.sysWrite("RVMMethod: (begin) compiling " + this + "\n"); CompiledMethod cm = genCode(); // Ensure that cm wasn't invalidated while it was being compiled. synchronized (cm) { if (cm.isInvalid()) { CompiledMethods.setCompiledMethodObsolete(cm); } else { currentCompiledMethod = cm; } } if (VM.TraceClassLoading && VM.runningVM) VM.sysWrite("RVMMethod: (end) compiling " + this + "\n"); }
/** * This method is called when a call stack edge needs to be sampled. Expect the sfp argument to * point to the stack frame that contains the target of the edge to be sampled. * * <p>NOTE: This method is uninterruptible, therefore we don't need to disable thread switching * during stackframe inspection. * * @param sfp a pointer to the stack frame that corresponds to the callee of the call graph edge * that is to be sampled. * @param whereFrom Was this a yieldpoint in a PROLOGUE, BACKEDGE, or EPILOGUE? */ @Override public final void update(Address sfp, int whereFrom) { if (DEBUG) { VM.sysWrite("EdgeListener.update(", sfp, ",", whereFrom); VM.sysWriteln("): enter ", samplesTaken); } Synchronization.fetchAndAdd(this, AosEntrypoints.edgeListenerUpdateCalledField.getOffset(), 1); // don't take a sample for back edge yield points if (whereFrom == RVMThread.BACKEDGE) return; int calleeCMID = 0; int callerCMID = 0; Address returnAddress = Address.zero(); if (sfp.loadAddress().EQ(STACKFRAME_SENTINEL_FP)) { if (DEBUG) VM.sysWrite(" Walking off end of stack!\n"); return; } calleeCMID = Magic.getCompiledMethodID(sfp); if (calleeCMID == INVISIBLE_METHOD_ID) { if (DEBUG) { VM.sysWrite(" INVISIBLE_METHOD_ID (assembler code) "); VM.sysWrite(calleeCMID); VM.sysWrite("\n"); } return; } returnAddress = Magic.getReturnAddress(sfp); // return address in caller sfp = Magic.getCallerFramePointer(sfp); // caller's frame pointer if (sfp.loadAddress().EQ(STACKFRAME_SENTINEL_FP)) { if (DEBUG) VM.sysWrite(" Walking off end of stack\n"); return; } callerCMID = Magic.getCompiledMethodID(sfp); if (callerCMID == INVISIBLE_METHOD_ID) { if (DEBUG) { VM.sysWrite(" INVISIBLE_METHOD_ID (assembler code) "); VM.sysWrite(callerCMID); VM.sysWrite("\n"); } return; } // store the offset of the return address from the beginning of the // instruction CompiledMethod callerCM = CompiledMethods.getCompiledMethod(callerCMID); if (callerCM.getCompilerType() == CompiledMethod.TRAP) { if (DEBUG) { VM.sysWriteln(" HARDWARE TRAP FRAME "); } return; } Offset callSite = callerCM.getInstructionOffset(returnAddress); if (DEBUG) { VM.sysWrite(" <"); VM.sysWrite(calleeCMID); VM.sysWrite(","); VM.sysWrite(callerCMID); VM.sysWrite(","); VM.sysWrite(returnAddress); VM.sysWrite(">\n"); } // Find out what sample we are. int sampleNumber = Synchronization.fetchAndAdd( this, AosEntrypoints.edgeListenerSamplesTakenField.getOffset(), 1); int idx = 3 * sampleNumber; // If we got buffer slots that are beyond the end of the buffer, that means // that we're actually not supposed to take the sample at all (the system // is in the process of activating our organizer and processing the buffer). if (idx < buffer.length) { buffer[idx + 1] = callerCMID; buffer[idx + 2] = callSite.toInt(); Magic.sync(); buffer[idx + 0] = calleeCMID; // If we are the last sample, we need to activate the organizer. if (sampleNumber + 1 == desiredSamples) { activateOrganizer(); } } }