public override bool ProcessEvent(JvmtiEnvironment environment, JniEnvironment nativeEnvironment, EventProcessor processor, ThreadId thread, TaggedReferenceTypeId @class, Location? location) { if (!base.ProcessEvent(environment, nativeEnvironment, processor, thread, @class, location)) return false; // Step Out is implemented with Frame Pop events set at the correct depth if (_depth == StepDepth.Out) { if (location.HasValue && !location.Value.Method.Equals(_lastMethod)) { _lastLocation = new jlocation((long)location.Value.Index); _lastMethod = location.Value.Method; UpdateLastLine(environment); } return true; } using (var threadHandle = environment.VirtualMachine.GetLocalReferenceForThread(nativeEnvironment, thread)) { int stackDepth; JvmtiErrorHandler.ThrowOnFailure(environment.GetFrameCount(threadHandle.Value, out stackDepth)); if (_hasMethodInfo && stackDepth > _stackDepth) { bool convertToFramePop; if (location.HasValue && (!_convertedToFramePop || !_framePopMethod.Equals(location.Value.Method)) && ShouldSkipCurrentMethod(processor.VirtualMachine, environment, nativeEnvironment, threadHandle.Value, stackDepth, location.Value, out convertToFramePop)) { if (convertToFramePop) { // remove the single step event JvmtiErrorHandler.ThrowOnFailure((jvmtiError)processor.ClearEventInternal(EventKind.FramePop, this.RequestId)); JvmtiErrorHandler.ThrowOnFailure((jvmtiError)processor.ClearEventInternal(EventKind.SingleStep, this.RequestId)); // set an actual step filter to respond when the thread arrives back in this frame JvmtiErrorHandler.ThrowOnFailure((jvmtiError)processor.SetEventInternal(environment, nativeEnvironment, EventKind.FramePop, this)); _convertedToFramePop = true; _framePopMethod = location.Value.Method; } return false; } else { _convertedToFramePop = false; return true; } } else if (stackDepth == _stackDepth) { if (_size == StepSize.Statement && _disassembledMethod != null) { int instructionIndex = _disassembledMethod.Instructions.FindIndex(i => (uint)i.Offset == location.Value.Index); if (instructionIndex >= 0 && _evaluationStackDepths != null && (_evaluationStackDepths[instructionIndex] ?? 0) != 0) { return false; } else if (instructionIndex >= 0 && _disassembledMethod.Instructions[instructionIndex].OpCode.FlowControl == JavaFlowControl.Branch) { // follow branch instructions before stopping return false; } } else if (_lastLine != null) { // see if we're on the same line LineNumberData[] lines; jvmtiError error = environment.GetLineNumberTable(location.Value.Method, out lines); if (error == jvmtiError.None) { LineNumberData entry = lines.LastOrDefault(i => i.LineCodeIndex <= (long)location.Value.Index); if (entry.LineNumber == _lastLine) return false; } } } if (location.HasValue) { _lastLocation = new jlocation((long)location.Value.Index); _lastMethod = location.Value.Method; UpdateLastLine(environment); } _stackDepth = stackDepth; return true; } }
public StepEventFilter(EventKind internalEventKind, RequestId requestId, SuspendPolicy suspendPolicy, IEnumerable<EventRequestModifier> modifiers, ThreadId thread, JvmtiEnvironment environment, JniEnvironment nativeEnvironment, StepSize size, StepDepth depth) : base(internalEventKind, requestId, suspendPolicy, modifiers, thread) { if (size == StepSize.Statement && JavaVM.DisableStatementStepping) size = StepSize.Line; _size = size; _depth = depth; // gather reference information for the thread using (var threadHandle = environment.VirtualMachine.GetLocalReferenceForThread(nativeEnvironment, thread)) { if (threadHandle.IsAlive) { jvmtiError error = environment.GetFrameLocation(threadHandle.Value, 0, out _lastMethod, out _lastLocation); if (error == jvmtiError.None) error = environment.GetFrameCount(threadHandle.Value, out _stackDepth); if (error == jvmtiError.None) _hasMethodInfo = true; UpdateLastLine(environment); if (error == jvmtiError.None && size == StepSize.Statement && (depth == StepDepth.Over || depth == StepDepth.Into)) { byte[] bytecode; JvmtiErrorHandler.ThrowOnFailure(environment.GetBytecodes(_lastMethod, out bytecode)); _disassembledMethod = BytecodeDisassembler.Disassemble(bytecode); TaggedReferenceTypeId declaringClass; JvmtiErrorHandler.ThrowOnFailure(environment.GetMethodDeclaringClass(nativeEnvironment, _lastMethod, out declaringClass)); using (var classHandle = environment.VirtualMachine.GetLocalReferenceForClass(nativeEnvironment, declaringClass.TypeId)) { int constantPoolCount; byte[] data; JvmtiErrorHandler.ThrowOnFailure(environment.GetConstantPool(classHandle.Value, out constantPoolCount, out data)); List<ConstantPoolEntry> entryList = new List<ConstantPoolEntry>(); int currentPosition = 0; for (int i = 0; i < constantPoolCount - 1; i++) { entryList.Add(ConstantPoolEntry.FromBytes(data, ref currentPosition)); switch (entryList.Last().Type) { case ConstantType.Double: case ConstantType.Long: // these entries take 2 slots entryList.Add(ConstantPoolEntry.Reserved); i++; break; default: break; } } _constantPool = entryList.AsReadOnly(); string classSignature; string classGenericSignature; JvmtiErrorHandler.ThrowOnFailure(environment.GetClassSignature(classHandle.Value, out classSignature, out classGenericSignature)); string methodName; string methodSignature; string methodGenericSignature; JvmtiErrorHandler.ThrowOnFailure(environment.GetMethodName(_lastMethod, out methodName, out methodSignature, out methodGenericSignature)); jobject classLoader; JvmtiErrorHandler.ThrowOnFailure(environment.GetClassLoader(classHandle.Value, out classLoader)); long classLoaderTag; JvmtiErrorHandler.ThrowOnFailure(environment.TagClassLoader(classLoader, out classLoaderTag)); ReadOnlyCollection<ExceptionTableEntry> exceptionTable; JvmtiErrorHandler.ThrowOnFailure(environment.VirtualMachine.GetExceptionTable(classLoaderTag, classSignature, methodName, methodSignature, out exceptionTable)); _evaluationStackDepths = BytecodeDisassembler.GetEvaluationStackDepths(_disassembledMethod, _constantPool, exceptionTable); } } } } }