/**
   * 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");
  }
Beispiel #3
0
  /**
   * 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();
      }
    }
  }