jdk/src/share/classes/com/sun/tools/jdi/StackFrameImpl.java
changeset 2 90ce3da70b43
child 51 6fe31bc95bbc
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1998-2005 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package com.sun.tools.jdi;
       
    27 
       
    28 import com.sun.jdi.*;
       
    29 
       
    30 import java.util.List;
       
    31 import java.util.Map;
       
    32 import java.util.ArrayList;
       
    33 import java.util.Arrays;
       
    34 import java.util.HashMap;
       
    35 import java.util.Iterator;
       
    36 import java.util.Collections;
       
    37 
       
    38 public class StackFrameImpl extends MirrorImpl
       
    39                             implements StackFrame, ThreadListener
       
    40 {
       
    41     /* Once false, frame should not be used.
       
    42      * access synchronized on (vm.state())
       
    43      */
       
    44     private boolean isValid = true;
       
    45 
       
    46     private final ThreadReferenceImpl thread;
       
    47     private final long id;
       
    48     private final Location location;
       
    49     private Map<String, LocalVariable> visibleVariables =  null;
       
    50     private ObjectReference thisObject = null;
       
    51 
       
    52     StackFrameImpl(VirtualMachine vm, ThreadReferenceImpl thread,
       
    53                    long id, Location location) {
       
    54         super(vm);
       
    55         this.thread = thread;
       
    56         this.id = id;
       
    57         this.location = location;
       
    58         thread.addListener(this);
       
    59     }
       
    60 
       
    61     /*
       
    62      * ThreadListener implementation
       
    63      * Must be synchronized since we must protect against
       
    64      * sending defunct (isValid == false) stack ids to the back-end.
       
    65      */
       
    66     public boolean threadResumable(ThreadAction action) {
       
    67         synchronized (vm.state()) {
       
    68             if (isValid) {
       
    69                 isValid = false;
       
    70                 return false;   /* remove this stack frame as a listener */
       
    71             } else {
       
    72                 throw new InternalException(
       
    73                                   "Invalid stack frame thread listener");
       
    74             }
       
    75         }
       
    76     }
       
    77 
       
    78     void validateStackFrame() {
       
    79         if (!isValid) {
       
    80             throw new InvalidStackFrameException("Thread has been resumed");
       
    81         }
       
    82     }
       
    83 
       
    84     /**
       
    85      * Return the frame location.
       
    86      * Need not be synchronized since it cannot be provably stale.
       
    87      */
       
    88     public Location location() {
       
    89         validateStackFrame();
       
    90         return location;
       
    91     }
       
    92 
       
    93     /**
       
    94      * Return the thread holding the frame.
       
    95      * Need not be synchronized since it cannot be provably stale.
       
    96      */
       
    97     public ThreadReference thread() {
       
    98         validateStackFrame();
       
    99         return thread;
       
   100     }
       
   101 
       
   102     public boolean equals(Object obj) {
       
   103         if ((obj != null) && (obj instanceof StackFrameImpl)) {
       
   104             StackFrameImpl other = (StackFrameImpl)obj;
       
   105             return (id == other.id) &&
       
   106                    (thread().equals(other.thread())) &&
       
   107                    (location().equals(other.location())) &&
       
   108                     super.equals(obj);
       
   109         } else {
       
   110             return false;
       
   111         }
       
   112     }
       
   113 
       
   114     public int hashCode() {
       
   115         return (thread().hashCode() << 4) + ((int)id);
       
   116     }
       
   117 
       
   118     public ObjectReference thisObject() {
       
   119         validateStackFrame();
       
   120         MethodImpl currentMethod = (MethodImpl)location.method();
       
   121         if (currentMethod.isStatic() || currentMethod.isNative()) {
       
   122             return null;
       
   123         } else {
       
   124             if (thisObject == null) {
       
   125                 PacketStream ps;
       
   126 
       
   127                 /* protect against defunct frame id */
       
   128                 synchronized (vm.state()) {
       
   129                     validateStackFrame();
       
   130                     ps = JDWP.StackFrame.ThisObject.
       
   131                                       enqueueCommand(vm, thread, id);
       
   132                 }
       
   133 
       
   134                 /* actually get it, now that order is guaranteed */
       
   135                 try {
       
   136                     thisObject = JDWP.StackFrame.ThisObject.
       
   137                                       waitForReply(vm, ps).objectThis;
       
   138                 } catch (JDWPException exc) {
       
   139                     switch (exc.errorCode()) {
       
   140                     case JDWP.Error.INVALID_FRAMEID:
       
   141                     case JDWP.Error.THREAD_NOT_SUSPENDED:
       
   142                     case JDWP.Error.INVALID_THREAD:
       
   143                         throw new InvalidStackFrameException();
       
   144                     default:
       
   145                         throw exc.toJDIException();
       
   146                     }
       
   147                 }
       
   148             }
       
   149         }
       
   150         return thisObject;
       
   151     }
       
   152 
       
   153     /**
       
   154      * Build the visible variable map.
       
   155      * Need not be synchronized since it cannot be provably stale.
       
   156      */
       
   157     private void createVisibleVariables() throws AbsentInformationException {
       
   158         if (visibleVariables == null) {
       
   159             List<LocalVariable> allVariables = location.method().variables();
       
   160             Map<String, LocalVariable> map = new HashMap<String, LocalVariable>(allVariables.size());
       
   161 
       
   162             for (LocalVariable variable : allVariables) {
       
   163                 String name = variable.name();
       
   164                 if (variable.isVisible(this)) {
       
   165                     LocalVariable existing = (LocalVariable)map.get(name);
       
   166                     if ((existing == null) ||
       
   167                         ((LocalVariableImpl)variable).hides(existing)) {
       
   168                         map.put(name, variable);
       
   169                     }
       
   170                 }
       
   171             }
       
   172             visibleVariables = map;
       
   173         }
       
   174     }
       
   175 
       
   176     /**
       
   177      * Return the list of visible variable in the frame.
       
   178      * Need not be synchronized since it cannot be provably stale.
       
   179      */
       
   180     public List<LocalVariable> visibleVariables() throws AbsentInformationException {
       
   181         validateStackFrame();
       
   182         createVisibleVariables();
       
   183         List<LocalVariable> mapAsList = new ArrayList<LocalVariable>(visibleVariables.values());
       
   184         Collections.sort(mapAsList);
       
   185         return mapAsList;
       
   186     }
       
   187 
       
   188     /**
       
   189      * Return a particular variable in the frame.
       
   190      * Need not be synchronized since it cannot be provably stale.
       
   191      */
       
   192     public LocalVariable visibleVariableByName(String name) throws AbsentInformationException  {
       
   193         validateStackFrame();
       
   194         createVisibleVariables();
       
   195         return visibleVariables.get(name);
       
   196     }
       
   197 
       
   198     public Value getValue(LocalVariable variable) {
       
   199         List<LocalVariable> list = new ArrayList<LocalVariable>(1);
       
   200         list.add(variable);
       
   201         return getValues(list).get(variable);
       
   202     }
       
   203 
       
   204     public Map<LocalVariable, Value> getValues(List<? extends LocalVariable> variables) {
       
   205         validateStackFrame();
       
   206         validateMirrors(variables);
       
   207 
       
   208         int count = variables.size();
       
   209         JDWP.StackFrame.GetValues.SlotInfo[] slots =
       
   210                            new JDWP.StackFrame.GetValues.SlotInfo[count];
       
   211 
       
   212         for (int i=0; i<count; ++i) {
       
   213             LocalVariableImpl variable = (LocalVariableImpl)variables.get(i);
       
   214             if (!variable.isVisible(this)) {
       
   215                 throw new IllegalArgumentException(variable.name() +
       
   216                                  " is not valid at this frame location");
       
   217             }
       
   218             slots[i] = new JDWP.StackFrame.GetValues.SlotInfo(variable.slot(),
       
   219                                       (byte)variable.signature().charAt(0));
       
   220         }
       
   221 
       
   222         PacketStream ps;
       
   223 
       
   224         /* protect against defunct frame id */
       
   225         synchronized (vm.state()) {
       
   226             validateStackFrame();
       
   227             ps = JDWP.StackFrame.GetValues.enqueueCommand(vm, thread, id, slots);
       
   228         }
       
   229 
       
   230         /* actually get it, now that order is guaranteed */
       
   231         ValueImpl[] values;
       
   232         try {
       
   233             values = JDWP.StackFrame.GetValues.waitForReply(vm, ps).values;
       
   234         } catch (JDWPException exc) {
       
   235             switch (exc.errorCode()) {
       
   236                 case JDWP.Error.INVALID_FRAMEID:
       
   237                 case JDWP.Error.THREAD_NOT_SUSPENDED:
       
   238                 case JDWP.Error.INVALID_THREAD:
       
   239                     throw new InvalidStackFrameException();
       
   240                 default:
       
   241                     throw exc.toJDIException();
       
   242             }
       
   243         }
       
   244 
       
   245         if (count != values.length) {
       
   246             throw new InternalException(
       
   247                       "Wrong number of values returned from target VM");
       
   248         }
       
   249         Map<LocalVariable, Value> map = new HashMap<LocalVariable, Value>(count);
       
   250         for (int i=0; i<count; ++i) {
       
   251             LocalVariableImpl variable = (LocalVariableImpl)variables.get(i);
       
   252             map.put(variable, values[i]);
       
   253         }
       
   254         return map;
       
   255     }
       
   256 
       
   257     public void setValue(LocalVariable variableIntf, Value valueIntf)
       
   258         throws InvalidTypeException, ClassNotLoadedException {
       
   259 
       
   260         validateStackFrame();
       
   261         validateMirror(variableIntf);
       
   262         validateMirrorOrNull(valueIntf);
       
   263 
       
   264         LocalVariableImpl variable = (LocalVariableImpl)variableIntf;
       
   265         ValueImpl value = (ValueImpl)valueIntf;
       
   266 
       
   267         if (!variable.isVisible(this)) {
       
   268             throw new IllegalArgumentException(variable.name() +
       
   269                              " is not valid at this frame location");
       
   270         }
       
   271 
       
   272         try {
       
   273             // Validate and convert value if necessary
       
   274             value = ValueImpl.prepareForAssignment(value, variable);
       
   275 
       
   276             JDWP.StackFrame.SetValues.SlotInfo[] slotVals =
       
   277                 new JDWP.StackFrame.SetValues.SlotInfo[1];
       
   278             slotVals[0] = new JDWP.StackFrame.SetValues.
       
   279                                        SlotInfo(variable.slot(), value);
       
   280 
       
   281             PacketStream ps;
       
   282 
       
   283             /* protect against defunct frame id */
       
   284             synchronized (vm.state()) {
       
   285                 validateStackFrame();
       
   286                 ps = JDWP.StackFrame.SetValues.
       
   287                                      enqueueCommand(vm, thread, id, slotVals);
       
   288             }
       
   289 
       
   290             /* actually set it, now that order is guaranteed */
       
   291             try {
       
   292                 JDWP.StackFrame.SetValues.waitForReply(vm, ps);
       
   293             } catch (JDWPException exc) {
       
   294                 switch (exc.errorCode()) {
       
   295                 case JDWP.Error.INVALID_FRAMEID:
       
   296                 case JDWP.Error.THREAD_NOT_SUSPENDED:
       
   297                 case JDWP.Error.INVALID_THREAD:
       
   298                     throw new InvalidStackFrameException();
       
   299                 default:
       
   300                     throw exc.toJDIException();
       
   301                 }
       
   302             }
       
   303         } catch (ClassNotLoadedException e) {
       
   304             /*
       
   305              * Since we got this exception,
       
   306              * the variable type must be a reference type. The value
       
   307              * we're trying to set is null, but if the variable's
       
   308              * class has not yet been loaded through the enclosing
       
   309              * class loader, then setting to null is essentially a
       
   310              * no-op, and we should allow it without an exception.
       
   311              */
       
   312             if (value != null) {
       
   313                 throw e;
       
   314             }
       
   315         }
       
   316     }
       
   317 
       
   318     public List<Value> getArgumentValues() {
       
   319         validateStackFrame();
       
   320         MethodImpl mmm = (MethodImpl)location.method();
       
   321         List<String> argSigs = mmm.argumentSignatures();
       
   322         int count = argSigs.size();
       
   323         JDWP.StackFrame.GetValues.SlotInfo[] slots =
       
   324                            new JDWP.StackFrame.GetValues.SlotInfo[count];
       
   325 
       
   326         int slot;
       
   327         if (mmm.isStatic()) {
       
   328             slot = 0;
       
   329         } else {
       
   330             slot = 1;
       
   331         }
       
   332         for (int ii = 0; ii < count; ++ii) {
       
   333             char sigChar =  (char)argSigs.get(ii).charAt(0);
       
   334             slots[ii] = new JDWP.StackFrame.GetValues.SlotInfo(slot++,(byte)sigChar);
       
   335             if (sigChar == 'J' || sigChar == 'D') {
       
   336                 slot++;
       
   337             }
       
   338         }
       
   339 
       
   340         PacketStream ps;
       
   341 
       
   342         /* protect against defunct frame id */
       
   343         synchronized (vm.state()) {
       
   344             validateStackFrame();
       
   345             ps = JDWP.StackFrame.GetValues.enqueueCommand(vm, thread, id, slots);
       
   346         }
       
   347 
       
   348         ValueImpl[] values;
       
   349         try {
       
   350             values = JDWP.StackFrame.GetValues.waitForReply(vm, ps).values;
       
   351         } catch (JDWPException exc) {
       
   352             switch (exc.errorCode()) {
       
   353                 case JDWP.Error.INVALID_FRAMEID:
       
   354                 case JDWP.Error.THREAD_NOT_SUSPENDED:
       
   355                 case JDWP.Error.INVALID_THREAD:
       
   356                     throw new InvalidStackFrameException();
       
   357                 default:
       
   358                     throw exc.toJDIException();
       
   359             }
       
   360         }
       
   361 
       
   362         if (count != values.length) {
       
   363             throw new InternalException(
       
   364                       "Wrong number of values returned from target VM");
       
   365         }
       
   366         return Arrays.asList((Value[])values);
       
   367     }
       
   368 
       
   369     void pop() throws IncompatibleThreadStateException {
       
   370         validateStackFrame();
       
   371         // flush caches and disable caching until command completion
       
   372         CommandSender sender =
       
   373             new CommandSender() {
       
   374                 public PacketStream send() {
       
   375                     return JDWP.StackFrame.PopFrames.enqueueCommand(vm,
       
   376                                  thread, id);
       
   377                 }
       
   378         };
       
   379         try {
       
   380             PacketStream stream = thread.sendResumingCommand(sender);
       
   381             JDWP.StackFrame.PopFrames.waitForReply(vm, stream);
       
   382         } catch (JDWPException exc) {
       
   383             switch (exc.errorCode()) {
       
   384             case JDWP.Error.THREAD_NOT_SUSPENDED:
       
   385                 throw new IncompatibleThreadStateException(
       
   386                          "Thread not current or suspended");
       
   387             case JDWP.Error.INVALID_THREAD:   /* zombie */
       
   388                 throw new IncompatibleThreadStateException("zombie");
       
   389             case JDWP.Error.NO_MORE_FRAMES:
       
   390                 throw new InvalidStackFrameException(
       
   391                          "No more frames on the stack");
       
   392             default:
       
   393                 throw exc.toJDIException();
       
   394             }
       
   395         }
       
   396 
       
   397         // enable caching - suspended again
       
   398         vm.state().freeze();
       
   399     }
       
   400 
       
   401     public String toString() {
       
   402        return location.toString() + " in thread " + thread.toString();
       
   403     }
       
   404 }