예제 #1
0
  /**
   * * Visit any byte-code instruction
   *
   * <p>This allows us to instrument methods an the instruction level. Instructions that are
   * instrumented this way regard exiting and synchronising byte-code instructions
   */
  @Override
  public void visitInsn(int opcode) {

    instrumentationStatsRecord.addInstruction();

    // if (opcode != ATHROW) {
    if (performanceModelParameters != null) {
      if (performanceModelParameters.removingMethodBody()) {
        if ((opcode >= IRETURN && opcode <= RETURN)
            || (!instrumentExceptionHandlingCode && opcode == ATHROW)) {
          if (profile) {
            onMethodExitInstrumentation();
          }
          mv.visitInsn(opcode);
        }
        return;
      }
    }

    // These are all instructions which terminate a method
    if ((opcode >= IRETURN && opcode <= RETURN)
        || (!instrumentExceptionHandlingCode && opcode == ATHROW && tryCatchDepth == 0)) {

      if (profile) {
        onMethodExitInstrumentation();
      }

      if (iparams.onlyLimitedJvmtiUsage() && isSynchronised) {
        if (isStatic) {
          mv.visitLdcInsn(Type.getType("L" + className + ";"));
        } else {
          mv.visitVarInsn(ALOAD, 0);
        }
        //				mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "hashCode", "()I");
        mv.visitMethodInsn(
            INVOKESTATIC, "java/lang/System", "identityHashCode", "(Ljava/lang/Object;)I");
        mv.visitMethodInsn(
            INVOKESTATIC, "virtualtime/EventNotifier", "_beforeReleasingMonitor", "(I)V");
      }

      if (shouldBeWrappedWithVexOptimizerLoop) {
        mv.visitMethodInsn(
            INVOKESTATIC,
            "virtualtime/EventNotifier",
            "_exportAndProcessMainIterationResults",
            "()V");
        mv.visitJumpInsn(GOTO, startMainWrappedWithVexOptimizer);
        mv.visitLabel(endMainWrappedWithVexOptimizer);
      }
      mv.visitInsn(opcode);
      return;
    }

    // Monitor enter instrumentation - suspend thread
    if (opcode == MONITORENTER || opcode == MONITOREXIT) {
      instrumentationStatsRecord.addSyncPrimitive();

      if (iparams.onlyLimitedJvmtiUsage()) {

        if (!iparams.shouldRemoveMonitors()) {
          mv.visitInsn(DUP);
        }
        if (opcode == MONITORENTER) {
          //					mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "hashCode", "()I");
          mv.visitMethodInsn(
              INVOKESTATIC, "java/lang/System", "identityHashCode", "(Ljava/lang/Object;)I");
          onInteractionPointEncounter();
          mv.visitMethodInsn(
              INVOKESTATIC, "virtualtime/EventNotifier", "_beforeAcquiringMonitor", "(I)V");

        } else {
          onInteractionPointEncounter();
          // mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "hashCode", "()I");
          mv.visitMethodInsn(
              INVOKESTATIC, "java/lang/System", "identityHashCode", "(Ljava/lang/Object;)I");

          mv.visitMethodInsn(
              INVOKESTATIC, "virtualtime/EventNotifier", "_beforeReleasingMonitor", "(I)V");
        }

        if (iparams.shouldRemoveMonitors()) {
          return;
        }
      }
    }
    mv.visitInsn(opcode);
  }
