Bug 63040 - Rapidly clicking on Drop to Frame results in deadlock
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIStackFrame.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIStackFrame.java
index afb83d8..695aa8a 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIStackFrame.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIStackFrame.java
@@ -219,16 +219,18 @@
 	 * Returns the underlying method associated with this stack frame,
 	 * retreiving the method is necessary.
 	 */
-	public synchronized Method getUnderlyingMethod() throws DebugException {
-		if (fStackFrame == null || fMethod == null) {
-			try {
-				fMethod= getUnderlyingStackFrame().location().method();
-				fLastMethod = fMethod;
-			} catch (RuntimeException e) {
-				targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.getString("JDIStackFrame.exception_retrieving_method"), new String[] {e.toString()}), e); //$NON-NLS-1$
+	public Method getUnderlyingMethod() throws DebugException {
+		synchronized (fThread) {
+			if (fStackFrame == null || fMethod == null) {
+				try {
+					fMethod= getUnderlyingStackFrame().location().method();
+					fLastMethod = fMethod;
+				} catch (RuntimeException e) {
+					targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.getString("JDIStackFrame.exception_retrieving_method"), new String[] {e.toString()}), e); //$NON-NLS-1$
+				}
 			}
+			return fMethod;
 		}
-		return fMethod;
 	}
 
 	/**
@@ -239,69 +241,71 @@
 		return (IVariable[])list.toArray(new IVariable[list.size()]);
 	}
 	
-	protected synchronized List getVariables0() throws DebugException {
-		if (fVariables == null) {
-			
-			// throw exception if native method, so variable view will update
-			// with information message
-			if (isNative()) {
-				requestFailed(JDIDebugModelMessages.getString("JDIStackFrame.Variable_information_unavailable_for_native_methods"), null); //$NON-NLS-1$
-			}
-			
-			Method method= getUnderlyingMethod();
-			fVariables= new ArrayList();
-			// #isStatic() does not claim to throw any exceptions - so it is not try/catch coded
-			if (method.isStatic()) {
-				// add statics
-				List allFields= null;
-				ReferenceType declaringType = method.declaringType();
-				try {
-					allFields= declaringType.allFields();
-				} catch (RuntimeException e) {
-					targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.getString("JDIStackFrame.exception_retrieving_fields"),new String[] {e.toString()}), e); //$NON-NLS-1$
-					// execution will not reach this line, as 
-					// #targetRequestFailed will throw an exception					
-					return Collections.EMPTY_LIST;
+	protected List getVariables0() throws DebugException {
+		synchronized (fThread) {
+			if (fVariables == null) {
+				
+				// throw exception if native method, so variable view will update
+				// with information message
+				if (isNative()) {
+					requestFailed(JDIDebugModelMessages.getString("JDIStackFrame.Variable_information_unavailable_for_native_methods"), null); //$NON-NLS-1$
 				}
-				if (allFields != null) {
-					Iterator fields= allFields.iterator();
-					while (fields.hasNext()) {
-						Field field= (Field) fields.next();
-						if (field.isStatic()) {
-							fVariables.add(new JDIFieldVariable((JDIDebugTarget)getDebugTarget(), field, declaringType));
-						}
+				
+				Method method= getUnderlyingMethod();
+				fVariables= new ArrayList();
+				// #isStatic() does not claim to throw any exceptions - so it is not try/catch coded
+				if (method.isStatic()) {
+					// add statics
+					List allFields= null;
+					ReferenceType declaringType = method.declaringType();
+					try {
+						allFields= declaringType.allFields();
+					} catch (RuntimeException e) {
+						targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.getString("JDIStackFrame.exception_retrieving_fields"),new String[] {e.toString()}), e); //$NON-NLS-1$
+						// execution will not reach this line, as 
+						// #targetRequestFailed will throw an exception					
+						return Collections.EMPTY_LIST;
 					}
-					Collections.sort(fVariables, new Comparator() {
-						public int compare(Object a, Object b) {
-							JDIFieldVariable v1= (JDIFieldVariable)a;
-							JDIFieldVariable v2= (JDIFieldVariable)b;
-							try {
-								return v1.getName().compareToIgnoreCase(v2.getName());
-							} catch (DebugException de) {
-								logError(de);
-								return -1;
+					if (allFields != null) {
+						Iterator fields= allFields.iterator();
+						while (fields.hasNext()) {
+							Field field= (Field) fields.next();
+							if (field.isStatic()) {
+								fVariables.add(new JDIFieldVariable((JDIDebugTarget)getDebugTarget(), field, declaringType));
 							}
 						}
-					});
+						Collections.sort(fVariables, new Comparator() {
+							public int compare(Object a, Object b) {
+								JDIFieldVariable v1= (JDIFieldVariable)a;
+								JDIFieldVariable v2= (JDIFieldVariable)b;
+								try {
+									return v1.getName().compareToIgnoreCase(v2.getName());
+								} catch (DebugException de) {
+									logError(de);
+									return -1;
+								}
+							}
+						});
+					}
+				} else {
+					// add "this"
+					ObjectReference t= getUnderlyingThisObject();
+					if (t != null) {
+						fVariables.add(new JDIThisVariable((JDIDebugTarget)getDebugTarget(), t));
+					}
 				}
-			} else {
-				// add "this"
-				ObjectReference t= getUnderlyingThisObject();
-				if (t != null) {
-					fVariables.add(new JDIThisVariable((JDIDebugTarget)getDebugTarget(), t));
+				// add locals
+				Iterator variables= getUnderlyingVisibleVariables().iterator();
+				while (variables.hasNext()) {
+					LocalVariable var= (LocalVariable) variables.next();
+					fVariables.add(new JDILocalVariable(this, var));
 				}
+			} else if (fRefreshVariables) {
+				updateVariables();
 			}
-			// add locals
-			Iterator variables= getUnderlyingVisibleVariables().iterator();
-			while (variables.hasNext()) {
-				LocalVariable var= (LocalVariable) variables.next();
-				fVariables.add(new JDILocalVariable(this, var));
-			}
-		} else if (fRefreshVariables) {
-			updateVariables();
+			fRefreshVariables = false;
+			return fVariables;
 		}
-		fRefreshVariables = false;
-		return fVariables;
 	}
 
 	/**
@@ -947,19 +951,19 @@
 	 *  interim state where this frame's thead has been
 	 *  resumed, and is not yet suspended).
 	 */
