public void replay(IoAdapter adapter) { adapter.seek(_address); }
/** * * 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); }