예제 #2
0
  /**
   * * Visitor of the method-calling byte-code instructions called by the method
   *
   * <p>This allows us to instrument the method-calling byte-code instructions of a profiled method.
   * These methods can be divided into the ones that: - denote thread start - denote thread yield -
   * denote thread wait - trigger synchronisation points - should register I/O points
   */
  @Override
  public void visitMethodInsn(int opcode, String owner, String name, String desc) {

    if (DEBUG) {
      System.out.println(owner + " --> " + name + ": " + desc + " (" + opcode + ")");
    }
    // called at the beginning of a method
    if (removingMethodBody()) {
      return;
    }

    instrumentationStatsRecord.addInstruction();

    // Thread.yield - cannot be instrumented in java.lang.Thread, because it's a native method
    if (opcode == INVOKESTATIC
        && owner.equals("java/lang/Thread")
        && name.equals("yield")
        && desc.equals("()V")) {
      instrumentationStatsRecord.addSyncPrimitive();
      mv.visitMethodInsn(INVOKESTATIC, "virtualtime/EventNotifier", "_yield", "()V");
      return;
    }

    // Virtualizing waiting calls
    if (iparams.shouldTransformWaits()) {

      // In the limited JVMTI case we do not rely on JVMTI to trap Object.wait(), so we trap both
      // indefinite and timed-waiting events
      if (iparams.onlyLimitedJvmtiUsage()) {
        if (opcode == INVOKEVIRTUAL && owner.equals("java/lang/Object") && name.equals("wait")) {
          instrumentationStatsRecord.addSyncPrimitive();

          if (iparams.shouldRemoveMonitors()) {
            mv.visitLdcInsn(ICONST_0);
          } else {
            mv.visitLdcInsn(ICONST_1);
          }

          if (desc.equals("()V")) {
            mv.visitMethodInsn(
                INVOKESTATIC,
                "virtualtime/EventNotifier",
                "waitInVirtualTimeWithoutJvmti",
                "(Ljava/lang/Object;Z)V");

          } else if (desc.equals("(J)V")) {
            mv.visitMethodInsn(
                INVOKESTATIC,
                "virtualtime/EventNotifier",
                "waitInVirtualTimeWithoutJvmti",
                "(Ljava/lang/Object;JZ)V");

          } else {
            mv.visitMethodInsn(
                INVOKESTATIC,
                "virtualtime/EventNotifier",
                "waitInVirtualTimeWithoutJvmti",
                "(Ljava/lang/Object;J*Z)V");
          }
          return;
        }

      } else {
        // JVMTI traps Object.wait(), so we only trap timed-waiting events
        if (opcode == INVOKEVIRTUAL
            && owner.equals("java/lang/Object")
            && name.equals("wait")
            && desc.equals("(J)V")) {
          instrumentationStatsRecord.addSyncPrimitive();
          mv.visitMethodInsn(
              INVOKESTATIC,
              "virtualtime/EventNotifier",
              "waitInVirtualTime",
              "(Ljava/lang/Object;J)V");
          return;
        }

        if (opcode == INVOKEVIRTUAL
            && owner.equals("java/lang/Object")
            && name.equals("wait")
            && desc.equals("(JI)V")) {
          instrumentationStatsRecord.addSyncPrimitive();
          // Object.wait(timeout, nanos)
          mv.visitMethodInsn(
              INVOKESTATIC,
              "virtualtime/EventNotifier",
              "waitInVirtualTime",
              "(Ljava/lang/Object;JI)V");
          return;
        }
      }

      // Hack to include subclasses of Thread that override sleep - naive onLoad check does not work
      if (name.equals("sleep")
          && (desc.equals("(J)V") || desc.equals("(JI)V"))
          && (!owner.equals(className)
              || iparams
                  .isSubClassOfJavaLangThread())) { // && owner.equals("java/lang/Thread")) {	// ||
                                                    // iparams.isExtendindJavaLangThread(owner)
        instrumentationStatsRecord.addSyncPrimitive();
        //				System.out.println("changing sleep for " + owner + " "  + name + " " + desc + " " +
        // className + " " + methodName);
        mv.visitMethodInsn(INVOKESTATIC, "virtualtime/EventNotifier", "sleepInVirtualTime", desc);
        return;
      } else if (name.equals("sleep")) {
        //				System.out.println("*NOT* changing sleep for " + owner + " "  + name + " " + desc + "
        // " + className + " " + methodName);
      }
    }

    if (iparams.shouldTransformWaits()) {
      if (!iparams.shouldRemoveMonitors()) {

        // Object.notifyAll():
        if (opcode == INVOKEVIRTUAL
            && owner.equals("java/lang/Object")
            && name.equals("notifyAll")
            && desc.equals("()V")) {
          instrumentationStatsRecord.addSyncPrimitive();
          mv.visitMethodInsn(
              INVOKESTATIC,
              "virtualtime/EventNotifier",
              "beforeNotifyAll",
              "(Ljava/lang/Object;)V");
          return;
        }

        // Object.notify():
        if (opcode == INVOKEVIRTUAL
            && owner.equals("java/lang/Object")
            && name.equals("notify")
            && desc.equals("()V")) {
          instrumentationStatsRecord.addSyncPrimitive();
          mv.visitMethodInsn(
              INVOKESTATIC, "virtualtime/EventNotifier", "beforeNotify", "(Ljava/lang/Object;)V");
          return;
        }
      } else {
        // WITHOUT MONITORS
        // Object.notifyAll():
        if (opcode == INVOKEVIRTUAL
            && owner.equals("java/lang/Object")
            && name.equals("notifyAll")
            && desc.equals("()V")) {
          instrumentationStatsRecord.addSyncPrimitive();
          mv.visitMethodInsn(
              INVOKESTATIC,
              "virtualtime/EventNotifier",
              "beforeNotifyAllWithoutMonitors",
              "(Ljava/lang/Object;)V");
          return;
        }

        // Object.notify():
        if (opcode == INVOKEVIRTUAL
            && owner.equals("java/lang/Object")
            && name.equals("notify")
            && desc.equals("()V")) {
          instrumentationStatsRecord.addSyncPrimitive();
          mv.visitMethodInsn(
              INVOKESTATIC,
              "virtualtime/EventNotifier",
              "beforeNotifyWithoutMonitors",
              "(Ljava/lang/Object;)V");
          return;
        }
      }
    }

    // Any I/O method: store invocation id before every I/O call of a profiled method
    if (owner.startsWith("java/io/")
        || (owner.startsWith("java/net/") && (name.equals("write") || name.equals("read")))) {
      instrumentationStatsRecord.addIoPoint();
      mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;");
      mv.visitIntInsn(SIPUSH, IoAdapter.getNextInvocationPointId());
      mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "setVtfIoInvocationPoint", "(I)V");
    }

    // Adapting recursive call to self
    if (iparams.isRecursiveRetransformation() && iparams.usingExternalInstrumentation()) {
      if (owner.equals(className)
          && methodName.equals(iparams.getRetransformingMethodName())
          && desc.equals(iparams.getRetransformingMethodDesc())) {
        if (DEBUG) {
          System.out.println(
              "Found recursive call " + owner + " --> " + name + ": " + desc + " (" + opcode + ")");
        }

        name = "_vtfmethod_" + name;
        //				if (!name.endsWith("init>")) {
        //					name = "_vtfmethod_"+ name;
        //				} else {
        //					if (name.equals("<init>")) {
        //						name = "_vtfmethod_constructor";
        //					} else {
        //		        		name = "_vtfmethod_class_initialization";
        //					}
        //				}
      }
    }

    if (iparams.shouldModifyTimeCalls()) {
      if ((opcode == INVOKESTATIC
              && owner.equals("java/lang/System")
              && name.equals("currentTimeMillis")
              && desc.equals("()J"))
          || (opcode == INVOKESTATIC
              && owner.equals("java/lang/System")
              && name.equals("nanoTime")
              && desc.equals("()J"))) {
        mv.visitMethodInsn(INVOKESTATIC, "virtualtime/EventNotifier", name, desc);
        return;
      }
    }
    mv.visitMethodInsn(opcode, owner, name, desc);
  }