Merge remote-tracking branch 'origin/master' into BETA_JAVA9
diff --git a/org.eclipse.jdt.debug.tests/testprograms/DropTests.java b/org.eclipse.jdt.debug.tests/testprograms/DropTests.java
index f1e2267..ad753d5 100644
--- a/org.eclipse.jdt.debug.tests/testprograms/DropTests.java
+++ b/org.eclipse.jdt.debug.tests/testprograms/DropTests.java
@@ -4,32 +4,32 @@
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
 
 public class DropTests {
- 
+
  	public static void main(String[] args) {
  		DropTests dt = new DropTests();
  		dt.method1();
  	}
- 
+
  	public void method1() {
  		method2();
  	}
- 	
+
  	public void method2() {
  		method3();
  	}
- 	
+
  	public void method3() {
  		method4();
  	}
- 	
- 	public void method4() {
+
+ 	public synchronized void method4() {
  		System.out.println("Finally, I got to method 4");
  	}
- 
- }
+
+}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
index 6f52d2b..b106fc4 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
@@ -74,6 +74,7 @@
 import org.eclipse.debug.internal.ui.launchConfigurations.LaunchShortcutExtension;
 import org.eclipse.debug.internal.ui.preferences.IDebugPreferenceConstants;
 import org.eclipse.debug.internal.ui.views.breakpoints.BreakpointOrganizerManager;
+import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
 import org.eclipse.debug.ui.DebugUITools;
 import org.eclipse.debug.ui.IDebugModelPresentation;
 import org.eclipse.debug.ui.IDebugUIConstants;
@@ -184,6 +185,7 @@
 	public static final String ONE_SEVEN_PROJECT_NAME = "OneSeven";
 	public static final String ONE_EIGHT_PROJECT_NAME = "OneEight";
 	public static final String BOUND_JRE_PROJECT_NAME = "BoundJRE";
