view agent/src/share/classes/sun/jvm/hotspot/jdi/StackFrameImpl.java @ 17716:cdb71841f4bc

6498581: ThreadInterruptTest3 produces wrong output on Windows Summary: There is race condition between os::interrupt and os::is_interrupted on Windows. In JVM_Sleep(Thread.sleep), check if thread gets interrupted, it may see interrupted but not really interrupted so cause spurious waking up (early return from sleep). Fix by checking if interrupt event really gets set thus prevent false return. For intrinsic of _isInterrupted, on Windows, go fastpath only on bit not set. Reviewed-by: acorn, kvn Contributed-by: david.holmes@oracle.com, yumin.qi@oracle.com
author minqi
date Wed, 26 Feb 2014 15:20:41 -0800
parents 7588156f5cf9
children
line wrap: on
line source

/*
 * Copyright (c) 2002, 2005, Oracle and/or its affiliates. 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.
 *
 * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */

package sun.jvm.hotspot.jdi;

import com.sun.jdi.*;
import sun.jvm.hotspot.oops.ObjectHeap;
import sun.jvm.hotspot.debugger.OopHandle;
import sun.jvm.hotspot.oops.Array;
import sun.jvm.hotspot.oops.ObjArray;
import sun.jvm.hotspot.oops.TypeArray;
import sun.jvm.hotspot.oops.Instance;
import sun.jvm.hotspot.runtime.BasicType;
import sun.jvm.hotspot.runtime.JavaVFrame;
import sun.jvm.hotspot.runtime.StackValue;
import sun.jvm.hotspot.runtime.StackValueCollection;
import sun.jvm.hotspot.utilities.Assert;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Collections;

