mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-114593 Debugger: Show variable information when no debug info
This commit is contained in:
+6
-2
@@ -18,19 +18,23 @@ package com.intellij.debugger.impl.descriptors.data;
|
||||
import com.intellij.debugger.ui.impl.watch.ArgumentValueDescriptorImpl;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.sun.jdi.Value;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ArgValueData extends DescriptorData<ArgumentValueDescriptorImpl>{
|
||||
private final int myIndex;
|
||||
private final Value myValue;
|
||||
@Nullable
|
||||
private final String myDisplayName;
|
||||
|
||||
public ArgValueData(int index, Value value) {
|
||||
public ArgValueData(int index, Value value, @Nullable String displayName) {
|
||||
super();
|
||||
myIndex = index;
|
||||
myValue = value;
|
||||
myDisplayName = displayName;
|
||||
}
|
||||
|
||||
protected ArgumentValueDescriptorImpl createDescriptorImpl(Project project) {
|
||||
return new ArgumentValueDescriptorImpl(project, myIndex, myValue);
|
||||
return new ArgumentValueDescriptorImpl(project, myIndex, myValue, myDisplayName);
|
||||
}
|
||||
|
||||
public boolean equals(Object object) {
|
||||
|
||||
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.debugger.jdi;
|
||||
|
||||
/**
|
||||
* As defined in ADM4 library
|
||||
*/
|
||||
class Bytecodes {
|
||||
/**
|
||||
* Pseudo access flag to distinguish between the synthetic attribute and
|
||||
* the synthetic access flag.
|
||||
*/
|
||||
static final int ACC_SYNTHETIC_ATTRIBUTE = 0x40000;
|
||||
|
||||
/**
|
||||
* The type of instructions without any argument.
|
||||
*/
|
||||
static final int NOARG_INSN = 0;
|
||||
|
||||
/**
|
||||
* The type of instructions with an signed byte argument.
|
||||
*/
|
||||
static final int SBYTE_INSN = 1;
|
||||
|
||||
/**
|
||||
* The type of instructions with an signed short argument.
|
||||
*/
|
||||
static final int SHORT_INSN = 2;
|
||||
|
||||
/**
|
||||
* The type of instructions with a local variable index argument.
|
||||
*/
|
||||
static final int VAR_INSN = 3;
|
||||
|
||||
/**
|
||||
* The type of instructions with an implicit local variable index argument.
|
||||
*/
|
||||
static final int IMPLVAR_INSN = 4;
|
||||
|
||||
/**
|
||||
* The type of instructions with a type descriptor argument.
|
||||
*/
|
||||
static final int TYPE_INSN = 5;
|
||||
|
||||
/**
|
||||
* The type of field and method invocations instructions.
|
||||
*/
|
||||
static final int FIELDORMETH_INSN = 6;
|
||||
|
||||
/**
|
||||
* The type of the INVOKEINTERFACE/INVOKEDYNAMIC instruction.
|
||||
*/
|
||||
static final int ITFMETH_INSN = 7;
|
||||
|
||||
/**
|
||||
* The type of the INVOKEDYNAMIC instruction.
|
||||
*/
|
||||
static final int INDYMETH_INSN = 8;
|
||||
|
||||
/**
|
||||
* The type of instructions with a 2 bytes bytecode offset label.
|
||||
*/
|
||||
static final int LABEL_INSN = 9;
|
||||
|
||||
/**
|
||||
* The type of instructions with a 4 bytes bytecode offset label.
|
||||
*/
|
||||
static final int LABELW_INSN = 10;
|
||||
|
||||
/**
|
||||
* The type of the LDC instruction.
|
||||
*/
|
||||
static final int LDC_INSN = 11;
|
||||
|
||||
/**
|
||||
* The type of the LDC_W and LDC2_W instructions.
|
||||
*/
|
||||
static final int LDCW_INSN = 12;
|
||||
|
||||
/**
|
||||
* The type of the IINC instruction.
|
||||
*/
|
||||
static final int IINC_INSN = 13;
|
||||
|
||||
/**
|
||||
* The type of the TABLESWITCH instruction.
|
||||
*/
|
||||
static final int TABL_INSN = 14;
|
||||
|
||||
/**
|
||||
* The type of the LOOKUPSWITCH instruction.
|
||||
*/
|
||||
static final int LOOK_INSN = 15;
|
||||
|
||||
/**
|
||||
* The type of the MULTIANEWARRAY instruction.
|
||||
*/
|
||||
static final int MANA_INSN = 16;
|
||||
|
||||
/**
|
||||
* The type of the WIDE instruction.
|
||||
*/
|
||||
static final int WIDE_INSN = 17;
|
||||
|
||||
/**
|
||||
* The instruction types of all JVM opcodes.
|
||||
*/
|
||||
static final byte[] TYPE;
|
||||
|
||||
/**
|
||||
* The type of CONSTANT_Class constant pool items.
|
||||
*/
|
||||
static final int CLASS = 7;
|
||||
|
||||
/**
|
||||
* The type of CONSTANT_Fieldref constant pool items.
|
||||
*/
|
||||
static final int FIELD = 9;
|
||||
|
||||
/**
|
||||
* The type of CONSTANT_Methodref constant pool items.
|
||||
*/
|
||||
static final int METH = 10;
|
||||
|
||||
/**
|
||||
* The type of CONSTANT_InterfaceMethodref constant pool items.
|
||||
*/
|
||||
static final int IMETH = 11;
|
||||
|
||||
/**
|
||||
* The type of CONSTANT_String constant pool items.
|
||||
*/
|
||||
static final int STR = 8;
|
||||
|
||||
/**
|
||||
* The type of CONSTANT_Integer constant pool items.
|
||||
*/
|
||||
static final int INT = 3;
|
||||
|
||||
/**
|
||||
* The type of CONSTANT_Float constant pool items.
|
||||
*/
|
||||
static final int FLOAT = 4;
|
||||
|
||||
/**
|
||||
* The type of CONSTANT_Long constant pool items.
|
||||
*/
|
||||
static final int LONG = 5;
|
||||
|
||||
/**
|
||||
* The type of CONSTANT_Double constant pool items.
|
||||
*/
|
||||
static final int DOUBLE = 6;
|
||||
|
||||
/**
|
||||
* The type of CONSTANT_NameAndType constant pool items.
|
||||
*/
|
||||
static final int NAME_TYPE = 12;
|
||||
|
||||
/**
|
||||
* The type of CONSTANT_Utf8 constant pool items.
|
||||
*/
|
||||
static final int UTF8 = 1;
|
||||
|
||||
/**
|
||||
* The type of CONSTANT_MethodType constant pool items.
|
||||
*/
|
||||
static final int MTYPE = 16;
|
||||
|
||||
/**
|
||||
* The type of CONSTANT_MethodHandle constant pool items.
|
||||
*/
|
||||
static final int HANDLE = 15;
|
||||
|
||||
/**
|
||||
* The type of CONSTANT_InvokeDynamic constant pool items.
|
||||
*/
|
||||
static final int INDY = 18;
|
||||
|
||||
/**
|
||||
* The base value for all CONSTANT_MethodHandle constant pool items.
|
||||
* Internally, ASM store the 9 variations of CONSTANT_MethodHandle into
|
||||
* 9 different items.
|
||||
*/
|
||||
static final int HANDLE_BASE = 20;
|
||||
|
||||
/**
|
||||
* Normal type Item stored in the ClassWriter {@link ClassWriter#typeTable},
|
||||
* instead of the constant pool, in order to avoid clashes with normal
|
||||
* constant pool items in the ClassWriter constant pool's hash table.
|
||||
*/
|
||||
static final int TYPE_NORMAL = 30;
|
||||
|
||||
/**
|
||||
* Uninitialized type Item stored in the ClassWriter
|
||||
* {@link ClassWriter#typeTable}, instead of the constant pool, in order to
|
||||
* avoid clashes with normal constant pool items in the ClassWriter constant
|
||||
* pool's hash table.
|
||||
*/
|
||||
static final int TYPE_UNINIT = 31;
|
||||
|
||||
/**
|
||||
* Merged type Item stored in the ClassWriter {@link ClassWriter#typeTable},
|
||||
* instead of the constant pool, in order to avoid clashes with normal
|
||||
* constant pool items in the ClassWriter constant pool's hash table.
|
||||
*/
|
||||
static final int TYPE_MERGED = 32;
|
||||
|
||||
/**
|
||||
* The type of BootstrapMethods items. These items are stored in a
|
||||
* special class attribute named BootstrapMethods and
|
||||
* not in the constant pool.
|
||||
*/
|
||||
static final int BSM = 33;
|
||||
|
||||
/**
|
||||
* Computes the instruction types of JVM opcodes.
|
||||
*/
|
||||
static {
|
||||
int i;
|
||||
byte[] b = new byte[220];
|
||||
String s = "AAAAAAAAAAAAAAAABCLMMDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADD"
|
||||
+ "DDDEEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
+ "AAAAAAAAAAAAAAAAANAAAAAAAAAAAAAAAAAAAAJJJJJJJJJJJJJJJJDOPAA"
|
||||
+ "AAAAGGGGGGGHIFBFAAFFAARQJJKKJJJJJJJJJJJJJJJJJJ";
|
||||
for (i = 0; i < b.length; ++i) {
|
||||
b[i] = (byte) (s.charAt(i) - 'A');
|
||||
}
|
||||
TYPE = b;
|
||||
}
|
||||
|
||||
|
||||
static final int NOP = 0; // visitInsn
|
||||
static final int ACONST_NULL = 1; // -
|
||||
static final int ICONST_M1 = 2; // -
|
||||
static final int ICONST_0 = 3; // -
|
||||
static final int ICONST_1 = 4; // -
|
||||
static final int ICONST_2 = 5; // -
|
||||
static final int ICONST_3 = 6; // -
|
||||
static final int ICONST_4 = 7; // -
|
||||
static final int ICONST_5 = 8; // -
|
||||
static final int LCONST_0 = 9; // -
|
||||
static final int LCONST_1 = 10; // -
|
||||
static final int FCONST_0 = 11; // -
|
||||
static final int FCONST_1 = 12; // -
|
||||
static final int FCONST_2 = 13; // -
|
||||
static final int DCONST_0 = 14; // -
|
||||
static final int DCONST_1 = 15; // -
|
||||
static final int BIPUSH = 16; // visitIntInsn
|
||||
static final int SIPUSH = 17; // -
|
||||
static final int LDC = 18; // visitLdcInsn
|
||||
static final int LDC_W = 19; // -
|
||||
static final int LDC2_W = 20; // -
|
||||
static final int ILOAD = 21; // visitVarInsn
|
||||
static final int LLOAD = 22; // -
|
||||
static final int FLOAD = 23; // -
|
||||
static final int DLOAD = 24; // -
|
||||
static final int ALOAD = 25; // -
|
||||
static final int ILOAD_0 = 26; // -
|
||||
static final int ILOAD_1 = 27; // -
|
||||
static final int ILOAD_2 = 28; // -
|
||||
static final int ILOAD_3 = 29; // -
|
||||
static final int LLOAD_0 = 30; // -
|
||||
static final int LLOAD_1 = 31; // -
|
||||
static final int LLOAD_2 = 32; // -
|
||||
static final int LLOAD_3 = 33; // -
|
||||
static final int FLOAD_0 = 34; // -
|
||||
static final int FLOAD_1 = 35; // -
|
||||
static final int FLOAD_2 = 36; // -
|
||||
static final int FLOAD_3 = 37; // -
|
||||
static final int DLOAD_0 = 38; // -
|
||||
static final int DLOAD_1 = 39; // -
|
||||
static final int DLOAD_2 = 40; // -
|
||||
static final int DLOAD_3 = 41; // -
|
||||
static final int ALOAD_0 = 42; // -
|
||||
static final int ALOAD_1 = 43; // -
|
||||
static final int ALOAD_2 = 44; // -
|
||||
static final int ALOAD_3 = 45; // -
|
||||
static final int IALOAD = 46; // visitInsn
|
||||
static final int LALOAD = 47; // -
|
||||
static final int FALOAD = 48; // -
|
||||
static final int DALOAD = 49; // -
|
||||
static final int AALOAD = 50; // -
|
||||
static final int BALOAD = 51; // -
|
||||
static final int CALOAD = 52; // -
|
||||
static final int SALOAD = 53; // -
|
||||
static final int ISTORE = 54; // visitVarInsn
|
||||
static final int LSTORE = 55; // -
|
||||
static final int FSTORE = 56; // -
|
||||
static final int DSTORE = 57; // -
|
||||
static final int ASTORE = 58; // -
|
||||
static final int ISTORE_0 = 59; // -
|
||||
static final int ISTORE_1 = 60; // -
|
||||
static final int ISTORE_2 = 61; // -
|
||||
static final int ISTORE_3 = 62; // -
|
||||
static final int LSTORE_0 = 63; // -
|
||||
static final int LSTORE_1 = 64; // -
|
||||
static final int LSTORE_2 = 65; // -
|
||||
static final int LSTORE_3 = 66; // -
|
||||
static final int FSTORE_0 = 67; // -
|
||||
static final int FSTORE_1 = 68; // -
|
||||
static final int FSTORE_2 = 69; // -
|
||||
static final int FSTORE_3 = 70; // -
|
||||
static final int DSTORE_0 = 71; // -
|
||||
static final int DSTORE_1 = 72; // -
|
||||
static final int DSTORE_2 = 73; // -
|
||||
static final int DSTORE_3 = 74; // -
|
||||
static final int ASTORE_0 = 75; // -
|
||||
static final int ASTORE_1 = 76; // -
|
||||
static final int ASTORE_2 = 77; // -
|
||||
static final int ASTORE_3 = 78; // -
|
||||
static final int IASTORE = 79; // visitInsn
|
||||
static final int LASTORE = 80; // -
|
||||
static final int FASTORE = 81; // -
|
||||
static final int DASTORE = 82; // -
|
||||
static final int AASTORE = 83; // -
|
||||
static final int BASTORE = 84; // -
|
||||
static final int CASTORE = 85; // -
|
||||
static final int SASTORE = 86; // -
|
||||
static final int POP = 87; // -
|
||||
static final int POP2 = 88; // -
|
||||
static final int DUP = 89; // -
|
||||
static final int DUP_X1 = 90; // -
|
||||
static final int DUP_X2 = 91; // -
|
||||
static final int DUP2 = 92; // -
|
||||
static final int DUP2_X1 = 93; // -
|
||||
static final int DUP2_X2 = 94; // -
|
||||
static final int SWAP = 95; // -
|
||||
static final int IADD = 96; // -
|
||||
static final int LADD = 97; // -
|
||||
static final int FADD = 98; // -
|
||||
static final int DADD = 99; // -
|
||||
static final int ISUB = 100; // -
|
||||
static final int LSUB = 101; // -
|
||||
static final int FSUB = 102; // -
|
||||
static final int DSUB = 103; // -
|
||||
static final int IMUL = 104; // -
|
||||
static final int LMUL = 105; // -
|
||||
static final int FMUL = 106; // -
|
||||
static final int DMUL = 107; // -
|
||||
static final int IDIV = 108; // -
|
||||
static final int LDIV = 109; // -
|
||||
static final int FDIV = 110; // -
|
||||
static final int DDIV = 111; // -
|
||||
static final int IREM = 112; // -
|
||||
static final int LREM = 113; // -
|
||||
static final int FREM = 114; // -
|
||||
static final int DREM = 115; // -
|
||||
static final int INEG = 116; // -
|
||||
static final int LNEG = 117; // -
|
||||
static final int FNEG = 118; // -
|
||||
static final int DNEG = 119; // -
|
||||
static final int ISHL = 120; // -
|
||||
static final int LSHL = 121; // -
|
||||
static final int ISHR = 122; // -
|
||||
static final int LSHR = 123; // -
|
||||
static final int IUSHR = 124; // -
|
||||
static final int LUSHR = 125; // -
|
||||
static final int IAND = 126; // -
|
||||
static final int LAND = 127; // -
|
||||
static final int IOR = 128; // -
|
||||
static final int LOR = 129; // -
|
||||
static final int IXOR = 130; // -
|
||||
static final int LXOR = 131; // -
|
||||
static final int IINC = 132; // visitIincInsn
|
||||
static final int I2L = 133; // visitInsn
|
||||
static final int I2F = 134; // -
|
||||
static final int I2D = 135; // -
|
||||
static final int L2I = 136; // -
|
||||
static final int L2F = 137; // -
|
||||
static final int L2D = 138; // -
|
||||
static final int F2I = 139; // -
|
||||
static final int F2L = 140; // -
|
||||
static final int F2D = 141; // -
|
||||
static final int D2I = 142; // -
|
||||
static final int D2L = 143; // -
|
||||
static final int D2F = 144; // -
|
||||
static final int I2B = 145; // -
|
||||
static final int I2C = 146; // -
|
||||
static final int I2S = 147; // -
|
||||
static final int LCMP = 148; // -
|
||||
static final int FCMPL = 149; // -
|
||||
static final int FCMPG = 150; // -
|
||||
static final int DCMPL = 151; // -
|
||||
static final int DCMPG = 152; // -
|
||||
static final int IFEQ = 153; // visitJumpInsn
|
||||
static final int IFNE = 154; // -
|
||||
static final int IFLT = 155; // -
|
||||
static final int IFGE = 156; // -
|
||||
static final int IFGT = 157; // -
|
||||
static final int IFLE = 158; // -
|
||||
static final int IF_ICMPEQ = 159; // -
|
||||
static final int IF_ICMPNE = 160; // -
|
||||
static final int IF_ICMPLT = 161; // -
|
||||
static final int IF_ICMPGE = 162; // -
|
||||
static final int IF_ICMPGT = 163; // -
|
||||
static final int IF_ICMPLE = 164; // -
|
||||
static final int IF_ACMPEQ = 165; // -
|
||||
static final int IF_ACMPNE = 166; // -
|
||||
static final int GOTO = 167; // -
|
||||
static final int JSR = 168; // -
|
||||
static final int RET = 169; // visitVarInsn
|
||||
static final int TABLESWITCH = 170; // visiTableSwitchInsn
|
||||
static final int LOOKUPSWITCH = 171; // visitLookupSwitch
|
||||
static final int IRETURN = 172; // visitInsn
|
||||
static final int LRETURN = 173; // -
|
||||
static final int FRETURN = 174; // -
|
||||
static final int DRETURN = 175; // -
|
||||
static final int ARETURN = 176; // -
|
||||
static final int RETURN = 177; // -
|
||||
static final int GETSTATIC = 178; // visitFieldInsn
|
||||
static final int PUTSTATIC = 179; // -
|
||||
static final int GETFIELD = 180; // -
|
||||
static final int PUTFIELD = 181; // -
|
||||
static final int INVOKEVIRTUAL = 182; // visitMethodInsn
|
||||
static final int INVOKESPECIAL = 183; // -
|
||||
static final int INVOKESTATIC = 184; // -
|
||||
static final int INVOKEINTERFACE = 185; // -
|
||||
static final int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn
|
||||
static final int NEW = 187; // visitTypeInsn
|
||||
static final int NEWARRAY = 188; // visitIntInsn
|
||||
static final int ANEWARRAY = 189; // visitTypeInsn
|
||||
static final int ARRAYLENGTH = 190; // visitInsn
|
||||
static final int ATHROW = 191; // -
|
||||
static final int CHECKCAST = 192; // visitTypeInsn
|
||||
static final int INSTANCEOF = 193; // -
|
||||
static final int MONITORENTER = 194; // visitInsn
|
||||
static final int MONITOREXIT = 195; // -
|
||||
static final int WIDE = 196; // NOT VISITED
|
||||
static final int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
|
||||
static final int IFNULL = 198; // visitJumpInsn
|
||||
static final int IFNONNULL = 199; // -
|
||||
static final int GOTO_W = 200; // -
|
||||
static final int JSR_W = 201; // -
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.debugger.jdi;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 10/7/13
|
||||
*/
|
||||
public class DecompiledLocalVariable{
|
||||
public static final Comparator<DecompiledLocalVariable> COMPARATOR = new Comparator<DecompiledLocalVariable>() {
|
||||
@Override
|
||||
public int compare(DecompiledLocalVariable v1, DecompiledLocalVariable v2) {
|
||||
return v1.getSlot() - v2.getSlot();
|
||||
}
|
||||
};
|
||||
|
||||
private final int mySlot;
|
||||
private final String mySignature;
|
||||
private final String myName;
|
||||
|
||||
public DecompiledLocalVariable(int slot, String name, String signature) {
|
||||
mySlot = slot;
|
||||
mySignature = signature;
|
||||
myName = name;
|
||||
}
|
||||
|
||||
public int getSlot() {
|
||||
return mySlot;
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return mySignature;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.debugger.jdi;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* "Code" attribute parsing extracted from ASM4 library and adopted to finding operations with local variables
|
||||
*/
|
||||
public class InstructionParser {
|
||||
private final byte[] myCode;
|
||||
private final long myCurrentInstructionIndex;
|
||||
|
||||
public InstructionParser(byte[] code, long instructionIndex) {
|
||||
myCode = code;
|
||||
myCurrentInstructionIndex = instructionIndex;
|
||||
}
|
||||
|
||||
public void parse() {
|
||||
final int codeEnd = myCode.length;
|
||||
int v = 0;
|
||||
int instructionIndex = 0;
|
||||
while (v < codeEnd) {
|
||||
if (instructionIndex++ >= myCurrentInstructionIndex) {
|
||||
break;
|
||||
}
|
||||
int opcode = myCode[v] & 0xFF;
|
||||
switch (Bytecodes.TYPE[opcode]) {
|
||||
case Bytecodes.NOARG_INSN:
|
||||
v += 1;
|
||||
break;
|
||||
case Bytecodes.IMPLVAR_INSN: {
|
||||
final int varOpcode;
|
||||
if (opcode > Bytecodes.ISTORE) {
|
||||
opcode -= Bytecodes.ISTORE_0;
|
||||
varOpcode = Bytecodes.ISTORE + (opcode >> 2);
|
||||
}
|
||||
else {
|
||||
opcode -= Bytecodes.ILOAD_0;
|
||||
varOpcode = Bytecodes.ILOAD + (opcode >> 2);
|
||||
}
|
||||
final String signature = getVarInstructionTypeSignature(varOpcode);
|
||||
if (signature != null) {
|
||||
localVariableInstructionFound(varOpcode, opcode & 0x3, signature);
|
||||
}
|
||||
v += 1;
|
||||
break;
|
||||
}
|
||||
case Bytecodes.LABEL_INSN:
|
||||
v += 3;
|
||||
break;
|
||||
case Bytecodes.LABELW_INSN:
|
||||
v += 5;
|
||||
break;
|
||||
case Bytecodes.WIDE_INSN: {
|
||||
opcode = myCode[v + 1] & 0xFF;
|
||||
final String signature = getVarInstructionTypeSignature(opcode);
|
||||
if (signature != null) {
|
||||
localVariableInstructionFound(opcode, readUnsignedShort(v + 2), signature);
|
||||
}
|
||||
if (opcode == Bytecodes.IINC) {
|
||||
v += 6;
|
||||
}
|
||||
else {
|
||||
v += 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Bytecodes.TABL_INSN:
|
||||
// skips 0 to 3 padding bytes
|
||||
v = v + 4 - (v & 3);
|
||||
// reads instruction
|
||||
int min = readInt(v + 4);
|
||||
int max = readInt(v + 8);
|
||||
v += 12;
|
||||
final int length = max - min + 1;
|
||||
v += 4 * length;
|
||||
break;
|
||||
case Bytecodes.LOOK_INSN:
|
||||
// skips 0 to 3 padding bytes
|
||||
v = v + 4 - (v & 3);
|
||||
// reads instruction
|
||||
final int len = readInt(v + 4);
|
||||
v += 8 * (len + 1);
|
||||
break;
|
||||
case Bytecodes.VAR_INSN: {
|
||||
final String signature = getVarInstructionTypeSignature(opcode);
|
||||
if (signature != null) {
|
||||
localVariableInstructionFound(opcode, myCode[v + 1] & 0xFF, signature);
|
||||
}
|
||||
v += 2;
|
||||
break;
|
||||
}
|
||||
case Bytecodes.SBYTE_INSN:
|
||||
v += 2;
|
||||
break;
|
||||
case Bytecodes.SHORT_INSN:
|
||||
v += 3;
|
||||
break;
|
||||
case Bytecodes.LDC_INSN:
|
||||
v += 2;
|
||||
break;
|
||||
case Bytecodes.LDCW_INSN:
|
||||
v += 3;
|
||||
break;
|
||||
case Bytecodes.FIELDORMETH_INSN:
|
||||
case Bytecodes.ITFMETH_INSN: {
|
||||
if (opcode == Bytecodes.INVOKEINTERFACE) {
|
||||
v += 5;
|
||||
}
|
||||
else {
|
||||
v += 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Bytecodes.INDYMETH_INSN: {
|
||||
v += 5;
|
||||
break;
|
||||
}
|
||||
case Bytecodes.TYPE_INSN:
|
||||
v += 3;
|
||||
break;
|
||||
case Bytecodes.IINC_INSN: {
|
||||
final String signature = getVarInstructionTypeSignature(opcode);
|
||||
if (signature != null) {
|
||||
localVariableInstructionFound(opcode, myCode[v + 1] & 0xFF, signature);
|
||||
}
|
||||
v += 3;
|
||||
break;
|
||||
}
|
||||
// case MANA_INSN:
|
||||
default:
|
||||
v += 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int readUnsignedShort(final int index) {
|
||||
final byte[] b = myCode;
|
||||
return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
|
||||
}
|
||||
|
||||
public int readInt(final int index) {
|
||||
final byte[] b = myCode;
|
||||
return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
|
||||
| ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
|
||||
}
|
||||
|
||||
protected void localVariableInstructionFound(int opcode, int slot, String typeSignature) {
|
||||
// override to perform actions
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getVarInstructionTypeSignature(int opcode) {
|
||||
switch (opcode) {
|
||||
case Bytecodes.ILOAD:
|
||||
case Bytecodes.ILOAD_0:
|
||||
case Bytecodes.ILOAD_1:
|
||||
case Bytecodes.ILOAD_2:
|
||||
case Bytecodes.ILOAD_3:
|
||||
case Bytecodes.ISTORE:
|
||||
case Bytecodes.ISTORE_0:
|
||||
case Bytecodes.ISTORE_1:
|
||||
case Bytecodes.ISTORE_2:
|
||||
case Bytecodes.ISTORE_3:
|
||||
case Bytecodes.IINC:
|
||||
return "I";
|
||||
|
||||
case Bytecodes.LLOAD:
|
||||
case Bytecodes.LLOAD_0:
|
||||
case Bytecodes.LLOAD_1:
|
||||
case Bytecodes.LLOAD_2:
|
||||
case Bytecodes.LLOAD_3:
|
||||
case Bytecodes.LSTORE:
|
||||
case Bytecodes.LSTORE_0:
|
||||
case Bytecodes.LSTORE_1:
|
||||
case Bytecodes.LSTORE_2:
|
||||
case Bytecodes.LSTORE_3:
|
||||
return "J"; // long
|
||||
|
||||
case Bytecodes.FLOAD:
|
||||
case Bytecodes.FLOAD_0:
|
||||
case Bytecodes.FLOAD_1:
|
||||
case Bytecodes.FLOAD_2:
|
||||
case Bytecodes.FLOAD_3:
|
||||
case Bytecodes.FSTORE:
|
||||
case Bytecodes.FSTORE_0:
|
||||
case Bytecodes.FSTORE_1:
|
||||
case Bytecodes.FSTORE_2:
|
||||
case Bytecodes.FSTORE_3:
|
||||
return "F"; // float
|
||||
|
||||
case Bytecodes.DLOAD:
|
||||
case Bytecodes.DLOAD_0:
|
||||
case Bytecodes.DLOAD_1:
|
||||
case Bytecodes.DLOAD_2:
|
||||
case Bytecodes.DLOAD_3:
|
||||
case Bytecodes.DSTORE:
|
||||
case Bytecodes.DSTORE_0:
|
||||
case Bytecodes.DSTORE_1:
|
||||
case Bytecodes.DSTORE_2:
|
||||
case Bytecodes.DSTORE_3:
|
||||
return "D"; // double
|
||||
|
||||
case Bytecodes.ALOAD:
|
||||
case Bytecodes.ALOAD_0:
|
||||
case Bytecodes.ALOAD_1:
|
||||
case Bytecodes.ALOAD_2:
|
||||
case Bytecodes.ALOAD_3:
|
||||
case Bytecodes.ASTORE:
|
||||
case Bytecodes.ASTORE_0:
|
||||
case Bytecodes.ASTORE_1:
|
||||
case Bytecodes.ASTORE_2:
|
||||
case Bytecodes.ASTORE_3:
|
||||
return "L"; // object ref
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.debugger.jdi;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.sun.jdi.InternalException;
|
||||
import com.sun.jdi.StackFrame;
|
||||
import com.sun.jdi.Value;
|
||||
import com.sun.jdi.VirtualMachine;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* From JDI sources:
|
||||
*
|
||||
validateStackFrame();
|
||||
validateMirrors(variables);
|
||||
|
||||
int count = variables.size();
|
||||
JDWP.StackFrame.GetValues.SlotInfo[] slots =
|
||||
new JDWP.StackFrame.GetValues.SlotInfo[count];
|
||||
|
||||
for (int i=0; i<count; ++i) {
|
||||
LocalVariableImpl variable = (LocalVariableImpl)variables.get(i);
|
||||
if (!variable.isVisible(this)) {
|
||||
throw new IllegalArgumentException(variable.name() +
|
||||
" is not valid at this frame location");
|
||||
}
|
||||
slots[i] = new JDWP.StackFrame.GetValues.SlotInfo(variable.slot(),
|
||||
(byte)variable.signature().charAt(0));
|
||||
}
|
||||
|
||||
PacketStream ps;
|
||||
|
||||
synchronized (vm.state()) {
|
||||
validateStackFrame();
|
||||
ps = JDWP.StackFrame.GetValues.enqueueCommand(vm, thread, id, slots);
|
||||
}
|
||||
|
||||
ValueImpl[] values;
|
||||
try {
|
||||
values = JDWP.StackFrame.GetValues.waitForReply(vm, ps).values;
|
||||
} catch (JDWPException exc) {
|
||||
switch (exc.errorCode()) {
|
||||
case JDWP.Error.INVALID_FRAMEID:
|
||||
case JDWP.Error.THREAD_NOT_SUSPENDED:
|
||||
case JDWP.Error.INVALID_THREAD:
|
||||
throw new InvalidStackFrameException();
|
||||
default:
|
||||
throw exc.toJDIException();
|
||||
}
|
||||
}
|
||||
|
||||
if (count != values.length) {
|
||||
throw new InternalException(
|
||||
"Wrong number of values returned from target VM");
|
||||
}
|
||||
Map map = new HashMap(count);
|
||||
for (int i=0; i<count; ++i) {
|
||||
LocalVariableImpl variable = (LocalVariableImpl)variables.get(i);
|
||||
map.put(variable, values[i]);
|
||||
}
|
||||
return map;
|
||||
*/
|
||||
public class LocalVariablesUtil {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.jdi.LocalVariablesUtil");
|
||||
|
||||
private static final boolean ourInitializationOk;
|
||||
private static Class<?> ourSlotInfoClass;
|
||||
private static Constructor<?> slotInfoConstructor;
|
||||
private static Class<?> ourGetValuesClass;
|
||||
private static Method ourEnqueueMethod;
|
||||
private static Method ourWaitForReplyMethod;
|
||||
|
||||
static {
|
||||
boolean success = false;
|
||||
try {
|
||||
ourSlotInfoClass = Class.forName("com.sun.tools.jdi.JDWP$StackFrame$GetValues$SlotInfo");
|
||||
slotInfoConstructor = ourSlotInfoClass.getDeclaredConstructor(int.class, byte.class);
|
||||
slotInfoConstructor.setAccessible(true);
|
||||
|
||||
ourGetValuesClass = Class.forName("com.sun.tools.jdi.JDWP$StackFrame$GetValues");
|
||||
ourEnqueueMethod = findMethod(ourGetValuesClass, "enqueueCommand");
|
||||
ourEnqueueMethod.setAccessible(true);
|
||||
ourWaitForReplyMethod = findMethod(ourGetValuesClass, "waitForReply");
|
||||
ourWaitForReplyMethod.setAccessible(true);
|
||||
|
||||
success = true;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
ourInitializationOk = success;
|
||||
}
|
||||
|
||||
public static Map<DecompiledLocalVariable, Value> fetchValues(StackFrame frame, Collection<DecompiledLocalVariable> vars) throws Exception {
|
||||
if (!ourInitializationOk) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
final Field frameIdField = frame.getClass().getDeclaredField("id");
|
||||
frameIdField.setAccessible(true);
|
||||
final Object frameId = frameIdField.get(frame);
|
||||
|
||||
final VirtualMachine vm = frame.virtualMachine();
|
||||
final Method stateMethod = vm.getClass().getDeclaredMethod("state");
|
||||
stateMethod.setAccessible(true);
|
||||
|
||||
Object slotInfoArray = createSlotInfoArray(vars);
|
||||
|
||||
Object ps;
|
||||
final Object vmState = stateMethod.invoke(vm);
|
||||
synchronized(vmState) {
|
||||
ps = ourEnqueueMethod.invoke(null, vm, frame.thread(), frameId, slotInfoArray);
|
||||
}
|
||||
|
||||
try {
|
||||
final Object reply = ourWaitForReplyMethod.invoke(null, vm, ps);
|
||||
final Field valuesField = reply.getClass().getDeclaredField("values");
|
||||
valuesField.setAccessible(true);
|
||||
final Value[] values = (Value[])valuesField.get(reply);
|
||||
if (vars.size() != values.length) {
|
||||
throw new InternalException("Wrong number of values returned from target VM");
|
||||
}
|
||||
final Map<DecompiledLocalVariable, Value> map = new HashMap<DecompiledLocalVariable, Value>(vars.size());
|
||||
int idx = 0;
|
||||
for (DecompiledLocalVariable var : vars) {
|
||||
map.put(var, values[idx++]);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
final Throwable target = e.getTargetException();
|
||||
if (target instanceof Exception) {
|
||||
throw (Exception)target;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static Object createSlotInfoArray(Collection<DecompiledLocalVariable> vars) throws Exception {
|
||||
final Object arrayInstance = Array.newInstance(ourSlotInfoClass, vars.size());
|
||||
|
||||
int idx = 0;
|
||||
for (DecompiledLocalVariable var : vars) {
|
||||
final Object info = slotInfoConstructor.newInstance(var.getSlot(), (byte)var.getSignature().charAt(0));
|
||||
Array.set(arrayInstance, idx++, info);
|
||||
}
|
||||
|
||||
return arrayInstance;
|
||||
}
|
||||
|
||||
private static Method findMethod(Class aClass, String methodName) throws NoSuchMethodException {
|
||||
for (Method method : aClass.getDeclaredMethods()) {
|
||||
if (methodName.equals(method.getName())) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
throw new NoSuchMethodException(aClass.getName() + "." + methodName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,11 +30,10 @@ import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.engine.evaluation.TextWithImports;
|
||||
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
|
||||
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
|
||||
import com.intellij.debugger.engine.jdi.StackFrameProxy;
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl;
|
||||
import com.intellij.debugger.impl.DebuggerSession;
|
||||
import com.intellij.debugger.jdi.LocalVariableProxyImpl;
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl;
|
||||
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
|
||||
import com.intellij.debugger.jdi.*;
|
||||
import com.intellij.debugger.settings.ViewsGeneralSettings;
|
||||
import com.intellij.debugger.ui.impl.watch.*;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
@@ -53,9 +52,9 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.text.CharArrayUtil;
|
||||
import com.intellij.util.ui.tree.TreeModelAdapter;
|
||||
import com.intellij.xdebugger.XDebuggerBundle;
|
||||
import com.sun.jdi.AbsentInformationException;
|
||||
import com.sun.jdi.ObjectCollectedException;
|
||||
import com.sun.jdi.Value;
|
||||
import com.sun.jdi.*;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
import gnu.trove.TObjectProcedure;
|
||||
|
||||
import javax.swing.event.TreeModelEvent;
|
||||
import javax.swing.tree.TreeModel;
|
||||
@@ -167,10 +166,25 @@ public class FrameVariablesTree extends DebuggerTree {
|
||||
final Collection<Value> argValues = frame.getArgumentValues();
|
||||
int index = 0;
|
||||
for (Value argValue : argValues) {
|
||||
final ArgumentValueDescriptorImpl descriptor = myNodeManager.getArgumentValueDescriptor(stackDescriptor, index++, argValue);
|
||||
final ArgumentValueDescriptorImpl descriptor = myNodeManager.getArgumentValueDescriptor(stackDescriptor, index++, argValue, null);
|
||||
final DebuggerTreeNodeImpl variableNode = myNodeManager.createNode(descriptor, evaluationContext);
|
||||
myChildren.add(variableNode);
|
||||
}
|
||||
final List<DecompiledLocalVariable> decompiled = collectVariablesFromBytecode(frame, argValues.size());
|
||||
if (!decompiled.isEmpty()) {
|
||||
try {
|
||||
final Map<DecompiledLocalVariable, Value> values = LocalVariablesUtil.fetchValues(frame.getStackFrame(), decompiled);
|
||||
for (DecompiledLocalVariable var : decompiled) {
|
||||
final Value value = values.get(var);
|
||||
final ArgumentValueDescriptorImpl descriptor = myNodeManager.getArgumentValueDescriptor(stackDescriptor, var.getSlot(), value, var.getName());
|
||||
final DebuggerTreeNodeImpl variableNode = myNodeManager.createNode(descriptor, evaluationContext);
|
||||
myChildren.add(variableNode);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
LOG.info(ex);
|
||||
}
|
||||
}
|
||||
myChildren.add(myNodeManager.createMessageNode(MessageDescriptor.LOCAL_VARIABLES_INFO_UNAVAILABLE));
|
||||
}
|
||||
else {
|
||||
@@ -180,6 +194,56 @@ public class FrameVariablesTree extends DebuggerTree {
|
||||
}
|
||||
}
|
||||
|
||||
private static List<DecompiledLocalVariable> collectVariablesFromBytecode(final StackFrameProxy frame, int argumentCount) throws EvaluateException {
|
||||
if (!frame.getVirtualMachine().canGetBytecodes()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
try {
|
||||
final Location location = frame.location();
|
||||
final Method method = location.method();
|
||||
final Location methodLocation = method.location();
|
||||
if (methodLocation == null || methodLocation.codeIndex() < 0) {
|
||||
// native or abstract method
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final byte[] bytecodes = method.bytecodes();
|
||||
if (bytecodes != null && bytecodes.length > 0) {
|
||||
final int firstLocalVariableSlot = argumentCount + (method.isStatic()? 0 : 1);
|
||||
final long instructionIndex = location.codeIndex();
|
||||
final TIntObjectHashMap<DecompiledLocalVariable> usedVars = new TIntObjectHashMap<DecompiledLocalVariable>();
|
||||
new InstructionParser(bytecodes, instructionIndex) {
|
||||
@Override
|
||||
protected void localVariableInstructionFound(int opcode, int slot, String typeSignature) {
|
||||
if (slot >= firstLocalVariableSlot) {
|
||||
DecompiledLocalVariable variable = usedVars.get(slot);
|
||||
if (variable == null || !typeSignature.equals(variable.getSignature())) {
|
||||
variable = new DecompiledLocalVariable(slot, "slot_" + slot, typeSignature);
|
||||
usedVars.put(slot, variable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}.parse();
|
||||
|
||||
if (usedVars.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final List<DecompiledLocalVariable> vars = new ArrayList<DecompiledLocalVariable>(usedVars.size());
|
||||
usedVars.forEachValue(new TObjectProcedure<DecompiledLocalVariable>() {
|
||||
@Override
|
||||
public boolean execute(DecompiledLocalVariable var) {
|
||||
vars.add(var);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Collections.sort(vars, DecompiledLocalVariable.COMPARATOR);
|
||||
return vars;
|
||||
}
|
||||
}
|
||||
catch (UnsupportedOperationException ignored) {
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static Map<String, LocalVariableProxyImpl> getVisibleVariables(final StackFrameDescriptorImpl stackDescriptor) throws EvaluateException {
|
||||
final StackFrameProxyImpl frame = stackDescriptor.getFrameProxy();
|
||||
if (frame == null) {
|
||||
|
||||
+55
-2
@@ -30,17 +30,21 @@ import com.intellij.util.IncorrectOperationException;
|
||||
import com.sun.jdi.PrimitiveValue;
|
||||
import com.sun.jdi.Value;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
public class ArgumentValueDescriptorImpl extends ValueDescriptorImpl{
|
||||
private final int myIndex;
|
||||
private final Value myValue;
|
||||
private String myName;
|
||||
private boolean myParameterNameCalcutated;
|
||||
private final String myDefaultName;
|
||||
|
||||
public ArgumentValueDescriptorImpl(Project project, int index, Value value) {
|
||||
public ArgumentValueDescriptorImpl(Project project, int index, Value value, String name) {
|
||||
super(project);
|
||||
myIndex = index;
|
||||
myValue = value;
|
||||
myName = "arg" + String.valueOf(index);
|
||||
myDefaultName = name != null ? name : "arg" + String.valueOf(index);
|
||||
myName = myDefaultName;
|
||||
setLvalue(true);
|
||||
}
|
||||
|
||||
@@ -61,6 +65,55 @@ public class ArgumentValueDescriptorImpl extends ValueDescriptorImpl{
|
||||
myName = param.getName();
|
||||
myParameterNameCalcutated = true;
|
||||
}
|
||||
else {
|
||||
// treat myIndex as a variable slot index
|
||||
final PsiCodeBlock body = method.getBody();
|
||||
if (body != null) {
|
||||
final StringBuilder nameBuilder = new StringBuilder();
|
||||
nameBuilder.append(myDefaultName);
|
||||
try {
|
||||
final int startSlot = params.getParametersCount() + (method.hasModifierProperty(PsiModifier.STATIC)? 0 : 1);
|
||||
body.accept(new JavaRecursiveElementVisitor() {
|
||||
private int myCurrentSlotIndex = startSlot;
|
||||
private final Stack<Integer> myIndexStack = new Stack<Integer>();
|
||||
@Override
|
||||
public void visitCodeBlock(PsiCodeBlock block) {
|
||||
myIndexStack.push(myCurrentSlotIndex);
|
||||
try {
|
||||
super.visitCodeBlock(block);
|
||||
}
|
||||
finally {
|
||||
myCurrentSlotIndex = myIndexStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(PsiLocalVariable variable) {
|
||||
if (myCurrentSlotIndex == myIndex) {
|
||||
if (nameBuilder.length() == myDefaultName.length()) {
|
||||
nameBuilder.append(": ");
|
||||
}
|
||||
else {
|
||||
nameBuilder.append("|");
|
||||
}
|
||||
nameBuilder.append(variable.getName());
|
||||
}
|
||||
final PsiType varType = variable.getType();
|
||||
myCurrentSlotIndex += (varType == PsiType.DOUBLE || varType == PsiType.LONG)? 2 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClass(PsiClass aClass) {
|
||||
// skip local and anonymous classes
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
finally {
|
||||
myName = nameBuilder.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -152,8 +152,8 @@ public class NodeDescriptorFactoryImpl implements NodeDescriptorFactory {
|
||||
return getDescriptor(parent, new LocalData((LocalVariableProxyImpl)local));
|
||||
}
|
||||
|
||||
public ArgumentValueDescriptorImpl getArgumentValueDescriptor(NodeDescriptor parent, int index, Value value) {
|
||||
return getDescriptor(parent, new ArgValueData(index, value));
|
||||
public ArgumentValueDescriptorImpl getArgumentValueDescriptor(NodeDescriptor parent, int index, Value value, final String name) {
|
||||
return getDescriptor(parent, new ArgValueData(index, value, name));
|
||||
}
|
||||
|
||||
public StackFrameDescriptorImpl getStackFrameDescriptor(NodeDescriptorImpl parent, StackFrameProxyImpl frameProxy) {
|
||||
|
||||
@@ -26,6 +26,8 @@ import java.util.List;
|
||||
public interface VirtualMachineProxy {
|
||||
List<ReferenceType> allClasses();
|
||||
|
||||
boolean canGetBytecodes();
|
||||
|
||||
boolean versionHigher(String version);
|
||||
|
||||
boolean canWatchFieldModification();
|
||||
|
||||
Reference in New Issue
Block a user