+	public static final String CLONE_SUFFIX = "Clone";
 
 	final String[] LAUNCH_CONFIG_NAMES_1_4 = {"LargeSourceFile", "LotsOfFields", "Breakpoints", "InstanceVariablesTests", "LocalVariablesTests", "LocalVariableTests2", "StaticVariablesTests",
  "DropTests", "ThrowsNPE", "ThrowsException", "org.eclipse.debug.tests.targets.Watchpoint",
@@ -329,7 +331,7 @@
 	 */
 	synchronized void assert14Project() {
 		IJavaProject jp = null;
-		ArrayList<ILaunchConfiguration> cfgs = new ArrayList<ILaunchConfiguration>(1);
+		ArrayList<ILaunchConfiguration> cfgs = new ArrayList<>(1);
         try {
 	        if (!loaded14) {
 	        	try {
@@ -386,7 +388,7 @@
 	 */
 	void assert15Project() {
 		IJavaProject jp = null;
-		ArrayList<ILaunchConfiguration> cfgs = new ArrayList<ILaunchConfiguration>(1);
+		ArrayList<ILaunchConfiguration> cfgs = new ArrayList<>(1);
         try {
 	        if (!loaded15) {
 				jp = createProject(ONE_FIVE_PROJECT_NAME, JavaProjectHelper.TEST_1_5_SRC_DIR.toString(), JavaProjectHelper.J2SE_1_5_EE_NAME, true);
@@ -398,6 +400,7 @@
 				cfgs.add(createLaunchConfiguration(jp, "a.b.c.bug403028"));
 				cfgs.add(createLaunchConfiguration(jp, "a.b.c.bug484686"));
 				cfgs.add(createLaunchConfiguration(jp, "a.b.c.GenericMethodEntryTest"));
+				cfgs.add(createLaunchConfiguration(jp, "org.eclipse.debug.tests.targets.HcrClass", true));
 				loaded15 = true;
 				waitForBuild();
 	        }
@@ -423,7 +426,7 @@
 	 */
 	synchronized void assert17Project() {
 		IJavaProject jp = null;
-		ArrayList<ILaunchConfiguration> cfgs = new ArrayList<ILaunchConfiguration>(1);
+		ArrayList<ILaunchConfiguration> cfgs = new ArrayList<>(1);
         try {
 	        if (!loaded17) {
 	        	jp = createProject(ONE_SEVEN_PROJECT_NAME, JavaProjectHelper.TEST_1_7_SRC_DIR.toString(), JavaProjectHelper.JAVA_SE_1_7_EE_NAME, false);
@@ -453,7 +456,7 @@
 	 */
 	synchronized void assert18Project() {
 		IJavaProject jp = null;
-		ArrayList<ILaunchConfiguration> cfgs = new ArrayList<ILaunchConfiguration>(1);
+		ArrayList<ILaunchConfiguration> cfgs = new ArrayList<>(1);
         try {
 	        if (!loaded18) {
 	        	jp = createProject(ONE_EIGHT_PROJECT_NAME, JavaProjectHelper.TEST_1_8_SRC_DIR.toString(), JavaProjectHelper.JAVA_SE_1_8_EE_NAME, false);
@@ -1182,6 +1185,21 @@
 	}
 
 	/**
+	 * Launches the type with the given name, and waits for a breakpoint-caused
+	 * suspend event in that program. Returns the thread in which the suspend
+	 * event occurred.
+	 *
+	 * @param mainTypeName the program to launch
+	 * @param register whether to register the launch
+	 * @return thread in which the first suspend event occurred
+	 */
+	protected IJavaThread launchToBreakpoint(IJavaProject project, String mainTypeName, String launchName, boolean register) throws Exception {
+		ILaunchConfiguration config = getLaunchConfiguration(project, launchName);
+		assertNotNull("Could not locate launch configuration for " + mainTypeName, config); //$NON-NLS-1$
+		return launchToBreakpoint(config, register);
+	}
+
+	/**
 	 * Launches the given configuration in debug mode, and waits for a breakpoint-caused
 	 * suspend event in that program. Returns the thread in which the suspend
 	 * event occurred.
@@ -1656,7 +1674,7 @@
 	 */
 	protected Map<String, Object> getExtraBreakpointAttributes(IMember element) throws Exception {
 		if (element != null && element.exists()) {
-			Map<String, Object> map = new HashMap<String, Object>();
+			Map<String, Object> map = new HashMap<>();
 			ISourceRange sourceRange = element.getSourceRange();
 			int start = sourceRange.getOffset();
 			int end = start + sourceRange.getLength();
@@ -2379,6 +2397,8 @@
             try {
                 Job.getJobManager().join(ResourcesPlugin.FAMILY_AUTO_BUILD, null);
                 Job.getJobManager().join(ResourcesPlugin.FAMILY_MANUAL_BUILD, null);
+				// Let also all other pending jobs proceed, ignore console jobs
+				TestUtil.waitForJobs("waitForBuild", 100, 1000, ProcessConsole.class);
                 wasInterrupted = false;
             } catch (OperationCanceledException e) {
                 e.printStackTrace();
@@ -2443,19 +2463,30 @@
      * Creates a shared launch configuration for the type with the given name.
      */
     protected ILaunchConfiguration createLaunchConfiguration(IJavaProject project, String mainTypeName) throws Exception {
+		return createLaunchConfiguration(project, mainTypeName, false);
+	}
+
+	/**
+	 * Creates a shared launch configuration for the type with the given name.
+	 *
+	 * @param clone
+	 *            true if the launch config name should be different from the main type name
+	 */
+	protected ILaunchConfiguration createLaunchConfiguration(IJavaProject project, String mainTypeName, boolean clone) throws Exception {
         ILaunchConfigurationType type = getLaunchManager().getLaunchConfigurationType(IJavaLaunchConfigurationConstants.ID_JAVA_APPLICATION);
-        ILaunchConfigurationWorkingCopy config = type.newInstance(project.getProject().getFolder(LAUNCHCONFIGURATIONS), mainTypeName);
+		String configName = clone ? mainTypeName + CLONE_SUFFIX : mainTypeName;
+		ILaunchConfigurationWorkingCopy config = type.newInstance(project.getProject().getFolder(LAUNCHCONFIGURATIONS), configName);
         config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, mainTypeName);
         config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, project.getElementName());
-		Set<String> modes = new HashSet<String>();
+		Set<String> modes = new HashSet<>();
 		modes.add(ILaunchManager.RUN_MODE);
 		config.setPreferredLaunchDelegate(modes, LOCAL_JAVA_APPLICATION_TYPE_ID);
-		modes = new HashSet<String>();
+		modes = new HashSet<>();
 		modes.add(ILaunchManager.DEBUG_MODE);
 		config.setPreferredLaunchDelegate(modes, LOCAL_JAVA_APPLICATION_TYPE_ID);
         // use 'java' instead of 'javaw' to launch tests (javaw is problematic
         // on JDK1.4.2)
-        Map<String, String> map = new HashMap<String, String>(1);
+        Map<String, String> map = new HashMap<>(1);
         map.put(IJavaLaunchConfigurationConstants.ATTR_JAVA_COMMAND, JAVA);
         config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_TYPE_SPECIFIC_ATTRS_MAP, map);
         return config.doSave();
@@ -2469,15 +2500,15 @@
         ILaunchConfigurationWorkingCopy config = type.newInstance(project.getProject().getFolder(containername), mainTypeName);
         config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, mainTypeName);
         config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, project.getElementName());
-		Set<String> modes = new HashSet<String>();
+		Set<String> modes = new HashSet<>();
 		modes.add(ILaunchManager.RUN_MODE);
 		config.setPreferredLaunchDelegate(modes, LOCAL_JAVA_APPLICATION_TYPE_ID);
-		modes = new HashSet<String>();
+		modes = new HashSet<>();
 		modes.add(ILaunchManager.DEBUG_MODE);
 		config.setPreferredLaunchDelegate(modes, LOCAL_JAVA_APPLICATION_TYPE_ID);
         // use 'java' instead of 'javaw' to launch tests (javaw is problematic
         // on JDK1.4.2)
-        Map<String, String> map = new HashMap<String, String>(1);
+        Map<String, String> map = new HashMap<>(1);
         map.put(IJavaLaunchConfigurationConstants.ATTR_JAVA_COMMAND, JAVA);
         config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_TYPE_SPECIFIC_ATTRS_MAP, map);
         return config.doSave();
@@ -2499,11 +2530,16 @@
 			} catch (TestAgainException e) {
 				TestUtil.log(IStatus.ERROR, getName(), "Test failed attempt " + attempts + ". Re-testing.", e);
 				TestUtil.cleanUp(getName());
-				if (attempts > 5) {
-					tryAgain = false;
+				if (attempts > 4) {
+					// the next attempt will fail
+					break;
 				}
 			}
 		}
+		if (tryAgain) {
+			// last attempt and if it fails then we should fail, see bug 515988
+			super.runBare();
+		}
 	}
 
 	@Override
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
index be248dc..6e8ee0f 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
@@ -38,6 +38,7 @@
 import org.eclipse.jdt.debug.tests.breakpoints.TestToggleBreakpointsTarget;
 import org.eclipse.jdt.debug.tests.breakpoints.TestToggleBreakpointsTarget8;
 import org.eclipse.jdt.debug.tests.breakpoints.ThreadFilterBreakpointsTests;
+import org.eclipse.jdt.debug.tests.breakpoints.JavaThreadEventHandlerTests;
 import org.eclipse.jdt.debug.tests.breakpoints.TriggerPointBreakpointsTests;
 import org.eclipse.jdt.debug.tests.breakpoints.TypeNameBreakpointTests;
 import org.eclipse.jdt.debug.tests.breakpoints.WatchpointTests;
@@ -116,6 +117,7 @@
 import org.eclipse.jdt.debug.tests.sourcelookup.SourceLookupTests;
 import org.eclipse.jdt.debug.tests.sourcelookup.TypeResolutionTests;
 import org.eclipse.jdt.debug.tests.state.RefreshStateTests;
+import org.eclipse.jdt.debug.tests.ui.DebugViewTests;
 import org.eclipse.jdt.debug.tests.ui.DetailPaneManagerTests;
 import org.eclipse.jdt.debug.tests.ui.OpenFromClipboardTests;
 import org.eclipse.jdt.debug.tests.ui.ViewManagementTests;
@@ -192,6 +194,7 @@
 		addTest(new TestSuite(RunToLineTests.class));
 		addTest(new TestSuite(TestToggleBreakpointsTarget.class));
 		addTest(new TestSuite(TriggerPointBreakpointsTests.class));
+		addTest(new TestSuite(JavaThreadEventHandlerTests.class));
 
 		if (JavaProjectHelper.isJava8Compatible()) {
 			addTest(new TestSuite(TestToggleBreakpointsTarget8.class));
@@ -315,6 +318,9 @@
 	// Layout tests
 		addTest(new TestSuite(ViewManagementTests.class));
 
+	// Debug view tests
+		addTest(new TestSuite(DebugViewTests.class));
+
 	// Leak tests
 		addTest(new TestSuite(InstructionPointerTests.class));
 
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/TestUtil.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/TestUtil.java
index c9417c4..d0f785a 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/TestUtil.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/TestUtil.java
@@ -10,6 +10,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.debug.tests;
 
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.LinkedHashSet;
@@ -158,15 +160,22 @@
 		StringBuilder sb = new StringBuilder();
 		for (Job job : jobs) {
 			runningJobs.add(job);
-			sb.append("'").append(job.getName()).append("'/");
+			sb.append("\n'").append(job.toString()).append("'/");
 			sb.append(job.getClass().getName());
+			Thread thread = job.getThread();
+			if (thread != null) {
+				ThreadInfo[] threadInfos = ManagementFactory.getThreadMXBean().getThreadInfo(new long[] { thread.getId() }, true, true);
+				if (threadInfos[0] != null) {
+					sb.append("\nthread info: ").append(threadInfos[0]);
+				}
+			}
 			sb.append(", ");
 		}
 		sb.setLength(sb.length() - 2);
 		return sb.toString();
 	}
 
-	private static List<Job> getRunningOrWaitingJobs(Object jobFamily, Object... excludedFamilies) {
+	public static List<Job> getRunningOrWaitingJobs(Object jobFamily, Object... excludedFamilies) {
 		List<Job> running = new ArrayList<>();
 		Job[] jobs = Job.getJobManager().find(jobFamily);
 		for (Job job : jobs) {
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/ConditionalBreakpointsTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/ConditionalBreakpointsTests.java
index 581cde2..3281e6d 100755
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/ConditionalBreakpointsTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/ConditionalBreakpointsTests.java
@@ -195,7 +195,7 @@
 	public void testSuspendLongRunningCondition() throws Exception {
 		String typeName = "MethodLoop";
 		IJavaLineBreakpoint first = createLineBreakpoint(19, typeName);
-		createConditionalLineBreakpoint(29, typeName, "for (int x = 0; x < 1000; x++) { System.out.println(x);} Thread.sleep(200); return true;", true);
+		createConditionalLineBreakpoint(29, typeName, "for (int x = 0; x < 1000; x++) { System.out.println(x); Thread.sleep(30); } return true;", true);
 
 		IJavaThread thread= null;
 		try {
@@ -203,12 +203,14 @@
 			IStackFrame top = thread.getTopStackFrame();
 			assertNotNull("Missing top frame", top);
 			thread.resume();
-			Thread.sleep(100);
+			Thread.sleep(3000);
 			thread.suspend();
 			assertTrue("Thread should be suspended", thread.isSuspended());
 			IJavaStackFrame frame = (IJavaStackFrame) thread.getTopStackFrame();
 			assertNotNull("Missing top frame", frame);
 			assertEquals("Wrong location", "calculateSum", frame.getName());
+			thread.resume();
+			assertFalse("Thread should be resumed", thread.isSuspended());
 		} finally {
 			terminateAndRemove(thread);
 			removeAllBreakpoints();
@@ -507,10 +509,9 @@
 		IJavaThread thread = null;
 		try {
 			thread = launchToLineBreakpoint(typeName, bp1);
-
+			assertNotNull(thread);
 		}
 		finally {
-			assertNotNull(thread);
 			terminateAndRemove(thread);
 			removeAllBreakpoints();
 		}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/JavaThreadEventHandlerTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/JavaThreadEventHandlerTests.java
new file mode 100644
index 0000000..b941ead
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/JavaThreadEventHandlerTests.java
@@ -0,0 +1,254 @@
+/*******************************************************************************
+ *  Copyright (c) 2017 Andrey Loskutov and others.
+ *  All rights reserved. This program and the accompanying materials
+ *  are made available under the terms of the Eclipse Public License v1.0
+ *  which accompanies this distribution, and is available at
+ *  http://www.eclipse.org/legal/epl-v10.html
+ *
+ *  Contributors:
+ *     Andrey Loskutov <loskutov@gmx.de> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.debug.tests.breakpoints;
+
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.core.model.IStackFrame;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy;
+import org.eclipse.jdt.debug.core.IJavaBreakpoint;
+import org.eclipse.jdt.debug.core.IJavaDebugTarget;
+import org.eclipse.jdt.debug.core.IJavaMethodBreakpoint;
+import org.eclipse.jdt.debug.core.IJavaStackFrame;
+import org.eclipse.jdt.debug.core.IJavaThread;
+import org.eclipse.jdt.debug.eval.IEvaluationListener;
+import org.eclipse.jdt.debug.eval.IEvaluationResult;
+import org.eclipse.jdt.debug.tests.AbstractDebugTest;
+import org.eclipse.jdt.debug.tests.TestAgainException;
+import org.eclipse.jdt.internal.debug.eval.ast.engine.ASTEvaluationEngine;
+import org.eclipse.jdt.internal.debug.ui.threadgroups.JavaDebugTargetProxy;
+import org.eclipse.jdt.internal.debug.ui.threadgroups.JavaThreadEventHandler;
+
+/**
+ * Tests for JavaThreadEventHandler
+ */
+public class JavaThreadEventHandlerTests extends AbstractDebugTest {
+
+
+	public JavaThreadEventHandlerTests(String name) {
+		super(name);
+	}
+
+	/**
+	 * Tests that we can compute frame index for arbitrary frames, see bug 515696
+	 */
+	public void testComputeFrameIndexOnSecondFrameAndMonitorsOn() throws Exception {
+		final String typeName = "DropTests";
+		final int expectedFramesCount = 5;
+		IJavaBreakpoint bp = createMethodBreakpoint(typeName, "method" + (expectedFramesCount - 1), "()V", true, false);
+		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_VM);
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToBreakpoint(typeName);
+
+			IBreakpoint hit = getBreakpoint(thread);
+			assertNotNull("suspended, but not by breakpoint", hit);
+			assertTrue("breakpoint was not a method breakpoint", hit instanceof IJavaMethodBreakpoint);
+
+			IJavaStackFrame frame = (IJavaStackFrame) thread.getTopStackFrame();
+			assertNotNull("There should be a stackframe", frame);
+
+			IDebugTarget debugTarget = thread.getDebugTarget();
+			JavaDebugTargetProxy proxy = new JavaDebugTargetProxy(debugTarget);
+			MyJavaThreadEventHandler eventHandler = new MyJavaThreadEventHandler(proxy);
+
+			eventHandler.displayMonitors = true;
+
+			IStackFrame[] frames = frame.getThread().getStackFrames();
+			assertEquals(expectedFramesCount, frames.length);
+
+			// They are all off by one, because we have one monitor installed
+			int monitorCount = 1;
+			for (int i = 0; i < frames.length; i++) {
+				int index = eventHandler.indexOf(frames[i]);
+				assertEquals(i + monitorCount, index);
+			}
+		}
+		finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	/**
+	 * Tests that we can compute frame index for arbitrary frames, see bug 515696
+	 */
+	public void testComputeFrameIndexOnSecondFrameAndMonitorsOff() throws Exception {
+		final String typeName = "DropTests";
+		final int expectedFramesCount = 5;
+		IJavaBreakpoint bp = createMethodBreakpoint(typeName, "method" + (expectedFramesCount - 1), "()V", true, false);
+		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_VM);
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToBreakpoint(typeName);
+
+			IBreakpoint hit = getBreakpoint(thread);
+			assertNotNull("suspended, but not by breakpoint", hit);
+			assertTrue("breakpoint was not a method breakpoint", hit instanceof IJavaMethodBreakpoint);
+
+			IJavaStackFrame frame = (IJavaStackFrame) thread.getTopStackFrame();
+			assertNotNull("There should be a stackframe", frame);
+
+			IDebugTarget debugTarget = thread.getDebugTarget();
+			JavaDebugTargetProxy proxy = new JavaDebugTargetProxy(debugTarget);
+			MyJavaThreadEventHandler eventHandler = new MyJavaThreadEventHandler(proxy);
+
+			eventHandler.displayMonitors = false;
+
+			IStackFrame[] frames = frame.getThread().getStackFrames();
+			assertEquals(expectedFramesCount, frames.length);
+
+			for (int i = 0; i < frames.length; i++) {
+				int index = eventHandler.indexOf(frames[i]);
+				assertEquals(i, index);
+			}
+		}
+		finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	/**
+	 * Tests that we can (or can't) compute frame index during evaluation
+	 *
+	 * @throws Exception
+	 */
+	public void testComputeFrameIndexDuringEvaluation() throws Exception {
+		String typeName = "DropTests";
+		final int expectedFramesCount = 5;
+		IJavaBreakpoint bp = createMethodBreakpoint(typeName, "method" + (expectedFramesCount - 1), "()V", true, false);
+		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_VM);
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToBreakpoint(typeName);
+
+			IBreakpoint hit = getBreakpoint(thread);
+			assertNotNull("suspended, but not by breakpoint", hit);
+			assertTrue("breakpoint was not a method breakpoint", hit instanceof IJavaMethodBreakpoint);
+
+			final int sleepTimeMillis = 750;
+			String snippet = "java.lang.Thread.sleep(" + sleepTimeMillis + "); return true;";
+			TaskOnFrame task = new TaskOnFrame() {
+				@Override
+				public void performChecks(IJavaThread thread, IStackFrame[] frames, MyJavaThreadEventHandler eventHandler) throws Exception {
+					assertEquals(expectedFramesCount, frames.length);
+
+					IStackFrame[] currFrames = frames[0].getThread().getStackFrames();
+					// thread not suspended, so no stack frames as per method contract
+					assertEquals(0, currFrames.length);
+					assertTrue(thread.isPerformingEvaluation());
+
+					// indexOf method waits for evaluation and computes the right result
+					for (int i = 0; i < expectedFramesCount; i++) {
+						int index = eventHandler.indexOf(frames[i]);
+						if (index == -1) {
+							throw new TestAgainException("Evaluation took too long");
+						}
+						assertEquals(i, index);
+					}
+					Thread.sleep(sleepTimeMillis);
+					// evaluation should be done by now
+					assertFalse(thread.isPerformingEvaluation());
+				}
+			};
+			IValue value = doEvalAndRunInParallel(thread, snippet, task);
+			assertTrue("The result of '" + snippet + "') should be true", Boolean.parseBoolean(value.getValueString()));
+		}
+		finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	private IValue doEvalAndRunInParallel(IJavaThread thread, String snippet, TaskOnFrame task) throws Exception {
+		class Listener implements IEvaluationListener {
+			IEvaluationResult fResult;
+
+			@Override
+			public void evaluationComplete(IEvaluationResult result) {
+				fResult = result;
+			}
+
+			public IEvaluationResult getResult() {
+				return fResult;
+			}
+		}
+		Listener listener = new Listener();
+		IJavaStackFrame frame = (IJavaStackFrame) thread.getTopStackFrame();
+		assertNotNull("There should be a stackframe", frame);
+		IStackFrame[] frames = thread.getStackFrames();
+
+		IDebugTarget debugTarget = thread.getDebugTarget();
+		JavaDebugTargetProxy proxy = new JavaDebugTargetProxy(debugTarget);
+		MyJavaThreadEventHandler eventHandler = new MyJavaThreadEventHandler(proxy);
+
+		ASTEvaluationEngine engine = new ASTEvaluationEngine(getProjectContext(), (IJavaDebugTarget) debugTarget);
+		try {
+			assertTrue(thread.isSuspended());
+			engine.evaluate(snippet, frame, listener, DebugEvent.EVALUATION_IMPLICIT, false);
+			long timeout = System.currentTimeMillis() + 5000;
+			while (thread.isSuspended() && System.currentTimeMillis() < timeout) {
+				System.out.println("Waiting for evaluation to start..");
+				Thread.sleep(10);
+			}
+
+			// evaluation must be running now
+			assertTrue(thread.isPerformingEvaluation());
+			assertFalse(thread.isSuspended());
+			assertNull(listener.getResult());
+
+			// Actual test
+			task.performChecks(thread, frames, eventHandler);
+
+			// Checck post-conditions
+			IEvaluationResult result = listener.getResult();
+			assertNotNull("The evaluation should have result: ", result);
+			assertNull("The evaluation should not have exception : " + result.getException(), result.getException());
+
+			String firstError = result.hasErrors() ? result.getErrorMessages()[0] : "";
+			assertFalse("The evaluation should not have errors : " + firstError, result.hasErrors());
+			return listener.getResult().getValue();
+		}
+		finally {
+			engine.dispose();
+			eventHandler.dispose();
+		}
+	}
+
+	static class MyJavaThreadEventHandler extends JavaThreadEventHandler {
+		boolean displayMonitors;
+
+		public MyJavaThreadEventHandler(AbstractModelProxy proxy) {
+			super(proxy);
+		}
+
+		@Override
+		public int indexOf(IStackFrame frame) {
+			return super.indexOf(frame);
+		}
+
+		@Override
+		protected boolean isDisplayMonitors() {
+			return displayMonitors;
+		}
+	}
+
+	interface TaskOnFrame {
+		void performChecks(IJavaThread thread, IStackFrame[] frames, MyJavaThreadEventHandler eventHandler) throws Exception;
+	}
+
+}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/HcrTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/HcrTests.java
index 70a3a7d..55cd091 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/HcrTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/HcrTests.java
@@ -10,12 +10,17 @@
  *******************************************************************************/
 package org.eclipse.jdt.debug.tests.core;
 
+import static org.junit.Assert.assertNotEquals;
+
 import org.eclipse.debug.core.DebugEvent;
 import org.eclipse.debug.core.DebugException;
 import org.eclipse.jdt.core.IBuffer;
 import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.debug.core.IJavaDebugTarget;
 import org.eclipse.jdt.debug.core.IJavaHotCodeReplaceListener;
+import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
 import org.eclipse.jdt.debug.core.IJavaStackFrame;
 import org.eclipse.jdt.debug.core.IJavaThread;
 import org.eclipse.jdt.debug.core.IJavaVariable;
@@ -1214,4 +1219,74 @@
 			JDIDebugModel.removeHotCodeReplaceListener(listener);
 		}
 	}
+
+	/**
+	 * Tests that HCR is NOT triggered if the code change is happened on an unrelated type, see bug 508524 and 5188
+	 */
+	public void testNoHcrOnUnrelatedType() throws Exception {
+		String typeName = "org.eclipse.debug.tests.targets.HcrClass";
+		IJavaProject unrelatedProject = get14Project();
+		IJavaProject debuggedProject = get15Project();
+		IType type1 = unrelatedProject.findType(typeName);
+		IType type2 = debuggedProject.findType(typeName);
+		assertNotEquals(type1, type2);
+
+		// Types FQNs are same
+		assertEquals(type1.getFullyQualifiedName(), type2.getFullyQualifiedName());
+
+		// Paths are same, except the project part
+		assertEquals(type1.getResource().getFullPath().removeFirstSegments(1), type2.getResource().getFullPath().removeFirstSegments(1));
+
+		final int lineNumber = 39;
+		IJavaLineBreakpoint bp1 = createLineBreakpoint(type1, lineNumber);
+		IJavaLineBreakpoint bp2 = createLineBreakpoint(type2, lineNumber);
+		assertNotEquals(bp1, bp2);
+
+		HCRListener listener = new HCRListener();
+		HCRListener listener2 = new HCRListener();
+		JDIDebugModel.addHotCodeReplaceListener(listener);
+		IJavaThread thread = null;
+		try {
+			// We start debugging on the one project but do modifications on the unrelated one!
+			thread = launchToBreakpoint(debuggedProject, typeName, typeName + CLONE_SUFFIX, true);
+			assertNotNull("Breakpoint not hit within timeout period", thread);
+
+			IJavaDebugTarget target = (IJavaDebugTarget) thread.getDebugTarget();
+			if (target.supportsHotCodeReplace()) {
+				target.addHotCodeReplaceListener(listener2);
+				// look at the value of 'x' - it should be "One"
+				IJavaStackFrame frame = (IJavaStackFrame) thread.getTopStackFrame();
+				IJavaVariable variable = findVariable(frame, "x");
+				assertNotNull("Could not find 'x'", variable);
+				assertEquals("value of 'x' should be 'One'", "One", variable.getValue().getValueString());
+				removeAllBreakpoints();
+				// now modify the source in *unrelated* project => NO HCR should happen, even if type names are same!
+				ICompilationUnit cu = getCompilationUnit(unrelatedProject, "src", "org.eclipse.debug.tests.targets", "HcrClass.java");
+				cu = cu.getPrimary();
+				if (!cu.isWorkingCopy()) {
+					cu = cu.getWorkingCopy(null);
+				}
+				assertTrue("HcrClass.java does not exist", cu.exists());
+				IBuffer buffer = cu.getBuffer();
+				String contents = buffer.getContents();
+				int index = contents.indexOf("\"One\"");
+				assertTrue("Could not find code to replace", index > 0);
+				String newCode = contents.substring(0, index) + "\"Two\"" + contents.substring(index + 5);
+				buffer.setContents(newCode);
+
+				// save contents
+				cu.commitWorkingCopy(true, null);
+				waitForBuild();
+				assertFalse("Specific listener should not have been notified", listener2.waitNotification());
+				assertFalse("General listener should not have been notified", listener.wasNotified());
+			} else {
+				System.err.println("Warning: HCR test skipped since target VM does not support HCR.");
+			}
+		}
+		finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+			JDIDebugModel.removeHotCodeReplaceListener(listener);
+		}
+	}
 }
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/JavaDebugTargetTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/JavaDebugTargetTests.java
index e45d6e0..b6b3e07 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/JavaDebugTargetTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/JavaDebugTargetTests.java
@@ -10,9 +10,17 @@
  *******************************************************************************/
 package org.eclipse.jdt.debug.tests.core;
 
+import static org.junit.Assert.assertNotEquals;
+
+import java.lang.reflect.Method;
+
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.debug.core.IJavaDebugTarget;
+import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
 import org.eclipse.jdt.debug.core.IJavaThread;
 import org.eclipse.jdt.debug.tests.AbstractDebugTest;
+import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
 
 /**
  * Tests IJavaDebugTarget API
@@ -61,4 +69,148 @@
 		}
 	}
 
+	public void testIsAvailable() throws Exception {
+		String typeName = "Breakpoints";
+		createLineBreakpoint(52, typeName);
+
+		IJavaThread thread = null;
+		try {
+			// do not register launch - see bug 130911
+			thread = launchToBreakpoint(typeName, false);
+			assertNotNull("Breakpoint not hit within timeout period", thread);
+			JDIDebugTarget target = (JDIDebugTarget) thread.getDebugTarget();
+			assertTrue(target.isAvailable());
+			JDIDebugTargetProxy proxy = new JDIDebugTargetProxy(target);
+			assertTrue(proxy.isAvailable());
+			assertFalse(proxy.isDisconnecting());
+			assertFalse(proxy.isTerminating());
+
+			proxy.setDisconnecting(true);
+			assertFalse(proxy.isAvailable());
+			assertTrue(proxy.isDisconnecting());
+			assertFalse(proxy.isTerminating());
+
+			proxy.setDisconnecting(false);
+			assertTrue(proxy.isAvailable());
+			assertFalse(proxy.isDisconnecting());
+			assertFalse(proxy.isTerminating());
+
+			proxy.setTerminating(true);
+			assertFalse(proxy.isAvailable());
+			assertFalse(proxy.isDisconnecting());
+			assertTrue(proxy.isTerminating());
+
+			proxy.setTerminating(false);
+			assertTrue(proxy.isAvailable());
+			assertFalse(proxy.isDisconnecting());
+			assertFalse(proxy.isTerminating());
+
+			terminateAndRemove(thread);
+			assertFalse(proxy.isAvailable());
+			assertFalse(proxy.isDisconnecting());
+			assertFalse(proxy.isTerminating());
+		}
+		finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	/**
+	 * Tests that debug target ignores breakpoints from unrelated projects, see bugs 5188 and 508524
+	 */
+	public void testSupportsResource() throws Exception {
+		String typeName = "org.eclipse.debug.tests.targets.HcrClass";
+		IJavaProject project1 = get14Project();
+		IJavaProject project2 = get15Project();
+		IType type1 = project1.findType(typeName);
+		IType type2 = project2.findType(typeName);
+		assertNotEquals(type1, type2);
+
+		// Types FQNs are same
+		assertEquals(type1.getFullyQualifiedName(), type2.getFullyQualifiedName());
+
+		// Paths are same, except the project part
+		assertEquals(type1.getResource().getFullPath().removeFirstSegments(1), type2.getResource().getFullPath().removeFirstSegments(1));
+
+		final int lineNumber = 21;
+		IJavaLineBreakpoint bp1 = createLineBreakpoint(type1, lineNumber);
+		IJavaLineBreakpoint bp2 = createLineBreakpoint(type2, lineNumber);
+		assertNotEquals(bp1, bp2);
+
+		IJavaThread thread = null;
+		try {
+			// Launch the first project config: the breakpoint from second one shouldn't be supported
+			thread = launchToBreakpoint(project1, typeName, typeName, true);
+			assertNotNull("Breakpoint not hit within timeout period", thread);
+			JDIDebugTarget target = (JDIDebugTarget) thread.getDebugTarget();
+			assertTrue(target.isAvailable());
+			assertEquals(1, target.getBreakpoints().size());
+			assertEquals(bp1, target.getBreakpoints().get(0));
+			assertTrue(target.supportsResource(() -> typeName, type1.getResource()));
+			assertFalse(target.supportsResource(() -> typeName, type2.getResource()));
+			terminateAndRemove(thread);
+			// Line above *deletes all breakpoints!*
+
+			bp1 = createLineBreakpoint(type1, lineNumber);
+			bp2 = createLineBreakpoint(type2, lineNumber);
+			assertNotEquals(bp1, bp2);
+
+			// Launch the second project config: the breakpoint from first one shouldn't be supported
+			thread = launchToBreakpoint(project2, typeName, typeName + CLONE_SUFFIX, true);
+			assertNotNull("Breakpoint not hit within timeout period", thread);
+			target = (JDIDebugTarget) thread.getDebugTarget();
+			assertTrue(target.isAvailable());
+			assertEquals(1, target.getBreakpoints().size());
+			assertEquals(bp2, target.getBreakpoints().get(0));
+			assertFalse(target.supportsResource(() -> typeName, type1.getResource()));
+			assertTrue(target.supportsResource(() -> typeName, type2.getResource()));
+		}
+		finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	static private class JDIDebugTargetProxy {
+
+		private JDIDebugTarget target;
+
+		public JDIDebugTargetProxy(JDIDebugTarget target) {
+			this.target = target;
+		}
+
+		public boolean isAvailable() {
+			return target.isAvailable();
+		}
+
+		public boolean isTerminating() throws Exception {
+			return callBooleanGetMethod("isTerminating");
+		}
+
+		public boolean isDisconnecting() throws Exception {
+			return callBooleanGetMethod("isDisconnecting");
+		}
+
+		public void setTerminating(boolean terminating) throws Exception {
+			callBooleanSetMethod("setTerminating", terminating);
+		}
+
+		public void setDisconnecting(boolean disconnecting) throws Exception {
+			callBooleanSetMethod("setDisconnecting", disconnecting);
+		}
+
+		private boolean callBooleanGetMethod(String name) throws Exception {
+			Method method = JDIDebugTarget.class.getDeclaredMethod(name);
+			method.setAccessible(true);
+			return (Boolean) method.invoke(target);
+		}
+
+		private void callBooleanSetMethod(String name, boolean arg) throws Exception {
+			Method method = JDIDebugTarget.class.getDeclaredMethod(name, boolean.class);
+			method.setAccessible(true);
+			method.invoke(target, Boolean.valueOf(arg));
+		}
+	}
+
 }
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/GeneralEvalTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/GeneralEvalTests.java
index 6dfdd34..196bff8 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/GeneralEvalTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/GeneralEvalTests.java
@@ -465,4 +465,71 @@
 			terminateAndRemove(thread);
 		}
 	}
+
+	/**
+	 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=508105
+	 *
+	 * @throws Exception
+	 */
+	public void testMultiByteCharacters() throws Exception {
+		IJavaThread thread = null;
+		try {
+			String typename = "bug401270";
+			createLineBreakpoint(25, typename);
+			thread = launchToBreakpoint(typename);
+			assertNotNull("the program did not suspend", thread);
+
+			String snippet = "int äüßö€ = 1; { if(äüßö€ < 0) return false; }; return äüßö€ > 0";
+			IValue value = doEval(thread, snippet);
+			assertTrue("The result of 'int äüßö€ = 1; { if(äüßö€ < 0) return false; }; return äüßö€ > 0' should be true", Boolean.parseBoolean(value.getValueString()));
+
+			snippet = "\"ทดสอบ\".length() > 0";
+			value = doEval(thread, snippet);
+			assertTrue("The result of '\"ทดสอบ\".length() > 0' should be true", Boolean.parseBoolean(value.getValueString()));
+
+			snippet = "return \"ทดสอบ\".length() == 5";
+			value = doEval(thread, snippet);
+			assertTrue("The result of 'return \"ทดสอบ\".length() == 5' should be true", Boolean.parseBoolean(value.getValueString()));
+
+			snippet = "{return \"ทดสอบ\".length() != 5;}";
+			value = doEval(thread, snippet);
+			assertFalse("The result of '{return \"ทดสอบ\".length() != 5;}' should be false", Boolean.parseBoolean(value.getValueString()));
+
+			snippet = "{/**/};\n{return \"ทดสอบ\".charAt(0) == '\\\\';}";
+			value = doEval(thread, snippet);
+			assertFalse("The result of '{/**/};\\n{return \\\"ทดสอบ\\\".charAt(0) == '\\\\\\\\';}' should be false", Boolean.parseBoolean(value.getValueString()));
+		}
+		finally {
+			removeAllBreakpoints();
+			terminateAndRemove(thread);
+		}
+	}
+
+	/**
+	 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=508105
+	 *
+	 * @throws Exception
+	 */
+	public void XtestAReturn() throws Exception {
+		IJavaThread thread = null;
+		try {
+			String typename = "bug401270";
+			createLineBreakpoint(25, typename);
+			thread = launchToBreakpoint(typename);
+			assertNotNull("the program did not suspend", thread);
+
+			String snippet = "int a = 1; return a > 0";
+			IValue value = doEval(thread, snippet);
+			assertTrue("The result of 'int a = 1; return a > 0' should be true", Boolean.parseBoolean(value.getValueString()));
+
+			snippet = "int areturn = 1; return areturn > 0";
+			value = doEval(thread, snippet);
+			assertTrue("The result of 'int areturn = 1; return areturn > 0' should be true", Boolean.parseBoolean(value.getValueString()));
+
+		}
+		finally {
+			removeAllBreakpoints();
+			terminateAndRemove(thread);
+		}
+	}
 }
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/refactoring/AbstractRefactoringDebugTest.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/refactoring/AbstractRefactoringDebugTest.java
index 4636962..bc3763a 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/refactoring/AbstractRefactoringDebugTest.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/refactoring/AbstractRefactoringDebugTest.java
@@ -10,17 +10,18 @@
  *******************************************************************************/
 package org.eclipse.jdt.debug.tests.refactoring;
 
-import org.eclipse.core.internal.resources.ResourceException;
 import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.Status;
+import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IPackageFragment;
 import org.eclipse.jdt.core.IPackageFragmentRoot;
-import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.search.IJavaSearchConstants;
 import org.eclipse.jdt.core.search.IJavaSearchScope;
 import org.eclipse.jdt.core.search.SearchEngine;
@@ -31,6 +32,7 @@
 import org.eclipse.ltk.core.refactoring.CheckConditionsOperation;
 import org.eclipse.ltk.core.refactoring.PerformRefactoringOperation;
 import org.eclipse.ltk.core.refactoring.Refactoring;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
 
 /**
  * Common refactoring utils.
@@ -53,8 +55,8 @@
 	}
 
 	/**
-	 * Performs the given refactoring. If a {@link ResourceException} occurs during the refactoring,
-	 * we trap it and throw a {@link TestAgainException} to try the test again.
+	 * Performs the given refactoring. If a {@link CoreException} occurs during the refactoring, we trap it and throw a {@link TestAgainException} to
+	 * try the test again.
 	 *
 	 * @param refactoring
 	 * @throws Exception
@@ -67,18 +69,10 @@
 		try {
 			ResourcesPlugin.getWorkspace().run(op, new NullProgressMonitor());
 			waitForBuild();
-			assertEquals(true, op.getValidationStatus().isOK());
-			assertEquals(true, op.getConditionStatus().isOK());
-		}
-		catch(ResourceException re) {
-			//try the test again - the tests reset the workspace to remove any half-moved / change files
-			//see https://bugs.eclipse.org/bugs/show_bug.cgi?id=412486
-			throw new TestAgainException(re.getLocalizedMessage());
-		}
-		catch(JavaModelException jme) {
-			//try the test again - the tests reset the workspace to remove any half-moved / change files
-			//see https://bugs.eclipse.org/bugs/show_bug.cgi?id=183206
-			throw new TestAgainException(jme.getLocalizedMessage());
+			RefactoringStatus validationStatus = op.getValidationStatus();
+			assertTrue(validationStatus.toString(), validationStatus.isOK());
+			RefactoringStatus conditionStatus = op.getConditionStatus();
+			assertTrue(conditionStatus.toString(), conditionStatus.isOK());
 		}
 		catch(CoreException ce) {
 			//try the test again - the tests reset the workspace to remove any half-moved / change files
@@ -106,8 +100,12 @@
 	 * @throws Exception
 	 */
 	private void doClean() throws Exception {
-		IProject project = get14Project().getProject();
-		IPackageFragmentRoot root = getPackageFragmentRoot(get14Project(), "src");
+		IJavaProject javaProject = get14Project();
+		IProject project = javaProject.getProject();
+		IFolder folder = project.getFolder("src");
+		folder.refreshLocal(IResource.DEPTH_INFINITE, null);
+
+		IPackageFragmentRoot root = getPackageFragmentRoot(javaProject, "src");
 		IPackageFragment fragment = root.getPackageFragment("renamedPackage");
 		if (fragment.exists()) {
 			fragment.delete(true, new NullProgressMonitor());
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/ExternalArchiveSourceContainerTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/ExternalArchiveSourceContainerTests.java
index 682c75f..746f545 100755
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/ExternalArchiveSourceContainerTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/ExternalArchiveSourceContainerTests.java
@@ -11,6 +11,10 @@
 package org.eclipse.jdt.debug.tests.sourcelookup;
 
 import java.io.File;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Path;
@@ -151,4 +155,51 @@
 		storage = (ZipEntryStorage) objects[0];
 		assertEquals("Wrong file", "file-c.txt", storage.getName());
 	}
+
+	/**
+	 * Test for bug 515941 (ConcurrentModificationException on container dispose)
+	 */
+	public void testDisposed() throws Exception {
+		int threads = Math.min(Runtime.getRuntime().availableProcessors(), 4);
+		ExecutorService exec = Executors.newFixedThreadPool(threads);
+		AtomicReference<Throwable> err = new AtomicReference<>();
+		AtomicReference<ExternalArchiveSourceContainer> container = new AtomicReference<>();
+		AtomicReference<Boolean> stop = new AtomicReference<>(Boolean.FALSE);
+		CountDownLatch latch = new CountDownLatch(1);
+		for (int i = 0; i < threads; i++) {
+			exec.submit(() -> {
+				try {
+					latch.await();
+					while (!stop.get()) {
+						ExternalArchiveSourceContainer c = container.get();
+						if (c != null) {
+							c.dispose();
+						}
+					}
+				}
+				catch (Throwable e) {
+					err.set(e);
+				}
+			});
+		}
+		latch.countDown();
+		try {
+			for (int i = 0; i < 5_000; i++) {
+				ExternalArchiveSourceContainer cont = getContainer("testresources/source-test.zip", true, false);
+				try {
+					container.set(cont);
+					Thread.sleep(1);
+					cont.findSourceElements("one/two/Three.java");
+
+				}
+				finally {
+					cont.dispose();
+				}
+			}
+		}
+		finally {
+			stop.set(true);
+			exec.shutdownNow();
+		}
+	}
 }
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/JarSourceLookupTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/JarSourceLookupTests.java
index 0476ded..ab14790 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/JarSourceLookupTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/JarSourceLookupTests.java
@@ -17,7 +17,6 @@
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.debug.core.ILaunch;
 import org.eclipse.debug.core.ILaunchConfiguration;
@@ -76,8 +75,7 @@
 
 	@Override
 	protected void setUp() throws Exception {
-		TestUtil.log(IStatus.INFO, getName(), "setUp");
-		assertWelcomeScreenClosed();
+		super.setUp();
 		TestUtil.cleanUp(getName());
 		IPath testrpath = new Path("testresources");
 		IProject jarProject = createProjectClone(fJarProject, testrpath.append(fJarProject).toString(), true);
@@ -110,7 +108,19 @@
 	protected void tearDown() throws Exception {
 		removeAllBreakpoints();
 		if (fgJarProject.exists()) {
-			fgJarProject.getProject().delete(true, null);
+			IProject project = fgJarProject.getProject();
+			// Before deleting, let indexer to finish his work to avoid error below (see 516351)
+			TestUtil.waitForJobs(getName(), 100, 3000);
+			try {
+				project.delete(true, null);
+			}
+			catch (ResourceException e) {
+				// Indexer still running on our jars?
+				TestUtil.waitForJobs(getName(), 1000, 5000);
+				if (project.exists()) {
+					project.delete(true, null);
+				}
+			}
 		}
 		super.tearDown();
 	}
@@ -176,7 +186,7 @@
 	 */
 	public void testInspectClassFileFromJar() throws Exception {
 		createLaunchConfiguration(fgJarProject, LAUNCHCONFIGURATIONS, A_RUN_JAR);
-		createLineBreakpoint(16, A_RUN_JAR);
+		createLineBreakpoint(18, A_RUN_JAR);
 		ILaunchConfiguration config = getLaunchConfiguration(fgJarProject, LAUNCHCONFIGURATIONS, A_RUN_JAR);
 		IJavaThread thread = null;
 		try {
@@ -203,7 +213,7 @@
 	 */
 	public void testShowClassFileFromJar() throws Exception {
 		createLaunchConfiguration(fgJarProject, LAUNCHCONFIGURATIONS, A_RUN_JAR);
-		createLineBreakpoint(16, A_RUN_JAR);
+		createLineBreakpoint(18, A_RUN_JAR);
 		ILaunchConfiguration config = getLaunchConfiguration(fgJarProject, LAUNCHCONFIGURATIONS, A_RUN_JAR);
 		IJavaThread thread = null;
 		try {
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/DebugViewTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/DebugViewTests.java
new file mode 100644
index 0000000..23b3d44
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/ui/DebugViewTests.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ *  Copyright (c) 2017 Andrey Loskutov and others.
+ *  All rights reserved. This program and the accompanying materials
+ *  are made available under the terms of the Eclipse Public License v1.0
+ *  which accompanies this distribution, and is available at
+ *  http://www.eclipse.org/legal/epl-v10.html
+ *
+ *  Contributors:
+ *     Andrey Loskutov <loskutov@gmx.de> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.debug.tests.ui;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.core.model.IStackFrame;
+import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
+import org.eclipse.debug.internal.ui.views.launch.LaunchView;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.jdt.debug.core.IJavaBreakpoint;
+import org.eclipse.jdt.debug.core.IJavaMethodBreakpoint;
+import org.eclipse.jdt.debug.core.IJavaStackFrame;
+import org.eclipse.jdt.debug.core.IJavaThread;
+import org.eclipse.jdt.debug.tests.TestAgainException;
+import org.eclipse.jdt.debug.tests.TestUtil;
+import org.eclipse.jdt.debug.ui.IJavaDebugUIConstants;
+import org.eclipse.jdt.internal.debug.core.model.JDIStackFrame;
+import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.test.OrderedTestSuite;
+
+import junit.framework.Test;
+
+/**
+ * Tests for debug view.
+ */
+public class DebugViewTests extends AbstractDebugUiTests {
+
+	public static Test suite() {
+		return new OrderedTestSuite(DebugViewTests.class);
+	}
+
+	private LaunchView debugView;
+	private boolean showMonitorsOriginal;
+
+	public DebugViewTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		IPreferenceStore jdiUIPreferences = JDIDebugUIPlugin.getDefault().getPreferenceStore();
+		showMonitorsOriginal = jdiUIPreferences.getBoolean(IJavaDebugUIConstants.PREF_SHOW_MONITOR_THREAD_INFO);
+		jdiUIPreferences.setValue(IJavaDebugUIConstants.PREF_SHOW_MONITOR_THREAD_INFO, true);
+		resetPerspective(DebugViewPerspectiveFactory.ID);
+		debugView = sync(() -> (LaunchView) getActivePage().showView(IDebugUIConstants.ID_DEBUG_VIEW));
+		processUiEvents(100);
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		IPreferenceStore jdiUIPreferences = JDIDebugUIPlugin.getDefault().getPreferenceStore();
+		jdiUIPreferences.setValue(IJavaDebugUIConstants.PREF_SHOW_MONITOR_THREAD_INFO, showMonitorsOriginal);
+		sync(() -> getActivePage().closeAllEditors(false));
+		processUiEvents(100);
+		super.tearDown();
+	}
+
+	public void testLastStackElementShown() throws Exception {
+		final String typeName = "DropTests";
+		final int expectedFramesNumber = 5;
+		final String expectedMethod = "method" + (expectedFramesNumber - 1);
+		IJavaBreakpoint bp = createMethodBreakpoint(typeName, expectedMethod, "()V", true, false);
+		bp.setSuspendPolicy(IJavaBreakpoint.SUSPEND_THREAD);
+
+		// Open editor to avoid UI overhead on suspend
+		sync(() -> openEditor(typeName + ".java"));
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToBreakpoint(typeName);
+			processUiEvents(100);
+
+			// Prepare breakpoint and check everything below UI is OK
+			IBreakpoint hit = getBreakpoint(thread);
+			assertNotNull("Suspended, but not by breakpoint", hit);
+			assertTrue("Breakpoint was not a method breakpoint", hit instanceof IJavaMethodBreakpoint);
+
+			IJavaStackFrame topFrame = (IJavaStackFrame) thread.getTopStackFrame();
+			assertNotNull("There should be a stackframe", topFrame);
+			assertEquals(expectedMethod, topFrame.getMethodName());
+
+			IStackFrame[] frames = topFrame.getThread().getStackFrames();
+			assertEquals(expectedFramesNumber, frames.length);
+
+			IJavaStackFrame mainFrame = (IJavaStackFrame) frames[expectedFramesNumber - 1];
+			assertEquals("First frame must be 'main'", "main", mainFrame.getMethodName());
+
+			// Let now all pending jobs proceed, ignore console jobs
+			sync(() -> TestUtil.waitForJobs(getName(), 2000, 10000, ProcessConsole.class));
+			processUiEvents(100);
+
+			// Get and check the selection form the tree, we expect only one method selected
+			TreeItem[] selected = getSelectedItemsFromDebugView(true);
+			Object[] selectedText = sync(() -> Arrays.stream(selected).map(x -> x.getText()).toArray());
+			if (selected.length != 1) {
+				if (Platform.getOS().equals(Platform.OS_MACOSX)) {
+					// skip this test on Mac - see bug 516024
+					return;
+				}
+				throw new TestAgainException("Unexpected selection: " + Arrays.toString(selectedText));
+			}
+			assertEquals("Unexpected selection: " + Arrays.toString(selectedText), 1, selected.length);
+			TreeItem selectedTreeItem = selected[selected.length - 1];
+			IJavaStackFrame selectedFrame = (IJavaStackFrame) sync(() -> {
+				Object data = selectedTreeItem.getData();
+				assertNotNull("No data for selected frame in the tree?", data);
+				assertEquals("Wrong object selected: " + data, JDIStackFrame.class, data.getClass());
+				return data;
+			});
+
+			// DropTests.method5() should be selected
+			assertEquals(selectedFrame.getMethodName(), topFrame.getMethodName());
+
+			// Now we inspect the children of the stopped thread (parent element of selected method)
+			TreeItem threadItem = sync(() -> selectedTreeItem.getParentItem());
+			TreeItem[] children = sync(() -> threadItem.getItems());
+			Object[] childrenText = sync(() -> Arrays.stream(children).map(x -> x.getText()).toArray());
+
+			// we expect to see one monitor + frames
+			final int expectedChildrenCount = expectedFramesNumber + 1;
+			if (childrenText.length != expectedChildrenCount) {
+				throw new TestAgainException("Not all frames shown: " + dumpFrames(childrenText));
+			}
+			assertEquals("Unexpected stack: " + dumpFrames(childrenText), expectedChildrenCount, childrenText.length);
+
+			// This is too unstable, see bug 516024 comment 10
+
+			// // Now we will check if the very first frame (main) is shown in the tree (on the bottom of the stack)
+			// Object firstFrame = childrenText[expectedChildrenCount - 1].toString();
+			//
+			// String frameLabel = firstFrame.toString();
+			// if (frameLabel.trim().isEmpty()) {
+			// // Some times (see bug 516024 comment 7) tree items are there but they are "empty", let restart test
+			// throw new TestAgainException("Tree children not rendered: " + dumpFrames(childrenText));
+			// }
+			//
+			// assertTrue("Unexpected first frame: " + firstFrame + ", ALL: "
+			// + dumpFrames(childrenText), frameLabel.contains("DropTests.main"));
+		}
+		finally {
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
+
+	private String dumpFrames(Object[] childrenData) {
+		return Arrays.toString(Arrays.stream(childrenData).map(x -> Objects.toString(x)).toArray());
+	}
+
+	private TreeItem[] getSelectedItemsFromDebugView(boolean wait) throws Exception {
+		return sync(() -> {
+			Tree tree = (Tree) debugView.getViewer().getControl();
+			TreeItem[] selected = tree.getSelection();
+			if (!wait) {
+				return selected;
+			}
+			long start = System.currentTimeMillis();
+
+			// At least on GTK3 it takes some time until we see the viewer selection propagated to the SWT tree
+			while (selected.length != 1 && System.currentTimeMillis() - start < 10000) {
+				TreeViewer treeViewer = (TreeViewer) debugView.getViewer();
+				treeViewer.refresh(true);
+				processUiEvents(500);
+				TestUtil.log(IStatus.INFO, getName(), "Waiting for selection, current size: " + selected.length);
+				selected = tree.getSelection();
+			}
+			return selected;
+		});
+	}
+
+}
diff --git a/org.eclipse.jdt.debug.tests/testsource-j2se-1.5/org/eclipse/debug/tests/targets/HcrClass.java b/org.eclipse.jdt.debug.tests/testsource-j2se-1.5/org/eclipse/debug/tests/targets/HcrClass.java
new file mode 100644
index 0000000..9d0b89f
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/testsource-j2se-1.5/org/eclipse/debug/tests/targets/HcrClass.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.debug.tests.targets;
+
+/**
+ * Class used to test hot code replace
+ */
+public class HcrClass {
+	
+	protected String instVar = null;
+	
+	public static void main(String[] args) {
+		new HcrClass().one();
+	}
+	
+	public void one() {
+		instVar = "One";
+		two();
+	}
+	
+	public void two() {
+		three();
+	}
+	
+	public void three() {
+		four();
+	}
+	
+	public void four() {
+		String x = instVar;
+		System.out.println(x);
+	}
+
+}
diff --git a/org.eclipse.jdt.debug.ui/META-INF/MANIFEST.MF b/org.eclipse.jdt.debug.ui/META-INF/MANIFEST.MF
index 3d39517..9bbda62 100644
--- a/org.eclipse.jdt.debug.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.debug.ui/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.debug.ui; singleton:=true
-Bundle-Version: 3.8.0.qualifier
+Bundle-Version: 3.8.100.qualifier
 Bundle-Activator: org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/org.eclipse.jdt.debug.ui/icons/full/etool16/java_app copy.gif b/org.eclipse.jdt.debug.ui/icons/full/etool16/java_app copy.gif
deleted file mode 100644
index a42a7c8..0000000
--- a/org.eclipse.jdt.debug.ui/icons/full/etool16/java_app copy.gif
+++ /dev/null
Binary files differ
diff --git a/org.eclipse.jdt.debug.ui/icons/full/obj16/class_obj.png b/org.eclipse.jdt.debug.ui/icons/full/obj16/class_obj.png
index b763245..bc915da 100644
--- a/org.eclipse.jdt.debug.ui/icons/full/obj16/class_obj.png
+++ b/org.eclipse.jdt.debug.ui/icons/full/obj16/class_obj.png
Binary files differ
diff --git a/org.eclipse.jdt.debug.ui/icons/full/obj16/class_obj@2x.png b/org.eclipse.jdt.debug.ui/icons/full/obj16/class_obj@2x.png
index aaf6754..6fca18f 100644
--- a/org.eclipse.jdt.debug.ui/icons/full/obj16/class_obj@2x.png
+++ b/org.eclipse.jdt.debug.ui/icons/full/obj16/class_obj@2x.png
Binary files differ
diff --git a/org.eclipse.jdt.debug.ui/plugin.properties b/org.eclipse.jdt.debug.ui/plugin.properties
index 7476dad..c454609 100644
--- a/org.eclipse.jdt.debug.ui/plugin.properties
+++ b/org.eclipse.jdt.debug.ui/plugin.properties
@@ -272,7 +272,6 @@
 FormatStackTraceActionDelegate.tooltip= Format
 
 javaLogicalStruturePref.name=Logical Structures
-EditLogicalStructure.label=Edit Logical Structure...
 
 allInstances.label=All Ins&tances...
 allInstances.tooltip=Displays a popup window showing all live instances of the selected type in the current running VM
diff --git a/org.eclipse.jdt.debug.ui/plugin.xml b/org.eclipse.jdt.debug.ui/plugin.xml
index 81ceaef..ee5c856 100644
--- a/org.eclipse.jdt.debug.ui/plugin.xml
+++ b/org.eclipse.jdt.debug.ui/plugin.xml
@@ -895,21 +895,6 @@
             </not>
          </visibility>
       </objectContribution>
-      <objectContribution
-            objectClass="org.eclipse.jdt.debug.core.IJavaVariable"
-            id="org.eclipse.jdt.debug.ui.JavaLogicalStructureActions">
-         <action
-               enablesFor="1"
-               label="%EditLogicalStructure.label"
-               class="org.eclipse.jdt.internal.debug.ui.actions.EditVariableLogicalStructureAction"
-               menubarPath="emptyNavigationGroup"
-               id="EditLogicalStructure"/>
-         <visibility>
-            <objectState
-                  value="canEditLogicalStructure"
-                  name="JavaLogicalStructureFilter"/>
-         </visibility>
-      </objectContribution>
       <viewerContribution
             targetID="#JavaSnippetEditorContext"
             id="org.eclipse.jdt.debug.ui.JavaSnippetPopupActions">
diff --git a/org.eclipse.jdt.debug.ui/pom.xml b/org.eclipse.jdt.debug.ui/pom.xml
index 647e7b6..a65d40e 100644
--- a/org.eclipse.jdt.debug.ui/pom.xml
+++ b/org.eclipse.jdt.debug.ui/pom.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-  Copyright (c) 2012, 2016 Eclipse Foundation and others.
+  Copyright (c) 2012, 2017 Eclipse Foundation and others.
   All rights reserved. This program and the accompanying materials
   are made available under the terms of the Eclipse Distribution License v1.0
   which accompanies this distribution, and is available at
@@ -18,7 +18,7 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.debug.ui</artifactId>
-  <version>3.8.0-SNAPSHOT</version>
+  <version>3.8.100-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
   <properties>
     <code.ignoredWarnings>-warn:+resource,-deprecation,unavoidableGenericProblems</code.ignoredWarnings>
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/launchConfigurations/JavaConnectTab.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/launchConfigurations/JavaConnectTab.java
index b344005..ba53ed9 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/launchConfigurations/JavaConnectTab.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/launchConfigurations/JavaConnectTab.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2017 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -32,6 +32,7 @@
 import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
 import org.eclipse.jdt.launching.IVMConnector;
 import org.eclipse.jdt.launching.JavaRuntime;
+import org.eclipse.jface.action.LegacyActionTools;
 import org.eclipse.jface.preference.BooleanFieldEditor;
 import org.eclipse.jface.preference.ComboFieldEditor;
 import org.eclipse.jface.preference.FieldEditor;
@@ -362,7 +363,13 @@
 			if (editor instanceof StringFieldEditor) {
 				String value = ((StringFieldEditor)editor).getStringValue();
 				if (!arg.isValid(value)) {
-					setErrorMessage(arg.label() + LauncherMessages.JavaConnectTab__is_invalid__5);
+					// Remove mnemonics from the label
+					String errorLabel = LegacyActionTools.removeMnemonics(arg.label());
+					// Remove ":" from the end
+					if (errorLabel.lastIndexOf(':') == errorLabel.length() - 1) {
+						errorLabel = errorLabel.substring(0, errorLabel.length() - 1);
+					}
+					setErrorMessage(errorLabel + LauncherMessages.JavaConnectTab__is_invalid__5);
 					return false;
 				}
 			}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIElementImageDescriptor.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIElementImageDescriptor.java
new file mode 100644
index 0000000..6643b11
--- /dev/null
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIElementImageDescriptor.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2017 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.debug.ui;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.debug.internal.ui.DebugPluginImages;
+import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
+import org.eclipse.jface.resource.CompositeImageDescriptor;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Point;
+
+public class JDIElementImageDescriptor extends CompositeImageDescriptor {
+
+	private ImageDescriptor fBaseImage;
+	private int fFlags;
+	private Point fSize;
+	public JDIElementImageDescriptor(ImageDescriptor baseImage, int flags, Point size) {
+		fBaseImage = baseImage;
+		Assert.isNotNull(fBaseImage);
+		fFlags = flags;
+		Assert.isTrue(fFlags >= 0);
+		fSize = size;
+		Assert.isNotNull(fSize);
+	}
+
+	@Override
+	protected void drawCompositeImage(int width, int height) {
+		drawImage(createCachedImageDataProvider(fBaseImage), 0, 0);
+		drawRightBottom();
+	}
+
+	private void drawRightBottom() {
+		Point size = getSize();
+		Point pos = new Point(size.x, size.y);
+
+		if ((fFlags & JDIImageDescriptor.LOGICAL_STRUCTURE) != 0) {
+			addRightBottomImage(DebugPluginImages.getImageDescriptor(IInternalDebugUIConstants.IMG_OVR_SHOW_LOGICAL_STRUCTURE), pos);
+		}
+	}
+
+	private void addRightBottomImage(ImageDescriptor desc, Point pos) {
+		CachedImageDataProvider provider = createCachedImageDataProvider(desc);
+		int x = pos.x - provider.getWidth();
+		int y = pos.y - provider.getHeight();
+		if (x >= 0 && y >= 0) {
+			drawImage(provider, x, y);
+			pos.x = x;
+		}
+	}
+
+	@Override
+	protected Point getSize() {
+		if (fSize == null) {
+			CachedImageDataProvider provider = createCachedImageDataProvider(fBaseImage);
+			fSize = new Point(provider.getWidth(), provider.getHeight());
+		}
+		return fSize;
+	}
+
+	/**
+	 * @see Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object object) {
+		if (!(object instanceof JDIElementImageDescriptor)) {
+			return false;
+		}
+		JDIElementImageDescriptor other = (JDIElementImageDescriptor) object;
+		return (fBaseImage.equals(other.fBaseImage) && fFlags == other.fFlags);
+	}
+
+	/**
+	 * @see Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		return fBaseImage.hashCode() | fFlags;
+	}
+
+}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIImageDescriptor.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIImageDescriptor.java
index eefa81b..69cb384 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIImageDescriptor.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIImageDescriptor.java
@@ -62,6 +62,8 @@
 	/** Flag to render disabled due to trigger point adornment */
 	public final static int TRIGGER_SUPPRESSED = 0x20000;
 
+	public final static int LOGICAL_STRUCTURE = 0x400000;
+
 	private ImageDescriptor fBaseImage;
 	private int fFlags;
 	private Point fSize;
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java
index b7f7df0..5750161 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java
@@ -22,6 +22,7 @@
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.debug.core.DebugException;
 import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILogicalStructureType;
 import org.eclipse.debug.core.model.IBreakpoint;
 import org.eclipse.debug.core.model.IDisconnect;
 import org.eclipse.debug.core.model.IExpression;
@@ -29,10 +30,13 @@
 import org.eclipse.debug.core.model.ITerminate;
 import org.eclipse.debug.core.model.IThread;
 import org.eclipse.debug.core.model.IValue;
+import org.eclipse.debug.core.model.IVariable;
 import org.eclipse.debug.core.model.IWatchExpression;
 import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage;
 import org.eclipse.debug.core.sourcelookup.containers.ZipEntryStorage;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
 import org.eclipse.debug.internal.ui.DefaultLabelProvider;
+import org.eclipse.debug.internal.ui.views.variables.VariablesView;
 import org.eclipse.debug.ui.DebugUITools;
 import org.eclipse.debug.ui.IDebugModelPresentation;
 import org.eclipse.debug.ui.IDebugModelPresentationExtension;
@@ -84,6 +88,7 @@
 import org.eclipse.jdt.ui.JavaElementImageDescriptor;
 import org.eclipse.jdt.ui.JavaElementLabelProvider;
 import org.eclipse.jdt.ui.JavaUI;
+import org.eclipse.jface.resource.CompositeImageDescriptor;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.viewers.IColorProvider;
 import org.eclipse.jface.viewers.LabelProvider;
@@ -93,6 +98,8 @@
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.ui.IEditorDescriptor;
 import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPage;
 import org.eclipse.ui.IWorkbenchWindow;
 import org.eclipse.ui.PartInitException;
 import org.eclipse.ui.PlatformUI;
@@ -913,9 +920,12 @@
 	}
 
 	protected Image getVariableImage(IAdaptable element) {
-		JavaElementImageDescriptor descriptor= new JavaElementImageDescriptor(
+		CompositeImageDescriptor descriptor = new JavaElementImageDescriptor(
 			computeBaseImageDescriptor(element), computeAdornmentFlags(element), BIG_SIZE);
-		return JavaPlugin.getImageDescriptorRegistry().get(descriptor);
+		descriptor = new JDIElementImageDescriptor(descriptor, computeLogicalStructureAdornmentFlags(element), BIG_SIZE);
+		Image image = JDIDebugUIPlugin.getImageDescriptorRegistry().get(descriptor);
+
+		return image;
 	}
 
 	/**
@@ -1133,6 +1143,38 @@
 		return flags;
 	}
 
+	private int computeLogicalStructureAdornmentFlags(IAdaptable element) {
+		int flags = 0;
+		 if (element instanceof IVariable) {
+            try {
+                IValue value= ((IVariable) element).getValue();
+                ILogicalStructureType[] types = DebugPlugin.getLogicalStructureTypes(value);
+				if (types.length == 0) {
+					return flags; // no logical structure is defined for the value type
+		        }
+				ILogicalStructureType enabledType = DebugPlugin.getDefaultStructureType(types);
+				if (enabledType == null) {
+					return flags; // no logical structure is enabled for this type
+				}
+				IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows();
+				for (IWorkbenchWindow window : windows) {
+					IWorkbenchPage page = window.getActivePage();
+					IViewPart viewPart = page.findView(IDebugUIConstants.ID_VARIABLE_VIEW);
+					if (viewPart instanceof VariablesView) {
+						if (((VariablesView) viewPart).isShowLogicalStructure()) {
+							// a logical structure is enabled for this type and global toggle to show logical structure is on
+							return flags |= JDIImageDescriptor.LOGICAL_STRUCTURE;
+						}
+						return flags;
+					}
+				}
+            }catch (DebugException e) {
+				DebugUIPlugin.log(e.getStatus());
+            }
+		}
+        return flags;
+	}
+
 	/**
 	 * @see IDebugModelPresentation#getEditorInput(Object)
 	 */
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaLogicalStructuresPreferencePage.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaLogicalStructuresPreferencePage.java
index ef4c59c..07c859d 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaLogicalStructuresPreferencePage.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaLogicalStructuresPreferencePage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2016 IBM Corporation and others.
+ * Copyright (c) 2004, 2017 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -212,6 +212,23 @@
 	}
 
 	@Override
+	public void applyData(Object data) {
+		if (data instanceof String) {
+			Object[] logicalStructures = fLogicalStructuresContentProvider.getElements(null);
+			for (int i = 0, length = logicalStructures.length; i < length; i++) {
+				JavaLogicalStructure javaLogicalStructure = ((JavaLogicalStructure) logicalStructures[i]);
+				if (((String) data).compareToIgnoreCase(javaLogicalStructure.getId() + javaLogicalStructure.getDescription()
+						+ javaLogicalStructure.hashCode()) == 0) {
+					fLogicalStructuresViewer.setSelection(new StructuredSelection(logicalStructures[i]));
+					return;
+				}
+			}
+		} else {
+			super.applyData(data);
+		}
+	}
+
+	@Override
 	public void createControl(Composite parent) {
 		super.createControl(parent);
 		PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IJavaDebugHelpContextIds.JAVA_LOGICAL_STRUCTURES_PAGE);
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaVarActionFilter.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaVarActionFilter.java
index 93639d8..af0ec12 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaVarActionFilter.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaVarActionFilter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2015 IBM Corporation and others.
+ * Copyright (c) 2005, 2017 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -21,11 +21,9 @@
 import org.eclipse.jdt.debug.core.IJavaObject;
 import org.eclipse.jdt.debug.core.IJavaType;
 import org.eclipse.jdt.debug.core.IJavaVariable;
-import org.eclipse.jdt.internal.debug.core.logicalstructures.JavaStructureErrorValue;
 import org.eclipse.jdt.internal.debug.core.model.JDINullValue;
 import org.eclipse.jdt.internal.debug.core.model.JDIPlaceholderValue;
 import org.eclipse.jdt.internal.debug.core.model.JDIReferenceListVariable;
-import org.eclipse.jdt.internal.debug.ui.actions.EditVariableLogicalStructureAction;
 import org.eclipse.jdt.internal.debug.ui.display.JavaInspectExpression;
 import org.eclipse.ui.IActionFilter;
 
@@ -213,9 +211,6 @@
 						return JavaDetailFormattersManager.getDefault().hasSuperclassDetailFormatter(((IJavaObject)varValue).getJavaType());
 					}
 				}
-				else if (name.equals("JavaLogicalStructureFilter") && value.equals("canEditLogicalStructure")) {  //$NON-NLS-1$ //$NON-NLS-2$
-                    return varValue instanceof JavaStructureErrorValue || EditVariableLogicalStructureAction.getLogicalStructure(varValue) != null;
-                }
 			} catch (DebugException e) {}
 		}
 		else if (target instanceof JavaInspectExpression) {
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/EditVariableLogicalStructureAction.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/EditVariableLogicalStructureAction.java
deleted file mode 100644
index 5fefc2a..0000000
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/EditVariableLogicalStructureAction.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2005, 2015 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- *     IBM Corporation - initial implementation
- *******************************************************************************/
-package org.eclipse.jdt.internal.debug.ui.actions;
-
-import org.eclipse.debug.core.DebugException;
-import org.eclipse.debug.core.DebugPlugin;
-import org.eclipse.debug.core.ILogicalStructureType;
-import org.eclipse.debug.core.model.IValue;
-import org.eclipse.jdt.debug.core.IJavaVariable;
-import org.eclipse.jdt.internal.debug.core.logicalstructures.JavaLogicalStructure;
-import org.eclipse.jdt.internal.debug.core.logicalstructures.JavaLogicalStructures;
-import org.eclipse.jdt.internal.debug.core.logicalstructures.JavaStructureErrorValue;
-import org.eclipse.jdt.internal.debug.ui.EditLogicalStructureDialog;
-import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
-import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.window.Window;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.ui.IObjectActionDelegate;
-import org.eclipse.ui.IWorkbenchPart;
-import org.eclipse.ui.actions.ActionDelegate;
-
-/**
- * Action which prompts the user to edit the logical structure that
- * is currently active on the given object.
- */
-public class EditVariableLogicalStructureAction extends ActionDelegate implements IObjectActionDelegate {
-
-    /**
-     * The editable structure for the currently selected variable or
-     * <code>null</code> if none.
-     */
-    private JavaLogicalStructure fStructure= null;
-
-    /* (non-Javadoc)
-     * @see org.eclipse.ui.IObjectActionDelegate#setActivePart(org.eclipse.jface.action.IAction, org.eclipse.ui.IWorkbenchPart)
-     */
-    @Override
-	public void setActivePart(IAction action, IWorkbenchPart targetPart) {
-    }
-
-    /**
-     * Prompt the user to edit the logical structure associated with the currently
-     * selected variable.
-     */
-    @Override
-	public void run(IAction action) {
-        if (fStructure == null) {
-            return;
-        }
-        Shell shell= JDIDebugUIPlugin.getActiveWorkbenchShell();
-        if (shell != null) {
-            EditLogicalStructureDialog dialog= new EditLogicalStructureDialog(shell, fStructure);
-            if (dialog.open() == Window.OK) {
-                JavaLogicalStructures.saveUserDefinedJavaLogicalStructures();
-            }
-        }
-    }
-
-    /**
-     * @see ActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
-     */
-    @Override
-	public void selectionChanged(IAction action, ISelection selection) {
-        fStructure= null;
-        Object element = ((IStructuredSelection) selection).getFirstElement();
-        if (element instanceof IJavaVariable) {
-            try {
-                IValue value= ((IJavaVariable) element).getValue();
-                if (value instanceof JavaStructureErrorValue) {
-                    value= ((JavaStructureErrorValue) value).getParentValue();
-                }
-                ILogicalStructureType type= getLogicalStructure(value);
-                if (type instanceof JavaLogicalStructure) {
-                    JavaLogicalStructure javaStructure= (JavaLogicalStructure) type;
-                    if (!javaStructure.isContributed()) {
-                        fStructure= javaStructure;
-                    }
-                }
-            } catch (DebugException e) {
-                JDIDebugUIPlugin.log(e.getStatus());
-            }
-        }
-        action.setEnabled(fStructure != null);
-    }
-
-    /**
-     * Returns the logical structure currently associated with the given
-     * value or <code>null</code> if none.
-     * @param value the value
-     * @return the logical structure currently associated with the given
-     *  value or <code>null</code> if none.
-     */
-    public static ILogicalStructureType getLogicalStructure(IValue value) {
-        // This code is based on VariablesViewContentProvider#getLogicalValue(IValue)
-        ILogicalStructureType type = null;
-        ILogicalStructureType[] types = DebugPlugin.getLogicalStructureTypes(value);
-        if (types.length > 0) {
-            type= DebugPlugin.getDefaultStructureType(types);
-        }
-        return type;
-    }
-}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/threadgroups/JavaDebugTargetProxy.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/threadgroups/JavaDebugTargetProxy.java
index 3a06ee0..715bd52 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/threadgroups/JavaDebugTargetProxy.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/threadgroups/JavaDebugTargetProxy.java
@@ -67,9 +67,6 @@
 				new StackFrameEventHandler(this, fThreadEventHandler)};
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.debug.internal.ui.viewers.update.DebugTargetProxy#installed(org.eclipse.jface.viewers.Viewer)
-	 */
 	@Override
 	public void installed(Viewer viewer) {
 		if (fIsScrapbook) {
@@ -87,6 +84,11 @@
 				}
 				return Status.OK_STATUS;
 			}
+
+			@Override
+			public boolean belongsTo(Object family) {
+				return JavaDebugTargetProxy.this == family;
+			}
 		};
 		job.setSystem(true);
 		job.schedule(500);
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/threadgroups/JavaThreadEventHandler.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/threadgroups/JavaThreadEventHandler.java
index 6755f87..a0b3042 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/threadgroups/JavaThreadEventHandler.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/threadgroups/JavaThreadEventHandler.java
@@ -145,15 +145,12 @@
 	    return fDisplayMonitors;
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.debug.internal.ui.viewers.update.ThreadEventHandler#indexOf(org.eclipse.debug.core.model.IStackFrame)
-	 */
 	@Override
 	protected int indexOf(IStackFrame frame) {
+		int index = 0;
 		if (isDisplayMonitors()) {
-			if (((IJavaDebugTarget)frame.getDebugTarget()).supportsMonitorInformation()) {
-				IJavaThread thread = (IJavaThread)frame.getThread();
-				int index = 0;
+			if (((IJavaDebugTarget) frame.getDebugTarget()).supportsMonitorInformation()) {
+				IJavaThread thread = (IJavaThread) frame.getThread();
 				try {
 					index = thread.getOwnedMonitors().length;
 					if (thread.getContendedMonitor() != null) {
@@ -161,12 +158,41 @@
 					}
 				} catch (DebugException e) {
 				}
-				return index;
+			} else {
+				// make room for the 'no monitor info' element
+				index = 1;
 			}
-			// make room for the 'no monitor info' element
-			return 1;
 		}
-		return super.indexOf(frame);
+		IThread thread = frame.getThread();
+		if (thread instanceof IJavaThread) {
+			// If the thread is performing evaluation right now, it will report no frames and so we would be unable to compute the right index.
+			// Check and in case evaluation is running, wait a second, see bug 515206
+			waitIfEvaluationRuns((IJavaThread) thread, 1000);
+		}
+		return index + super.indexOf(frame);
+	}
+
+	/**
+	 * Waits given time in case thread is performing evaluation.
+	 *
+	 * @param thread
+	 *            non null
+	 * @param maxWaitTimeMillis
+	 *            max time to wait in milliseconds
+	 */
+	private void waitIfEvaluationRuns(IJavaThread thread, final long maxWaitTimeMillis) {
+		long start = System.currentTimeMillis();
+		while (thread.isPerformingEvaluation() && !thread.isTerminated()) {
+			try {
+				Thread.sleep(50);
+			}
+			catch (InterruptedException e) {
+				break;
+			}
+			if (System.currentTimeMillis() - start > maxWaitTimeMillis) {
+				break;
+			}
+		}
 	}
 
 	/**
diff --git a/org.eclipse.jdt.debug/META-INF/MANIFEST.MF b/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
index 283cc24..307a3f7 100644
--- a/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.debug; singleton:=true
-Bundle-Version: 3.11.0.qualifier
+Bundle-Version: 3.11.100.qualifier
 Bundle-ClassPath: jdi.jar,
  jdimodel.jar,
  tools.jar
diff --git a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java
index 4c1cae6..8198fa0 100644
--- a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java
+++ b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java
@@ -750,58 +750,66 @@
 
 			EvaluationRunnable er = new EvaluationRunnable();
 			CoreException exception = null;
-			long start = System.currentTimeMillis();
 			try {
-				fThread.runEvaluation(er, null, fEvaluationDetail,
-						fHitBreakpoints);
-			} catch (DebugException e) {
-				exception = e;
-			}
-			long end = System.currentTimeMillis();
-
-			IJavaValue value = interpreter.getResult();
-
-			if (exception == null) {
-				exception = er.getException();
-			}
-
-			result.setTerminated(er.fTerminated);
-			if (exception != null) {
-				if (JDIDebugOptions.DEBUG_AST_EVAL) {
-					StringBuffer buf = new StringBuffer();
-					buf.append("\tException: "); //$NON-NLS-1$
-					buf.append(exception.toString());
-					JDIDebugOptions.trace(buf.toString());
+				long start = System.currentTimeMillis();
+				try {
+					fThread.runEvaluation(er, null, fEvaluationDetail,
+							fHitBreakpoints);
+				} catch (DebugException e) {
+					exception = e;
+				} catch (Exception e) {
+					IStatus status = new Status(IStatus.ERROR,
+							JDIDebugPlugin.getUniqueIdentifier(),
+							JDIDebugPlugin.ERROR,
+							EvaluationEngineMessages.ASTEvaluationEngine_An_unknown_error_occurred_during_evaluation, e);
+					exception = new DebugException(status);
 				}
-				if (exception instanceof DebugException) {
-					result.setException((DebugException) exception);
-				} else {
-					result.setException(new DebugException(exception
-							.getStatus()));
+				long end = System.currentTimeMillis();
+
+				IJavaValue value = interpreter.getResult();
+
+				if (exception == null) {
+					exception = er.getException();
 				}
-			} else {
-				if (value != null) {
-					result.setValue(value);
+
+				result.setTerminated(er.fTerminated);
+				if (exception != null) {
 					if (JDIDebugOptions.DEBUG_AST_EVAL) {
 						StringBuffer buf = new StringBuffer();
-						buf.append("\tResult: "); //$NON-NLS-1$
-						buf.append(value);
+						buf.append("\tException: "); //$NON-NLS-1$
+						buf.append(exception.toString());
 						JDIDebugOptions.trace(buf.toString());
 					}
+					if (exception instanceof DebugException) {
+						result.setException((DebugException) exception);
+					} else {
+						result.setException(new DebugException(exception
+								.getStatus()));
+					}
 				} else {
-					result.addError(EvaluationEngineMessages.ASTEvaluationEngine_An_unknown_error_occurred_during_evaluation);
+					if (value != null) {
+						result.setValue(value);
+						if (JDIDebugOptions.DEBUG_AST_EVAL) {
+							StringBuffer buf = new StringBuffer();
+							buf.append("\tResult: "); //$NON-NLS-1$
+							buf.append(value);
+							JDIDebugOptions.trace(buf.toString());
+						}
+					} else {
+						result.addError(EvaluationEngineMessages.ASTEvaluationEngine_An_unknown_error_occurred_during_evaluation);
+					}
 				}
-			}
 
-			if (JDIDebugOptions.DEBUG_AST_EVAL) {
-				StringBuffer buf = new StringBuffer();
-				buf.append("\tDuration: "); //$NON-NLS-1$
-				buf.append(end - start);
-				buf.append("ms"); //$NON-NLS-1$
-				JDIDebugOptions.trace(buf.toString());
+				if (JDIDebugOptions.DEBUG_AST_EVAL) {
+					StringBuffer buf = new StringBuffer();
+					buf.append("\tDuration: "); //$NON-NLS-1$
+					buf.append(end - start);
+					buf.append("ms"); //$NON-NLS-1$
+					JDIDebugOptions.trace(buf.toString());
+				}
+			} finally {
+				evaluationFinished(result);
 			}
-
-			evaluationFinished(result);
 		}
 
 		private void evaluationFinished(IEvaluationResult result) {
diff --git a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationSourceGenerator.java b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationSourceGenerator.java
index 4e10c8d..1bb3fc0 100644
--- a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationSourceGenerator.java
+++ b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationSourceGenerator.java
@@ -79,8 +79,11 @@
 	 */
 	protected String getCompleteSnippet(String codeSnippet) {
 		codeSnippet = codeSnippet.trim(); // remove whitespaces at the end
+		if(codeSnippet.isEmpty()) {
+			return "return;"; //$NON-NLS-1$
+		}
 		boolean inString = false;
-		byte[] chars = codeSnippet.getBytes();
+		char[] chars = codeSnippet.toCharArray();
 
 		int semicolonIndex = -1;
 		int lastSemilcolonIndex = -1;
diff --git a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.properties b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.properties
index a10c8bd..4c45d2d 100644
--- a/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.properties
+++ b/org.eclipse.jdt.debug/jdi/org/eclipse/jdi/internal/connect/ConnectMessages.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2016 IBM Corporation and others.
+# Copyright (c) 2000, 2017 IBM Corporation and others.
 # All rights reserved. This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License v1.0
 # which accompanies this distribution, and is available at
@@ -14,9 +14,9 @@
 PacketReceiveManager_Got_IOException_from_Virtual_Machine_2=Got IOException from Virtual Machine
 PacketSendManager_Got_IOException_from_Virtual_Machine_1=Got IOException from Virtual Machine
 SocketAttachingConnectorImpl_Machine_name_to_which_to_attach_for_VM_connections_1=Machine name to which to attach for VM connections
-SocketAttachingConnectorImpl_Host_2=Host:
+SocketAttachingConnectorImpl_Host_2=&Host:
 SocketAttachingConnectorImpl_Port_number_to_which_to_attach_for_VM_connections_3=Port number to which to attach for VM connections
-SocketAttachingConnectorImpl_Port_4=Port:
+SocketAttachingConnectorImpl_Port_4=&Port:
 SocketAttachingConnectorImpl_1=Connection Timeout
 SocketAttachingConnectorImpl_2=Connection Timeout:
 SocketAttachingConnectorImpl_Attaches_by_socket_to_other_VMs_5=Attaches by socket to other VMs
@@ -40,14 +40,14 @@
 SocketLaunchingConnectorImpl_Necessary_connection_argument_is_null_15=Necessary connection argument is null
 SocketLaunchingConnectorImpl_Connection_argument_is_not_a_number_16=Connection argument is not a number
 SocketListeningConnectorImpl_Port_number_at_which_to_listen_for_VM_connections_1=Port number at which to listen for VM connections
-SocketListeningConnectorImpl_Port_2=Port:
+SocketListeningConnectorImpl_Port_2=&Port:
 SocketListeningConnectorImpl_Timeout_before_accept_returns_3=Timeout before accept returns
 SocketListeningConnectorImpl_Timeout_4=Timeout:
 SocketListeningConnectorImpl_Accepts_socket_connections_initiated_by_other_VMs_5=Accepts socket connections initiated by other VMs
 SocketListeningConnectorImpl_Connection_argument_is_not_of_the_right_type_6=Connection argument is not of the right type
 SocketListeningConnectorImpl_Necessary_connection_argument_is_null_7=Necessary connection argument is null
 SocketListeningConnectorImpl_Connection_argument_is_not_a_number_8=Connection argument is not a number
-SocketListeningConnectorImpl_Limit=Connection limit:
+SocketListeningConnectorImpl_Limit=&Connection limit:
 SocketListeningConnectorImpl_Limit_incoming_connections=Limit incoming connections (0 = no limit)
 SocketListeningConnectorImpl_ListeningConnector_Socket_Port=ListeningConnector Socket Port=
 SocketRawLaunchingConnectorImpl_Raw_command_to_start_the_debugged_application_VM_1=Raw command to start the debugged application VM
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/EventDispatcher.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/EventDispatcher.java
index 92c0328..216b9c4 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/EventDispatcher.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/EventDispatcher.java
@@ -265,6 +265,16 @@
 								}
 								return false;
 							}
+
+							@Override
+							public String toString() {
+								try {
+									return super.toString() + " for [" + fTarget.getName() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+								}
+								catch (DebugException e) {
+									return super.toString();
+								}
+							}
 						};
 						job.setSystem(true);
 						job.schedule();
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JavaHotCodeReplaceManager.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JavaHotCodeReplaceManager.java
index c1b48cd..ef7576a 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JavaHotCodeReplaceManager.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/hcr/JavaHotCodeReplaceManager.java
@@ -469,8 +469,15 @@
 			// unloaded types on a per-target basis.
 			List<IResource> resourcesToReplace = new ArrayList<>(resources);
 			List<String> qualifiedNamesToReplace = new ArrayList<>(qualifiedNames);
-			filterUnloadedTypes(target, resourcesToReplace,
-					qualifiedNamesToReplace);
+
+			// Make sure we only try to replace types from related projects
+			filterUnrelatedResources(target, resourcesToReplace, qualifiedNamesToReplace);
+			if (qualifiedNamesToReplace.isEmpty()) {
+				// If none of the changed types are related to our target, do nothing.
+				continue;
+			}
+
+			filterUnloadedTypes(target, resourcesToReplace, qualifiedNamesToReplace);
 			if (qualifiedNamesToReplace.isEmpty()) {
 				// If none of the changed types are loaded, do nothing.
 				continue;
@@ -541,6 +548,18 @@
 		fDeltaCache.clear();
 	}
 
+	private void filterUnrelatedResources(JDIDebugTarget target, List<IResource> resourcesToReplace, List<String> qualifiedNamesToReplace) {
+		Iterator<IResource> resources = resourcesToReplace.iterator();
+		Iterator<String> names = qualifiedNamesToReplace.iterator();
+		while (resources.hasNext()) {
+			boolean supported = target.supportsResource(() -> names.next(), resources.next());
+			if (!supported) {
+				resources.remove();
+				names.remove();
+			}
+		}
+	}
+
 	/**
 	 * Returns whether the given exception, which occurred during HCR, should be
 	 * logged. We anticipate that we can get IncompatibleThreadStateExceptions
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java
index 519f877..f76bac1 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugTarget.java
@@ -23,6 +23,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Callable;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.eclipse.core.resources.IFile;
@@ -160,6 +161,12 @@
 	 * Whether in the process of terminating
 	 */
 	private boolean fTerminating;
+
+	/**
+	 * Whether in the process of disconnecting
+	 */
+	private boolean fDisconnecting;
+
 	/**
 	 * Whether disconnected
 	 */
@@ -349,6 +356,7 @@
 		setTerminated(false);
 		setTerminating(false);
 		setDisconnected(false);
+		setDisconnecting(false);
 		setName(name);
 		prepareBreakpointsSearchScope();
 		setBreakpoints(new ArrayList<IBreakpoint>(5));
@@ -862,6 +870,7 @@
 		}
 
 		try {
+			setDisconnecting(true);
 			disposeThreadHandler();
 			VirtualMachine vm = getVM();
 			if (vm != null) {
@@ -1136,7 +1145,7 @@
 	 * Returns whether this target is available to handle VM requests
 	 */
 	public boolean isAvailable() {
-		return !(isTerminated() || isTerminating() || isDisconnected());
+		return !(isTerminated() || isTerminating() || isDisconnected() || isDisconnecting());
 	}
 
 	/**
@@ -1383,7 +1392,15 @@
 			return true;
 		}
 
-		IResource resource = marker.getResource();
+		return supportsResource(() -> jBreakpoint.getTypeName(), marker.getResource());
+	}
+
+
+	public boolean supportsResource(Callable<String> typeNameSupplier, IResource resource) {
+		if (fScope == null) {
+			// No checks, everything in scope: the filtering is disabled
+			return true;
+		}
 		// Java exception breakpoints have wsp root as resource
 		if(resource == null || resource == ResourcesPlugin.getWorkspace().getRoot()) {
 			return true;
@@ -1419,7 +1436,7 @@
 		// This can be also an incomplete resource mapping.
 		// Try to see if the type available multiple times in workspace
 		try {
-			String typeName = jBreakpoint.getTypeName();
+			String typeName = typeNameSupplier.call();
 			if(typeName != null){
 				Boolean known = knownTypes.get(typeName);
 				if(known != null){
@@ -1429,7 +1446,8 @@
 				knownTypes.put(typeName, Boolean.valueOf(supportedBreakpoint));
 				return supportedBreakpoint;
 			}
-		} catch (CoreException e) {
+		}
+		catch (Exception e) {
 			logError(e);
 		}
 		// we don't know why computation failed, so let assume the breakpoint is supported.
@@ -1839,6 +1857,7 @@
 	 */
 	@Override
 	protected void disconnected() {
+		setDisconnecting(false);
 		if (!isDisconnected()) {
 			setDisconnected(true);
 			cleanup();
@@ -2262,6 +2281,14 @@
 		fTerminating = terminating;
 	}
 
+	protected boolean isDisconnecting() {
+		return fDisconnecting;
+	}
+
+	protected void setDisconnecting(boolean disconnecting) {
+		fDisconnecting = disconnecting;
+	}
+
 	/**
 	 * An event handler for thread start events. When a thread starts in the
 	 * target VM, a model thread is created.
diff --git a/org.eclipse.jdt.debug/pom.xml b/org.eclipse.jdt.debug/pom.xml
index 184b714..3191d5d 100644
--- a/org.eclipse.jdt.debug/pom.xml
+++ b/org.eclipse.jdt.debug/pom.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-  Copyright (c) 2012, 2016 Eclipse Foundation and others.
+  Copyright (c) 2012, 2017 Eclipse Foundation and others.
   All rights reserved. This program and the accompanying materials
   are made available under the terms of the Eclipse Distribution License v1.0
   which accompanies this distribution, and is available at
@@ -18,6 +18,6 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.debug</artifactId>
-  <version>3.11.0-SNAPSHOT</version>
+  <version>3.11.100-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 </project>