public class StackFrameImpl extends MirrorImpl
                            implements StackFrame
{
    /* Once false, frame should not be used.
     * access synchronized on (vm.state())
     */
    private boolean isValid = true;

    private final ThreadReferenceImpl thread;
    private final JavaVFrame saFrame;
    private final Location location;
    private Map visibleVariables =  null;
    private ObjectReference thisObject = null;

    StackFrameImpl(VirtualMachine vm, ThreadReferenceImpl thread,
                   JavaVFrame jvf) {
        super(vm);
        this.thread = thread;
        this.saFrame = jvf;

        sun.jvm.hotspot.oops.Method SAMethod = jvf.getMethod();

        ReferenceType rt = ((VirtualMachineImpl)vm).referenceType(SAMethod.getMethodHolder());

        this.location = new LocationImpl(vm, rt, SAMethod, (long)jvf.getBCI());
    }

    private void validateStackFrame() {
        if (!isValid) {
            throw new InvalidStackFrameException("Thread has been resumed");
        }
    }

    JavaVFrame getJavaVFrame() {
        return saFrame;
    }

    /**
     * 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 (saFrame.equals(other.saFrame));
        } else {
            return false;
        }
    }

    public int hashCode() {
        return saFrame.hashCode();
    }

    public ObjectReference thisObject() {
        validateStackFrame();
        MethodImpl currentMethod = (MethodImpl)location.method();
        if (currentMethod.isStatic() || currentMethod.isNative()) {
            return null;
        }
        if (thisObject == null) {
            StackValueCollection values = saFrame.getLocals();
            if (Assert.ASSERTS_ENABLED) {
                Assert.that(values.size() > 0, "this is missing");
            }
            // 'this' at index 0.
            if (values.get(0).getType() == BasicType.getTConflict()) {
              return null;
            }
            OopHandle handle = values.oopHandleAt(0);
            ObjectHeap heap = vm.saObjectHeap();
            thisObject = vm.objectMirror(heap.newOop(handle));
        }
        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());

            Iterator iter = allVariables.iterator();
            while (iter.hasNext()) {
                LocalVariableImpl variable = (LocalVariableImpl)iter.next();
                String name = variable.name();
                if (variable.isVisible(this)) {
                    LocalVariable existing = (LocalVariable)map.get(name);
                    if ((existing == null) ||
                        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 (LocalVariable)visibleVariables.get(name);
    }

    public Value getValue(LocalVariable variable) {
        List list = new ArrayList(1);
        list.add(variable);
        Map map = getValues(list);
        return (Value)map.get(variable);
    }

    public Map getValues(List variables) {
        validateStackFrame();
        StackValueCollection values = saFrame.getLocals();

        int count = variables.size();
        Map map = new HashMap(count);
        for (int ii=0; ii<count; ++ii) {
            LocalVariableImpl variable = (LocalVariableImpl)variables.get(ii);
            if (!variable.isVisible(this)) {
                throw new IllegalArgumentException(variable.name() +
                                 " is not valid at this frame location");
            }
            ValueImpl valueImpl;
            int ss = variable.slot();
            char c = variable.signature().charAt(0);
            BasicType variableType = BasicType.charToBasicType(c);
            valueImpl = getSlotValue(values, variableType, ss);
            map.put(variable, valueImpl);
        }
        return map;
    }

    public List getArgumentValues() {
        validateStackFrame();
        StackValueCollection values = saFrame.getLocals();
        MethodImpl mmm = (MethodImpl)location.method();
        if (mmm.isNative())
            return null;
        List argSigs = mmm.argumentSignatures();
        int count = argSigs.size();
        List res = new ArrayList(0);

        int slot = mmm.isStatic()? 0 : 1;
        for (int ii = 0; ii < count; ++slot, ++ii) {
            char sigChar = ((String)argSigs.get(ii)).charAt(0);
            BasicType variableType = BasicType.charToBasicType(sigChar);
            res.add(getSlotValue(values, variableType, slot));
            if (sigChar == 'J' || sigChar == 'D') {
                slot++;
            }
        }
        return res;
    }

    private ValueImpl getSlotValue(StackValueCollection values,
                       BasicType variableType, int ss) {
        ValueImpl valueImpl = null;
        OopHandle handle = null;
        ObjectHeap heap = vm.saObjectHeap();
        if (values.get(ss).getType() == BasicType.getTConflict()) {
          // Dead locals, so just represent them as a zero of the appropriate type
          if (variableType == BasicType.T_BOOLEAN) {
            valueImpl = (BooleanValueImpl) vm.mirrorOf(false);
          } else if (variableType == BasicType.T_CHAR) {
            valueImpl = (CharValueImpl) vm.mirrorOf((char)0);
          } else if (variableType == BasicType.T_FLOAT) {
            valueImpl = (FloatValueImpl) vm.mirrorOf((float)0);
          } else if (variableType == BasicType.T_DOUBLE) {
            valueImpl = (DoubleValueImpl) vm.mirrorOf((double)0);
          } else if (variableType == BasicType.T_BYTE) {
            valueImpl = (ByteValueImpl) vm.mirrorOf((byte)0);
          } else if (variableType == BasicType.T_SHORT) {
            valueImpl = (ShortValueImpl) vm.mirrorOf((short)0);
          } else if (variableType == BasicType.T_INT) {
            valueImpl = (IntegerValueImpl) vm.mirrorOf((int)0);
          } else if (variableType == BasicType.T_LONG) {
            valueImpl = (LongValueImpl) vm.mirrorOf((long)0);
          } else if (variableType == BasicType.T_OBJECT) {
            // we may have an [Ljava/lang/Object; - i.e., Object[] with the
            // elements themselves may be arrays because every array is an Object.
            handle = null;
            valueImpl = (ObjectReferenceImpl) vm.objectMirror(heap.newOop(handle));
          } else if (variableType == BasicType.T_ARRAY) {
            handle = null;
            valueImpl = vm.arrayMirror((Array)heap.newOop(handle));
          } else if (variableType == BasicType.T_VOID) {
            valueImpl = new VoidValueImpl(vm);
          } else {
            throw new RuntimeException("Should not read here");
          }
        } else {
          if (variableType == BasicType.T_BOOLEAN) {
            valueImpl = (BooleanValueImpl) vm.mirrorOf(values.booleanAt(ss));
          } else if (variableType == BasicType.T_CHAR) {
            valueImpl = (CharValueImpl) vm.mirrorOf(values.charAt(ss));
          } else if (variableType == BasicType.T_FLOAT) {
            valueImpl = (FloatValueImpl) vm.mirrorOf(values.floatAt(ss));
          } else if (variableType == BasicType.T_DOUBLE) {
            valueImpl = (DoubleValueImpl) vm.mirrorOf(values.doubleAt(ss));
          } else if (variableType == BasicType.T_BYTE) {
            valueImpl = (ByteValueImpl) vm.mirrorOf(values.byteAt(ss));
          } else if (variableType == BasicType.T_SHORT) {
            valueImpl = (ShortValueImpl) vm.mirrorOf(values.shortAt(ss));
          } else if (variableType == BasicType.T_INT) {
            valueImpl = (IntegerValueImpl) vm.mirrorOf(values.intAt(ss));
          } else if (variableType == BasicType.T_LONG) {
            valueImpl = (LongValueImpl) vm.mirrorOf(values.longAt(ss));
          } else if (variableType == BasicType.T_OBJECT) {
            // we may have an [Ljava/lang/Object; - i.e., Object[] with the
            // elements themselves may be arrays because every array is an Object.
            handle = values.oopHandleAt(ss);
            valueImpl = (ObjectReferenceImpl) vm.objectMirror(heap.newOop(handle));
          } else if (variableType == BasicType.T_ARRAY) {
            handle = values.oopHandleAt(ss);
            valueImpl = vm.arrayMirror((Array)heap.newOop(handle));
          } else if (variableType == BasicType.T_VOID) {
            valueImpl = new VoidValueImpl(vm);
          } else {
            throw new RuntimeException("Should not read here");
          }
        }

        return valueImpl;
    }

    public void setValue(LocalVariable variableIntf, Value valueIntf)
        throws InvalidTypeException, ClassNotLoadedException {

        vm.throwNotReadOnlyException("StackFrame.setValue()");
    }

    public String toString() {
        return location.toString() + " in thread " + thread.toString();
    }
}