public void TestExecutor_Execute() { JavaInstruction ji = new JavaInstruction((char)EnumJavaOpCode.aaload, "aaload", "无|将引用型数组指定索引的值推送至栈顶", null); NativeInterpreter executor = new NativeInterpreter(); executor.Execute(EnumJavaOpCode.getstatic, null); }
public static JavaInstrArguments ArgsType(this JavaInstruction instr) { switch (instr) { case JavaInstruction.newarray: return(JavaInstrArguments.AType); case JavaInstruction.bipush: return(JavaInstrArguments.Byte); case JavaInstruction.ldc: return(JavaInstrArguments.ByteCpIndex); case JavaInstruction.iload: case JavaInstruction.lload: case JavaInstruction.fload: case JavaInstruction.dload: case JavaInstruction.aload: case JavaInstruction.istore: case JavaInstruction.lstore: case JavaInstruction.fstore: case JavaInstruction.dstore: case JavaInstruction.astore: case JavaInstruction.ret: return(JavaInstrArguments.LocalVarIndex); case JavaInstruction.ifeq: case JavaInstruction.ifne: case JavaInstruction.iflt: case JavaInstruction.ifge: case JavaInstruction.ifgt: case JavaInstruction.ifle: case JavaInstruction.if_icmpeq: case JavaInstruction.if_icmpne: case JavaInstruction.if_icmplt: case JavaInstruction.if_icmpge: case JavaInstruction.if_icmpgt: case JavaInstruction.if_icmple: case JavaInstruction.if_acmpeq: case JavaInstruction.if_acmpne: case JavaInstruction.@goto: case JavaInstruction.jsr: case JavaInstruction.ifnull: case JavaInstruction.ifnonnull: return(JavaInstrArguments.BranchOffset); case JavaInstruction.sipush: return(JavaInstrArguments.Short); case JavaInstruction.iinc: return(JavaInstrArguments.Iinc); case JavaInstruction.ldc_w: case JavaInstruction.ldc2_w: case JavaInstruction.getstatic: case JavaInstruction.putstatic: case JavaInstruction.getfield: case JavaInstruction.putfield: case JavaInstruction.invokevirtual: case JavaInstruction.invokespecial: case JavaInstruction.invokestatic: case JavaInstruction.@new: case JavaInstruction.anewarray: case JavaInstruction.checkcast: case JavaInstruction.instanceof: return(JavaInstrArguments.CpIndex); case JavaInstruction.wide: return(JavaInstrArguments.WidePrefix); case JavaInstruction.lookupswitch: return(JavaInstrArguments.LookupSwitch); case JavaInstruction.tableswitch: return(JavaInstrArguments.TableSwitch); case JavaInstruction.multianewarray: return(JavaInstrArguments.MultiNewArray); case JavaInstruction.goto_w: case JavaInstruction.jsr_w: return(JavaInstrArguments.WideBranchOffset); case JavaInstruction.invokedynamic: return(JavaInstrArguments.InvokeDynamic); case JavaInstruction.invokeinterface: return(JavaInstrArguments.InvokeInterface); default: return(JavaInstrArguments.Niladic); } }
protected JavaOp(int offset, JavaInstruction instr) { Offset = offset; Instr = instr; }
public Niladic(int start, JavaInstruction instr) : base(start, instr) { }
/// <summary> /// Reads instructions starting from the current position in the disassembly stream. /// </summary> /// <param name="dwInstructions">[in] The number of instructions to disassemble. This value is also the maximum length of the prgDisassembly array.</param> /// <param name="dwFields">[in] A combination of flags from the DISASSEMBLY_STREAM_FIELDS enumeration that indicate which fields of prgDisassembly are to be filled out.</param> /// <param name="pdwInstructionsRead">[out] Returns the number of instructions actually disassembled.</param> /// <param name="prgDisassembly">[out] An array of DisassemblyData structures that is filled in with the disassembled code, one structure per disassembled instruction. The length of this array is dictated by the dwInstructions parameter.</param> /// <returns>If successful, returns S_OK; otherwise, returns an error code.</returns> /// <remarks> /// The maximum number of instructions that are available in the current scope can be obtained by calling the IDebugDisassemblyStream2.GetSize method. /// /// The current position where the next instruction is read from can be changed by calling the IDebugDisassemblyStream2.Seek method. /// /// The DSF_OPERANDS_SYMBOLS flag can be added to the DSF_OPERANDS flag in the dwFields parameter to indicate that symbol names should be used when disassembling instructions. /// </remarks> public int Read(uint dwInstructions, enum_DISASSEMBLY_STREAM_FIELDS dwFields, out uint pdwInstructionsRead, DisassemblyData[] prgDisassembly) { pdwInstructionsRead = 0; uint actualInstructions = Math.Min(dwInstructions, (uint)(_disassembledMethod.Instructions.Count - _currentInstructionIndex)); if (prgDisassembly == null || prgDisassembly.Length < dwInstructions) { return(VSConstants.E_INVALIDARG); } IMethod method = _executionContext.Location.GetMethod(); ReadOnlyCollection <ILocalVariable> localVariables = method.GetHasVariableInfo() ? method.GetVariables() : new ReadOnlyCollection <ILocalVariable>(new ILocalVariable[0]); ReadOnlyCollection <ConstantPoolEntry> constantPool = _executionContext.Location.GetDeclaringType().GetConstantPool(); int addressFieldWidth = 1; int addressFieldRange = 10 * addressFieldWidth; while (addressFieldRange <= _bytecode.Length) { addressFieldWidth++; addressFieldRange *= 10; } for (int i = 0; i < actualInstructions; i++) { JavaInstruction instruction = _disassembledMethod.Instructions[_currentInstructionIndex + i]; int instructionStart = instruction.Offset; int instructionSize = instruction.Size; #if false // bstrAddress is supposed to refer to an absolute offset if (dwFields.GetAddress()) { prgDisassembly[i].bstrAddress = string.Format("{0," + addressFieldWidth + "}", instructionStart); prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS; } #endif if (dwFields.GetCodeBytes()) { prgDisassembly[i].bstrCodeBytes = string.Join(" ", _bytecode.Skip(instructionStart).Take(instructionSize).Select(x => x.ToString("X2"))); prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODEBYTES; } if (dwFields.GetCodeLocationId()) { prgDisassembly[i].uCodeLocationId = (ulong)instructionStart; prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID; } if (dwFields.GetOpCode()) { prgDisassembly[i].bstrOpcode = string.Format("[{0}]{1}", _evaluationStackDepths[_currentInstructionIndex + i], instruction.OpCode.Name ?? "???"); prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE; } if (dwFields.GetAddressOffset()) { prgDisassembly[i].bstrAddressOffset = string.Format("{0," + addressFieldWidth + "}", instructionStart); prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESSOFFSET; } if (dwFields.GetDocumentUrl()) { // "For text documents that can be represented as file names, the bstrDocumentUrl // field is filled in with the file name where the source can be found, using the // format file://file name." string sourcePath = _executionContext.Location.GetSourcePath(); Uri sourceUri; if (!string.IsNullOrEmpty(sourcePath) && Uri.TryCreate(sourcePath, UriKind.Absolute, out sourceUri)) { prgDisassembly[i].bstrDocumentUrl = sourceUri.AbsoluteUri; // if it starts with file:/// one of the / characters will show in disassembly view if (prgDisassembly[i].bstrDocumentUrl.StartsWith("file:///")) { prgDisassembly[i].bstrDocumentUrl = "file://" + prgDisassembly[i].bstrDocumentUrl.Substring("file:///".Length); } prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL; } } if (dwFields.GetOperands()) { prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS; bool includeSymbolNames = dwFields.GetOperandsSymbols(); if (includeSymbolNames) { prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS_SYMBOLS; } // operand 0 switch (instruction.OpCode.OperandType) { case JavaOperandType.InlineI1: prgDisassembly[i].bstrOperands = instruction.Operands.InlineSByte.ToString(); break; case JavaOperandType.InlineI2: prgDisassembly[i].bstrOperands = instruction.Operands.InlineInt16.ToString(); break; case JavaOperandType.InlineShortBranchTarget: case JavaOperandType.InlineBranchTarget: prgDisassembly[i].bstrOperands = (instructionStart + instruction.Operands.Operand1).ToString(); break; case JavaOperandType.InlineLookupSwitch: prgDisassembly[i].bstrOperands = "Switch?"; break; case JavaOperandType.InlineTableSwitch: prgDisassembly[i].bstrOperands = "TableSwitch?"; break; case JavaOperandType.InlineVar: case JavaOperandType.InlineVar_I1: if (includeSymbolNames) { int localIndex = _bytecode[instructionStart + 1]; int testLocation = instructionStart; if (instruction.OpCode.StackBehaviorPop != JavaStackBehavior.Pop0) { // this is a store instruction - the variable might not be visible until the following instruction testLocation += instruction.Size; } ILocation currentLocation = _executionContext.Location.GetMethod().GetLocationOfCodeIndex(testLocation); var local = localVariables.SingleOrDefault(variable => variable.GetSlot() == localIndex && variable.GetIsVisible(currentLocation)); if (local != null) { prgDisassembly[i].bstrOperands = local.GetName(); } } if (string.IsNullOrEmpty(prgDisassembly[i].bstrOperands)) { prgDisassembly[i].bstrOperands = "#" + instruction.Operands.VariableSlot.ToString(); } break; case JavaOperandType.InlineShortConst: case JavaOperandType.InlineConst: case JavaOperandType.InlineField: case JavaOperandType.InlineMethod: case JavaOperandType.InlineMethod_U1_0: case JavaOperandType.InlineType: case JavaOperandType.InlineType_U1: if (includeSymbolNames) { int index = instruction.Operands.ConstantPoolIndex; var entry = constantPool[index - 1]; prgDisassembly[i].bstrOperands = entry.ToString(constantPool); } if (string.IsNullOrEmpty(prgDisassembly[i].bstrOperands)) { prgDisassembly[i].bstrOperands = "#" + instruction.Operands.ConstantPoolIndex.ToString(); } break; case JavaOperandType.InlineArrayType: prgDisassembly[i].bstrOperands = "T_" + instruction.Operands.ArrayType.ToString().ToUpperInvariant(); break; case JavaOperandType.InlineNone: if (includeSymbolNames) { int?localIndex = null; switch (instruction.OpCode.OpCode) { case JavaOpCodeTag.Aload_0: case JavaOpCodeTag.Astore_0: case JavaOpCodeTag.Dload_0: case JavaOpCodeTag.Dstore_0: case JavaOpCodeTag.Fload_0: case JavaOpCodeTag.Fstore_0: case JavaOpCodeTag.Iload_0: case JavaOpCodeTag.Istore_0: case JavaOpCodeTag.Lload_0: case JavaOpCodeTag.Lstore_0: localIndex = 0; break; case JavaOpCodeTag.Aload_1: case JavaOpCodeTag.Astore_1: case JavaOpCodeTag.Dload_1: case JavaOpCodeTag.Dstore_1: case JavaOpCodeTag.Fload_1: case JavaOpCodeTag.Fstore_1: case JavaOpCodeTag.Iload_1: case JavaOpCodeTag.Istore_1: case JavaOpCodeTag.Lload_1: case JavaOpCodeTag.Lstore_1: localIndex = 1; break; case JavaOpCodeTag.Aload_2: case JavaOpCodeTag.Astore_2: case JavaOpCodeTag.Dload_2: case JavaOpCodeTag.Dstore_2: case JavaOpCodeTag.Fload_2: case JavaOpCodeTag.Fstore_2: case JavaOpCodeTag.Iload_2: case JavaOpCodeTag.Istore_2: case JavaOpCodeTag.Lload_2: case JavaOpCodeTag.Lstore_2: localIndex = 2; break; case JavaOpCodeTag.Aload_3: case JavaOpCodeTag.Astore_3: case JavaOpCodeTag.Dload_3: case JavaOpCodeTag.Dstore_3: case JavaOpCodeTag.Fload_3: case JavaOpCodeTag.Fstore_3: case JavaOpCodeTag.Iload_3: case JavaOpCodeTag.Istore_3: case JavaOpCodeTag.Lload_3: case JavaOpCodeTag.Lstore_3: localIndex = 3; break; } if (localIndex.HasValue) { int testLocation = instructionStart; if (instruction.OpCode.StackBehaviorPop != JavaStackBehavior.Pop0) { // this is a store instruction - the variable might not be visible until the following instruction testLocation += instruction.Size; } ILocation currentLocation = _executionContext.Location.GetMethod().GetLocationOfCodeIndex(testLocation); var local = localVariables.SingleOrDefault(variable => variable.GetSlot() == localIndex && variable.GetIsVisible(currentLocation)); if (local != null) { prgDisassembly[i].bstrOperands = local.GetName(); } } } break; default: prgDisassembly[i].bstrOperands = string.Empty; break; } // operand 1 switch (instruction.OpCode.OperandType) { case JavaOperandType.InlineVar_I1: prgDisassembly[i].bstrOperands += " " + instruction.Operands.Increment.ToString(); break; case JavaOperandType.InlineMethod_U1_0: prgDisassembly[i].bstrOperands += " " + instruction.Operands.Operand2.ToString(); break; case JavaOperandType.InlineType_U1: prgDisassembly[i].bstrOperands += " " + instruction.Operands.Dimensions.ToString(); break; default: break; } // operand 2 if (instruction.OpCode.OperandType == JavaOperandType.InlineMethod_U1_0) { prgDisassembly[i].bstrOperands += " 0"; } } if (dwFields.GetPosition()) { try { ILocation location = _executionContext.Location.GetMethod().GetLocationOfCodeIndex(instructionStart); prgDisassembly[i].posBeg.dwLine = (uint)location.GetLineNumber(); prgDisassembly[i].posBeg.dwColumn = 0; prgDisassembly[i].posEnd = prgDisassembly[i].posBeg; prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION; } catch (Exception e) { if (ErrorHandler.IsCriticalException(e)) { throw; } prgDisassembly[i].posBeg = default(TEXT_POSITION); prgDisassembly[i].posEnd = default(TEXT_POSITION); prgDisassembly[i].dwFields &= ~enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION; } } if (dwFields.GetFlags()) { // TODO: determine when the following condition is met? // "Indicates that this instruction is one of the next instructions to be executed (there may be more than one)." bool active = false; if (active) { prgDisassembly[i].dwFlags |= enum_DISASSEMBLY_FLAGS.DF_INSTRUCTION_ACTIVE; } // Check for location information to determine when this condition is met: // "Indicates that this instruction has source. Some instructions, such as profiling or garbage collection code, have no corresponding source." bool hasSource = prgDisassembly[i].dwFields.GetPosition(); if (hasSource) { prgDisassembly[i].dwFlags |= enum_DISASSEMBLY_FLAGS.DF_HASSOURCE; } // The current single-method disassembly only includes source from a single file, so this is for all but the first line: // "Indicates that this instruction is in a different document than the previous one." bool documentChange = i == 0 && _currentInstructionIndex == 0; if (documentChange) { prgDisassembly[i].dwFlags |= enum_DISASSEMBLY_FLAGS.DF_DOCUMENTCHANGE; } // Javac removes code that is statically determined to be unreachable (even in debug mode), so this is false: // "Indicates that this instruction will not be executed." bool disabled = false; if (disabled) { prgDisassembly[i].dwFlags |= enum_DISASSEMBLY_FLAGS.DF_DISABLED; } // This is always false in bytecode: // "Indicates that this instruction is really data (not code)." bool data = false; if (data) { prgDisassembly[i].dwFlags |= enum_DISASSEMBLY_FLAGS.DF_DATA; } // The Java debugging information format does not include document checksum information bool documentChecksum = false; if (documentChecksum) { prgDisassembly[i].dwFlags |= enum_DISASSEMBLY_FLAGS.DF_DOCUMENT_CHECKSUM; } prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS; } if (dwFields.GetByteOffset() && prgDisassembly[i].dwFields.GetPosition()) { // "The number of bytes the instruction is from the beginning of the code line." int byteOffset = 0; for (int j = _currentInstructionIndex + i - 1; j >= 0; j--) { JavaInstruction priorInstruction = _disassembledMethod.Instructions[j]; try { ILocation location = _executionContext.Location.GetMethod().GetLocationOfCodeIndex(priorInstruction.Offset); if (location.GetLineNumber() != prgDisassembly[i].posBeg.dwLine) { break; } byteOffset = instruction.Offset - priorInstruction.Offset; } catch (Exception e) { if (ErrorHandler.IsCriticalException(e)) { throw; } break; } } prgDisassembly[i].dwByteOffset = (uint)Math.Max(0, byteOffset); prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET; } if (dwFields.GetSymbol()) { switch (instruction.OpCode.OperandType) { case JavaOperandType.InlineLookupSwitch: prgDisassembly[i].bstrSymbol = "// switch"; break; case JavaOperandType.InlineTableSwitch: prgDisassembly[i].bstrSymbol = "// table switch"; break; default: break; } if (prgDisassembly[i].bstrSymbol != null) { prgDisassembly[i].dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_SYMBOL; } } } _currentInstructionIndex += (int)actualInstructions; pdwInstructionsRead = actualInstructions; return(actualInstructions == dwInstructions ? VSConstants.S_OK : VSConstants.S_FALSE); }