diff -r fd16c54261b3 -r 90ce3da70b43 jdk/src/share/classes/com/sun/tools/jdi/StackFrameImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/tools/jdi/StackFrameImpl.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,404 @@ +/* + * Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.tools.jdi; + +import com.sun.jdi.*; + +import java.util.List; +import java.util.Map; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Collections; + +public class StackFrameImpl extends MirrorImpl + implements StackFrame, ThreadListener +{ + /* Once false, frame should not be used. + * access synchronized on (vm.state()) + */ + private boolean isValid = true; + + private final ThreadReferenceImpl thread; + private final long id; + private final Location location; + private Map visibleVariables = null; + private ObjectReference thisObject = null; + + StackFrameImpl(VirtualMachine vm, ThreadReferenceImpl thread, + long id, Location location) { + super(vm); + this.thread = thread; + this.id = id; + this.location = location; + thread.addListener(this); + } + + /* + * ThreadListener implementation + * Must be synchronized since we must protect against + * sending defunct (isValid == false) stack ids to the back-end. + */ + public boolean threadResumable(ThreadAction action) { + synchronized (vm.state()) { + if (isValid) { + isValid = false; + return false; /* remove this stack frame as a listener */ + } else { + throw new InternalException( + "Invalid stack frame thread listener"); + } + } + } + + void validateStackFrame() { + if (!isValid) { + throw new InvalidStackFrameException("Thread has been resumed"); + } + } + + /** + * Return the frame location. + * Need not be synchronized since it cannot be provably stale. + */ + public Location location() { + validateStackFrame(); + return location; + } + + /** + * Return the thread holding the frame. + * Need not be synchronized since it cannot be provably stale. + */ + public ThreadReference thread() { + validateStackFrame(); + return thread; + } + + public boolean equals(Object obj) { + if ((obj != null) && (obj instanceof StackFrameImpl)) { + StackFrameImpl other = (StackFrameImpl)obj; + return (id == other.id) && + (thread().equals(other.thread())) && + (location().equals(other.location())) && + super.equals(obj); + } else { + return false; + } + } + + public int hashCode() { + return (thread().hashCode() << 4) + ((int)id); + } + + public ObjectReference thisObject() { + validateStackFrame(); + MethodImpl currentMethod = (MethodImpl)location.method(); + if (currentMethod.isStatic() || currentMethod.isNative()) { + return null; + } else { + if (thisObject == null) { + PacketStream ps; + + /* protect against defunct frame id */ + synchronized (vm.state()) { + validateStackFrame(); + ps = JDWP.StackFrame.ThisObject. + enqueueCommand(vm, thread, id); + } + + /* actually get it, now that order is guaranteed */ + try { + thisObject = JDWP.StackFrame.ThisObject. + waitForReply(vm, ps).objectThis; + } 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(); + } + } + } + } + return thisObject; + } + + /** + * Build the visible variable map. + * Need not be synchronized since it cannot be provably stale. + */ + private void createVisibleVariables() throws AbsentInformationException { + if (visibleVariables == null) { + List allVariables = location.method().variables(); + Map map = new HashMap(allVariables.size()); + + for (LocalVariable variable : allVariables) { + String name = variable.name(); + if (variable.isVisible(this)) { + LocalVariable existing = (LocalVariable)map.get(name); + if ((existing == null) || + ((LocalVariableImpl)variable).hides(existing)) { + map.put(name, variable); + } + } + } + visibleVariables = map; + } + } + + /** + * Return the list of visible variable in the frame. + * Need not be synchronized since it cannot be provably stale. + */ + public List visibleVariables() throws AbsentInformationException { + validateStackFrame(); + createVisibleVariables(); + List mapAsList = new ArrayList(visibleVariables.values()); + Collections.sort(mapAsList); + return mapAsList; + } + + /** + * Return a particular variable in the frame. + * Need not be synchronized since it cannot be provably stale. + */ + public LocalVariable visibleVariableByName(String name) throws AbsentInformationException { + validateStackFrame(); + createVisibleVariables(); + return visibleVariables.get(name); + } + + public Value getValue(LocalVariable variable) { + List list = new ArrayList(1); + list.add(variable); + return getValues(list).get(variable); + } + + public Map getValues(List variables) { + validateStackFrame(); + validateMirrors(variables); + + int count = variables.size(); + JDWP.StackFrame.GetValues.SlotInfo[] slots = + new JDWP.StackFrame.GetValues.SlotInfo[count]; + + for (int i=0; i map = new HashMap(count); + for (int i=0; i getArgumentValues() { + validateStackFrame(); + MethodImpl mmm = (MethodImpl)location.method(); + List argSigs = mmm.argumentSignatures(); + int count = argSigs.size(); + JDWP.StackFrame.GetValues.SlotInfo[] slots = + new JDWP.StackFrame.GetValues.SlotInfo[count]; + + int slot; + if (mmm.isStatic()) { + slot = 0; + } else { + slot = 1; + } + for (int ii = 0; ii < count; ++ii) { + char sigChar = (char)argSigs.get(ii).charAt(0); + slots[ii] = new JDWP.StackFrame.GetValues.SlotInfo(slot++,(byte)sigChar); + if (sigChar == 'J' || sigChar == 'D') { + slot++; + } + } + + PacketStream ps; + + /* protect against defunct frame id */ + 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"); + } + return Arrays.asList((Value[])values); + } + + void pop() throws IncompatibleThreadStateException { + validateStackFrame(); + // flush caches and disable caching until command completion + CommandSender sender = + new CommandSender() { + public PacketStream send() { + return JDWP.StackFrame.PopFrames.enqueueCommand(vm, + thread, id); + } + }; + try { + PacketStream stream = thread.sendResumingCommand(sender); + JDWP.StackFrame.PopFrames.waitForReply(vm, stream); + } catch (JDWPException exc) { + switch (exc.errorCode()) { + case JDWP.Error.THREAD_NOT_SUSPENDED: + throw new IncompatibleThreadStateException( + "Thread not current or suspended"); + case JDWP.Error.INVALID_THREAD: /* zombie */ + throw new IncompatibleThreadStateException("zombie"); + case JDWP.Error.NO_MORE_FRAMES: + throw new InvalidStackFrameException( + "No more frames on the stack"); + default: + throw exc.toJDIException(); + } + } + + // enable caching - suspended again + vm.state().freeze(); + } + + public String toString() { + return location.toString() + " in thread " + thread.toString(); + } +}