-	protected synchronized StackFrame getUnderlyingStackFrame() throws DebugException {
-		StackFrame stackFrame= fStackFrame;
-		if (stackFrame == null) {
-			int depth= getDepth();
-			if (depth == -1) {
-				// Depth is set to -1 when the thread clears its handles
-				// to this object. See Bug 47198.
-				throw new DebugException(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), IStatus.ERROR, JDIDebugModelMessages.getString("JDIStackFrame.25"), null)); //$NON-NLS-1$
+	protected StackFrame getUnderlyingStackFrame() throws DebugException {
+		synchronized (fThread) {
+			if (fStackFrame == null) {
+				int depth= getDepth();
+				if (depth == -1) {
+					// Depth is set to -1 when the thread clears its handles
+					// to this object. See Bug 47198.
+					throw new DebugException(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), IStatus.ERROR, JDIDebugModelMessages.getString("JDIStackFrame.25"), null)); //$NON-NLS-1$
+				}
+				setUnderlyingStackFrame(((JDIThread)getThread()).getUnderlyingFrame(depth));
 			}
-			stackFrame= ((JDIThread)getThread()).getUnderlyingFrame(depth);
-			setUnderlyingStackFrame(stackFrame);
+			return fStackFrame;
 		}
-		return stackFrame;
 	}
 	
 	/**
@@ -969,7 +973,9 @@
 	 * @param frame The underlying stack frame
 	 */
 	protected void setUnderlyingStackFrame(StackFrame frame) {
-		fStackFrame = frame;
+		synchronized (fThread) {
+			fStackFrame = frame;
+		}
 	}
 	
 	/**