Update jdt.core to 4.14 M1 (I20191009-1800)
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/ParserTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/ParserTest.java
index e9c12eb..407758e 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/ParserTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/ParserTest.java
@@ -759,7 +759,7 @@
 			"1. ERROR in X.java (at line 4)\n" + 
 			"	Srtring bar = \"\"\"\n" + 
 			"    }\n" + 
-			"	              ^^^^^^^^^\n" + 
+			"	              ^^^^\n" + 
 			"Text block is not properly closed with the delimiter\n" + 
 			"----------\n" :
 			"----------\n" + 
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java
index 53389d3..582f257 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java
@@ -106,7 +106,7 @@
 public abstract class AbstractRegressionTest extends AbstractCompilerTest implements StopableTestCase {
 
 	static final String[] env = System.getenv().entrySet().stream()
-		.filter(e -> !"JAVA_TOOL_OPTIONS".equals(e.getKey()))
+		.filter(e -> !"JAVA_TOOL_OPTIONS".equals(e.getKey()) && !"_JAVA_OPTIONS".equals(e.getKey()))
 		.map(e -> e.getKey() + "=" + e.getValue())
 		.toArray(String[]::new);
 
@@ -382,6 +382,12 @@
 			if ("1.8.0_182".equals(rawVersion)) {
 				return 2500;
 			}
+			if ("1.8.0_202".equals(rawVersion)) {
+				return 2600;
+			}
+			if ("1.8.0_212".equals(rawVersion)) {
+				return 2700;
+			}
 		}
 		if (version == JavaCore.VERSION_9) {
 			if ("9".equals(rawVersion)) {
@@ -2440,6 +2446,8 @@
 }
 private void deleteSourceFiles(File directory) {
 	try {
+		if (!directory.exists())
+			return;
 		Files.walk(directory.toPath())
 			.filter(f -> f.endsWith(SuffixConstants.SUFFIX_STRING_java))
 			.map(java.nio.file.Path::toFile)
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
index 884b680..195dc75 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
@@ -10783,17 +10783,17 @@
 		+ " -proceedOnError -err:+unused -d \"" + OUTPUT_DIR + "\"",
 		"",
 		"----------\n" + 
-		"1. INFO in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 2)\n" + 
+		"1. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 2)\n" + 
 		"	@SuppressWarnings(\"unused\")\n" + 
 		"	                  ^^^^^^^^\n" + 
-		"At least one of the problems in category 'unused' is not analysed due to a compiler option being ignored\n" + 
+		"Unnecessary @SuppressWarnings(\"unused\")\n" +
 		"----------\n" + 
 		"2. ERROR in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 3)\n" + 
 		"	private int i;\n" + 
 		"	            ^\n" + 
 		"The value of the field X.i is not used\n" + 
 		"----------\n" + 
-		"2 problems (1 error, 0 warnings, 1 info)\n",
+		"2 problems (1 error, 1 warning)\n",
 		true);
 }
 //https://bugs.eclipse.org/bugs/show_bug.cgi?id=295551
@@ -10874,17 +10874,17 @@
 		+ " -proceedOnError -warn:-suppress -err:+suppress,unused -warn:+suppress -d \"" + OUTPUT_DIR + "\"",
 		"",
 		"----------\n" + 
-		"1. INFO in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 2)\n" + 
+		"1. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 2)\n" + 
 		"	@SuppressWarnings(\"unused\")\n" + 
 		"	                  ^^^^^^^^\n" + 
-		"At least one of the problems in category 'unused' is not analysed due to a compiler option being ignored\n" + 
+		"Unnecessary @SuppressWarnings(\"unused\")\n" +
 		"----------\n" + 
 		"2. ERROR in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 3)\n" + 
 		"	private int i;\n" + 
 		"	            ^\n" + 
 		"The value of the field X.i is not used\n" + 
 		"----------\n" + 
-		"2 problems (1 error, 0 warnings, 1 info)\n",
+		"2 problems (1 error, 1 warning)\n",
 		true);
 }
 //https://bugs.eclipse.org/bugs/show_bug.cgi?id=295551
@@ -13257,4 +13257,28 @@
 		"",
 		true);
 }
+public void testUnusedObjectAllocation() {
+	runNegativeTest(
+		new String[] {
+			"X.java",
+			"public class X {\n" +
+			"	void foo() {\n" +
+			"		new X();\n" +
+			"	}\n" +
+			"}\n"
+		},
+		"\"" + OUTPUT_DIR +  File.separator + "X.java\""
+		+ " -err:+unused"
+		+ " -d \"" + OUTPUT_DIR + File.separator + "bin/\"",
+		"",
+		"----------\n" + 
+		"1. ERROR in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 3)\n" + 
+		"	new X();\n" + 
+		"	^^^^^^^\n" + 
+		"The allocated object is never used\n" + 
+		"----------\n" + 
+		"1 problem (1 error)\n",
+		true);
+
+}
 }
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ConditionalExpressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ConditionalExpressionTest.java
index d63e379..c959426 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ConditionalExpressionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ConditionalExpressionTest.java
@@ -576,20 +576,39 @@
 		if (this.complianceLevel < ClassFileConstants.JDK1_8)
 			return;
 		this.runNegativeTest(
-				new String[] {
-						"X.java",
-						"public class X extends Y {\n" +
-						"    public X(Z[] n) {\n" +
-						"        super((n == null) ? null : n.clone());\n" +
-						"    }\n" +
-						"}\n" +
-						"class Y  {\n" +
-						"    public Y(Z[] notifications) {\n" +
-						"    }\n" +
-						"}\n" +
-						"interface Z {}\n",
-				},
-				"");
+			new String[] {
+					"X.java",
+					"public class X extends Y {\n" +
+					"    public X(Z[] n) {\n" +
+					"        super((n == null) ? null : n.clone());\n" +
+					"    }\n" +
+					"}\n" +
+					"class Y  {\n" +
+					"    public Y(Z[] notifications) {\n" +
+					"    }\n" +
+					"}\n" +
+					"interface Z {}\n",
+			},
+			"");
+	}
+	public void test437444_2() {
+		if (this.complianceLevel < ClassFileConstants.JDK1_8)
+			return;
+		this.runNegativeTest(
+			new String[] {
+					"X.java",
+					"public class X extends Y {\n" +
+					"    public X(int[] n) {\n" +
+					"        super((n == null) ? null : n.clone());\n" +
+					"    }\n" +
+					"}\n" +
+					"class Y  {\n" +
+					"    public Y(int[] notifications) {\n" +
+					"    }\n" +
+					"}\n" +
+					"interface Z {}\n",
+			},
+			"");
 	}
 	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=484425: [bytecode] Bad type on operand stack - compiler omitted instructions for unboxing null Boolean
 	public void test484425() {
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ConstantTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ConstantTest.java
index 693beee..28c2127 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ConstantTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ConstantTest.java
@@ -367,134 +367,126 @@
 			ClassFileBytesDisassembler.DETAILED);
 
 	String expectedOutput =
-		"  // Method descriptor #15 ([Ljava/lang/String;)V\n" +
-		"  // Stack: 3, Locals: 4\n" + 
-		"  public static void main(java.lang.String[] args);\n" + 
-		"     0  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
-		"     3  ldc <String \"1\"> [22]\n" + 
-		"     5  invokevirtual java.io.PrintStream.print(java.lang.String) : void [24]\n" + 
-		"     8  aconst_null\n" + 
-		"     9  goto 13\n" + 
-		"    12  aconst_null\n" + 
-		"    13  aconst_null\n" + 
-		"    14  goto 18\n" + 
-		"    17  aconst_null\n" + 
-		"    18  if_acmpne 29\n" + 
-		"    21  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
-		"    24  ldc <String \"2\"> [30]\n" + 
-		"    26  invokevirtual java.io.PrintStream.print(java.lang.String) : void [24]\n" + 
-		"    29  new java.lang.StringBuffer [32]\n" + 
-		"    32  dup\n" + 
-		"    33  ldc <String \"[\"> [34]\n" + 
-		"    35  invokespecial java.lang.StringBuffer(java.lang.String) [36]\n" + 
-		"    38  aconst_null\n" + 
-		"    39  invokevirtual java.lang.StringBuffer.append(java.lang.Object) : java.lang.StringBuffer [38]\n" + 
-		"    42  ldc <String \"]\"> [42]\n" + 
-		"    44  invokevirtual java.lang.StringBuffer.append(java.lang.String) : java.lang.StringBuffer [44]\n" + 
-		"    47  invokevirtual java.lang.StringBuffer.toString() : java.lang.String [47]\n" + 
-		"    50  ldc <String \"[null]\"> [51]\n" + 
-		"    52  if_acmpne 59\n" + 
-		"    55  iconst_1\n" + 
-		"    56  goto 60\n" + 
-		"    59  iconst_0\n" + 
-		"    60  istore_1 [b]\n" + 
-		"    61  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
-		"    64  ldc <String \"3\"> [53]\n" + 
-		"    66  invokevirtual java.io.PrintStream.print(java.lang.String) : void [24]\n" + 
-		"    69  aconst_null\n" + 
-		"    70  astore_2 [s]\n" + 
-		"    71  aload_2 [s]\n" + 
-		"    72  ifnonnull 83\n" + 
-		"    75  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
-		"    78  ldc <String \"4\"> [55]\n" + 
-		"    80  invokevirtual java.io.PrintStream.print(java.lang.String) : void [24]\n" + 
-		"    83  ldc <String \"aaa\"> [57]\n" + 
-		"    85  astore_3 [s2]\n" + 
-		"    86  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
-		"    89  ldc <String \"5\"> [59]\n" + 
-		"    91  invokevirtual java.io.PrintStream.println(java.lang.String) : void [61]\n" + 
-		"    94  return\n" + 
-		"      Line numbers:\n" + 
-		"        [pc: 0, line: 3]\n" + 
-		"        [pc: 8, line: 4]\n" + 
-		"        [pc: 21, line: 5]\n" + 
-		"        [pc: 29, line: 6]\n" + 
-		"        [pc: 61, line: 7]\n" + 
-		"        [pc: 69, line: 8]\n" + 
-		"        [pc: 71, line: 9]\n" + 
-		"        [pc: 83, line: 10]\n" + 
-		"        [pc: 86, line: 11]\n" + 
-		"        [pc: 94, line: 12]\n" + 
-		"      Local variable table:\n" + 
-		"        [pc: 0, pc: 95] local: args index: 0 type: java.lang.String[]\n" + 
-		"        [pc: 61, pc: 95] local: b index: 1 type: boolean\n" + 
-		"        [pc: 71, pc: 95] local: s index: 2 type: java.lang.String\n" + 
-		"        [pc: 86, pc: 95] local: s2 index: 3 type: java.lang.String\n";
+			"  // Method descriptor #15 ([Ljava/lang/String;)V\n" + 
+			"  // Stack: 3, Locals: 4\n" + 
+			"  public static void main(java.lang.String[] args);\n" + 
+			"     0  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
+			"     3  ldc <String \"1\"> [22]\n" + 
+			"     5  invokevirtual java.io.PrintStream.print(java.lang.String) : void [24]\n" + 
+			"     8  aconst_null\n" + 
+			"     9  aconst_null\n" + 
+			"    10  if_acmpne 21\n" + 
+			"    13  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
+			"    16  ldc <String \"2\"> [30]\n" + 
+			"    18  invokevirtual java.io.PrintStream.print(java.lang.String) : void [24]\n" + 
+			"    21  new java.lang.StringBuffer [32]\n" + 
+			"    24  dup\n" + 
+			"    25  ldc <String \"[\"> [34]\n" + 
+			"    27  invokespecial java.lang.StringBuffer(java.lang.String) [36]\n" + 
+			"    30  aconst_null\n" + 
+			"    31  invokevirtual java.lang.StringBuffer.append(java.lang.Object) : java.lang.StringBuffer [38]\n" + 
+			"    34  ldc <String \"]\"> [42]\n" + 
+			"    36  invokevirtual java.lang.StringBuffer.append(java.lang.String) : java.lang.StringBuffer [44]\n" + 
+			"    39  invokevirtual java.lang.StringBuffer.toString() : java.lang.String [47]\n" + 
+			"    42  ldc <String \"[null]\"> [51]\n" + 
+			"    44  if_acmpne 51\n" + 
+			"    47  iconst_1\n" + 
+			"    48  goto 52\n" + 
+			"    51  iconst_0\n" + 
+			"    52  istore_1 [b]\n" + 
+			"    53  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
+			"    56  ldc <String \"3\"> [53]\n" + 
+			"    58  invokevirtual java.io.PrintStream.print(java.lang.String) : void [24]\n" + 
+			"    61  aconst_null\n" + 
+			"    62  astore_2 [s]\n" + 
+			"    63  aload_2 [s]\n" + 
+			"    64  ifnonnull 75\n" + 
+			"    67  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
+			"    70  ldc <String \"4\"> [55]\n" + 
+			"    72  invokevirtual java.io.PrintStream.print(java.lang.String) : void [24]\n" + 
+			"    75  ldc <String \"aaa\"> [57]\n" + 
+			"    77  astore_3 [s2]\n" + 
+			"    78  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
+			"    81  ldc <String \"5\"> [59]\n" + 
+			"    83  invokevirtual java.io.PrintStream.println(java.lang.String) : void [61]\n" + 
+			"    86  return\n" + 
+			"      Line numbers:\n" + 
+			"        [pc: 0, line: 3]\n" + 
+			"        [pc: 8, line: 4]\n" + 
+			"        [pc: 13, line: 5]\n" + 
+			"        [pc: 21, line: 6]\n" + 
+			"        [pc: 53, line: 7]\n" + 
+			"        [pc: 61, line: 8]\n" + 
+			"        [pc: 63, line: 9]\n" + 
+			"        [pc: 75, line: 10]\n" + 
+			"        [pc: 78, line: 11]\n" + 
+			"        [pc: 86, line: 12]\n" + 
+			"      Local variable table:\n" + 
+			"        [pc: 0, pc: 87] local: args index: 0 type: java.lang.String[]\n" + 
+			"        [pc: 53, pc: 87] local: b index: 1 type: boolean\n" + 
+			"        [pc: 63, pc: 87] local: s index: 2 type: java.lang.String\n" + 
+			"        [pc: 78, pc: 87] local: s2 index: 3 type: java.lang.String\n";
 
 	String expectedOutput15 =
-		"  // Method descriptor #15 ([Ljava/lang/String;)V\n" +
-		"  // Stack: 3, Locals: 4\n" + 
-		"  public static void main(java.lang.String[] args);\n" + 
-		"     0  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
-		"     3  ldc <String \"1\"> [22]\n" + 
-		"     5  invokevirtual java.io.PrintStream.print(java.lang.String) : void [24]\n" + 
-		"     8  aconst_null\n" + 
-		"     9  goto 13\n" + 
-		"    12  aconst_null\n" + 
-		"    13  aconst_null\n" + 
-		"    14  goto 18\n" + 
-		"    17  aconst_null\n" + 
-		"    18  if_acmpne 29\n" + 
-		"    21  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
-		"    24  ldc <String \"2\"> [30]\n" + 
-		"    26  invokevirtual java.io.PrintStream.print(java.lang.String) : void [24]\n" + 
-		"    29  new java.lang.StringBuilder [32]\n" + 
-		"    32  dup\n" + 
-		"    33  ldc <String \"[\"> [34]\n" + 
-		"    35  invokespecial java.lang.StringBuilder(java.lang.String) [36]\n" + 
-		"    38  aconst_null\n" + 
-		"    39  invokevirtual java.lang.StringBuilder.append(java.lang.Object) : java.lang.StringBuilder [38]\n" + 
-		"    42  ldc <String \"]\"> [42]\n" + 
-		"    44  invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [44]\n" + 
-		"    47  invokevirtual java.lang.StringBuilder.toString() : java.lang.String [47]\n" + 
-		"    50  ldc <String \"[null]\"> [51]\n" + 
-		"    52  if_acmpne 59\n" + 
-		"    55  iconst_1\n" + 
-		"    56  goto 60\n" + 
-		"    59  iconst_0\n" + 
-		"    60  istore_1 [b]\n" + 
-		"    61  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
-		"    64  ldc <String \"3\"> [53]\n" + 
-		"    66  invokevirtual java.io.PrintStream.print(java.lang.String) : void [24]\n" + 
-		"    69  aconst_null\n" + 
-		"    70  astore_2 [s]\n" + 
-		"    71  aload_2 [s]\n" + 
-		"    72  ifnonnull 83\n" + 
-		"    75  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
-		"    78  ldc <String \"4\"> [55]\n" + 
-		"    80  invokevirtual java.io.PrintStream.print(java.lang.String) : void [24]\n" + 
-		"    83  ldc <String \"aaa\"> [57]\n" + 
-		"    85  astore_3 [s2]\n" + 
-		"    86  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
-		"    89  ldc <String \"5\"> [59]\n" + 
-		"    91  invokevirtual java.io.PrintStream.println(java.lang.String) : void [61]\n" + 
-		"    94  return\n" + 
-		"      Line numbers:\n" + 
-		"        [pc: 0, line: 3]\n" + 
-		"        [pc: 8, line: 4]\n" + 
-		"        [pc: 21, line: 5]\n" + 
-		"        [pc: 29, line: 6]\n" + 
-		"        [pc: 61, line: 7]\n" + 
-		"        [pc: 69, line: 8]\n" + 
-		"        [pc: 71, line: 9]\n" + 
-		"        [pc: 83, line: 10]\n" + 
-		"        [pc: 86, line: 11]\n" + 
-		"        [pc: 94, line: 12]\n" + 
-		"      Local variable table:\n" + 
-		"        [pc: 0, pc: 95] local: args index: 0 type: java.lang.String[]\n" + 
-		"        [pc: 61, pc: 95] local: b index: 1 type: boolean\n" + 
-		"        [pc: 71, pc: 95] local: s index: 2 type: java.lang.String\n" + 
-		"        [pc: 86, pc: 95] local: s2 index: 3 type: java.lang.String\n";
+			"  // Method descriptor #15 ([Ljava/lang/String;)V\n" + 
+			"  // Stack: 3, Locals: 4\n" + 
+			"  public static void main(java.lang.String[] args);\n" + 
+			"     0  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
+			"     3  ldc <String \"1\"> [22]\n" + 
+			"     5  invokevirtual java.io.PrintStream.print(java.lang.String) : void [24]\n" + 
+			"     8  aconst_null\n" + 
+			"     9  aconst_null\n" + 
+			"    10  if_acmpne 21\n" + 
+			"    13  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
+			"    16  ldc <String \"2\"> [30]\n" + 
+			"    18  invokevirtual java.io.PrintStream.print(java.lang.String) : void [24]\n" + 
+			"    21  new java.lang.StringBuilder [32]\n" + 
+			"    24  dup\n" + 
+			"    25  ldc <String \"[\"> [34]\n" + 
+			"    27  invokespecial java.lang.StringBuilder(java.lang.String) [36]\n" + 
+			"    30  aconst_null\n" + 
+			"    31  invokevirtual java.lang.StringBuilder.append(java.lang.Object) : java.lang.StringBuilder [38]\n" + 
+			"    34  ldc <String \"]\"> [42]\n" + 
+			"    36  invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [44]\n" + 
+			"    39  invokevirtual java.lang.StringBuilder.toString() : java.lang.String [47]\n" + 
+			"    42  ldc <String \"[null]\"> [51]\n" + 
+			"    44  if_acmpne 51\n" + 
+			"    47  iconst_1\n" + 
+			"    48  goto 52\n" + 
+			"    51  iconst_0\n" + 
+			"    52  istore_1 [b]\n" + 
+			"    53  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
+			"    56  ldc <String \"3\"> [53]\n" + 
+			"    58  invokevirtual java.io.PrintStream.print(java.lang.String) : void [24]\n" + 
+			"    61  aconst_null\n" + 
+			"    62  astore_2 [s]\n" + 
+			"    63  aload_2 [s]\n" + 
+			"    64  ifnonnull 75\n" + 
+			"    67  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
+			"    70  ldc <String \"4\"> [55]\n" + 
+			"    72  invokevirtual java.io.PrintStream.print(java.lang.String) : void [24]\n" + 
+			"    75  ldc <String \"aaa\"> [57]\n" + 
+			"    77  astore_3 [s2]\n" + 
+			"    78  getstatic java.lang.System.out : java.io.PrintStream [16]\n" + 
+			"    81  ldc <String \"5\"> [59]\n" + 
+			"    83  invokevirtual java.io.PrintStream.println(java.lang.String) : void [61]\n" + 
+			"    86  return\n" + 
+			"      Line numbers:\n" + 
+			"        [pc: 0, line: 3]\n" + 
+			"        [pc: 8, line: 4]\n" + 
+			"        [pc: 13, line: 5]\n" + 
+			"        [pc: 21, line: 6]\n" + 
+			"        [pc: 53, line: 7]\n" + 
+			"        [pc: 61, line: 8]\n" + 
+			"        [pc: 63, line: 9]\n" + 
+			"        [pc: 75, line: 10]\n" + 
+			"        [pc: 78, line: 11]\n" + 
+			"        [pc: 86, line: 12]\n" + 
+			"      Local variable table:\n" + 
+			"        [pc: 0, pc: 87] local: args index: 0 type: java.lang.String[]\n" + 
+			"        [pc: 53, pc: 87] local: b index: 1 type: boolean\n" + 
+			"        [pc: 63, pc: 87] local: s index: 2 type: java.lang.String\n" + 
+			"        [pc: 78, pc: 87] local: s2 index: 3 type: java.lang.String\n";
 
 	if (this.complianceLevel >= ClassFileConstants.JDK1_5) {
 		int index = actualOutput.indexOf(expectedOutput15);
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java
index 50a2135..fa024bc 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java
@@ -18283,7 +18283,7 @@
 	runner.runNegativeTest();
 }
 public void testBug542707_1() {
-	if (this.complianceLevel < ClassFileConstants.JDK12) return; // switch expression
+	if (this.complianceLevel < ClassFileConstants.JDK13) return; // switch expression
 	Runner runner = new Runner();
 	runner.customOptions = new HashMap<>();
 	runner.customOptions.put(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES, JavaCore.ENABLED);
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java
index 17ef64b..c6e8637 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java
@@ -17772,7 +17772,7 @@
 	);
 }
 public void testBug542707_1() {
-	if (this.complianceLevel < ClassFileConstants.JDK12) return; // switch expression
+	if (this.complianceLevel < ClassFileConstants.JDK13) return; // switch expression
 	// switch expression has a functional type with interesting type inference and various null issues:
 	Runner runner = new Runner();
 	runner.customOptions = getCompilerOptions();
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/StackMapAttributeTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/StackMapAttributeTest.java
index 36470b3..ce9e6cf 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/StackMapAttributeTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/StackMapAttributeTest.java
@@ -851,13 +851,9 @@
 					"        [pc: 5, pc: 24] local: bar index: 2 type: java.lang.String\n" +
 					"      Stack map table: number of frames 2\n" +
 					"        [pc: 19, full, stack: {java.io.PrintStream}, locals: {java.lang.String[], int, java.lang.String}]\n" +
-					(this.complianceLevel >= ClassFileConstants.JDK1_8 ? // in 1.8 the ternary is resolved to its target type j.l.Object
-					"        [pc: 20, full, stack: {java.io.PrintStream, java.lang.Object}, locals: {java.lang.String[], int, java.lang.String}]\n" :
-					"        [pc: 20, full, stack: {java.io.PrintStream, java.lang.Comparable}, locals: {java.lang.String[], int, java.lang.String}]\n") +
+					"        [pc: 20, full, stack: {java.io.PrintStream, java.lang.Comparable}, locals: {java.lang.String[], int, java.lang.String}]\n" +
 					"  \n" +
-					(this.complianceLevel >= ClassFileConstants.JDK1_8 ?
-					"  // Method descriptor #46 (Ljava/lang/Comparable;)V\n" :
-					"  // Method descriptor #48 (Ljava/lang/Comparable;)V\n") +
+					"  // Method descriptor #48 (Ljava/lang/Comparable;)V\n" +
 					"  // Signature: <T::Ljava/lang/Comparable<*>;>(TT;)V\n" +
 					"  // Stack: 2, Locals: 3\n" +
 					"  void foo(java.lang.Comparable foo);\n" +
@@ -884,11 +880,7 @@
 					"        [pc: 2, pc: 18] local: bar index: 2 type: T\n" +
 					"      Stack map table: number of frames 2\n" +
 					"        [pc: 13, full, stack: {java.io.PrintStream}, locals: {X, java.lang.Comparable, java.lang.Comparable}]\n" +
-					(this.complianceLevel < ClassFileConstants.JDK1_8 ?
-					"        [pc: 14, full, stack: {java.io.PrintStream, java.lang.Comparable}, locals: {X, java.lang.Comparable, java.lang.Comparable}]\n"
-					: // in 1.8 the ternary is resolved to its target type j.l.Object
-					"        [pc: 14, full, stack: {java.io.PrintStream, java.lang.Object}, locals: {X, java.lang.Comparable, java.lang.Comparable}]\n"
-					);
+					"        [pc: 14, full, stack: {java.io.PrintStream, java.lang.Comparable}, locals: {X, java.lang.Comparable, java.lang.Comparable}]\n";
 
 			int index = actualOutput.indexOf(expectedOutput);
 			if (index == -1 || expectedOutput.length() == 0) {
@@ -2536,17 +2528,16 @@
 	}
 	public void test032() {
 		this.runConformTest(
-				new String[] {
-						"X.java",
-						"import java.util.*;\n" +
-						"public class X {\n" +
-						"    public static void main(String[] args) {\n" +
-						"		int i = args.length;\n" +
-						"       X[] array = new X[] { i == 0 ? null : null };\n" +
-						"		System.out.print(\"SUCCESS\" + array.length);\n" +
-						"    }\n" +
-						"}",
-				},
+			new String[] {
+					"X.java",
+					"public class X {\n" +
+					"    public static void main(String[] args) {\n" +
+					"		int i = args.length;\n" +
+					"       X[] array = new X[] { i == 0 ? null : null };\n" +
+					"		System.out.print(\"SUCCESS\" + array.length);\n" +
+					"    }\n" +
+					"}",
+			},
 		"SUCCESS1");
 	}
 
@@ -8731,4 +8722,112 @@
 				assertEquals("Wrong contents", expectedOutput, actualOutput);
 			}
 	}
+
+	public void test551368() {
+		this.runConformTest(
+            new String[] {
+        		"X.java",
+        		"interface A {\n" + 
+        		"}\n" + 
+        		"class B implements A {\n" + 
+        		"	public C c;\n" + 
+        		"	\n" + 
+        		"	protected B original() {\n" + 
+        		"		return this;\n" + 
+        		"	}\n" + 
+        		"}\n" + 
+        		"class C {\n" + 
+        		"	C parent;\n" + 
+        		"	A context;\n" + 
+        		"}\n" + 
+        		"class F extends C {\n" + 
+        		"	\n" + 
+        		"}\n" + 
+        		"class G extends C {\n" + 
+        		"	\n" + 
+        		"}\n" + 
+        		"abstract class D implements A {\n" + 
+        		"	public F c;\n" + 
+        		"}\n" + 
+        		"class E implements A {\n" + 
+        		"	public G c;\n" + 
+        		"}\n" + 
+        		"public class X {\n" + 
+        		"	boolean foo(A a) {\n" + 
+        		"		if (a instanceof B && a != ((B) a).original())\n" + 
+        		"			return true;\n" + 
+        		"		C aC = a instanceof D ? ((D) a).c :\n" + 
+        		"			a instanceof E ? ((E) a).c : \n" + 
+        		"			a instanceof B ? ((B) a).c :\n" + 
+        		"				null;\n" + 
+        		"		return aC != null ? foo(aC.parent.context) : false;\n" + 
+        		"	}\n" + 
+        		"	public static void main(String[] args) {\n" + 
+        		"		System.out.println(\"SUCCESS\");\n" + 
+        		"	}\n" + 
+        		"}",
+            },
+			"SUCCESS");
+	}
+	public void test551368_2() {
+		this.runConformTest(
+            new String[] {
+        		"X.java",
+        		"public class X {\n" + 
+        		"\n" + 
+        		"	int size;\n" + 
+        		"	char[][][] elements;\n" + 
+        		"\n" + 
+        		"	public X() {\n" + 
+        		"		this.size = 0;\n" + 
+        		"		this.elements = new char[10][][];\n" + 
+        		"	}\n" + 
+        		"\n" + 
+        		"	public void insertIntoArray(char[][][] target) {\n" + 
+        		"	}\n" + 
+        		"\n" + 
+        		"	public void add(char[][] newElement) {\n" + 
+        		"		insertIntoArray(this.size < this.elements.length ? this.elements : new char[this.elements.length * 2][][]);\n" + 
+        		"	}\n" + 
+        		"\n" + 
+        		"	public static void main(String[] args) {\n" + 
+        		"		System.out.println(\"SUCCESS\");\n" + 
+        		"	}\n" + 
+        		"}",
+            },
+			"SUCCESS");
+	}
+	public void test551368_3() {
+		this.runConformTest(
+            new String[] {
+        		"X.java",
+        		"class B {\n" + 
+        		"	public boolean bar() {\n" + 
+        		"		return false;\n" + 
+        		"	}\n" + 
+        		"	public void foo() {}\n" + 
+        		"}\n" + 
+        		"public class X {\n" + 
+        		"	\n" + 
+        		"	public B foo(boolean test) {\n" + 
+        		"		B b =\n" + 
+        		"			test ?\n" + 
+        		"				new B() {\n" + 
+        		"					@Override\n" + 
+        		"					public boolean bar() {\n" + 
+        		"						return true;\n" + 
+        		"					}\n" + 
+        		"				} :\n" + 
+        		"			new B();\n" + 
+        		"		b.foo();\n" + 
+        		"		return b;\n" + 
+        		"	}\n" + 
+        		"\n" + 
+        		"	public static void main(String[] args) {\n" + 
+        		"		System.out.println(\"SUCCESS\");\n" + 
+        		"	}\n" + 
+        		"}",
+            },
+			"SUCCESS");
+	}
 }
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java
index 1fef2d0..32efd3c 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java
@@ -631,20 +631,20 @@
 		String[] testFiles = new String[] {
 				"X.java",
 				"public class X {\n" +
-						"public static void bar(Day day) {\n" + 
-						"		switch (day) {\n" + 
-						"		case SATURDAY, SUNDAY: \n" + 
-						"			System.out.println(Day.SUNDAY);\n" + 
-						"			break;\n" + 
-						"		case MONDAY : System.out.println(Day.MONDAY);\n" + 
-						"					break;\n" + 
-						"		}\n" + 
-						"	}" +
-						"	public static void main(String[] args) {\n" +
-						"		bar(Day.SATURDAY);\n" +
-						"	}\n" +
-						"}\n" +
-						"enum Day { SATURDAY, SUNDAY, MONDAY;}",
+				"public static void bar(Day day) {\n" + 
+				"		switch (day) {\n" + 
+				"		case SATURDAY, SUNDAY: \n" + 
+				"			System.out.println(Day.SUNDAY);\n" + 
+				"			break;\n" + 
+				"		case MONDAY : System.out.println(Day.MONDAY);\n" + 
+				"					break;\n" + 
+				"		}\n" + 
+				"	}" +
+				"	public static void main(String[] args) {\n" +
+				"		bar(Day.SATURDAY);\n" +
+				"	}\n" +
+				"}\n" +
+				"enum Day { SATURDAY, SUNDAY, MONDAY;}",
 		};
 
 		String expectedProblemLog =
@@ -2921,4 +2921,64 @@
 			"Duplicate case\n" + 
 			"----------\n");
 	}
+	public void _testBug544943() {
+		runConformTest(
+			new String[] {
+				"X.java",
+				"public class X {\n" + 
+				"	@SuppressWarnings(\"preview\")\n" + 
+				"	public static int foo(int i) throws MyException {\n" + 
+				"		int v = -1;\n" + 
+				"		try {\n" + 
+				"			v = switch (i) {\n" + 
+				"				case 0 -> switch(i) {\n" + 
+				"							case 0 -> 1;\n" + 
+				"							default -> throw new MyException();\n" + 
+				"						  };\n" + 
+				"				default -> 1;\n" + 
+				"			};\n" + 
+				"		} finally {\n" + 
+				"			// do nothing\n" + 
+				"		}\n" + 
+				"		return v;\n" + 
+				"	} \n" + 
+				"	public static void main(String argv[]) {\n" + 
+				"		try {\n" + 
+				"			System.out.println(X.foo(0));\n" + 
+				"		} catch (MyException e) {\n" + 
+				"			e.printStackTrace();\n" + 
+				"		}\n" + 
+				"	}\n" + 
+				"}\n" + 
+				"class MyException extends Exception {\n" + 
+				"	private static final long serialVersionUID = 3461899582505930473L;	\n" + 
+				"}"
+			},
+			"1");
+	}
+	public void _testBug544943_2() {
+		runConformTest(
+			new String[] {
+				"X.java",
+				"public class X {\n" + 
+				"	@SuppressWarnings({ \"preview\" })\n" + 
+				"	public static int foo(int i) throws Exception {\n" + 
+				"		int v = switch (i) {\n" + 
+				"			case 0 -> switch (i) {\n" + 
+				"				case 0 -> 0;\n" + 
+				"				default-> throw new Exception();\n" + 
+				"				case 3 -> 3;\n" + 
+				"				case 2 -> throw new Exception();\n" + 
+				"				};\n" + 
+				"			default -> 0;\n" + 
+				"		};\n" + 
+				"		return v;\n" + 
+				"	}\n" + 
+				"	public static void main(String argv[]) throws Exception {\n" + 
+				"		System.out.println(X.foo(1));\n" + 
+				"	}\n" +
+				"}"
+			},
+			"0");
+	}
 }
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java
index f0dd255..8c98176 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java
@@ -3480,4 +3480,64 @@
 			"String literal is not properly closed by a double-quote\n" + 
 			"----------\n");
 	}
+	public void testBug544943() {
+		runConformTest(
+			new String[] {
+				"X.java",
+				"public class X {\n" + 
+				"	@SuppressWarnings(\"preview\")\n" + 
+				"	public static int foo(int i) throws MyException {\n" + 
+				"		int v = -1;\n" + 
+				"		try {\n" + 
+				"			v = switch (i) {\n" + 
+				"				case 0 -> switch(i) {\n" + 
+				"							case 0 -> 1;\n" + 
+				"							default -> throw new MyException();\n" + 
+				"						  };\n" + 
+				"				default -> 1;\n" + 
+				"			};\n" + 
+				"		} finally {\n" + 
+				"			// do nothing\n" + 
+				"		}\n" + 
+				"		return v;\n" + 
+				"	} \n" + 
+				"	public static void main(String argv[]) {\n" + 
+				"		try {\n" + 
+				"			System.out.println(X.foo(0));\n" + 
+				"		} catch (MyException e) {\n" + 
+				"			e.printStackTrace();\n" + 
+				"		}\n" + 
+				"	}\n" + 
+				"}\n" + 
+				"class MyException extends Exception {\n" + 
+				"	private static final long serialVersionUID = 3461899582505930473L;	\n" + 
+				"}"
+			},
+			"1");
+	}
+	public void testBug544943_2() {
+		runConformTest(
+			new String[] {
+				"X.java",
+				"public class X {\n" + 
+				"	@SuppressWarnings({ \"preview\" })\n" + 
+				"	public static int foo(int i) throws Exception {\n" + 
+				"		int v = switch (i) {\n" + 
+				"			case 0 -> switch (i) {\n" + 
+				"				case 0 -> 0;\n" + 
+				"				default-> throw new Exception();\n" + 
+				"				case 3 -> 3;\n" + 
+				"				case 2 -> throw new Exception();\n" + 
+				"				};\n" + 
+				"			default -> 0;\n" + 
+				"		};\n" + 
+				"		return v;\n" + 
+				"	}\n" + 
+				"	public static void main(String argv[]) throws Exception {\n" + 
+				"		System.out.println(X.foo(1));\n" + 
+				"	}\n" +
+				"}"
+			},
+			"0");
+	}
 }
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter13Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter13Test.java
index 867723c..21d4e4b 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter13Test.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter13Test.java
@@ -48,7 +48,7 @@
 public class ASTConverter13Test extends ConverterTestSetup {
 
 	ICompilationUnit workingCopy;
-	private static final String jclLib = "CONVERTER_JCL9_LIB";
+	private static final String jclLib = "CONVERTER_JCL13_LIB";
 
 	public void setUpSuite() throws Exception {
 		super.setUpSuite();
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java
index 568caf7..995812c 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java
@@ -5424,5 +5424,39 @@
 	assertEquals("val$outerArg",synVars[0].getName());
 	assertEquals("val$outerLocal",synVars[1].getName());
 }
+public void testCaptureBinding18() throws CoreException {
+	this.workingCopy = getWorkingCopy("/Converter18/src/xyz/X.java", true/* resolve */);
+	StringBuilder buf= new StringBuilder();
+	buf.append("package xyz;\n");
+	buf.append("\n");
+	buf.append("import java.util.List;\n");
+	buf.append("\n");
+	buf.append("public class X {\n");
+	buf.append("\n");
+	buf.append("	protected <E extends Comparable<E>> List<E> createEmptySet() {\n");
+	buf.append("		return null;\n");
+	buf.append("	}\n");
+	buf.append("\n");
+	buf.append("	public void emptySet() {\n");
+	buf.append("		s = createEmptySet();\n");
+	buf.append("	}\n");
+	buf.append("\n");
+	buf.append("}");
+	String content= buf.toString();
+	CompilationUnit cu = (CompilationUnit) buildAST(content, this.workingCopy, false /*i.e. ignore errors*/);
+	MethodDeclaration method= ((TypeDeclaration)cu.types().get(0)).getMethods()[1];
+	Assignment assignment= (Assignment) ((ExpressionStatement) method.getBody().statements().get(0)).getExpression();
+	ITypeBinding binding = assignment.getRightHandSide().resolveTypeBinding();
+	assertTrue("main type is parameterized", binding.isParameterizedType());
+	binding = binding.getTypeArguments()[0];
+	assertTrue("treat as wildcard", binding.isWildcardType());
+	assertFalse("don't treat as capture", binding.isCapture());
+	assertTrue("has upper bound", binding.isUpperbound());
+	ITypeBinding[] typeBounds = binding.getTypeBounds();
+	assertEquals("number of bounds", 1, typeBounds.length);
+	ITypeBinding bound = typeBounds[0];
+	assertTrue("bound is parameterized", bound.isParameterizedType());
+	assertEquals("bound's type argument is the original type argument", binding, bound.getTypeArguments()[0]);
+}
 
 }
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ConverterTestSetup.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ConverterTestSetup.java
index b5f9366..8bd1281 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ConverterTestSetup.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ConverterTestSetup.java
@@ -184,10 +184,18 @@
 			if (JavaCore.getClasspathVariable("CONVERTER_JCL12_LIB") == null) {
 				setupExternalJCL("converterJclMin12");
 				JavaCore.setClasspathVariables(
-						new String[] {"CONVERTER_JCL11_LIB", "CONVERTER_JCL11_SRC", "CONVERTER_JCL11_SRCROOT"},
+						new String[] {"CONVERTER_JCL12_LIB", "CONVERTER_JCL12_SRC", "CONVERTER_JCL12_SRCROOT"},
 						new IPath[] {getConverterJCLPath("12"), getConverterJCLSourcePath("12"), getConverterJCLRootSourcePath()},
 						null);
 			}
+		} else if ("13".equals(compliance)) {
+			if (JavaCore.getClasspathVariable("CONVERTER_JCL13_LIB") == null) {
+				setupExternalJCL("converterJclMin13");
+				JavaCore.setClasspathVariables(
+						new String[] {"CONVERTER_JCL13_LIB", "CONVERTER_JCL13_SRC", "CONVERTER_JCL13_SRCROOT"},
+						new IPath[] {getConverterJCLPath("13"), getConverterJCLSourcePath("13"), getConverterJCLRootSourcePath()},
+						null);
+			}
 		} else if (JavaCore.getClasspathVariable("CONVERTER_JCL_LIB") == null) {
 			setupExternalJCL("converterJclMin");
 			JavaCore.setClasspathVariables(
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java
index 305d9b3..96e0469 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterBugsTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -13022,4 +13022,18 @@
 		"	}\n" + 
 		"}");
 }
+/**
+ * https://bugs.eclipse.org/551189 - Consistent ArrayIndexOutOfBounds when saving an incorrect Java file when code clean-up is enabled
+ */
+public void testBug551189() {
+	formatSource(
+		"public class AAA {\n" + 
+		"\n" + 
+		"import java.awt.*;\n" + 
+		"\n" + 
+		"public class BBB {\n" + 
+		"    int a;\n" + 
+		"\n" + 
+		"}}");
+}
 }
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java
index 320fe9a..567280f 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterRegressionTests.java
@@ -15242,4 +15242,147 @@
 	this.formatterPrefs.blank_lines_between_statement_groups_in_switch = ~0;
 	formatSourceInWorkspace("test390720", "in.java", "B_out.java");
 }
+/**
+ * https://bugs.eclipse.org/549436 - [13] Formatter support for JEP 355 Text Block
+ */
+public void testBug549436a() throws JavaModelException {
+	setComplianceLevel(CompilerOptions.VERSION_13);
+	setPageWidth80();
+	this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.SPACE;
+	this.formatterPrefs.use_tabs_only_for_leading_indentations = false;
+	this.formatterPrefs.indent_empty_lines = false;
+	this.formatterPrefs.text_block_indentation = Alignment.M_INDENT_PRESERVE;
+	this.formatterPrefs.continuation_indentation = 2;
+	formatSourceInWorkspace("test549436", "in.java", "A_out.java");
+}
+/**
+ * https://bugs.eclipse.org/549436 - [13] Formatter support for JEP 355 Text Block
+ */
+public void testBug549436b() throws JavaModelException {
+	setComplianceLevel(CompilerOptions.VERSION_13);
+	setPageWidth80();
+	this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.SPACE;
+	this.formatterPrefs.use_tabs_only_for_leading_indentations = false;
+	this.formatterPrefs.indent_empty_lines = false;
+	this.formatterPrefs.text_block_indentation = Alignment.M_INDENT_BY_ONE;
+	this.formatterPrefs.continuation_indentation = 2;
+	formatSourceInWorkspace("test549436", "in.java", "B_out.java");
+}
+/**
+ * https://bugs.eclipse.org/549436 - [13] Formatter support for JEP 355 Text Block
+ */
+public void testBug549436c() throws JavaModelException {
+	setComplianceLevel(CompilerOptions.VERSION_13);
+	setPageWidth80();
+	this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.SPACE;
+	this.formatterPrefs.use_tabs_only_for_leading_indentations = false;
+	this.formatterPrefs.indent_empty_lines = false;
+	this.formatterPrefs.text_block_indentation = Alignment.M_INDENT_DEFAULT;
+	this.formatterPrefs.continuation_indentation = 2;
+	formatSourceInWorkspace("test549436", "in.java", "C_out.java");
+}
+/**
+ * https://bugs.eclipse.org/549436 - [13] Formatter support for JEP 355 Text Block
+ */
+public void testBug549436d() throws JavaModelException {
+	setComplianceLevel(CompilerOptions.VERSION_13);
+	setPageWidth80();
+	this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.SPACE;
+	this.formatterPrefs.use_tabs_only_for_leading_indentations = false;
+	this.formatterPrefs.indent_empty_lines = false;
+	this.formatterPrefs.text_block_indentation = Alignment.M_INDENT_DEFAULT;
+	this.formatterPrefs.continuation_indentation = 3;
+	formatSourceInWorkspace("test549436", "in.java", "D_out.java");
+}
+/**
+ * https://bugs.eclipse.org/549436 - [13] Formatter support for JEP 355 Text Block
+ */
+public void testBug549436e() throws JavaModelException {
+	setComplianceLevel(CompilerOptions.VERSION_13);
+	setPageWidth80();
+	this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.SPACE;
+	this.formatterPrefs.use_tabs_only_for_leading_indentations = false;
+	this.formatterPrefs.indent_empty_lines = false;
+	this.formatterPrefs.text_block_indentation = Alignment.M_INDENT_ON_COLUMN;
+	this.formatterPrefs.continuation_indentation = 2;
+	formatSourceInWorkspace("test549436", "in.java", "E_out.java");
+}
+/**
+ * https://bugs.eclipse.org/549436 - [13] Formatter support for JEP 355 Text Block
+ */
+public void testBug549436f() throws JavaModelException {
+	setComplianceLevel(CompilerOptions.VERSION_13);
+	setPageWidth80();
+	this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.TAB;
+	this.formatterPrefs.use_tabs_only_for_leading_indentations = false;
+	this.formatterPrefs.indent_empty_lines = false;
+	this.formatterPrefs.text_block_indentation = Alignment.M_INDENT_BY_ONE;
+	this.formatterPrefs.continuation_indentation = 2;
+	formatSourceInWorkspace("test549436", "in.java", "F_out.java");
+}
+/**
+ * https://bugs.eclipse.org/549436 - [13] Formatter support for JEP 355 Text Block
+ */
+public void testBug549436g() throws JavaModelException {
+	setComplianceLevel(CompilerOptions.VERSION_13);
+	setPageWidth80();
+	this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.TAB;
+	this.formatterPrefs.use_tabs_only_for_leading_indentations = false;
+	this.formatterPrefs.indent_empty_lines = true;
+	this.formatterPrefs.text_block_indentation = Alignment.M_INDENT_DEFAULT;
+	this.formatterPrefs.continuation_indentation = 2;
+	formatSourceInWorkspace("test549436", "in.java", "G_out.java");
+}
+/**
+ * https://bugs.eclipse.org/549436 - [13] Formatter support for JEP 355 Text Block
+ */
+public void testBug549436h() throws JavaModelException {
+	setComplianceLevel(CompilerOptions.VERSION_13);
+	setPageWidth80();
+	this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.TAB;
+	this.formatterPrefs.use_tabs_only_for_leading_indentations = true;
+	this.formatterPrefs.indent_empty_lines = false;
+	this.formatterPrefs.text_block_indentation = Alignment.M_INDENT_DEFAULT;
+	this.formatterPrefs.continuation_indentation = 3;
+	formatSourceInWorkspace("test549436", "in.java", "H_out.java");
+}
+/**
+ * https://bugs.eclipse.org/549436 - [13] Formatter support for JEP 355 Text Block
+ */
+public void testBug549436i() throws JavaModelException {
+	setComplianceLevel(CompilerOptions.VERSION_13);
+	setPageWidth80();
+	this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.TAB;
+	this.formatterPrefs.use_tabs_only_for_leading_indentations = true;
+	this.formatterPrefs.indent_empty_lines = true;
+	this.formatterPrefs.text_block_indentation = Alignment.M_INDENT_ON_COLUMN;
+	this.formatterPrefs.continuation_indentation = 2;
+	formatSourceInWorkspace("test549436", "in.java", "I_out.java");
+}
+/**
+ * https://bugs.eclipse.org/549436 - [13] Formatter support for JEP 355 Text Block
+ */
+public void testBug549436j() throws JavaModelException {
+	setComplianceLevel(CompilerOptions.VERSION_13);
+	setPageWidth80();
+	this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.MIXED;
+	this.formatterPrefs.use_tabs_only_for_leading_indentations = false;
+	this.formatterPrefs.indent_empty_lines = false;
+	this.formatterPrefs.text_block_indentation = Alignment.M_INDENT_ON_COLUMN;
+	this.formatterPrefs.continuation_indentation = 2;
+	formatSourceInWorkspace("test549436", "in.java", "J_out.java");
+}
+/**
+ * https://bugs.eclipse.org/549436 - [13] Formatter support for JEP 355 Text Block
+ */
+public void testBug549436k() throws JavaModelException {
+	setComplianceLevel(CompilerOptions.VERSION_13);
+	setPageWidth80();
+	this.formatterPrefs.tab_char = DefaultCodeFormatterOptions.TAB;
+	this.formatterPrefs.use_tabs_only_for_leading_indentations = false;
+	this.formatterPrefs.indent_empty_lines = false;
+	this.formatterPrefs.text_block_indentation = Alignment.M_INDENT_ON_COLUMN;
+	this.formatterPrefs.continuation_indentation = 2;
+	formatSourceInWorkspace("test549436", "in.java", "K_out.java");
+}
 }
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
index cf1f469..eae922b 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
@@ -875,7 +875,7 @@
 		}
 		assertEquals("Unexpected type hierarchy", expected, actual);
 	}
-	protected void assertMarkers(String message, String expectedMarkers, IJavaProject project) throws CoreException {
+	protected void assertBuildPathMarkers(String message, String expectedMarkers, IJavaProject project) throws CoreException {
 		waitForAutoBuild();
 		IMarker[] markers = project.getProject().findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
 		sortMarkers(markers);
@@ -891,6 +891,11 @@
 		};
 		org.eclipse.jdt.internal.core.util.Util.sort(markers, comparer);
 	}
+	protected void assertProblemMarkers(String message, String expectedMarkers, IProject project) throws CoreException {
+		IMarker[] markers = project.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
+		sortMarkers(markers);
+		assertMarkers(message, expectedMarkers, markers);
+	}
 	protected void assertMarkers(String message, String expectedMarkers, IMarker[] markers) throws CoreException {
 		StringBuffer buffer = new StringBuffer();
 		if (markers != null) {
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathInitializerTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathInitializerTests.java
index 38ebad0..2cbf889 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathInitializerTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathInitializerTests.java
@@ -830,7 +830,7 @@
 
 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[0]));
 		JavaCore.setClasspathContainer(new Path("org.eclipse.jdt.core.tests.model.TEST_CONTAINER"), new IJavaProject[] {p1}, new IClasspathContainer[] {null}, null);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Unbound classpath container: \'org.eclipse.jdt.core.tests.model.TEST_CONTAINER\' in project \'P1\'",
 			p1);
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java
index 1ebb8cb..bf51da4 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ClasspathTests.java
@@ -118,21 +118,22 @@
 	setupExternalJCL("jclMin");
 	setupExternalJCL("jclMin1.5");
 }
-protected void assertCycleMarkers(IJavaProject project, IJavaProject[] p, int[] expectedCycleParticipants) throws CoreException {
+protected void assertCycleMarkers(IJavaProject project, IJavaProject[] p, int[] expectedCycleParticipants, boolean includeAffected) throws CoreException {
 	waitForAutoBuild();
 	StringBuffer expected = new StringBuffer("{");
 	int expectedCount = 0;
 	StringBuffer computed = new StringBuffer("{");
 	int computedCount = 0;
+	int mask = includeAffected ? 3 : 1;
 	for (int j = 0; j < p.length; j++){
-		int markerCount = numberOfCycleMarkers(p[j]);
-		if (markerCount > 0){
+		int markerFlags = cycleMarkerFlags(p[j]);
+		if ((markerFlags & mask) > 0){
 			if (computedCount++ > 0) computed.append(", ");
 			computed.append(p[j].getElementName());
 			//computed.append(" (" + markerCount + ")");
 		}
-		markerCount = expectedCycleParticipants[j];
-		if (markerCount > 0){
+		markerFlags = expectedCycleParticipants[j];
+		if ((markerFlags & mask) > 0){
 			if (expectedCount++ > 0) expected.append(", ");
 			expected.append(p[j].getElementName());
 			//expected.append(" (" + markerCount + ")");
@@ -169,14 +170,20 @@
 	file.setLastModified(System.currentTimeMillis() + 2000);
 	return file;
 }
-protected int numberOfCycleMarkers(IJavaProject javaProject) throws CoreException {
+/** @return 1: participates in cycle, 2: affected by cycle (depends on) */
+protected int cycleMarkerFlags(IJavaProject javaProject) throws CoreException {
 	IMarker[] markers = javaProject.getProject().findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
 	int result = 0;
 	for (int i = 0, length = markers.length; i < length; i++) {
 		IMarker marker = markers[i];
 		String cycleAttr = (String)marker.getAttribute(IJavaModelMarker.CYCLE_DETECTED);
 		if (cycleAttr != null && cycleAttr.equals("true")){ //$NON-NLS-1$
-			result++;
+			String message = marker.getAttribute(IMarker.MESSAGE, "");
+			boolean isCycleMember = message.indexOf("\n->{") != -1; // cycle with no prefix
+			if (isCycleMember)
+				result |= 1;
+			else
+				result |= 2;
 		}
 	}
 	return result;
@@ -318,7 +325,7 @@
 		entries[length] = JavaCore.newContainerEntry(containerSuggestion.getPath());
 		p.setRawClasspath(entries, null);
 
-		assertMarkers("Failed to find marker", "The user library 'SomeUserLibrary' references non existing library \'" + getExternalResourcePath("idontexistthereforeiamnot.jar") + "'", p);
+		assertBuildPathMarkers("Failed to find marker", "The user library 'SomeUserLibrary' references non existing library \'" + getExternalResourcePath("idontexistthereforeiamnot.jar") + "'", p);
 	} finally {
 		deleteProject("Project");
 	}
@@ -454,7 +461,7 @@
 		IJavaProject p = createJavaProject("P");
 		createExternalFolder("externalLib");
 		setClasspath(p, new IClasspathEntry[] {JavaCore.newLibraryEntry(new Path(getExternalResourcePath("externalLib")), null, null)});
-		assertMarkers("Unexpected markers", "", p);
+		assertBuildPathMarkers("Unexpected markers", "", p);
 	} finally {
 		deleteExternalResource("externalLib");
 		deleteProject("P");
@@ -468,7 +475,7 @@
 	try {
 		createExternalFolder("externalLib");
 		IJavaProject p = createJavaProject("P", new String[0], new String[] {getExternalResourcePath("externalLib")}, "");
-		assertMarkers("Unexpected markers", "", p);
+		assertBuildPathMarkers("Unexpected markers", "", p);
 	} finally {
 		deleteExternalResource("externalLib");
 		deleteProject("P");
@@ -484,7 +491,7 @@
 		IJavaProject p = createJavaProject("P");
 		IPath path = new Path(getExternalResourcePath("externalLib"));
 		setClasspath(p, new IClasspathEntry[] {JavaCore.newLibraryEntry(path, null, null)});
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project \'P\' is missing required library: \'"+ getExternalPath() + "externalLib\'",
 			p);
@@ -500,7 +507,7 @@
 	try {
 		waitForAutoBuild();
 		IJavaProject p = createJavaProject("P", new String[0], new String[] {getExternalResourcePath("externalLib")}, "");
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project \'P\' is missing required library: \'"+ getExternalPath() + "externalLib\'",
 			p);
@@ -518,7 +525,7 @@
 		waitForAutoBuild();
 		createExternalFolder("externalLib");
 		refresh(p);
-		assertMarkers("Unexpected markers", "", p);
+		assertBuildPathMarkers("Unexpected markers", "", p);
 	} finally {
 		deleteExternalResource("externalLib");
 		deleteProject("P");
@@ -536,7 +543,7 @@
 		waitForAutoBuild();
 		createExternalFolder("externalLib");
 		refresh(p);
-		assertMarkers("Unexpected markers", "", p);
+		assertBuildPathMarkers("Unexpected markers", "", p);
 	} finally {
 		deleteExternalResource("externalLib");
 		deleteProject("P");
@@ -573,7 +580,7 @@
 				getExternalResourcePath("externalLib.abc"),
 				JavaCore.VERSION_1_4);
 		setClasspath(p, new IClasspathEntry[] {JavaCore.newLibraryEntry(new Path(getExternalResourcePath("externalLib.abc")), null, null)});
-		assertMarkers("Unexpected markers", "", p);
+		assertBuildPathMarkers("Unexpected markers", "", p);
 	} finally {
 		deleteExternalResource("externalLib.abc");
 		deleteProject("P");
@@ -589,7 +596,7 @@
 				getExternalResourcePath("externalLib.abc"),
 				JavaCore.VERSION_1_4);
 		IJavaProject p = createJavaProject("P", new String[0], new String[] {getExternalResourcePath("externalLib.abc")}, "");
-		assertMarkers("Unexpected markers", "", p);
+		assertBuildPathMarkers("Unexpected markers", "", p);
 	} finally {
 		deleteExternalResource("externalLib.abc");
 		deleteProject("P");
@@ -606,7 +613,7 @@
 		waitForAutoBuild();
 
 		setClasspath(p, new IClasspathEntry[] {JavaCore.newLibraryEntry(new Path(getExternalResourcePath("externalLib.abc")), null, null)});
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project \'P\' is missing required library: \'"+ getExternalPath() + "externalLib.abc\'",
 			p);
@@ -623,7 +630,7 @@
 		waitForAutoBuild();
 
 		IJavaProject p = createJavaProject("P", new String[0], new String[] {getExternalResourcePath("externalLib.abc")}, "");
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project \'P\' is missing required library: \'"+ getExternalPath() + "externalLib.abc\'",
 			p);
@@ -644,7 +651,7 @@
 				getExternalResourcePath("externalLib.abc"),
 				JavaCore.VERSION_1_4);
 		refreshExternalArchives(p);
-		assertMarkers("Unexpected markers", "", p);
+		assertBuildPathMarkers("Unexpected markers", "", p);
 	} finally {
 		deleteExternalResource("externalLib.abc");
 		deleteProject("P");
@@ -664,7 +671,7 @@
 				getExternalResourcePath("externalLib.abc"),
 				JavaCore.VERSION_1_4);
 		refreshExternalArchives(p);
-		assertMarkers("Unexpected markers", "", p);
+		assertBuildPathMarkers("Unexpected markers", "", p);
 	} finally {
 		deleteExternalResource("externalLib.abc");
 		deleteProject("P");
@@ -684,7 +691,7 @@
 					"Manifest-Version: 1.0\n"} , 
 					JavaCore.VERSION_1_4);
 		setClasspath(p, new IClasspathEntry[] {JavaCore.newLibraryEntry(new Path("/P/internalLib.abc"), null, null)});
-		assertMarkers("Unexpected markers", "", p);
+		assertBuildPathMarkers("Unexpected markers", "", p);
 	} finally {
 		deleteProject("P");
 	}
@@ -761,7 +768,7 @@
 
 		// now create the actual resource for the root
 		project.getProject().getFolder("src").create(false, true, null);
-		assertMarkers("Unexpected markers", "", project);
+		assertBuildPathMarkers("Unexpected markers", "", project);
 	} finally {
 		// cleanup
 		this.deleteProject("P");
@@ -2572,7 +2579,7 @@
 		IJavaProject[] projects = { p1, p2, p3 };
 		int cycleMarkerCount = 0;
 		for (int i = 0; i < projects.length; i++){
-			cycleMarkerCount += numberOfCycleMarkers(projects[i]);
+			cycleMarkerCount += (cycleMarkerFlags(projects[i]) & 1);
 		}
 		assertTrue("Should have no cycle markers", cycleMarkerCount == 0);
 
@@ -2597,7 +2604,7 @@
 		waitForAutoBuild(); // wait for cycle markers to be created
 		cycleMarkerCount = 0;
 		for (int i = 0; i < projects.length; i++){
-			cycleMarkerCount += numberOfCycleMarkers(projects[i]);
+			cycleMarkerCount += (cycleMarkerFlags(projects[i]) & 1);
 		}
 		assertEquals("Unexpected number of projects involved in a classpath cycle", 3, cycleMarkerCount);
 
@@ -2658,7 +2665,7 @@
 		IJavaProject p = createJavaProject("P");
 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P", "../../nonExisting.jar"}));
 		setClasspath(p, new IClasspathEntry[] {JavaCore.newContainerEntry(new Path("org.eclipse.jdt.core.tests.model.TEST_CONTAINER"))});
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers", 
 			"The container 'Test container' references non existing library \'" + getExternalPath() + "nonExisting.jar\'",
 			p);
@@ -2777,7 +2784,7 @@
 				externalJarPath,
 				JavaCore.VERSION_1_4);
 		setClasspath(p, new IClasspathEntry[] {JavaCore.newLibraryEntry(new Path("../external.jar"), null, null)});
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers", 
 			"", 
 			p);
@@ -2794,7 +2801,7 @@
 	try {
 		IJavaProject p = createJavaProject("P");
 		setClasspath(p, new IClasspathEntry[] {JavaCore.newLibraryEntry(new Path("../external.jar"), null, null)});
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers", 
 			"Project \'P\' is missing required library: \'"+ getWorkspacePath() + "external.jar\'",
 			p);
@@ -2894,7 +2901,7 @@
 		JavaCore.setClasspathVariable("TWO_UP", new Path("../.."), null);
 		IJavaProject p = createJavaProject("P");
 		setClasspath(p, new IClasspathEntry[] {JavaCore.newVariableEntry(new Path("TWO_UP/nonExisting.jar"), null, null)});
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers", 
 			"Project \'P\' is missing required library: \'"+ getExternalPath() + "nonExisting.jar\'",
 			p);
@@ -3184,7 +3191,7 @@
 				getExternalResourcePath("test185733.jar"),
 				JavaCore.VERSION_1_4);
 		refreshExternalArchives(p);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"",
 			p);
@@ -3208,7 +3215,7 @@
 
 		deleteResource(externalJar);
 		refreshExternalArchives(p);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project \'P\' is missing required library: \'" + externalJar.getPath() + "\'",
 			p);
@@ -3450,7 +3457,7 @@
 			},
 			JavaCore.VERSION_1_4);
 		createFile("/P/lib2.jar", "");
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"",
 			p);
@@ -3472,7 +3479,7 @@
 				"Class-Path: lib2.jar\n",
 			},
 			JavaCore.VERSION_1_4);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"",
 			p);
@@ -3522,7 +3529,7 @@
 			JavaCore.VERSION_1_4);
 		createExternalFile("lib2.jar", "");
 		refreshExternalArchives(p);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"",
 			p);
@@ -3546,7 +3553,7 @@
 				"Class-Path: lib2.jar\n",
 			},
 			JavaCore.VERSION_1_4);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"",
 			p);
@@ -3576,7 +3583,7 @@
 		
 		deleteExternalResource("lib2.jar");
 		refreshExternalArchives(p);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"",
 			p);
@@ -3707,7 +3714,7 @@
 			JavaCore.VERSION_1_4);
 		ContainerInitializer.setInitializer(new DefaultContainerInitializer(new String[] {"P", getExternalResourcePath("lib1.jar")}));
 		IJavaProject p = createJavaProject("P", new String[0], new String[] {"org.eclipse.jdt.core.tests.model.TEST_CONTAINER"}, "");
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"",
 			p);
@@ -3795,7 +3802,7 @@
 			null/*no classpath*/,
 			JavaCore.VERSION_1_4);
 		refreshExternalArchives(p);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"",
 			p);
@@ -3818,7 +3825,7 @@
 					"Manifest-Version: 1.0\n"} , 
 					JavaCore.VERSION_1_4);
 		
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"",
 			project);
@@ -3842,7 +3849,7 @@
 		simulateExitRestart();
 		refreshExternalArchives(p);
 		
-		assertMarkers("Unexpected markers", "", p);
+		assertBuildPathMarkers("Unexpected markers", "", p);
 	} finally {
 		deleteExternalResource("externalLib.abc");
 		deleteProject("P");
@@ -3911,7 +3918,7 @@
 			"    <classpathentry kind=\"output\" path=\"bin\"/>\n" +
 			"</classpath>"
 		);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"XML format error in \'.classpath\' file of project 'P': Bad format",
 			project);
@@ -3933,7 +3940,7 @@
 			"    <classpathentry kind=\"output\" path=\"bin\"/>\n" +
 			"</classpath>"
 		);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Illegal entry in \'.classpath\' of project 'P' file: Unknown kind: \'src1\'",
 			javaProject);
@@ -3943,7 +3950,7 @@
 		IProject project = javaProject.getProject();
 		project.build(IncrementalProjectBuilder.FULL_BUILD, null);
 		waitForAutoBuild();
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Illegal entry in \'.classpath\' of project 'P' file: Unknown kind: \'src1\'",
 			javaProject);
@@ -3962,7 +3969,7 @@
 		if (Path.fromOSString(externalPath).segmentCount() > 0)
 			externalPath = externalPath.substring(0, externalPath.length()-1);
 		IJavaProject proj =  createJavaProject("P", new String[] {}, new String[] {externalPath}, "bin");
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project \'P\' is missing required library: \'" + externalPath + "\'",
 			proj);
@@ -3977,7 +3984,7 @@
 	try {
 		String jarPath = getExternalPath() + "nonExisting.jar";
 		IJavaProject proj = createJavaProject("P", new String[] {}, new String[] {jarPath}, "bin");
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project 'P' is missing required library: \'" + jarPath + "\'",
 			proj);
@@ -4029,7 +4036,7 @@
 public void testInvalidInternalJar1() throws CoreException {
 	try {
 		IJavaProject proj = createJavaProject("P", new String[] {}, new String[] {"/P/nonExisting.jar"}, "bin");
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project 'P' is missing required library: \'nonExisting.jar\'",
 			proj);
@@ -4050,7 +4057,7 @@
 					"Manifest-Version: 1.0\n"} , 
 					JavaCore.VERSION_1_4);
 		proj =  createJavaProject("P2", new String[] {}, new String[] {"/P1/existing.txt"}, "bin");
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"",
 			proj);
@@ -4068,7 +4075,7 @@
 	try {
 		createJavaProject("P1");
 		IJavaProject proj = createJavaProject("P2", new String[] {}, new String[] {}, new String[] {"/P1/src1/src2"}, "bin");
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project 'P2' is missing required source folder: \'/P1/src1/src2\'",
 			proj);
@@ -4095,7 +4102,7 @@
 		waitForAutoBuild();
 		project.build(IncrementalProjectBuilder.FULL_BUILD, null);
 		waitForAutoBuild();
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Unable to read \'.classpath\' file of project 'P'",
 			javaProject);
@@ -4114,7 +4121,7 @@
 				JavaCore.newProjectEntry(new Path("/B"))
 			};
 		javaProject.setRawClasspath(classpath, null);
-		this.assertMarkers(
+		this.assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project 'A' is missing required Java project: \'B\'",
 			javaProject);
@@ -4134,7 +4141,7 @@
 				new String[] {}, // lib folders
 				new String[] {"/B"}, // projects
 				"");
-		this.assertMarkers(
+		this.assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project 'A' is missing required Java project: \'B\'",
 			javaProject);
@@ -4155,7 +4162,7 @@
 				new String[] {"/B"}, // projects
 				"");
 		this.createJavaProject("B", new String[] {}, "");
-		this.assertMarkers("Unexpected markers", "", javaProject);
+		this.assertBuildPathMarkers("Unexpected markers", "", javaProject);
 	} finally {
 		deleteProjects(new String[] {"A", "B"});
 	}
@@ -4181,18 +4188,20 @@
 				new String[] {}, // lib folders
 				new String[] {"/A"}, // projects
 				"");
-		this.assertMarkers(
+		this.assertBuildPathMarkers(
 			"Unexpected markers for project A",
-			"A cycle was detected in the build path of project 'A'. The cycle consists of projects {A, B}",
+			"One or more cycles were detected in the build path of project 'A'. The paths towards the cycle and cycle are:\n" + 
+			"->{A, B}",
 			projectA);
-		this.assertMarkers(
+		this.assertBuildPathMarkers(
 			"Unexpected markers for project B",
-			"A cycle was detected in the build path of project 'B'. The cycle consists of projects {A, B}",
+			"One or more cycles were detected in the build path of project 'B'. The paths towards the cycle and cycle are:\n" + 
+			"->{A, B}",
 			projectB);
 
 		// delete project B
 		this.deleteProject("B");
-		this.assertMarkers(
+		this.assertBuildPathMarkers(
 			"Unexpected markers for project A after deleting of project B",
 			"Project 'A' is missing required Java project: \'B\'",
 			projectA);
@@ -4205,13 +4214,15 @@
 				new String[] {}, // lib folders
 				new String[] {"/A"}, // projects
 				"");
-		this.assertMarkers(
+		this.assertBuildPathMarkers(
 			"Unexpected markers for project A after adding project B back",
-			"A cycle was detected in the build path of project 'A'. The cycle consists of projects {A, B}",
+			"One or more cycles were detected in the build path of project 'A'. The paths towards the cycle and cycle are:\n" + 
+			"->{A, B}",
 			projectA);
-		this.assertMarkers(
+		this.assertBuildPathMarkers(
 			"Unexpected markers for project B after adding project B back",
-			"A cycle was detected in the build path of project 'B'. The cycle consists of projects {A, B}",
+			"One or more cycles were detected in the build path of project 'B'. The paths towards the cycle and cycle are:\n" + 
+			"->{A, B}",
 			projectB);
 
 	} finally {
@@ -4458,6 +4469,14 @@
 			{ 1, 1, 1, 1, 1 }, // after setting CP p[4]
 		};
 
+		int[][] expectedAffectedProjects = new int[][] {
+			{ 0, 0, 0, 0, 0 }, // after setting CP p[0]
+			{ 0, 0, 0, 0, 0 }, // after setting CP p[1]
+			{ 1, 1, 1, 0, 0 }, // after setting CP p[2]
+			{ 1, 1, 1, 0, 0 }, // after setting CP p[3]
+			{ 1, 1, 1, 1, 1 }, // after setting CP p[4]
+		};
+
 		for (int i = 0; i < p.length; i++){
 
 			// append project references
@@ -4471,7 +4490,8 @@
 			p[i].setRawClasspath(newClasspath, null);
 
 			// check cycle markers
-			assertCycleMarkers(p[i], p, expectedCycleParticipants[i]);
+			assertCycleMarkers(p[i], p, expectedCycleParticipants[i], false);
+			assertCycleMarkers(p[i], p, expectedAffectedProjects[i], true);
 		}
 		//this.startDeltas();
 
@@ -4533,7 +4553,7 @@
 			JavaCore.setClasspathVariables(var, variableValues[i], null);
 
 			// check cycle markers
-			assertCycleMarkers(p[i], p, expectedCycleParticipants[i]);
+			assertCycleMarkers(p[i], p, expectedCycleParticipants[i], false);
 		}
 		//this.startDeltas();
 
@@ -4616,7 +4636,7 @@
 			}
 
 			// check cycle markers
-			assertCycleMarkers(p[i], p, expectedCycleParticipants[i]);
+			assertCycleMarkers(p[i], p, expectedCycleParticipants[i], false);
 		}
 		//this.startDeltas();
 
@@ -4699,7 +4719,7 @@
 			}
 
 			// check cycle markers
-			assertCycleMarkers(p[i], p, expectedCycleParticipants[i]);
+			assertCycleMarkers(p[i], p, expectedCycleParticipants[i], false);
 		}
 		//this.startDeltas();
 
@@ -4748,7 +4768,8 @@
 			p[i].setRawClasspath(newClasspath, null);
 
 			// check cycle markers
-			assertCycleMarkers(p[i], p, expectedCycleParticipants[i]);
+			assertCycleMarkers(p[i], p, expectedCycleParticipants[i], false);
+			assertCycleMarkers(p[i], p, expectedCycleParticipants[i], true);
 		}
 		//this.startDeltas();
 
@@ -4784,7 +4805,7 @@
 			{ 0, 0, 0, 0, 0, 0 }, // after setting CP p[2]
 			{ 1, 1, 1, 1, 0, 0 }, // after setting CP p[3]
 			{ 1, 1, 1, 1, 0, 0 }, // after setting CP p[4]
-			{ 1, 1, 1, 1, 1 , 1}, // after setting CP p[5]
+			{ 1, 1, 1, 1, 1 ,1 }, // after setting CP p[5]
 		};
 
 		for (int i = 0; i < p.length; i++){
@@ -4800,8 +4821,17 @@
 			p[i].setRawClasspath(newClasspath, null);
 
 			// check cycle markers
-			assertCycleMarkers(p[i], p, expectedCycleParticipants[i]);
+			assertCycleMarkers(p[i], p, expectedCycleParticipants[i], false);
+			assertCycleMarkers(p[i], p, expectedCycleParticipants[i], true);
 		}
+		
+		IMarker[] markers = p[0].getProject().findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
+		// additionally see that we actually have 2 cycles for P0!
+		assertMarkers("Markers of P0",
+				"One or more cycles were detected in the build path of project 'P0'. The paths towards the cycle and cycle are:\n" +
+				"->{P0, P2, P3, P1}\n" +
+				"->{P0, P4, P5, P1}",
+				markers);
 		//this.startDeltas();
 
 	} finally {
@@ -4840,7 +4870,7 @@
 		waitForAutoBuild();
 		getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.POST_CHANGE);
 		createFile("/P1/test.txt", "");
-		assertCycleMarkers(p1, new IJavaProject[] {p1, p2}, new int[] {1, 1});
+		assertCycleMarkers(p1, new IJavaProject[] {p1, p2}, new int[] {1, 1}, false);
 	} finally {
 		getWorkspace().removeResourceChangeListener(listener);
 		deleteProjects(new String[] {"P1", "P2"});
@@ -5027,7 +5057,7 @@
 			"    <classpathentry kind=\"output\" path=\"bin\"/>\n" +
 			"</classpath>"
 		);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Build path contains duplicate entry: \'src\' for project 'P'",
 			project);
@@ -5058,7 +5088,7 @@
 			"</classpath>"
 		);
 		waitForAutoBuild();
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"",
 			project);
@@ -5134,7 +5164,7 @@
 
 		for (int i = 0; i < numberOfParticipants; i++){
 			// check cycle markers
-			assertCycleMarkers(projects[i], projects, allProjectsInCycle);
+			assertCycleMarkers(projects[i], projects, allProjectsInCycle, false);
 		}
 
 	} finally {
@@ -5207,7 +5237,7 @@
 
 		for (int i = 0; i < numberOfParticipants; i++){
 			// check cycle markers
-			assertCycleMarkers(projects[i], projects, allProjectsInCycle);
+			assertCycleMarkers(projects[i], projects, allProjectsInCycle, false);
 		}
 
 	} finally {
@@ -5269,7 +5299,7 @@
 		// refresh
 		project.refreshLocal(IResource.DEPTH_INFINITE, null);
 
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Cannot nest \'P/src/src2\' inside \'P/src\'. To enable the nesting exclude \'src2/\' from \'P/src\'",
 			JavaCore.create(project));
@@ -5289,7 +5319,7 @@
 				JavaCore.newSourceEntry(new Path("/A/src"), new IPath[0], new IPath[0], new Path("/A/bin"), new IClasspathAttribute[] {attribute})
 			};
 		javaProject.setRawClasspath(classpath, null);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"",
 			javaProject);
@@ -5309,7 +5339,7 @@
 				JavaCore.newLibraryEntry(new Path("/A/lib"), null, null, null, new IClasspathAttribute[] {attribute}, false)
 			};
 		javaProject.setRawClasspath(classpath, null);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"",
 			javaProject);
@@ -5329,7 +5359,7 @@
 				JavaCore.newProjectEntry(new Path("/B"), null/*no access rules*/, false/*don't combine access rule*/, new IClasspathAttribute[] {attribute}, false/*not exported*/)
 			};
 		javaProject.setRawClasspath(classpath, null);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"",
 			javaProject);
@@ -5390,7 +5420,7 @@
 		// refresh
 		project.refreshLocal(IResource.DEPTH_INFINITE,null);
 
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project 'P' is missing required source folder: \'src1\'\n" +
 			"Project 'P' is missing required source folder: \'src2\'",
@@ -5440,7 +5470,7 @@
 		IJavaProject p = createJavaProject("P", new String[0], new String[] {getExternalResourcePath("externalLib")}, "");
 		waitForAutoBuild();
 		setClasspath(p, new IClasspathEntry[] {});
-		assertMarkers("Unexpected markers", "", p);
+		assertBuildPathMarkers("Unexpected markers", "", p);
 	} finally {
 		deleteExternalResource("externalLib");
 		deleteProject("P");
@@ -5455,7 +5485,7 @@
 		IJavaProject p = createJavaProject("P", new String[0], new String[] {getExternalResourcePath("externalLib")}, "");
 		waitForAutoBuild();
 		setClasspath(p, new IClasspathEntry[] {});
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"",
 			p);
@@ -5474,7 +5504,7 @@
 		waitForAutoBuild();
 		deleteExternalResource("externalLib");
 		refresh(p);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project \'P\' is missing required library: \'"+ getExternalPath() + "externalLib\'",
 			p);
@@ -5496,7 +5526,7 @@
 		waitForAutoBuild();
 		deleteExternalResource("externalLib");
 		refresh(p);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project \'P\' is missing required library: \'"+ getExternalPath() + "externalLib\'",
 			p);
@@ -5517,7 +5547,7 @@
 		waitForAutoBuild();
 
 		setClasspath(p, new IClasspathEntry[] {});
-		assertMarkers("Unexpected markers", "", p);
+		assertBuildPathMarkers("Unexpected markers", "", p);
 	} finally {
 		deleteExternalResource("externalLib.abc");
 		deleteProject("P");
@@ -5534,7 +5564,7 @@
 		waitForAutoBuild();
 
 		setClasspath(p, new IClasspathEntry[] {});
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"",
 			p);
@@ -5555,7 +5585,7 @@
 
 		deleteExternalResource("externalLib.abc");
 		refreshExternalArchives(p);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project \'P\' is missing required library: \'"+ getExternalPath() + "externalLib.abc\'",
 			p);
@@ -5578,7 +5608,7 @@
 
 		deleteExternalResource("externalLib.abc");
 		refreshExternalArchives(p);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project \'P\' is missing required library: \'"+ getExternalPath() + "externalLib.abc\'",
 			p);
@@ -5598,7 +5628,7 @@
 		waitForAutoBuild();
 
 		setClasspath(p, new IClasspathEntry[] {});
-		assertMarkers("Unexpected markers", "", p);
+		assertBuildPathMarkers("Unexpected markers", "", p);
 	} finally {
 		deleteProject("P");
 	}
@@ -5619,7 +5649,7 @@
 
 		deleteFile("/P/internalLib.abc");
 		waitForAutoBuild();
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Project \'P\' is missing required library: \'internalLib.abc\'",
 			p);
@@ -5657,7 +5687,7 @@
 
 		// rename .jar
 		getFile("/P/lib/test1.jar").move(new Path("/P/lib/test2.jar"), false, null);
-		assertMarkers("Unexpected markers", "", p);
+		assertBuildPathMarkers("Unexpected markers", "", p);
 	} finally {
 		if (listener != null)
 			getWorkspace().removeResourceChangeListener(listener);
@@ -5892,7 +5922,7 @@
 			"    <classpathentry kind=\"var\" path=\"TEST_LIB\" sourcepath=\"TEST_SRC\"/>\n" +
 			"</classpath>"
 		);
-		assertMarkers(
+		assertBuildPathMarkers(
 			"Unexpected markers",
 			"Source attachment path \'tmp.zip\' for IClasspathEntry must be absolute",
 			javaProject);
@@ -6134,7 +6164,7 @@
 			"/P/.classpath",
 			buffer.toString()
 		);
-		assertMarkers(
+		assertBuildPathMarkers(
 				"Unexpected markers",
 				"",
 				project);
@@ -6176,7 +6206,7 @@
 			"/P/.classpath",
 			buffer.toString()
 		);
-		assertMarkers(
+		assertBuildPathMarkers(
 				"Unexpected markers",
 				"Project \'P\' is missing required library: \'" + libPath.toOSString() + "'\n" + 
 				"Unbound classpath container: \'org.eclipse.jdt.core.tests.model.TEST_CONTAINER\' in project \'P\'\n" + 
@@ -6902,7 +6932,7 @@
 		IJavaProject p = createJavaProject("P");
 		createFile("/P/library.jar", "");
 		setClasspath(p, new IClasspathEntry[] { JavaCore.newLibraryEntry(new Path("/P/library.jar"), null,null)});
-		assertMarkers("Expected marker", 
+		assertBuildPathMarkers("Expected marker", 
 				"Archive for required library: \'library.jar\' in project \'P\' cannot be read or is not a valid ZIP file", p);
 		setClasspath(p, new IClasspathEntry[0]);
 		addLibrary(p, "library.jar", null, new String[0], 
@@ -6918,7 +6948,7 @@
 		assertNotNull(file);
 		file.touch(null);
 		waitForAutoBuild();
-		assertMarkers("Unexpected marker", 
+		assertBuildPathMarkers("Unexpected marker", 
 				"", p);
 		
 	} finally {
@@ -6965,7 +6995,7 @@
 		
 		refresh(javaProject);
 		waitForAutoBuild();
-		assertMarkers("Unexpected markers", "", javaProject);
+		assertBuildPathMarkers("Unexpected markers", "", javaProject);
 		
 	} finally {
 		deleteProject("ExternalProject");
@@ -7083,7 +7113,7 @@
 			status);
 		
 		proj.setRawClasspath(newCP, null);
-		assertMarkers("Unexpected markers", "", proj);
+		assertBuildPathMarkers("Unexpected markers", "", proj);
 		
 		// Test that with the option set to WARNING, status.isOK() returns true
 		proj.setOption(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, JavaCore.WARNING);
@@ -7094,7 +7124,7 @@
 			"Source folder \'src\' in project \'P\' cannot output to distinct source folder \'src2\'",
 			status);
 
-		assertMarkers("Unexpected markers", 
+		assertBuildPathMarkers("Unexpected markers", 
 				"Source folder \'src\' in project \'P\' cannot output to distinct source folder \'src2\'", proj);
 		
 		// Test that with the option set to WARNING and the presence of a more severe error scenario, the error status
@@ -7220,12 +7250,12 @@
 		eclipsePreferences.addPreferenceChangeListener(prefListener);
 		simulateExitRestart();
 		waitForAutoBuild();
-		assertMarkers("Unexpected markers", "", proj1);
+		assertBuildPathMarkers("Unexpected markers", "", proj1);
 		map = proj1.getOptions(false);
 		map.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_1);
 		proj1.setOptions(map);
 		waitForManualRefresh();
-		assertMarkers("Unexpected markers",
+		assertBuildPathMarkers("Unexpected markers",
 				"Incompatible .class files version in required binaries. Project \'P1\' is targeting a 1.1 runtime, but is compiled against \'P1/abc.jar\' which requires a 1.4 runtime", proj1);
 		 eclipsePreferences.removePreferenceChangeListener(prefListener);
 	} finally {
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests.java
index 92b530f..4a92277 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests.java
@@ -20590,6 +20590,66 @@
 			requestor.getResults());
 }
 
+/*
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=285379
+ */
+public void test285379a() throws JavaModelException {
+	CompletionTestsRequestor requestor = new CompletionTestsRequestor();
+	ICompilationUnit cu= getCompilationUnit("Completion", "src", "", "Completion285379.java");
+
+	String str = cu.getSource();
+	String completeBehind = "pkgtest285379.X1.";
+	int cursorLocation = str.indexOf(completeBehind) + completeBehind.length();
+	cu.codeComplete(cursorLocation, requestor);
+
+	// just not hang...	
+}
+
+/*
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=285379
+ */
+public void test285379b() throws JavaModelException {
+	CompletionTestsRequestor requestor = new CompletionTestsRequestor();
+	ICompilationUnit cu= getCompilationUnit("Completion", "src", "", "Completion285379.java");
+
+	String str = cu.getSource();
+	String completeBehind = "return ";
+	int cursorLocation = str.indexOf(completeBehind) + completeBehind.length();
+	cu.codeComplete(cursorLocation, requestor);
+
+	// just not hang...	
+}
+
+/*
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=285379
+ */
+public void test285379c() throws JavaModelException {
+	CompletionTestsRequestor requestor = new CompletionTestsRequestor();
+	ICompilationUnit cu= getCompilationUnit("Completion", "src", "", "Completion285379.java");
+
+	String str = cu.getSource();
+	String completeBehind = "equals";
+	int cursorLocation = str.indexOf(completeBehind) + completeBehind.length();
+	cu.codeComplete(cursorLocation, requestor);
+
+	// just not hang...	
+}
+
+/*
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=285379
+ */
+public void test285379d() throws JavaModelException {
+	CompletionTestsRequestor requestor = new CompletionTestsRequestor();
+	ICompilationUnit cu= getCompilationUnit("Completion", "src", "", "Completion285379.java");
+
+	String str = cu.getSource();
+	String completeBehind = "(var";
+	int cursorLocation = str.indexOf(completeBehind) + completeBehind.length();
+	cu.codeComplete(cursorLocation, requestor);
+
+	// just not hang...	
+}
+
 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=270436
 public void test270436a() throws JavaModelException {
 	// This test is to ensure that an interface is not offered as a choice when expecting a class.
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/Java9ElementTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/Java9ElementTests.java
index 867bf7a..29ce20f 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/Java9ElementTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/Java9ElementTests.java
@@ -869,7 +869,7 @@
 			assertTrue("Invalid selection result", (elements[0] instanceof BinaryModule));
 			IModuleDescription mod = (IModuleDescription) elements[0];
 			String id = mod.getHandleIdentifier();
-			assertTrue("incorrect id", id.matches("=Java9Elements/.*"+Pattern.quote("\\/jmods\\/java.base.jmod=/module=/true<'`java.base")));
+			assertTrue("incorrect id", id.matches("=Java9Elements/.*"+Pattern.quote("\\/jmods\\/java.base.jmod=/module=/true=/<'`java.base")));
 			IJavaElement element = JavaCore.create(id);
 			assertEquals("incorrect element type", IJavaElement.JAVA_MODULE, element.getElementType());
 			assertEquals("incorrect module name", "java.base", element.getElementName());
@@ -1337,6 +1337,7 @@
 			IPackageFragmentRoot fragmentRoot = project2.getPackageFragmentRoot(project1.getResource());
 			IModuleDescription mod2 = JavaCore.getAutomaticModuleDescription(fragmentRoot);
 			assertNotNull("auto module not found via package fragment root", mod2);
+			assertTrue("should be an auto module", mod2.isAutoModule());
 
 			assertEquals("names of module descriptions should be equal", mod1.getElementName(), mod2.getElementName());
 
@@ -1360,8 +1361,35 @@
 			assertEquals(fragmentRoot, mod2.getParent());
 		}
 		finally {
-			deleteProject("Java9Elements");
-			deleteProject("Java9Elements2");
+			deleteProject("my_mod");
+			deleteProject("your.mod");
+		}	
+	}
+	public void testSystemModule() throws Exception {
+		try {
+			IJavaProject project1 = createJava9Project("my_mod");
+			IModuleDescription mod = project1.findModule("java.base", this.wcOwner);
+			assertTrue("should be a system module", mod.isSystemModule());
+			mod = project1.findModule("java.desktop", this.wcOwner);
+			assertTrue("should be a system module", mod.isSystemModule());
+
+			createFile("/my_mod/src/module-info.java",
+					"module my_mod{\n" +
+					"}");
+			mod = project1.getModuleDescription();
+			assertFalse("should not be a system module", mod.isSystemModule());
+
+			addModularLibrary(project1, "mod.two.jar", "mod.two-sources.zip", 
+					new String[] {
+						"module-info.java",
+						"module mod.two {}\n"
+					}, JavaCore.VERSION_9);
+			
+			mod = project1.findModule("mod.two", this.wcOwner);
+			assertFalse("should not be a system module", mod.isSystemModule());
+			
+		} finally {
+			deleteProject("my_mod");
 		}	
 	}
 	public void test526761a() throws Exception {
@@ -1604,7 +1632,7 @@
 			assertTrue("Invalid selection result", (elements[0] instanceof BinaryModule));
 			IModuleDescription mod = (IModuleDescription) elements[0];
 			String id = mod.getHandleIdentifier();
-			assertEquals("identifier", "=Java9Elements/"+jdkRootPath.toString().replace("/", "\\/")+"\\/jmods\\/java.base.jmod=/module=/true<'`java.base", id);
+			assertEquals("identifier", "=Java9Elements/"+jdkRootPath.toString().replace("/", "\\/")+"\\/jmods\\/java.base.jmod=/module=/true=/<'`java.base", id);
 			ISourceRange ir =mod.getNameRange();
 			assertTrue("positive offset", ir.getOffset() > 0);
 			assertEquals("length", 9, ir.getLength());
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/MementoTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/MementoTests.java
index 2133ba2..4be167b 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/MementoTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/MementoTests.java
@@ -825,7 +825,7 @@
 				null);
 		String[] expectedIdentifiers = {
 			"=Test/src",
-			"=Test/lib.jar=/annotationpath=/\\/Test\\/annots"	
+			"=Test/lib.jar=/annotationpath=/\\/Test\\/annots=/"
 		};
 		IPackageFragmentRoot[] roots = project.getPackageFragmentRoots();
 		boolean archiveSeen = false;
@@ -867,7 +867,7 @@
 			JavaCore.newClasspathAttribute(IClasspathAttribute.ADD_EXPORTS, "jdk.rmic/sun.rmi.rmic=ALL-UNNAMED")
 		};
 		IJavaProject project = createJava9ProjectWithJREAttributes("Test", new String[] {"src"}, annPathAttr);
-		String attributesMemento = "=/annotationpath=/annots=/add-exports=/jdk.rmic\\/sun.rmi.rmic\\=ALL-UNNAMED";
+		String attributesMemento = "=/annotationpath=/annots=/=/add-exports=/jdk.rmic\\/sun.rmi.rmic\\=ALL-UNNAMED=/";
 
 		// Module java.base:
 		String expectedIdentifier = "=Test/"+getEscapedJrtJarPath()+"`java.base"+attributesMemento; // for specific PFR (see below)
@@ -903,4 +903,50 @@
 		deleteProject("Test");
 	}
 }
+public void testEmptyAttribute() throws CoreException, IOException {
+	try {
+		IJavaProject project = createJavaProject("Test", new String[] {"src"}, null, "bin", "1.8", false);
+		org.eclipse.jdt.core.tests.util.Util.createJar(
+				new String[] {"test/Test.java", "package test; public class Test {}\n" },
+				null, project.getProject().getLocation().toString()+"/lib.jar", null, "1.8", null);
+		
+		project.getProject().refreshLocal(IResource.DEPTH_INFINITE, null);
+		IClasspathAttribute[] attributes = {
+			JavaCore.newClasspathAttribute("foo", "")	
+		};
+		addLibraryEntry(project, new Path("/Test/lib.jar"), null, null, null, null, attributes, false);
+		String[] expectedIdentifiers = {
+			"=Test/src",
+			"=Test/lib.jar=/foo=/=/"	
+		};
+		IPackageFragmentRoot[] roots = project.getAllPackageFragmentRoots();
+		boolean archiveSeen = false;
+		for (int i = 0; i < roots.length; i++) {
+			IPackageFragmentRoot packageRoot = roots[i];
+			String handleIdentifier = packageRoot.getHandleIdentifier();
+			assertEquals("Root mementos", expectedIdentifiers[i], handleIdentifier);
+			IJavaElement element = JavaCore.create(handleIdentifier, null);
+			assertEquals("Root equivalence", packageRoot, element);
+			if (packageRoot.isArchive()) {
+				archiveSeen = true;
+				// PackageFragment
+				IPackageFragment test = packageRoot.getPackageFragment("test");
+				handleIdentifier = test.getHandleIdentifier();
+				String expected = expectedIdentifiers[i]+"<test"; 
+				assertEquals("PackageFragment mementos", expected, handleIdentifier);
+				element = JavaCore.create(handleIdentifier, null);
+				assertEquals("PackageFragment equivalence", test, element);
+				// ClassFile:
+				IClassFile classFile = test.getClassFile("Test.class");
+				handleIdentifier = classFile.getHandleIdentifier();
+				assertEquals("ClassFile mementos", expected+"(Test.class", handleIdentifier);
+				element = JavaCore.create(handleIdentifier);
+				assertEquals("ClassFile equivalence", classFile, element);
+			}
+		}
+		assertTrue("Should have seen an archive", archiveSeen);
+	} finally {
+		deleteProject("Test");
+	}
+}
 }
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java
index 940fc16..3ed24c8 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java
@@ -123,7 +123,7 @@
 				}
 			}
 			assertNotNull("Java.base module should not null", base);
-			assertMarkers("Unexpected markers", "", project);
+			assertProblemMarkers("Unexpected markers", "", project.getProject());
 		} finally {
 			deleteProject("Test01");
 		}
@@ -136,10 +136,12 @@
 							"	exports com.greetings;\n" +
 							"	requires java.base;\n" +
 							"}");
+			this.createFile("P1/src/com/greetings/Greet.java", "package com.greetings; public class Greet {}\n");
 			waitForManualRefresh();
 			this.currentProject.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
-			assertMarkers("Unexpected markers", "", this.currentProject);
+			assertProblemMarkers("Unexpected markers", "", this.currentProject.getProject());
 		} finally {
+			deleteFile("P1/src/com/greetings/Greet.java");
 		}
 	}
 	// Test that types from java.base module are seen by the compiler
@@ -2613,7 +2615,7 @@
 				}
 			}
 			assertNotNull("Java.base module should not null", base);
-			assertMarkers("Unexpected markers", "", project);
+			assertProblemMarkers("Unexpected markers", "", project.getProject());
 		} finally {
 			deleteProject("Test01");
 		}
@@ -5288,10 +5290,10 @@
 					this.problemRequestor);
 
 			javaProject.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
-			assertMarkers("markers in mod.one", "", javaProject);
+			assertProblemMarkers("markers in mod.one", "", javaProject.getProject());
 			
 			javaProject2.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
-			assertMarkers("markers in mod.two", "", javaProject2);
+			assertProblemMarkers("markers in mod.two", "", javaProject2.getProject());
 
 			javaProject.getProject().getWorkspace().build(IncrementalProjectBuilder.CLEAN_BUILD, null);
 			assertNoErrors();
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/OptionTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/OptionTests.java
index 069c3ec..4bffa2d 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/OptionTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/OptionTests.java
@@ -531,7 +531,7 @@
 		IJavaProject project = createJavaProject("P", new String[0], new String[] {"TEST"}, "");
 		waitForAutoBuild();
 		preferences.put(JavaModelManager.CP_VARIABLE_PREFERENCES_PREFIX+"TEST", getExternalJCLPathString());
-		assertMarkers("Unexpected markers", "", project);
+		assertBuildPathMarkers("Unexpected markers", "", project);
 	} finally {
 		deleteProject("P");
 		preferences.remove(JavaModelManager.CP_VARIABLE_PREFERENCES_PREFIX+"TEST");
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests9.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests9.java
index 6cbd027..9753ba5 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests9.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests9.java
@@ -34,6 +34,7 @@
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaModelMarker;
 import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IModuleDescription;
 import org.eclipse.jdt.core.IOrdinaryClassFile;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaCore;
@@ -559,4 +560,44 @@
 			deleteProject(logg);
 		}
 	}
+	public void testModuleCaching() throws Exception {
+		if (!isJRE9 || isJRE11) {
+			System.err.println("Test "+getName()+" requires a JRE [9,11)");
+			return;
+		}
+		IJavaProject prj = createJava9Project("caching");
+		try {
+			IFile file = createFile("caching/src/module-info.java",
+					"module caching {\n" +
+					"	requires java.xml.bind;\n" +
+					"}\n");
+			createFolder("caching/src/p");
+			createFile("caching/src/p/X.java",
+					"package p;\n" +
+					"@javax.xml.bind.annotation.XmlRootElement\n" +
+					"public class X {}\n");
+			prj.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			IMarker[] markers = prj.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("unexpected markers",
+					"The module java.xml.bind has been deprecated since version 9 and marked for removal",  markers);
+
+			IModuleDescription module = prj.getModuleDescription();
+			assertTrue("module exists", module.exists());
+			assertEquals("module name", "caching", module.getElementName());
+
+			// move module-info away ...
+			createFolder("caching/away");
+			file.move(new Path("/caching/away/module-info.java"), false, null);
+			IModuleDescription mod2 = prj.getModuleDescription();
+			assertNull("no longer a module", mod2);
+
+			// ... and observe javax.xml.bind unobservable:
+			prj.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			markers = prj.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("unexpected markers", 
+					"javax.xml.bind cannot be resolved to a type", markers);
+		} finally {
+			deleteProject(prj);
+		}
+	}
 }
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Completion/.classpath b/org.eclipse.jdt.core.tests.model/workspace/Completion/.classpath
index f1fe1cf..af46168 100644
--- a/org.eclipse.jdt.core.tests.model/workspace/Completion/.classpath
+++ b/org.eclipse.jdt.core.tests.model/workspace/Completion/.classpath
@@ -11,6 +11,7 @@
     <classpathentry kind="lib" path="constructors.jar" sourcepath="/Completion/constructorssrc.zip"/>
     <classpathentry kind="lib" path="generics.jar" sourcepath="/Completion/genericssrc.zip"/>
     <classpathentry kind="lib" path="bug185318.jar"/>
+    <classpathentry kind="lib" path="test285379.jar"/>
     <classpathentry kind="lib" path="class-folder"/>
     <classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Completion/src/Completion285379.java b/org.eclipse.jdt.core.tests.model/workspace/Completion/src/Completion285379.java
new file mode 100644
index 0000000..53d98a0
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Completion/src/Completion285379.java
@@ -0,0 +1,26 @@
+import pkgtest285379.X1;
+public class Completion285379 extends X1{
+	public interface testI{
+		void fooI();
+	};
+	X1 testVar;
+	Object o;
+	public static testI foo()
+	{
+		X1 a;
+		return 
+	}
+	public void foo1()
+	{
+		pkgtest285379.X1.
+	}
+	public boolean foo2(X1 var)
+	{
+		if (var.equals(testVar))
+			return;		
+	}
+	void bar(String var) {
+		X1 x;
+		x.equals(var);
+	}
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Converter13/.classpath b/org.eclipse.jdt.core.tests.model/workspace/Converter13/.classpath
index 3522bc0..1117818 100644
--- a/org.eclipse.jdt.core.tests.model/workspace/Converter13/.classpath
+++ b/org.eclipse.jdt.core.tests.model/workspace/Converter13/.classpath
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
 	<classpathentry kind="src" path="src"/>
-	<classpathentry kind="var" path="CONVERTER_JCL18_LIB" sourcepath="CONVERTER_JCL18_SRC" rootpath="CONVERTER_JCL_SRCROOT"/>
+	<classpathentry kind="var" path="CONVERTER_JCL13_LIB" sourcepath="CONVERTER_JCL13_SRC" rootpath="CONVERTER_JCL_SRCROOT"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/A_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/A_out.java
new file mode 100644
index 0000000..d9109d5
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/A_out.java
@@ -0,0 +1,86 @@
+public class Example {
+    String s = """
+aaa
+
+bbb
+
+
+ccc
+""";
+
+    String s2 = """
+ 	 	 	aaa
+
+	 	 	bbb
+
+
+    ccc""" + Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8,
+            9, 0, 1, 2, 3, 4, 5);
+
+    Object[] s3 = { "aaaa", """
+			bbb
+			
+			ccc
+			
+			
+			ddd
+			""", 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1,
+            2, 3, 4, 5 };
+
+    Object[] s4 = { "aaaa", //
+            """
+	bbb
+	
+	ccc
+	
+	
+	ddd
+	""", 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4,
+            5 };
+
+    void foo() {
+        Arrays.asList("""
+		              """, """
+					  1""", """
+					 2
+					 """, //
+                "", """
+						
+						
+						
+						""", /**/
+                """
+aaa
+            """);
+
+        Object o = new Object("""
+				a,b,c,d""".split("""
+						,""")) {
+            {
+                System.out.println("""
+              aaaaaaaaaaaaaaa
+              
+              bbbbbbbbbbbbbb""");
+            }
+
+            String bar(boolean arg) {
+                return (arg ? """
+					aaaa
+					""" : """
+						bbb
+						""") + (arg
+                        ? "cccccccccc" + "ddddddddddd" + "eeeeeeeeee"
+                                + "fffffffffff" + "ggggggggg" + """
+  hhhhhhhh"""
+                        : """
+  aaaaaaaaa""" + """
+  bbbbbbbbb""" + """
+     cccccccccccc""" + """
+          ddddddddddddd
+          """ + "eeeeeeee" + "fffffffffffff" + "ggggggggggggggggg"
+                                + "hhhhhhhhhhhhhhh" + "iiiiiiiiiiiiiiii"
+                                + "jjjjjjjjjjjjjjjjjjjjjjj");
+            }
+        };
+    }
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/B_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/B_out.java
new file mode 100644
index 0000000..6a5cd62
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/B_out.java
@@ -0,0 +1,87 @@
+public class Example {
+    String s = """
+        aaa
+
+        bbb
+
+
+        ccc
+        """;
+
+    String s2 = """
+         	aaa
+
+        	bbb
+
+
+        ccc""" + Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6,
+            7, 8, 9, 0, 1, 2, 3, 4, 5);
+
+    Object[] s3 = { "aaaa", """
+        bbb
+
+        ccc
+
+
+        ddd
+        """, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2,
+            3, 4, 5 };
+
+    Object[] s4 = { "aaaa", //
+            """
+                bbb
+
+                ccc
+
+
+                ddd
+                """, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+            1, 2, 3, 4, 5 };
+
+    void foo() {
+        Arrays.asList("""
+            """, """
+            1""", """
+            2
+            """, //
+                "", """
+
+
+
+                    """, /**/
+                """
+                    aaa
+                                """);
+
+        Object o = new Object("""
+            a,b,c,d""".split("""
+            ,""")) {
+            {
+                System.out.println("""
+                    aaaaaaaaaaaaaaa
+
+                    bbbbbbbbbbbbbb""");
+            }
+
+            String bar(boolean arg) {
+                return (arg ? """
+                    aaaa
+                    """ : """
+                    bbb
+                    """) + (arg
+                        ? "cccccccccc" + "ddddddddddd" + "eeeeeeeeee"
+                                + "fffffffffff" + "ggggggggg" + """
+                                    hhhhhhhh"""
+                        : """
+                            aaaaaaaaa""" + """
+                            bbbbbbbbb""" + """
+                            cccccccccccc""" + """
+                            ddddddddddddd
+                            """ + "eeeeeeee" + "fffffffffffff"
+                                + "ggggggggggggggggg" + "hhhhhhhhhhhhhhh"
+                                + "iiiiiiiiiiiiiiii"
+                                + "jjjjjjjjjjjjjjjjjjjjjjj");
+            }
+        };
+    }
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/C_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/C_out.java
new file mode 100644
index 0000000..220456b
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/C_out.java
@@ -0,0 +1,87 @@
+public class Example {
+    String s = """
+            aaa
+
+            bbb
+
+
+            ccc
+            """;
+
+    String s2 = """
+             	aaa
+
+            	bbb
+
+
+            ccc""" + Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
+            6, 7, 8, 9, 0, 1, 2, 3, 4, 5);
+
+    Object[] s3 = { "aaaa", """
+            bbb
+
+            ccc
+
+
+            ddd
+            """, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1,
+            2, 3, 4, 5 };
+
+    Object[] s4 = { "aaaa", //
+            """
+                    bbb
+
+                    ccc
+
+
+                    ddd
+                    """, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8,
+            9, 0, 1, 2, 3, 4, 5 };
+
+    void foo() {
+        Arrays.asList("""
+                """, """
+                1""", """
+                2
+                """, //
+                "", """
+
+
+
+                        """, /**/
+                """
+                        aaa
+                                    """);
+
+        Object o = new Object("""
+                a,b,c,d""".split("""
+                ,""")) {
+            {
+                System.out.println("""
+                        aaaaaaaaaaaaaaa
+
+                        bbbbbbbbbbbbbb""");
+            }
+
+            String bar(boolean arg) {
+                return (arg ? """
+                        aaaa
+                        """ : """
+                        bbb
+                        """) + (arg
+                        ? "cccccccccc" + "ddddddddddd" + "eeeeeeeeee"
+                                + "fffffffffff" + "ggggggggg" + """
+                                        hhhhhhhh"""
+                        : """
+                                aaaaaaaaa""" + """
+                                bbbbbbbbb""" + """
+                                cccccccccccc""" + """
+                                ddddddddddddd
+                                """ + "eeeeeeee" + "fffffffffffff"
+                                + "ggggggggggggggggg" + "hhhhhhhhhhhhhhh"
+                                + "iiiiiiiiiiiiiiii"
+                                + "jjjjjjjjjjjjjjjjjjjjjjj");
+            }
+        };
+    }
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/D_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/D_out.java
new file mode 100644
index 0000000..909d326
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/D_out.java
@@ -0,0 +1,87 @@
+public class Example {
+    String s = """
+                aaa
+
+                bbb
+
+
+                ccc
+                """;
+
+    String s2 = """
+                 	aaa
+
+                	bbb
+
+
+                ccc""" + Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4,
+                5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5);
+
+    Object[] s3 = { "aaaa", """
+                bbb
+
+                ccc
+
+
+                ddd
+                """, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+            1, 2, 3, 4, 5 };
+
+    Object[] s4 = { "aaaa", //
+            """
+                        bbb
+
+                        ccc
+
+
+                        ddd
+                        """, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,
+            8, 9, 0, 1, 2, 3, 4, 5 };
+
+    void foo() {
+        Arrays.asList("""
+                    """, """
+                    1""", """
+                    2
+                    """, //
+                    "", """
+
+
+
+                                """, /**/
+                    """
+                                aaa
+                                            """);
+
+        Object o = new Object("""
+                    a,b,c,d""".split("""
+                    ,""")) {
+            {
+                System.out.println("""
+                            aaaaaaaaaaaaaaa
+
+                            bbbbbbbbbbbbbb""");
+            }
+
+            String bar(boolean arg) {
+                return (arg ? """
+                            aaaa
+                            """ : """
+                            bbb
+                            """) + (arg
+                            ? "cccccccccc" + "ddddddddddd" + "eeeeeeeeee"
+                                        + "fffffffffff" + "ggggggggg" + """
+                                                    hhhhhhhh"""
+                            : """
+                                        aaaaaaaaa""" + """
+                                        bbbbbbbbb""" + """
+                                        cccccccccccc""" + """
+                                        ddddddddddddd
+                                        """ + "eeeeeeee" + "fffffffffffff"
+                                        + "ggggggggggggggggg"
+                                        + "hhhhhhhhhhhhhhh" + "iiiiiiiiiiiiiiii"
+                                        + "jjjjjjjjjjjjjjjjjjjjjjj");
+            }
+        };
+    }
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/E_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/E_out.java
new file mode 100644
index 0000000..e85dcf7
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/E_out.java
@@ -0,0 +1,88 @@
+public class Example {
+    String s = """
+               aaa
+
+               bbb
+
+
+               ccc
+               """;
+
+    String s2 = """
+                 	aaa
+
+                	bbb
+
+
+                ccc""" + Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4,
+            5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5);
+
+    Object[] s3 = { "aaaa", """
+                            bbb
+
+                            ccc
+
+
+                            ddd
+                            """, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6,
+            7, 8, 9, 0, 1, 2, 3, 4, 5 };
+
+    Object[] s4 = { "aaaa", //
+            """
+            bbb
+
+            ccc
+
+
+            ddd
+            """, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1,
+            2, 3, 4, 5 };
+
+    void foo() {
+        Arrays.asList("""
+                      """, """
+                           1""", """
+                                 2
+                                 """, //
+                "", """
+
+
+
+                    """, /**/
+                """
+                aaa
+                            """);
+
+        Object o = new Object("""
+                              a,b,c,d""".split("""
+                                               ,""")) {
+            {
+                System.out.println("""
+                                   aaaaaaaaaaaaaaa
+
+                                   bbbbbbbbbbbbbb""");
+            }
+
+            String bar(boolean arg) {
+                return (arg ? """
+                              aaaa
+                              """ : """
+                                    bbb
+                                    """) + (arg
+                        ? "cccccccccc" + "ddddddddddd" + "eeeeeeeeee"
+                                + "fffffffffff" + "ggggggggg" + """
+                                                                hhhhhhhh"""
+                        : """
+                          aaaaaaaaa""" + """
+                                         bbbbbbbbb""" + """
+                                                        cccccccccccc"""
+                                + """
+                                  ddddddddddddd
+                                  """ + "eeeeeeee" + "fffffffffffff"
+                                + "ggggggggggggggggg" + "hhhhhhhhhhhhhhh"
+                                + "iiiiiiiiiiiiiiii"
+                                + "jjjjjjjjjjjjjjjjjjjjjjj");
+            }
+        };
+    }
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/F_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/F_out.java
new file mode 100644
index 0000000..c748510
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/F_out.java
@@ -0,0 +1,87 @@
+public class Example {
+	String s = """
+		aaa
+
+		bbb
+
+
+		ccc
+		""";
+
+	String s2 = """
+		 	aaa
+
+			bbb
+
+
+		ccc""" + Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6,
+			7, 8, 9, 0, 1, 2, 3, 4, 5);
+
+	Object[] s3 = { "aaaa", """
+		bbb
+
+		ccc
+
+
+		ddd
+		""", 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2,
+			3, 4, 5 };
+
+	Object[] s4 = { "aaaa", //
+			"""
+				bbb
+
+				ccc
+
+
+				ddd
+				""", 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+			1, 2, 3, 4, 5 };
+
+	void foo() {
+		Arrays.asList("""
+			""", """
+			1""", """
+			2
+			""", //
+				"", """
+
+
+
+					""", /**/
+				"""
+					aaa
+					            """);
+
+		Object o = new Object("""
+			a,b,c,d""".split("""
+			,""")) {
+			{
+				System.out.println("""
+					aaaaaaaaaaaaaaa
+
+					bbbbbbbbbbbbbb""");
+			}
+
+			String bar(boolean arg) {
+				return (arg ? """
+					aaaa
+					""" : """
+					bbb
+					""") + (arg
+						? "cccccccccc" + "ddddddddddd" + "eeeeeeeeee"
+								+ "fffffffffff" + "ggggggggg" + """
+									hhhhhhhh"""
+						: """
+							aaaaaaaaa""" + """
+							bbbbbbbbb""" + """
+							cccccccccccc""" + """
+							ddddddddddddd
+							""" + "eeeeeeee" + "fffffffffffff"
+								+ "ggggggggggggggggg" + "hhhhhhhhhhhhhhh"
+								+ "iiiiiiiiiiiiiiii"
+								+ "jjjjjjjjjjjjjjjjjjjjjjj");
+			}
+		};
+	}
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/G_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/G_out.java
new file mode 100644
index 0000000..9405e25
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/G_out.java
@@ -0,0 +1,87 @@
+public class Example {
+	String s = """
+			aaa
+			
+			bbb
+			
+			
+			ccc
+			""";
+	
+	String s2 = """
+			 	aaa
+			
+				bbb
+			
+			
+			ccc""" + Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
+			6, 7, 8, 9, 0, 1, 2, 3, 4, 5);
+	
+	Object[] s3 = { "aaaa", """
+			bbb
+			
+			ccc
+			
+			
+			ddd
+			""", 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1,
+			2, 3, 4, 5 };
+	
+	Object[] s4 = { "aaaa", //
+			"""
+					bbb
+					
+					ccc
+					
+					
+					ddd
+					""", 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8,
+			9, 0, 1, 2, 3, 4, 5 };
+	
+	void foo() {
+		Arrays.asList("""
+				""", """
+				1""", """
+				2
+				""", //
+				"", """
+						
+						
+						
+						""", /**/
+				"""
+						aaa
+						            """);
+		
+		Object o = new Object("""
+				a,b,c,d""".split("""
+				,""")) {
+			{
+				System.out.println("""
+						aaaaaaaaaaaaaaa
+						
+						bbbbbbbbbbbbbb""");
+			}
+			
+			String bar(boolean arg) {
+				return (arg ? """
+						aaaa
+						""" : """
+						bbb
+						""") + (arg
+						? "cccccccccc" + "ddddddddddd" + "eeeeeeeeee"
+								+ "fffffffffff" + "ggggggggg" + """
+										hhhhhhhh"""
+						: """
+								aaaaaaaaa""" + """
+								bbbbbbbbb""" + """
+								cccccccccccc""" + """
+								ddddddddddddd
+								""" + "eeeeeeee" + "fffffffffffff"
+								+ "ggggggggggggggggg" + "hhhhhhhhhhhhhhh"
+								+ "iiiiiiiiiiiiiiii"
+								+ "jjjjjjjjjjjjjjjjjjjjjjj");
+			}
+		};
+	}
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/H_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/H_out.java
new file mode 100644
index 0000000..1bf3f50
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/H_out.java
@@ -0,0 +1,87 @@
+public class Example {
+	String s = """
+	            aaa
+
+	            bbb
+
+
+	            ccc
+	            """;
+
+	String s2 = """
+	             	aaa
+
+	            	bbb
+
+
+	            ccc""" + Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4,
+	            5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5);
+
+	Object[] s3 = { "aaaa", """
+	            bbb
+
+	            ccc
+
+
+	            ddd
+	            """, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
+	        1, 2, 3, 4, 5 };
+
+	Object[] s4 = { "aaaa", //
+	        """
+	                    bbb
+
+	                    ccc
+
+
+	                    ddd
+	                    """, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,
+	        8, 9, 0, 1, 2, 3, 4, 5 };
+
+	void foo() {
+		Arrays.asList("""
+		            """, """
+		            1""", """
+		            2
+		            """, //
+		            "", """
+
+
+
+		                        """, /**/
+		            """
+		                        aaa
+		                                    """);
+
+		Object o = new Object("""
+		            a,b,c,d""".split("""
+		            ,""")) {
+			{
+				System.out.println("""
+				            aaaaaaaaaaaaaaa
+
+				            bbbbbbbbbbbbbb""");
+			}
+
+			String bar(boolean arg) {
+				return (arg ? """
+				            aaaa
+				            """ : """
+				            bbb
+				            """) + (arg
+				            ? "cccccccccc" + "ddddddddddd" + "eeeeeeeeee"
+				                        + "fffffffffff" + "ggggggggg" + """
+				                                    hhhhhhhh"""
+				            : """
+				                        aaaaaaaaa""" + """
+				                        bbbbbbbbb""" + """
+				                        cccccccccccc""" + """
+				                        ddddddddddddd
+				                        """ + "eeeeeeee" + "fffffffffffff"
+				                        + "ggggggggggggggggg"
+				                        + "hhhhhhhhhhhhhhh" + "iiiiiiiiiiiiiiii"
+				                        + "jjjjjjjjjjjjjjjjjjjjjjj");
+			}
+		};
+	}
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/I_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/I_out.java
new file mode 100644
index 0000000..a46ed3b
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/I_out.java
@@ -0,0 +1,88 @@
+public class Example {
+	String s = """
+	           aaa
+	           
+	           bbb
+	           
+	           
+	           ccc
+	           """;
+	
+	String s2 = """
+	             	aaa
+	            
+	            	bbb
+	            
+	            
+	            ccc""" + Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4,
+	        5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5);
+	
+	Object[] s3 = { "aaaa", """
+	                        bbb
+	                        
+	                        ccc
+	                        
+	                        
+	                        ddd
+	                        """, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6,
+	        7, 8, 9, 0, 1, 2, 3, 4, 5 };
+	
+	Object[] s4 = { "aaaa", //
+	        """
+	        bbb
+	        
+	        ccc
+	        
+	        
+	        ddd
+	        """, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1,
+	        2, 3, 4, 5 };
+	
+	void foo() {
+		Arrays.asList("""
+		              """, """
+		                   1""", """
+		                         2
+		                         """, //
+		        "", """
+		            
+		            
+		            
+		            """, /**/
+		        """
+		        aaa
+		                    """);
+		
+		Object o = new Object("""
+		                      a,b,c,d""".split("""
+		                                       ,""")) {
+			{
+				System.out.println("""
+				                   aaaaaaaaaaaaaaa
+				                   
+				                   bbbbbbbbbbbbbb""");
+			}
+			
+			String bar(boolean arg) {
+				return (arg ? """
+				              aaaa
+				              """ : """
+				                    bbb
+				                    """) + (arg
+				        ? "cccccccccc" + "ddddddddddd" + "eeeeeeeeee"
+				                + "fffffffffff" + "ggggggggg" + """
+				                                                hhhhhhhh"""
+				        : """
+				          aaaaaaaaa""" + """
+				                         bbbbbbbbb""" + """
+				                                        cccccccccccc"""
+				                + """
+				                  ddddddddddddd
+				                  """ + "eeeeeeee" + "fffffffffffff"
+				                + "ggggggggggggggggg" + "hhhhhhhhhhhhhhh"
+				                + "iiiiiiiiiiiiiiii"
+				                + "jjjjjjjjjjjjjjjjjjjjjjj");
+			}
+		};
+	}
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/J_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/J_out.java
new file mode 100644
index 0000000..02e03da
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/J_out.java
@@ -0,0 +1,88 @@
+public class Example {
+	String s = """
+			   aaa
+
+			   bbb
+
+
+			   ccc
+			   """;
+
+	String s2 = """
+				 	aaa
+
+					bbb
+
+
+				ccc""" + Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4,
+			5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5);
+
+	Object[] s3 = { "aaaa", """
+							bbb
+
+							ccc
+
+
+							ddd
+							""", 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6,
+			7, 8, 9, 0, 1, 2, 3, 4, 5 };
+
+	Object[] s4 = { "aaaa", //
+			"""
+			bbb
+
+			ccc
+
+
+			ddd
+			""", 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1,
+			2, 3, 4, 5 };
+
+	void foo() {
+		Arrays.asList("""
+					  """, """
+						   1""", """
+								 2
+								 """, //
+				"", """
+
+
+
+					""", /**/
+				"""
+				aaa
+				            """);
+
+		Object o = new Object("""
+							  a,b,c,d""".split("""
+											   ,""")) {
+			{
+				System.out.println("""
+								   aaaaaaaaaaaaaaa
+
+								   bbbbbbbbbbbbbb""");
+			}
+
+			String bar(boolean arg) {
+				return (arg ? """
+							  aaaa
+							  """ : """
+									bbb
+									""") + (arg
+						? "cccccccccc" + "ddddddddddd" + "eeeeeeeeee"
+								+ "fffffffffff" + "ggggggggg" + """
+																hhhhhhhh"""
+						: """
+						  aaaaaaaaa""" + """
+										 bbbbbbbbb""" + """
+														cccccccccccc"""
+								+ """
+								  ddddddddddddd
+								  """ + "eeeeeeee" + "fffffffffffff"
+								+ "ggggggggggggggggg" + "hhhhhhhhhhhhhhh"
+								+ "iiiiiiiiiiiiiiii"
+								+ "jjjjjjjjjjjjjjjjjjjjjjj");
+			}
+		};
+	}
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/K_out.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/K_out.java
new file mode 100644
index 0000000..2dcea0b
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/K_out.java
@@ -0,0 +1,88 @@
+public class Example {
+	String s = """
+				aaa
+
+				bbb
+
+
+				ccc
+				""";
+
+	String s2 = """
+				 	aaa
+
+					bbb
+
+
+				ccc""" + Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4,
+			5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5);
+
+	Object[] s3 = { "aaaa", """
+							bbb
+
+							ccc
+
+
+							ddd
+							""", 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6,
+			7, 8, 9, 0, 1, 2, 3, 4, 5 };
+
+	Object[] s4 = { "aaaa", //
+			"""
+			bbb
+
+			ccc
+
+
+			ddd
+			""", 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1,
+			2, 3, 4, 5 };
+
+	void foo() {
+		Arrays.asList("""
+						""", """
+								1""", """
+										2
+										""", //
+				"", """
+
+
+
+					""", /**/
+				"""
+				aaa
+				            """);
+
+		Object o = new Object("""
+								a,b,c,d""".split("""
+													,""")) {
+			{
+				System.out.println("""
+									aaaaaaaaaaaaaaa
+
+									bbbbbbbbbbbbbb""");
+			}
+
+			String bar(boolean arg) {
+				return (arg ? """
+								aaaa
+								""" : """
+										bbb
+										""") + (arg
+						? "cccccccccc" + "ddddddddddd" + "eeeeeeeeee"
+								+ "fffffffffff" + "ggggggggg" + """
+																hhhhhhhh"""
+						: """
+							aaaaaaaaa""" + """
+											bbbbbbbbb""" + """
+															cccccccccccc"""
+								+ """
+									ddddddddddddd
+									""" + "eeeeeeee" + "fffffffffffff"
+								+ "ggggggggggggggggg" + "hhhhhhhhhhhhhhh"
+								+ "iiiiiiiiiiiiiiii"
+								+ "jjjjjjjjjjjjjjjjjjjjjjj");
+			}
+		};
+	}
+}
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/in.java b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/in.java
new file mode 100644
index 0000000..db75fb0
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Formatter/test549436/in.java
@@ -0,0 +1,79 @@
+public class Example {
+	String s = """
+aaa
+
+bbb
+
+
+ccc
+""";
+
+	String s2 = """
+ 	 	 	aaa
+
+	 	 	bbb
+
+
+    ccc""" + Arrays.asList(1, 2 , 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5);
+
+	Object[] s3 = { "aaaa", """
+			bbb
+			
+			ccc
+			
+			
+			ddd
+			""", 1, 2 , 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 };
+
+	Object[] s4 = { "aaaa", //
+	"""
+	bbb
+	
+	ccc
+	
+	
+	ddd
+	""", 1, 2 , 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5 };
+
+	void foo() {
+		Arrays.asList("""
+		              """,
+		              """
+					  1""","""
+					 2
+					 """, //
+					 "", """
+						
+						
+						
+						""", /**/
+"""
+aaa
+            """);
+
+		Object o = new Object("""
+				a,b,c,d""".split("""
+						,""")) {
+			{
+System.out.println("""
+              aaaaaaaaaaaaaaa
+              
+              bbbbbbbbbbbbbb""");
+			}
+			String bar (boolean arg) {
+				return (arg ? """
+					aaaa
+					""" : """
+						bbb
+						""") + (arg ? "cccccccccc" + "ddddddddddd" + "eeeeeeeeee"
+						+ "fffffffffff" + "ggggggggg" + """
+  hhhhhhhh""" : """
+  aaaaaaaaa""" + """
+  bbbbbbbbb""" + """
+     cccccccccccc""" + """
+          ddddddddddddd
+          """ + "eeeeeeee" + "fffffffffffff" + "ggggggggggggggggg" + "hhhhhhhhhhhhhhh" + "iiiiiiiiiiiiiiii" + "jjjjjjjjjjjjjjjjjjjjjjj");
+			}
+		};
+	}
+}
diff --git a/org.eclipse.jdt.core/.settings/org.eclipse.pde.api.tools.prefs b/org.eclipse.jdt.core/.settings/org.eclipse.pde.api.tools.prefs
index 6f7536a..2ec8851 100644
--- a/org.eclipse.jdt.core/.settings/org.eclipse.pde.api.tools.prefs
+++ b/org.eclipse.jdt.core/.settings/org.eclipse.pde.api.tools.prefs
@@ -1,94 +1,104 @@
-#Fri May 21 10:24:07 EDT 2010
-ANNOTATION_ELEMENT_TYPE_ADDED_METHOD_WITHOUT_DEFAULT_VALUE=Error
-ANNOTATION_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
-ANNOTATION_ELEMENT_TYPE_REMOVED_FIELD=Error
-ANNOTATION_ELEMENT_TYPE_REMOVED_METHOD=Error
-ANNOTATION_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
-API_COMPONENT_ELEMENT_TYPE_REMOVED_API_TYPE=Error
-API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_API_TYPE=Error
-API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_TYPE=Error
-API_COMPONENT_ELEMENT_TYPE_REMOVED_TYPE=Error
-CLASS_ELEMENT_TYPE_ADDED_METHOD=Error
-CLASS_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
-CLASS_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
-CLASS_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
-CLASS_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
-CLASS_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
-CLASS_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
-CLASS_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
-CLASS_ELEMENT_TYPE_REMOVED_CONSTRUCTOR=Error
-CLASS_ELEMENT_TYPE_REMOVED_FIELD=Error
-CLASS_ELEMENT_TYPE_REMOVED_METHOD=Error
-CLASS_ELEMENT_TYPE_REMOVED_SUPERCLASS=Error
-CLASS_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
-CLASS_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
-CONSTRUCTOR_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
-CONSTRUCTOR_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
-CONSTRUCTOR_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
-CONSTRUCTOR_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
-ENUM_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
-ENUM_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
-ENUM_ELEMENT_TYPE_REMOVED_ENUM_CONSTANT=Error
-ENUM_ELEMENT_TYPE_REMOVED_FIELD=Error
-ENUM_ELEMENT_TYPE_REMOVED_METHOD=Error
-ENUM_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
-FIELD_ELEMENT_TYPE_ADDED_VALUE=Error
-FIELD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
-FIELD_ELEMENT_TYPE_CHANGED_FINAL_TO_NON_FINAL_STATIC_CONSTANT=Error
-FIELD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
-FIELD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
-FIELD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
-FIELD_ELEMENT_TYPE_CHANGED_TYPE=Error
-FIELD_ELEMENT_TYPE_CHANGED_VALUE=Error
-FIELD_ELEMENT_TYPE_REMOVED_TYPE_ARGUMENT=Error
-FIELD_ELEMENT_TYPE_REMOVED_VALUE=Error
-ILLEGAL_EXTEND=Warning
-ILLEGAL_IMPLEMENT=Warning
-ILLEGAL_INSTANTIATE=Warning
-ILLEGAL_OVERRIDE=Warning
-ILLEGAL_REFERENCE=Warning
-INTERFACE_ELEMENT_TYPE_ADDED_FIELD=Error
-INTERFACE_ELEMENT_TYPE_ADDED_METHOD=Error
-INTERFACE_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
-INTERFACE_ELEMENT_TYPE_ADDED_SUPER_INTERFACE_WITH_METHODS=Error
-INTERFACE_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
-INTERFACE_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
-INTERFACE_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
-INTERFACE_ELEMENT_TYPE_REMOVED_FIELD=Error
-INTERFACE_ELEMENT_TYPE_REMOVED_METHOD=Error
-INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
-INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
-INVALID_JAVADOC_TAG=Warning
-INVALID_REFERENCE_IN_SYSTEM_LIBRARIES=Warning
-LEAK_EXTEND=Warning
-LEAK_FIELD_DECL=Warning
-LEAK_IMPLEMENT=Warning
-LEAK_METHOD_PARAM=Warning
-LEAK_METHOD_RETURN_TYPE=Warning
-METHOD_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
-METHOD_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
-METHOD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
-METHOD_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
-METHOD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
-METHOD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
-METHOD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
-METHOD_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
-METHOD_ELEMENT_TYPE_REMOVED_ANNOTATION_DEFAULT_VALUE=Error
-METHOD_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
-TYPE_PARAMETER_ELEMENT_TYPE_ADDED_CLASS_BOUND=Error
-TYPE_PARAMETER_ELEMENT_TYPE_ADDED_INTERFACE_BOUND=Error
-TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_CLASS_BOUND=Error
-TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_INTERFACE_BOUND=Error
-TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_CLASS_BOUND=Error
-TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_INTERFACE_BOUND=Error
-UNUSED_PROBLEM_FILTERS=Warning
-automatically_removed_unused_problem_filters=false
+ANNOTATION_ELEMENT_TYPE_ADDED_FIELD=Ignore
+ANNOTATION_ELEMENT_TYPE_ADDED_METHOD_WITHOUT_DEFAULT_VALUE=Ignore
+ANNOTATION_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Ignore
+ANNOTATION_ELEMENT_TYPE_REMOVED_FIELD=Ignore
+ANNOTATION_ELEMENT_TYPE_REMOVED_METHOD=Ignore
+ANNOTATION_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Ignore
+API_COMPONENT_ELEMENT_TYPE_REMOVED_API_TYPE=Ignore
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_API_TYPE=Ignore
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_TYPE=Ignore
+API_COMPONENT_ELEMENT_TYPE_REMOVED_TYPE=Ignore
+API_USE_SCAN_FIELD_SEVERITY=Ignore
+API_USE_SCAN_METHOD_SEVERITY=Ignore
+API_USE_SCAN_TYPE_SEVERITY=Ignore
+CLASS_ELEMENT_TYPE_ADDED_FIELD=Ignore
+CLASS_ELEMENT_TYPE_ADDED_METHOD=Ignore
+CLASS_ELEMENT_TYPE_ADDED_RESTRICTIONS=Ignore
+CLASS_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Ignore
+CLASS_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Ignore
+CLASS_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Ignore
+CLASS_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Ignore
+CLASS_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Ignore
+CLASS_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Ignore
+CLASS_ELEMENT_TYPE_REMOVED_CONSTRUCTOR=Ignore
+CLASS_ELEMENT_TYPE_REMOVED_FIELD=Ignore
+CLASS_ELEMENT_TYPE_REMOVED_METHOD=Ignore
+CLASS_ELEMENT_TYPE_REMOVED_SUPERCLASS=Ignore
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Ignore
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Ignore
+CONSTRUCTOR_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Ignore
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Ignore
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Ignore
+CONSTRUCTOR_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Ignore
+ENUM_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Ignore
+ENUM_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Ignore
+ENUM_ELEMENT_TYPE_REMOVED_ENUM_CONSTANT=Ignore
+ENUM_ELEMENT_TYPE_REMOVED_FIELD=Ignore
+ENUM_ELEMENT_TYPE_REMOVED_METHOD=Ignore
+ENUM_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Ignore
+FIELD_ELEMENT_TYPE_ADDED_VALUE=Ignore
+FIELD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Ignore
+FIELD_ELEMENT_TYPE_CHANGED_FINAL_TO_NON_FINAL_STATIC_CONSTANT=Ignore
+FIELD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Ignore
+FIELD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Ignore
+FIELD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Ignore
+FIELD_ELEMENT_TYPE_CHANGED_TYPE=Ignore
+FIELD_ELEMENT_TYPE_CHANGED_VALUE=Ignore
+FIELD_ELEMENT_TYPE_REMOVED_TYPE_ARGUMENT=Ignore
+FIELD_ELEMENT_TYPE_REMOVED_VALUE=Ignore
+ILLEGAL_EXTEND=Ignore
+ILLEGAL_IMPLEMENT=Ignore
+ILLEGAL_INSTANTIATE=Ignore
+ILLEGAL_OVERRIDE=Ignore
+ILLEGAL_REFERENCE=Ignore
+INTERFACE_ELEMENT_TYPE_ADDED_DEFAULT_METHOD=Ignore
+INTERFACE_ELEMENT_TYPE_ADDED_FIELD=Ignore
+INTERFACE_ELEMENT_TYPE_ADDED_METHOD=Ignore
+INTERFACE_ELEMENT_TYPE_ADDED_RESTRICTIONS=Ignore
+INTERFACE_ELEMENT_TYPE_ADDED_SUPER_INTERFACE_WITH_METHODS=Ignore
+INTERFACE_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Ignore
+INTERFACE_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Ignore
+INTERFACE_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Ignore
+INTERFACE_ELEMENT_TYPE_REMOVED_FIELD=Ignore
+INTERFACE_ELEMENT_TYPE_REMOVED_METHOD=Ignore
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Ignore
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Ignore
+INVALID_ANNOTATION=Ignore
+INVALID_JAVADOC_TAG=Ignore
+INVALID_REFERENCE_IN_SYSTEM_LIBRARIES=Ignore
+LEAK_EXTEND=Ignore
+LEAK_FIELD_DECL=Ignore
+LEAK_IMPLEMENT=Ignore
+LEAK_METHOD_PARAM=Ignore
+LEAK_METHOD_RETURN_TYPE=Ignore
+METHOD_ELEMENT_TYPE_ADDED_RESTRICTIONS=Ignore
+METHOD_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Ignore
+METHOD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Ignore
+METHOD_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Ignore
+METHOD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Ignore
+METHOD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Ignore
+METHOD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Ignore
+METHOD_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Ignore
+METHOD_ELEMENT_TYPE_REMOVED_ANNOTATION_DEFAULT_VALUE=Ignore
+METHOD_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Ignore
+MISSING_EE_DESCRIPTIONS=Ignore
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_CLASS_BOUND=Ignore
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_INTERFACE_BOUND=Ignore
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_CLASS_BOUND=Ignore
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_INTERFACE_BOUND=Ignore
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_CLASS_BOUND=Ignore
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_INTERFACE_BOUND=Ignore
+UNUSED_PROBLEM_FILTERS=Ignore
+automatically_removed_unused_problem_filters=Ignore
+changed_execution_env=Ignore
 eclipse.preferences.version=1
-incompatible_api_component_version=Error
+incompatible_api_component_version=Ignore
 incompatible_api_component_version_include_major_without_breaking_change=Disabled
 incompatible_api_component_version_include_minor_without_api_change=Disabled
-invalid_since_tag_version=Error
-malformed_since_tag=Error
-missing_since_tag=Error
+incompatible_api_component_version_report_major_without_breaking_change=Ignore
+incompatible_api_component_version_report_minor_without_api_change=Ignore
+invalid_since_tag_version=Ignore
+malformed_since_tag=Ignore
+missing_since_tag=Ignore
 report_api_breakage_when_major_version_incremented=Disabled
-report_resolution_errors_api_component=Warning
+report_resolution_errors_api_component=Ignore
diff --git a/org.eclipse.jdt.core/META-INF/MANIFEST.MF b/org.eclipse.jdt.core/META-INF/MANIFEST.MF
index 4611c49..6c317c4 100644
--- a/org.eclipse.jdt.core/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.core/META-INF/MANIFEST.MF
@@ -28,7 +28,7 @@
  org.eclipse.jdt.internal.compiler.codegen;x-friends:="org.eclipse.jdt.compiler.tool,org.eclipse.jdt.apt.pluggable.core,org.eclipse.pde.api.tools",
  org.eclipse.jdt.internal.compiler.env;x-friends:="org.eclipse.jdt.compiler.tool,org.eclipse.jdt.apt.pluggable.core",
  org.eclipse.jdt.internal.compiler.flow;x-friends:="org.eclipse.jdt.compiler.tool,org.eclipse.jdt.apt.pluggable.core",
- org.eclipse.jdt.internal.compiler.impl;x-friends:="org.eclipse.jdt.compiler.tool,org.eclipse.jdt.apt.pluggable.core",
+ org.eclipse.jdt.internal.compiler.impl;x-friends:="org.eclipse.jdt.compiler.tool,org.eclipse.jdt.apt.pluggable.core,org.eclipse.jdt.debug",
  org.eclipse.jdt.internal.compiler.lookup;x-friends:="org.eclipse.jdt.compiler.tool,org.eclipse.jdt.apt.pluggable.core",
  org.eclipse.jdt.internal.compiler.parser;x-friends:="org.eclipse.jdt.compiler.tool,org.eclipse.jdt.apt.pluggable.core",
  org.eclipse.jdt.internal.compiler.parser.diagnose;x-friends:="org.eclipse.jdt.compiler.tool,org.eclipse.jdt.apt.pluggable.core",
@@ -37,7 +37,8 @@
   x-friends:="org.eclipse.jdt.apt.pluggable.core,
    org.eclipse.jdt.compiler.tool,
    org.eclipse.pde.api.tools,
-   org.eclipse.jdt.apt.core",
+   org.eclipse.jdt.apt.core,
+   org.eclipse.jdt.debug",
  org.eclipse.jdt.internal.core;x-friends:="org.eclipse.jdt.apt.pluggable.core,org.eclipse.pde.api.tools,org.eclipse.jdt.launching",
  org.eclipse.jdt.internal.core.builder;x-friends:="org.eclipse.jdt.apt.pluggable.core,org.eclipse.pde.api.tools",
  org.eclipse.jdt.internal.core.dom;x-internal:=true,
@@ -57,7 +58,7 @@
  org.eclipse.jdt.internal.core.search.indexing;x-internal:=true,
  org.eclipse.jdt.internal.core.search.matching;x-internal:=true,
  org.eclipse.jdt.internal.core.search.processing;x-internal:=true,
- org.eclipse.jdt.internal.core.util;x-friends:="org.eclipse.jdt.apt.pluggable.core,org.eclipse.pde.api.tools",
+ org.eclipse.jdt.internal.core.util;x-friends:="org.eclipse.jdt.apt.pluggable.core,org.eclipse.pde.api.tools,org.eclipse.jdt.debug",
  org.eclipse.jdt.internal.eval;x-internal:=true,
  org.eclipse.jdt.internal.formatter;x-internal:=true,
  org.eclipse.jdt.internal.formatter.linewrap;x-internal:=true,
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
index 9bda4a9..a08a75c 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
@@ -4684,14 +4684,18 @@
 				setSeverity(CompilerOptions.OPTION_ReportUnqualifiedFieldAccess, severity, isEnabling);
 				return;
 			} else if (token.equals("unused")) { //$NON-NLS-1$
-				setSeverity(CompilerOptions.OPTION_ReportUnusedLocal, severity, isEnabling);
-				setSeverity(CompilerOptions.OPTION_ReportUnusedParameter, severity, isEnabling);
-				setSeverity(CompilerOptions.OPTION_ReportUnusedImport, severity, isEnabling);
-				setSeverity(CompilerOptions.OPTION_ReportUnusedPrivateMember, severity, isEnabling);
-				setSeverity(CompilerOptions.OPTION_ReportUnusedDeclaredThrownException, severity, isEnabling);
-				setSeverity(CompilerOptions.OPTION_ReportUnusedLabel, severity, isEnabling);
-				setSeverity(CompilerOptions.OPTION_ReportUnusedTypeArgumentsForMethodInvocation, severity, isEnabling);
+				setSeverity(CompilerOptions.OPTION_ReportDeadCode, severity, isEnabling);
+				setSeverity(CompilerOptions.OPTION_ReportRedundantSuperinterface, severity, isEnabling);
 				setSeverity(CompilerOptions.OPTION_ReportRedundantSpecificationOfTypeArguments, severity, isEnabling);
+				setSeverity(CompilerOptions.OPTION_ReportUnusedDeclaredThrownException, severity, isEnabling);
+				setSeverity(CompilerOptions.OPTION_ReportUnusedExceptionParameter, severity, isEnabling);
+				setSeverity(CompilerOptions.OPTION_ReportUnusedImport, severity, isEnabling);
+				setSeverity(CompilerOptions.OPTION_ReportUnusedLabel, severity, isEnabling);
+				setSeverity(CompilerOptions.OPTION_ReportUnusedLocal, severity, isEnabling);
+				setSeverity(CompilerOptions.OPTION_ReportUnusedObjectAllocation, severity,isEnabling);
+				setSeverity(CompilerOptions.OPTION_ReportUnusedParameter, severity, isEnabling);
+				setSeverity(CompilerOptions.OPTION_ReportUnusedPrivateMember, severity, isEnabling);
+				setSeverity(CompilerOptions.OPTION_ReportUnusedTypeArgumentsForMethodInvocation, severity, isEnabling);
 				setSeverity(CompilerOptions.OPTION_ReportUnusedTypeParameter, severity,isEnabling);
 				return;
 			} else if (token.equals("unusedParam")) { //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
index dcc0faf..80c0575 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
@@ -88,22 +88,25 @@
 import org.eclipse.jdt.internal.compiler.codegen.StackMapFrame;
 import org.eclipse.jdt.internal.compiler.codegen.StackMapFrameCodeStream;
 import org.eclipse.jdt.internal.compiler.codegen.StackMapFrameCodeStream.ExceptionMarker;
-import org.eclipse.jdt.internal.compiler.codegen.StackMapFrameCodeStream.StackDepthMarker;
-import org.eclipse.jdt.internal.compiler.codegen.StackMapFrameCodeStream.StackMarker;
 import org.eclipse.jdt.internal.compiler.codegen.TypeAnnotationCodeStream;
 import org.eclipse.jdt.internal.compiler.codegen.VerificationTypeInfo;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.impl.StringConstant;
+import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
 import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
 import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
 import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
 import org.eclipse.jdt.internal.compiler.lookup.PolymorphicMethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
+import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Scope;
 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding;
 import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding;
@@ -847,7 +850,8 @@
 		attributeNumber++; // code attribute
 		completeCodeAttributeForClinit(
 			codeAttributeOffset,
-			problemLine);
+			problemLine,
+			null);
 		if (this.contentsOffset + 2 >= this.contents.length) {
 			resizeContents(2);
 		}
@@ -1467,7 +1471,9 @@
 				.scope
 				.referenceCompilationUnit()
 				.compilationResult
-				.getLineSeparatorPositions());
+				.getLineSeparatorPositions(),
+			((SourceTypeBinding) methodBinding.declaringClass)
+				.scope);
 		// update the number of attributes
 		this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
 		this.contents[methodAttributeOffset] = (byte) attributeNumber;
@@ -1485,7 +1491,7 @@
 	 *
 	 * @param codeAttributeOffset <CODE>int</CODE>
 	 */
-	public void completeCodeAttribute(int codeAttributeOffset) {
+	public void completeCodeAttribute(int codeAttributeOffset, MethodScope scope) {
 		// reinitialize the localContents with the byte modified by the code stream
 		this.contents = this.codeStream.bCodeStream;
 		int localContentsOffset = this.codeStream.classFileOffset;
@@ -1605,7 +1611,8 @@
 					code_length,
 					codeAttributeOffset,
 					max_locals,
-					false);
+					false,
+					scope);
 		}
 
 		if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) {
@@ -1614,7 +1621,8 @@
 					code_length,
 					codeAttributeOffset,
 					max_locals,
-					false);
+					false,
+					scope);
 		}
 		
 		if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) {
@@ -1693,7 +1701,7 @@
 	 *
 	 * @param codeAttributeOffset <CODE>int</CODE>
 	 */
-	public void completeCodeAttributeForClinit(int codeAttributeOffset) {
+	public void completeCodeAttributeForClinit(int codeAttributeOffset, Scope scope) {
 		// reinitialize the contents with the byte modified by the code stream
 		this.contents = this.codeStream.bCodeStream;
 		int localContentsOffset = this.codeStream.classFileOffset;
@@ -1803,7 +1811,8 @@
 					code_length,
 					codeAttributeOffset,
 					max_locals,
-					true);
+					true,
+					scope);
 		}
 
 		if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) {
@@ -1812,7 +1821,8 @@
 					code_length,
 					codeAttributeOffset,
 					max_locals,
-					true);
+					true,
+					scope);
 		}
 
 		if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) {
@@ -1846,7 +1856,8 @@
 	 */
 	public void completeCodeAttributeForClinit(
 			int codeAttributeOffset,
-			int problemLine) {
+			int problemLine,
+			MethodScope scope) {
 		// reinitialize the contents with the byte modified by the code stream
 		this.contents = this.codeStream.bCodeStream;
 		int localContentsOffset = this.codeStream.classFileOffset;
@@ -1917,7 +1928,8 @@
 					code_length,
 					codeAttributeOffset,
 					max_locals,
-					true);
+					true,
+					scope);
 		}
 
 		if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) {
@@ -1926,7 +1938,8 @@
 					code_length,
 					codeAttributeOffset,
 					max_locals,
-					true);
+					true,
+					scope);
 		}
 
 		if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) {
@@ -2000,7 +2013,8 @@
 					code_length,
 					codeAttributeOffset,
 					max_locals,
-					false);
+					false,
+					null);
 		}
 
 		if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) {
@@ -2009,7 +2023,8 @@
 					code_length,
 					codeAttributeOffset,
 					max_locals,
-					false);
+					false,
+					null);
 		}
 
 		// then we do the local variable attribute
@@ -2096,7 +2111,8 @@
 					code_length,
 					codeAttributeOffset,
 					max_locals,
-					false);
+					false,
+					null);
 		}
 
 		if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) {
@@ -2105,7 +2121,8 @@
 					code_length,
 					codeAttributeOffset,
 					max_locals,
-					false);
+					false,
+					null);
 		}
 
 		// update the number of attributes// ensure first that there is enough space available inside the localContents array
@@ -2139,7 +2156,8 @@
 			boolean hasExceptionHandlers,
 			SyntheticMethodBinding binding,
 			int codeAttributeOffset,
-			int[] startLineIndexes) {
+			int[] startLineIndexes,
+			Scope scope) {
 		// reinitialize the contents with the byte modified by the code stream
 		this.contents = this.codeStream.bCodeStream;
 		int localContentsOffset = this.codeStream.classFileOffset;
@@ -2259,7 +2277,7 @@
 			attributesNumber += generateLocalVariableTableAttribute(code_length, methodDeclarationIsStatic, true);
 		}
 		if (addStackMaps) {
-			attributesNumber += generateStackMapTableAttribute(binding, code_length, codeAttributeOffset, max_locals, false);
+			attributesNumber += generateStackMapTableAttribute(binding, code_length, codeAttributeOffset, max_locals, false, scope);
 		}
 
 		if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) {
@@ -2268,7 +2286,8 @@
 					code_length,
 					codeAttributeOffset,
 					max_locals,
-					false);
+					false,
+					scope);
 		}
 
 		// update the number of attributes
@@ -2309,7 +2328,8 @@
 				false,
 				binding,
 				codeAttributeOffset,
-				startLineIndexes);
+				startLineIndexes,
+				((SourceTypeBinding) binding.declaringClass).scope);
 	}
 
 	private void completeArgumentAnnotationInfo(Argument[] arguments, List allAnnotationContexts) {
@@ -4733,14 +4753,15 @@
 			int code_length,
 			int codeAttributeOffset,
 			int max_locals,
-			boolean isClinit) {
+			boolean isClinit,
+			Scope scope) {
 		int attributesNumber = 0;
 		int localContentsOffset = this.contentsOffset;
 		StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream;
 		stackMapFrameCodeStream.removeFramePosition(code_length);
 		if (stackMapFrameCodeStream.hasFramePositions()) {
 			Map frames = new HashMap();
-			List realFrames = traverse(isClinit ? null : methodBinding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, isClinit);
+			List realFrames = traverse(isClinit ? null : methodBinding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, isClinit, scope);
 			int numberOfFrames = realFrames.size();
 			if (numberOfFrames > 1) {
 				int stackMapTableAttributeOffset = localContentsOffset;
@@ -4815,17 +4836,17 @@
 									break;
 								default:
 									this.contents[localContentsOffset++] = (byte) info.tag;
-								switch (info.tag) {
-									case VerificationTypeInfo.ITEM_UNINITIALIZED :
-										int offset = info.offset;
-										this.contents[localContentsOffset++] = (byte) (offset >> 8);
-										this.contents[localContentsOffset++] = (byte) offset;
-										break;
-									case VerificationTypeInfo.ITEM_OBJECT :
-										int indexForType = this.constantPool.literalIndexForType(info.constantPoolName());
-										this.contents[localContentsOffset++] = (byte) (indexForType >> 8);
-										this.contents[localContentsOffset++] = (byte) indexForType;
-								}
+									switch (info.tag) {
+										case VerificationTypeInfo.ITEM_UNINITIALIZED :
+											int offset = info.offset;
+											this.contents[localContentsOffset++] = (byte) (offset >> 8);
+											this.contents[localContentsOffset++] = (byte) offset;
+											break;
+										case VerificationTypeInfo.ITEM_OBJECT :
+											int indexForType = this.constantPool.literalIndexForType(info.constantPoolName());
+											this.contents[localContentsOffset++] = (byte) (indexForType >> 8);
+											this.contents[localContentsOffset++] = (byte) indexForType;
+									}
 							}
 							numberOfLocalEntries++;
 						}
@@ -4910,14 +4931,15 @@
 			int code_length,
 			int codeAttributeOffset,
 			int max_locals,
-			boolean isClinit) {
+			boolean isClinit,
+			Scope scope) {
 		int attributesNumber = 0;
 		int localContentsOffset = this.contentsOffset;
 		StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream;
 		stackMapFrameCodeStream.removeFramePosition(code_length);
 		if (stackMapFrameCodeStream.hasFramePositions()) {
 			Map frames = new HashMap();
-			List realFrames = traverse(isClinit ? null: methodBinding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, isClinit);
+			List realFrames = traverse(isClinit ? null: methodBinding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, isClinit, scope);
 			int numberOfFrames = realFrames.size();
 			if (numberOfFrames > 1) {
 				int stackMapTableAttributeOffset = localContentsOffset;
@@ -5456,8 +5478,7 @@
 		// skip type parameters
 		int paren = CharOperation.lastIndexOf(')', methodSignature);
 		// there could be thrown exceptions behind, thus scan one type exactly
-		return CharOperation.subarray(methodSignature, paren + 1,
-				methodSignature.length);
+		return CharOperation.subarray(methodSignature, paren + 1, methodSignature.length);
 	}
 
 	private final int i4At(byte[] reference, int relativeOffset,
@@ -5643,9 +5664,7 @@
 					localVariableBinding.recordInitializationStartPC(0);
 					localVariableBinding.recordInitializationEndPC(codeLength);
 
-					frame.putLocal(resolvedPosition, new VerificationTypeInfo(
-							TypeIds.T_JavaLangString,
-							ConstantPool.JavaLangStringConstantPoolName));
+					frame.putLocal(resolvedPosition, new VerificationTypeInfo(this.referenceBinding.scope.getJavaLangString()));
 					resolvedPosition++;
 
 					localVariableBinding = new LocalVariableBinding(" ordinal".toCharArray(), TypeBinding.INT, 0, false); //$NON-NLS-1$
@@ -5653,8 +5672,7 @@
 					this.codeStream.record(localVariableBinding);
 					localVariableBinding.recordInitializationStartPC(0);
 					localVariableBinding.recordInitializationEndPC(codeLength);
-					frame.putLocal(resolvedPosition, new VerificationTypeInfo(
-							TypeBinding.INT));
+					frame.putLocal(resolvedPosition, new VerificationTypeInfo(TypeBinding.INT));
 					resolvedPosition++;
 				}
 
@@ -5989,8 +6007,216 @@
 		});
 		return result;
 	}
+	
+	private TypeBinding getTypeBinding(char[] typeConstantPoolName, Scope scope, boolean checkcast) {
+		if (typeConstantPoolName.length == 1) {
+			// base type
+			switch(typeConstantPoolName[0]) {
+				case 'Z':
+					return TypeBinding.BOOLEAN;
+				case 'B':
+					return TypeBinding.BYTE;
+				case 'C':
+					return TypeBinding.CHAR;
+				case 'D':
+					return TypeBinding.DOUBLE;
+				case 'F':
+					return TypeBinding.FLOAT;
+				case 'I':
+					return TypeBinding.INT;
+				case 'J':
+					return TypeBinding.LONG;
+				case 'S':
+					return TypeBinding.SHORT;
+				default:
+					return null;
+			}
+		} else if (typeConstantPoolName[0] == '[') {
+			int dimensions = getDimensions(typeConstantPoolName);
+			if (typeConstantPoolName.length - dimensions == 1) {
+				// array of base types
+				TypeBinding baseType = null;
+				switch(typeConstantPoolName[typeConstantPoolName.length - 1]) {
+					case 'Z':
+						baseType = TypeBinding.BOOLEAN;
+						break;
+					case 'B':
+						baseType = TypeBinding.BYTE;
+						break;
+					case 'C':
+						baseType = TypeBinding.CHAR;
+						break;
+					case 'D':
+						baseType = TypeBinding.DOUBLE;
+						break;
+					case 'F':
+						baseType = TypeBinding.FLOAT;
+						break;
+					case 'I':
+						baseType = TypeBinding.INT;
+						break;
+					case 'J':
+						baseType = TypeBinding.LONG;
+						break;
+					case 'S':
+						baseType = TypeBinding.SHORT;
+						break;
+					case 'V':
+						baseType = TypeBinding.VOID;
+				}
+				return scope.createArrayType(baseType, dimensions);
+			} else {
+				// array of object types
+				char[] typeName = CharOperation.subarray(typeConstantPoolName, dimensions + 1, typeConstantPoolName.length - 1);
+				TypeBinding type = (TypeBinding) scope.getTypeOrPackage(CharOperation.splitOn('/', typeName));
+				if (!type.isValidBinding()) {
+					ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) type;
+					if ((problemReferenceBinding.problemId() & ProblemReasons.InternalNameProvided) != 0) {
+						type = problemReferenceBinding.closestMatch();
+					} else if ((problemReferenceBinding.problemId() & ProblemReasons.NotFound) != 0 && this.innerClassesBindings != null) {
+						// check local inner types to see if this is a anonymous type
+						Set<TypeBinding> innerTypeBindings = this.innerClassesBindings.keySet();
+						for (TypeBinding binding : innerTypeBindings) {
+							if (CharOperation.equals(binding.constantPoolName(), typeName)) {
+								type = binding;
+								break;
+							}
+						}
+					}
+				}
+				return scope.createArrayType(type, dimensions);
+			}
+		} else {
+			char[] typeName = checkcast ? typeConstantPoolName : CharOperation.subarray(typeConstantPoolName, 1, typeConstantPoolName.length - 1);
+			TypeBinding type = (TypeBinding) scope.getTypeOrPackage(CharOperation.splitOn('/', typeName));
+			if (!type.isValidBinding()) {
+				ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) type;
+				if ((problemReferenceBinding.problemId() & ProblemReasons.InternalNameProvided) != 0) {
+					type = problemReferenceBinding.closestMatch();
+				} else if ((problemReferenceBinding.problemId() & ProblemReasons.NotFound) != 0 && this.innerClassesBindings != null) {
+					// check local inner types to see if this is a anonymous type
+					Set<TypeBinding> innerTypeBindings = this.innerClassesBindings.keySet();
+					for (TypeBinding binding : innerTypeBindings) {
+						if (CharOperation.equals(binding.constantPoolName(), typeName)) {
+							type = binding;
+							break;
+						}
+					}
+				}
+			}
+			return type;
+		}
+	}
 
-	public List traverse(MethodBinding methodBinding, int maxLocals, byte[] bytecodes, int codeOffset, int codeLength, Map frames, boolean isClinit) {
+	private TypeBinding getNewTypeBinding(char[] typeConstantPoolName, Scope scope) {
+		char[] typeName = typeConstantPoolName;
+		TypeBinding type = (TypeBinding) scope.getTypeOrPackage(CharOperation.splitOn('/', typeName));
+		if (!type.isValidBinding()) {
+			ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) type;
+			if ((problemReferenceBinding.problemId() & ProblemReasons.InternalNameProvided) != 0) {
+				type = problemReferenceBinding.closestMatch();
+			} else if ((problemReferenceBinding.problemId() & ProblemReasons.NotFound) != 0 && this.innerClassesBindings != null) {
+				// check local inner types to see if this is a anonymous type
+				Set<TypeBinding> innerTypeBindings = this.innerClassesBindings.keySet();
+				for (TypeBinding binding : innerTypeBindings) {
+					if (CharOperation.equals(binding.constantPoolName(), typeName)) {
+						type = binding;
+						break;
+					}
+				}
+			}
+		}
+		return type;
+	}
+
+	private TypeBinding getANewArrayTypeBinding(char[] typeConstantPoolName, Scope scope) {
+		if (typeConstantPoolName[0] == '[') {
+			int dimensions = getDimensions(typeConstantPoolName);
+			if (typeConstantPoolName.length - dimensions == 1) {
+				// array of base types
+				TypeBinding baseType = null;
+				switch(typeConstantPoolName[typeConstantPoolName.length - 1]) {
+					case 'Z':
+						baseType = TypeBinding.BOOLEAN;
+						break;
+					case 'B':
+						baseType = TypeBinding.BYTE;
+						break;
+					case 'C':
+						baseType = TypeBinding.CHAR;
+						break;
+					case 'D':
+						baseType = TypeBinding.DOUBLE;
+						break;
+					case 'F':
+						baseType = TypeBinding.FLOAT;
+						break;
+					case 'I':
+						baseType = TypeBinding.INT;
+						break;
+					case 'J':
+						baseType = TypeBinding.LONG;
+						break;
+					case 'S':
+						baseType = TypeBinding.SHORT;
+						break;
+					case 'V':
+						baseType = TypeBinding.VOID;
+				}
+				return scope.createArrayType(baseType, dimensions);
+			} else {
+				// array of object types
+				char[] elementTypeClassName = CharOperation.subarray(typeConstantPoolName, dimensions + 1, typeConstantPoolName.length - 1);
+				TypeBinding type = (TypeBinding) scope.getTypeOrPackage(
+					CharOperation.splitOn('/', elementTypeClassName));
+				if (!type.isValidBinding()) {
+					ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) type;
+					if ((problemReferenceBinding.problemId() & ProblemReasons.InternalNameProvided) != 0) {
+						type = problemReferenceBinding.closestMatch();
+					} else if ((problemReferenceBinding.problemId() & ProblemReasons.NotFound) != 0 && this.innerClassesBindings != null) {
+						// check local inner types to see if this is a anonymous type
+						Set<TypeBinding> innerTypeBindings = this.innerClassesBindings.keySet();
+						for (TypeBinding binding : innerTypeBindings) {
+							if (CharOperation.equals(binding.constantPoolName(), elementTypeClassName)) {
+								type = binding;
+								break;
+							}
+						}
+					}
+				}
+				return scope.createArrayType(type, dimensions);
+			}
+		} else {
+			TypeBinding type = (TypeBinding) scope.getTypeOrPackage(
+				CharOperation.splitOn('/', typeConstantPoolName));
+			if (!type.isValidBinding()) {
+				ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) type;
+				if ((problemReferenceBinding.problemId() & ProblemReasons.InternalNameProvided) != 0) {
+					type = problemReferenceBinding.closestMatch();
+				} else if ((problemReferenceBinding.problemId() & ProblemReasons.NotFound) != 0 && this.innerClassesBindings != null) {
+					// check local inner types to see if this is a anonymous type
+					Set<TypeBinding> innerTypeBindings = this.innerClassesBindings.keySet();
+					for (TypeBinding binding : innerTypeBindings) {
+						if (CharOperation.equals(binding.constantPoolName(), typeConstantPoolName)) {
+							type = binding;
+							break;
+						}
+					}
+				}
+			}
+			return type;
+		}
+	}
+
+	public List traverse(
+			MethodBinding methodBinding,
+			int maxLocals,
+			byte[] bytecodes,
+			int codeOffset,
+			int codeLength,
+			Map<Integer, StackMapFrame> frames,
+			boolean isClinit,
+			Scope scope) {
 		Set realJumpTarget = new HashSet(); 
 
 		StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream;
@@ -6005,26 +6231,6 @@
 		int framePositionsLength = framePositions.length;
 		int currentFramePosition = framePositions[0];
 
-		// set initial values for stack depth markers
-		int indexInStackDepthMarkers = 0;
-		StackDepthMarker[] stackDepthMarkers = stackMapFrameCodeStream.getStackDepthMarkers();
-		int stackDepthMarkersLength = stackDepthMarkers == null ? 0 : stackDepthMarkers.length;
-		boolean hasStackDepthMarkers = stackDepthMarkersLength != 0;
-		StackDepthMarker stackDepthMarker = null;
-		if (hasStackDepthMarkers) {
-			stackDepthMarker = stackDepthMarkers[0];
-		}
-
-		// set initial values for stack markers (used only in cldc mode)
-		int indexInStackMarkers = 0;
-		StackMarker[] stackMarkers = stackMapFrameCodeStream.getStackMarkers();
-		int stackMarkersLength = stackMarkers == null ? 0 : stackMarkers.length;
-		boolean hasStackMarkers = stackMarkersLength != 0;
-		StackMarker stackMarker = null;
-		if (hasStackMarkers) {
-			stackMarker = stackMarkers[0];
-		}
-
 		// set initial values for exception markers
 		int indexInExceptionMarkers = 0;
 		ExceptionMarker[] exceptionMarkers= stackMapFrameCodeStream.getExceptionMarkers();
@@ -6040,7 +6246,7 @@
 			initializeDefaultLocals(frame, methodBinding, maxLocals, codeLength);
 		}
 		frame.pc = -1;
-		add(frames, frame.duplicate());
+		add(frames, frame.duplicate(), scope);
 		addRealJumpTarget(realJumpTarget, -1);
 		for (int i = 0, max = this.codeStream.exceptionLabelsCounter; i < max; i++) {
 			ExceptionLabel exceptionLabel = this.codeStream.exceptionLabels[i];
@@ -6050,43 +6256,9 @@
 		}
 		while (true) {
 			int currentPC = pc - codeOffset;
-			if (hasStackMarkers && stackMarker.pc == currentPC) {
-				VerificationTypeInfo[] infos = frame.stackItems;
-				VerificationTypeInfo[] tempInfos = new VerificationTypeInfo[frame.numberOfStackItems];
-				System.arraycopy(infos, 0, tempInfos, 0, frame.numberOfStackItems);
-				stackMarker.setInfos(tempInfos);
-			} else if (hasStackMarkers && stackMarker.destinationPC == currentPC) {
-				VerificationTypeInfo[] infos = stackMarker.infos;
-				frame.stackItems = infos;
-				frame.numberOfStackItems = infos.length;
-				indexInStackMarkers++;
-				if (indexInStackMarkers < stackMarkersLength) {
-					stackMarker = stackMarkers[indexInStackMarkers];
-				} else {
-					hasStackMarkers = false;
-				}
-			}
-			if (hasStackDepthMarkers && stackDepthMarker.pc == currentPC) {
-				TypeBinding typeBinding = stackDepthMarker.typeBinding;
-				if (typeBinding != null) {
-					if (stackDepthMarker.delta > 0) {
-						frame.addStackItem(new VerificationTypeInfo(typeBinding));
-					} else {
-						frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(typeBinding);
-					}
-				} else {
-					frame.numberOfStackItems--;
-				}
-				indexInStackDepthMarkers++;
-				if (indexInStackDepthMarkers < stackDepthMarkersLength) {
-					stackDepthMarker = stackDepthMarkers[indexInStackDepthMarkers];
-				} else {
-					hasStackDepthMarkers = false;
-				}
-			}
 			if (hasExceptionMarkers && exceptionMarker.pc == currentPC) {
 				frame.numberOfStackItems = 0;
-				frame.addStackItem(new VerificationTypeInfo(0, VerificationTypeInfo.ITEM_OBJECT, exceptionMarker.constantPoolName));
+				frame.addStackItem(new VerificationTypeInfo(exceptionMarker.getBinding()));
 				indexInExceptionMarkers++;
 				if (indexInExceptionMarkers < exceptionsMarkersLength) {
 					exceptionMarker = exceptionMarkers[indexInExceptionMarkers];
@@ -6106,12 +6278,13 @@
 			}
 			if (currentFramePosition == currentPC) {
 				// need to build a new frame and create a stack map attribute entry
-				StackMapFrame currentFrame = frame.duplicate();
-				currentFrame.pc = currentPC;
-				// initialize locals
-				initializeLocals(isClinit ? true : methodBinding.isStatic(), currentPC, currentFrame);
-				// insert a new frame
-				add(frames, currentFrame);
+				StackMapFrame currentFrame = frames.get(Integer.valueOf(currentPC));
+				if (currentFrame == null) {
+					currentFrame = createNewFrame(currentPC, frame, isClinit, methodBinding);
+					add(frames, currentFrame, scope);
+				} else {
+					frame = currentFrame.merge(frame.duplicate(), scope).duplicate();
+				}
 				indexInFramePositions++;
 				if (indexInFramePositions < framePositionsLength) {
 					currentFramePosition = framePositions[indexInFramePositions];
@@ -6125,7 +6298,7 @@
 					pc++;
 					break;
 				case Opcodes.OPC_aconst_null:
-					frame.addStackItem(TypeBinding.NULL);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.NULL));
 					pc++;
 					break;
 				case Opcodes.OPC_iconst_m1:
@@ -6135,31 +6308,31 @@
 				case Opcodes.OPC_iconst_3:
 				case Opcodes.OPC_iconst_4:
 				case Opcodes.OPC_iconst_5:
-					frame.addStackItem(TypeBinding.INT);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT));
 					pc++;
 					break;
 				case Opcodes.OPC_lconst_0:
 				case Opcodes.OPC_lconst_1:
-					frame.addStackItem(TypeBinding.LONG);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG));
 					pc++;
 					break;
 				case Opcodes.OPC_fconst_0:
 				case Opcodes.OPC_fconst_1:
 				case Opcodes.OPC_fconst_2:
-					frame.addStackItem(TypeBinding.FLOAT);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT));
 					pc++;
 					break;
 				case Opcodes.OPC_dconst_0:
 				case Opcodes.OPC_dconst_1:
-					frame.addStackItem(TypeBinding.DOUBLE);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE));
 					pc++;
 					break;
 				case Opcodes.OPC_bipush:
-					frame.addStackItem(TypeBinding.BYTE);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.BYTE));
 					pc += 2;
 					break;
 				case Opcodes.OPC_sipush:
-					frame.addStackItem(TypeBinding.SHORT);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.SHORT));
 					pc += 3;
 					break;
 				case Opcodes.OPC_ldc:
@@ -6167,20 +6340,16 @@
 					switch (u1At(poolContents, 0, constantPoolOffsets[index])) {
 						case ClassFileConstants.StringTag:
 							frame
-									.addStackItem(new VerificationTypeInfo(
-											TypeIds.T_JavaLangString,
-											ConstantPool.JavaLangStringConstantPoolName));
+									.addStackItem(new VerificationTypeInfo(scope.getJavaLangString()));
 							break;
 						case ClassFileConstants.IntegerTag:
-							frame.addStackItem(TypeBinding.INT);
+							frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT));
 							break;
 						case ClassFileConstants.FloatTag:
-							frame.addStackItem(TypeBinding.FLOAT);
+							frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT));
 							break;
 						case ClassFileConstants.ClassTag:
-							frame.addStackItem(new VerificationTypeInfo(
-									TypeIds.T_JavaLangClass,
-									ConstantPool.JavaLangClassConstantPoolName));
+							frame.addStackItem(new VerificationTypeInfo(scope.getJavaLangClass()));
 					}
 					pc += 2;
 					break;
@@ -6189,20 +6358,16 @@
 					switch (u1At(poolContents, 0, constantPoolOffsets[index])) {
 						case ClassFileConstants.StringTag:
 							frame
-									.addStackItem(new VerificationTypeInfo(
-											TypeIds.T_JavaLangString,
-											ConstantPool.JavaLangStringConstantPoolName));
+									.addStackItem(new VerificationTypeInfo(scope.getJavaLangString()));
 							break;
 						case ClassFileConstants.IntegerTag:
-							frame.addStackItem(TypeBinding.INT);
+							frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT));
 							break;
 						case ClassFileConstants.FloatTag:
-							frame.addStackItem(TypeBinding.FLOAT);
+							frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT));
 							break;
 						case ClassFileConstants.ClassTag:
-							frame.addStackItem(new VerificationTypeInfo(
-									TypeIds.T_JavaLangClass,
-									ConstantPool.JavaLangClassConstantPoolName));
+							frame.addStackItem(new VerificationTypeInfo(scope.getJavaLangClass()));
 					}
 					pc += 3;
 					break;
@@ -6210,28 +6375,28 @@
 					index = u2At(bytecodes, 1, pc);
 					switch (u1At(poolContents, 0, constantPoolOffsets[index])) {
 						case ClassFileConstants.DoubleTag:
-							frame.addStackItem(TypeBinding.DOUBLE);
+							frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE));
 							break;
 						case ClassFileConstants.LongTag:
-							frame.addStackItem(TypeBinding.LONG);
+							frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG));
 							break;
 					}
 					pc += 3;
 					break;
 				case Opcodes.OPC_iload:
-					frame.addStackItem(TypeBinding.INT);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT));
 					pc += 2;
 					break;
 				case Opcodes.OPC_lload:
-					frame.addStackItem(TypeBinding.LONG);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG));
 					pc += 2;
 					break;
 				case Opcodes.OPC_fload:
-					frame.addStackItem(TypeBinding.FLOAT);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT));
 					pc += 2;
 					break;
 				case Opcodes.OPC_dload:
-					frame.addStackItem(TypeBinding.DOUBLE);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE));
 					pc += 2;
 					break;
 				case Opcodes.OPC_aload:
@@ -6244,28 +6409,28 @@
 				case Opcodes.OPC_iload_1:
 				case Opcodes.OPC_iload_2:
 				case Opcodes.OPC_iload_3:
-					frame.addStackItem(TypeBinding.INT);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT));
 					pc++;
 					break;
 				case Opcodes.OPC_lload_0:
 				case Opcodes.OPC_lload_1:
 				case Opcodes.OPC_lload_2:
 				case Opcodes.OPC_lload_3:
-					frame.addStackItem(TypeBinding.LONG);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG));
 					pc++;
 					break;
 				case Opcodes.OPC_fload_0:
 				case Opcodes.OPC_fload_1:
 				case Opcodes.OPC_fload_2:
 				case Opcodes.OPC_fload_3:
-					frame.addStackItem(TypeBinding.FLOAT);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT));
 					pc++;
 					break;
 				case Opcodes.OPC_dload_0:
 				case Opcodes.OPC_dload_1:
 				case Opcodes.OPC_dload_2:
 				case Opcodes.OPC_dload_3:
-					frame.addStackItem(TypeBinding.DOUBLE);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE));
 					pc++;
 					break;
 				case Opcodes.OPC_aload_0:
@@ -6294,22 +6459,22 @@
 					break;
 				case Opcodes.OPC_iaload:
 					frame.numberOfStackItems -=2;
-					frame.addStackItem(TypeBinding.INT);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT));
 					pc++;
 					break;
 				case Opcodes.OPC_laload:
 					frame.numberOfStackItems -=2;
-					frame.addStackItem(TypeBinding.LONG);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG));
 					pc++;
 					break;
 				case Opcodes.OPC_faload:
 					frame.numberOfStackItems -=2;
-					frame.addStackItem(TypeBinding.FLOAT);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT));
 					pc++;
 					break;
 				case Opcodes.OPC_daload:
 					frame.numberOfStackItems -=2;
-					frame.addStackItem(TypeBinding.DOUBLE);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE));
 					pc++;
 					break;
 				case Opcodes.OPC_aaload:
@@ -6319,17 +6484,17 @@
 					break;
 				case Opcodes.OPC_baload:
 					frame.numberOfStackItems -=2;
-					frame.addStackItem(TypeBinding.BYTE);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.BYTE));
 					pc++;
 					break;
 				case Opcodes.OPC_caload:
 					frame.numberOfStackItems -=2;
-					frame.addStackItem(TypeBinding.CHAR);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.CHAR));
 					pc++;
 					break;
 				case Opcodes.OPC_saload:
 					frame.numberOfStackItems -=2;
-					frame.addStackItem(TypeBinding.SHORT);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.SHORT));
 					pc++;
 					break;
 				case Opcodes.OPC_istore:
@@ -6652,7 +6817,7 @@
 				case Opcodes.OPC_dcmpl:
 				case Opcodes.OPC_dcmpg:
 					frame.numberOfStackItems-=2;
-					frame.addStackItem(TypeBinding.INT);
+					frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT));
 					pc++;
 					break;
 				case Opcodes.OPC_ifeq:
@@ -6662,7 +6827,8 @@
 				case Opcodes.OPC_ifgt:
 				case Opcodes.OPC_ifle:
 					frame.numberOfStackItems--;
-					addRealJumpTarget(realJumpTarget, currentPC + i2At(bytecodes, 1, pc));
+					int jumpPC = currentPC + i2At(bytecodes, 1, pc);
+					addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope);
 					pc += 3;
 					break;
 				case Opcodes.OPC_if_icmpeq:
@@ -6674,21 +6840,25 @@
 				case Opcodes.OPC_if_acmpeq:
 				case Opcodes.OPC_if_acmpne:
 					frame.numberOfStackItems -= 2;
-					addRealJumpTarget(realJumpTarget, currentPC + i2At(bytecodes, 1, pc));
+					jumpPC = currentPC + i2At(bytecodes, 1, pc);
+					addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope);
 					pc += 3;
 					break;
 				case Opcodes.OPC_goto:
-					addRealJumpTarget(realJumpTarget, currentPC + i2At(bytecodes, 1, pc));
+					jumpPC = currentPC + i2At(bytecodes, 1, pc);
+					addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope);
 					pc += 3;
 					addRealJumpTarget(realJumpTarget, pc - codeOffset);
 					break;
 				case Opcodes.OPC_tableswitch:
+					frame.numberOfStackItems--;
 					pc++;
 					while (((pc - codeOffset) & 0x03) != 0) {
 						pc++;
 					}
 					// default offset
-					addRealJumpTarget(realJumpTarget, currentPC + i4At(bytecodes, 0, pc));
+					jumpPC = currentPC + i4At(bytecodes, 0, pc);
+					addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope);
 					pc += 4; // default
 					int low = i4At(bytecodes, 0, pc);
 					pc += 4;
@@ -6697,27 +6867,29 @@
 					int length = high - low + 1;
 					for (int i = 0; i < length; i++) {
 						// pair offset
-						addRealJumpTarget(realJumpTarget, currentPC + i4At(bytecodes, 0, pc));
+						jumpPC = currentPC + i4At(bytecodes, 0, pc);
+						addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope);
 						pc += 4;
 					}
-					frame.numberOfStackItems--;
 					break;
 				case Opcodes.OPC_lookupswitch:
+					frame.numberOfStackItems--;
 					pc++;
 					while (((pc - codeOffset) & 0x03) != 0) {
 						pc++;
 					}
-					addRealJumpTarget(realJumpTarget, currentPC + i4At(bytecodes, 0, pc));
+					jumpPC = currentPC + i4At(bytecodes, 0, pc);
+					addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope);
 					pc += 4; // default offset
 					int npairs = (int) u4At(bytecodes, 0, pc);
 					pc += 4; // npair value
 					for (int i = 0; i < npairs; i++) {
 						pc += 4; // case value
 						// pair offset
-						addRealJumpTarget(realJumpTarget, currentPC + i4At(bytecodes, 0, pc));
+						jumpPC = currentPC + i4At(bytecodes, 0, pc);
+						addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope);
 						pc += 4;
 					}
-					frame.numberOfStackItems--;
 					break;
 				case Opcodes.OPC_ireturn:
 				case Opcodes.OPC_lreturn:
@@ -6742,38 +6914,9 @@
 							constantPoolOffsets[utf8index] + 3, u2At(
 									poolContents, 1,
 									constantPoolOffsets[utf8index]));
-					if (descriptor.length == 1) {
-						// base type
-						switch(descriptor[0]) {
-							case 'Z':
-								frame.addStackItem(TypeBinding.BOOLEAN);
-								break;
-							case 'B':
-								frame.addStackItem(TypeBinding.BYTE);
-								break;
-							case 'C':
-								frame.addStackItem(TypeBinding.CHAR);
-								break;
-							case 'D':
-								frame.addStackItem(TypeBinding.DOUBLE);
-								break;
-							case 'F':
-								frame.addStackItem(TypeBinding.FLOAT);
-								break;
-							case 'I':
-								frame.addStackItem(TypeBinding.INT);
-								break;
-							case 'J':
-								frame.addStackItem(TypeBinding.LONG);
-								break;
-							case 'S':
-								frame.addStackItem(TypeBinding.SHORT);
-								break;
-						}
-					} else if (descriptor[0] == '[') {
-						frame.addStackItem(new VerificationTypeInfo(0, descriptor));
-					} else {
-						frame.addStackItem(new VerificationTypeInfo(0, CharOperation.subarray(descriptor, 1, descriptor.length - 1)));
+					TypeBinding typeBinding = getTypeBinding(descriptor, scope, false);
+					if (typeBinding != null) {
+						frame.addStackItem(new VerificationTypeInfo(typeBinding));
 					}
 					pc += 3;
 					break;
@@ -6792,38 +6935,9 @@
 									poolContents, 1,
 									constantPoolOffsets[utf8index]));
 					frame.numberOfStackItems--;
-					if (descriptor.length == 1) {
-						// base type
-						switch(descriptor[0]) {
-							case 'Z':
-								frame.addStackItem(TypeBinding.BOOLEAN);
-								break;
-							case 'B':
-								frame.addStackItem(TypeBinding.BYTE);
-								break;
-							case 'C':
-								frame.addStackItem(TypeBinding.CHAR);
-								break;
-							case 'D':
-								frame.addStackItem(TypeBinding.DOUBLE);
-								break;
-							case 'F':
-								frame.addStackItem(TypeBinding.FLOAT);
-								break;
-							case 'I':
-								frame.addStackItem(TypeBinding.INT);
-								break;
-							case 'J':
-								frame.addStackItem(TypeBinding.LONG);
-								break;
-							case 'S':
-								frame.addStackItem(TypeBinding.SHORT);
-								break;
-						}
-					} else if (descriptor[0] == '[') {
-						frame.addStackItem(new VerificationTypeInfo(0, descriptor));
-					} else {
-						frame.addStackItem(new VerificationTypeInfo(0, CharOperation.subarray(descriptor, 1, descriptor.length - 1)));
+					typeBinding = getTypeBinding(descriptor, scope, false);
+					if (typeBinding != null) {
+						frame.addStackItem(new VerificationTypeInfo(typeBinding));
 					}
 					pc += 3;
 					break;
@@ -6849,40 +6963,9 @@
 									constantPoolOffsets[utf8index]));
 					frame.numberOfStackItems -= (getParametersCount(descriptor) + 1);
 					char[] returnType = getReturnType(descriptor);
-					if (returnType.length == 1) {
-						// base type
-						switch(returnType[0]) {
-							case 'Z':
-								frame.addStackItem(TypeBinding.BOOLEAN);
-								break;
-							case 'B':
-								frame.addStackItem(TypeBinding.BYTE);
-								break;
-							case 'C':
-								frame.addStackItem(TypeBinding.CHAR);
-								break;
-							case 'D':
-								frame.addStackItem(TypeBinding.DOUBLE);
-								break;
-							case 'F':
-								frame.addStackItem(TypeBinding.FLOAT);
-								break;
-							case 'I':
-								frame.addStackItem(TypeBinding.INT);
-								break;
-							case 'J':
-								frame.addStackItem(TypeBinding.LONG);
-								break;
-							case 'S':
-								frame.addStackItem(TypeBinding.SHORT);
-								break;
-						}
-					} else {
-						if (returnType[0] == '[') {
-							frame.addStackItem(new VerificationTypeInfo(0, returnType));
-						} else {
-							frame.addStackItem(new VerificationTypeInfo(0, CharOperation.subarray(returnType, 1, returnType.length - 1)));
-						}
+					typeBinding = getTypeBinding(returnType, scope, false);
+					if (typeBinding != null) {
+						frame.addStackItem(new VerificationTypeInfo(typeBinding));
 					}
 					pc += 3;
 					break;
@@ -6898,40 +6981,9 @@
 									constantPoolOffsets[utf8index]));
 					frame.numberOfStackItems -= getParametersCount(descriptor);
 					returnType = getReturnType(descriptor);
-					if (returnType.length == 1) {
-						// base type
-						switch(returnType[0]) {
-							case 'Z':
-								frame.addStackItem(TypeBinding.BOOLEAN);
-								break;
-							case 'B':
-								frame.addStackItem(TypeBinding.BYTE);
-								break;
-							case 'C':
-								frame.addStackItem(TypeBinding.CHAR);
-								break;
-							case 'D':
-								frame.addStackItem(TypeBinding.DOUBLE);
-								break;
-							case 'F':
-								frame.addStackItem(TypeBinding.FLOAT);
-								break;
-							case 'I':
-								frame.addStackItem(TypeBinding.INT);
-								break;
-							case 'J':
-								frame.addStackItem(TypeBinding.LONG);
-								break;
-							case 'S':
-								frame.addStackItem(TypeBinding.SHORT);
-								break;
-						}
-					} else {
-						if (returnType[0] == '[') {
-							frame.addStackItem(new VerificationTypeInfo(0, returnType));
-						} else {
-							frame.addStackItem(new VerificationTypeInfo(0, CharOperation.subarray(returnType, 1, returnType.length - 1)));
-						}
+					typeBinding = getTypeBinding(returnType, scope, false);
+					if (typeBinding != null) {
+						frame.addStackItem(new VerificationTypeInfo(typeBinding));
 					}
 					pc += 5;
 					break;
@@ -6958,40 +7010,9 @@
 					}
 					frame.numberOfStackItems--;
 					returnType = getReturnType(descriptor);
-					if (returnType.length == 1) {
-						// base type
-						switch(returnType[0]) {
-							case 'Z':
-								frame.addStackItem(TypeBinding.BOOLEAN);
-								break;
-							case 'B':
-								frame.addStackItem(TypeBinding.BYTE);
-								break;
-							case 'C':
-								frame.addStackItem(TypeBinding.CHAR);
-								break;
-							case 'D':
-								frame.addStackItem(TypeBinding.DOUBLE);
-								break;
-							case 'F':
-								frame.addStackItem(TypeBinding.FLOAT);
-								break;
-							case 'I':
-								frame.addStackItem(TypeBinding.INT);
-								break;
-							case 'J':
-								frame.addStackItem(TypeBinding.LONG);
-								break;
-							case 'S':
-								frame.addStackItem(TypeBinding.SHORT);
-								break;
-						}
-					} else {
-						if (returnType[0] == '[') {
-							frame.addStackItem(new VerificationTypeInfo(0, returnType));
-						} else {
-							frame.addStackItem(new VerificationTypeInfo(0, CharOperation.subarray(returnType, 1, returnType.length - 1)));
-						}
+					typeBinding = getTypeBinding(returnType, scope, false);
+					if (typeBinding != null) {
+						frame.addStackItem(new VerificationTypeInfo(typeBinding));
 					}
 					pc += 3;
 					break;
@@ -7013,40 +7034,9 @@
 									constantPoolOffsets[utf8index]));
 					frame.numberOfStackItems -= getParametersCount(descriptor);
 					returnType = getReturnType(descriptor);
-					if (returnType.length == 1) {
-						// base type
-						switch(returnType[0]) {
-							case 'Z':
-								frame.addStackItem(TypeBinding.BOOLEAN);
-								break;
-							case 'B':
-								frame.addStackItem(TypeBinding.BYTE);
-								break;
-							case 'C':
-								frame.addStackItem(TypeBinding.CHAR);
-								break;
-							case 'D':
-								frame.addStackItem(TypeBinding.DOUBLE);
-								break;
-							case 'F':
-								frame.addStackItem(TypeBinding.FLOAT);
-								break;
-							case 'I':
-								frame.addStackItem(TypeBinding.INT);
-								break;
-							case 'J':
-								frame.addStackItem(TypeBinding.LONG);
-								break;
-							case 'S':
-								frame.addStackItem(TypeBinding.SHORT);
-								break;
-						}
-					} else {
-						if (returnType[0] == '[') {
-							frame.addStackItem(new VerificationTypeInfo(0, returnType));
-						} else {
-							frame.addStackItem(new VerificationTypeInfo(0, CharOperation.subarray(returnType, 1, returnType.length - 1)));
-						}
+					typeBinding = getTypeBinding(returnType, scope, false);
+					if (typeBinding != null) {
+						frame.addStackItem(new VerificationTypeInfo(typeBinding));
 					}
 					pc += 3;
 					break;
@@ -7071,40 +7061,9 @@
 					// u1At(bytecodes, 4, pc); // extra args
 					frame.numberOfStackItems -= (getParametersCount(descriptor) + 1);
 					returnType = getReturnType(descriptor);
-					if (returnType.length == 1) {
-						// base type
-						switch(returnType[0]) {
-							case 'Z':
-								frame.addStackItem(TypeBinding.BOOLEAN);
-								break;
-							case 'B':
-								frame.addStackItem(TypeBinding.BYTE);
-								break;
-							case 'C':
-								frame.addStackItem(TypeBinding.CHAR);
-								break;
-							case 'D':
-								frame.addStackItem(TypeBinding.DOUBLE);
-								break;
-							case 'F':
-								frame.addStackItem(TypeBinding.FLOAT);
-								break;
-							case 'I':
-								frame.addStackItem(TypeBinding.INT);
-								break;
-							case 'J':
-								frame.addStackItem(TypeBinding.LONG);
-								break;
-							case 'S':
-								frame.addStackItem(TypeBinding.SHORT);
-								break;
-						}
-					} else {
-						if (returnType[0] == '[') {
-							frame.addStackItem(new VerificationTypeInfo(0, returnType));
-						} else {
-							frame.addStackItem(new VerificationTypeInfo(0, CharOperation.subarray(returnType, 1, returnType.length - 1)));
-						}
+					typeBinding = getTypeBinding(returnType, scope, false);
+					if (typeBinding != null) {
+						frame.addStackItem(new VerificationTypeInfo(typeBinding));
 					}
 					pc += 5;
 					break;
@@ -7116,40 +7075,41 @@
 							constantPoolOffsets[utf8index] + 3, u2At(
 									poolContents, 1,
 									constantPoolOffsets[utf8index]));
-					VerificationTypeInfo verificationTypeInfo = new VerificationTypeInfo(0, VerificationTypeInfo.ITEM_UNINITIALIZED, className);
+					typeBinding =  getNewTypeBinding(className, scope);
+					VerificationTypeInfo verificationTypeInfo = new VerificationTypeInfo(VerificationTypeInfo.ITEM_UNINITIALIZED, typeBinding);
 					verificationTypeInfo.offset = currentPC;
 					frame.addStackItem(verificationTypeInfo);
 					pc += 3;
 					break;
 				case Opcodes.OPC_newarray:
-					char[] constantPoolName = null;
+					TypeBinding arrayType = null;
 					switch (u1At(bytecodes, 1, pc)) {
 						case ClassFileConstants.INT_ARRAY :
-							constantPoolName = new char[] { '[', 'I' };
+							arrayType = scope.createArrayType(TypeBinding.INT, 1);
 							break;
 						case ClassFileConstants.BYTE_ARRAY :
-							constantPoolName = new char[] { '[', 'B' };
+							arrayType = scope.createArrayType(TypeBinding.BYTE, 1);
 							break;
 						case ClassFileConstants.BOOLEAN_ARRAY :
-							constantPoolName = new char[] { '[', 'Z' };
+							arrayType = scope.createArrayType(TypeBinding.BOOLEAN, 1);
 							break;
 						case ClassFileConstants.SHORT_ARRAY :
-							constantPoolName = new char[] { '[', 'S' };
+							arrayType = scope.createArrayType(TypeBinding.SHORT, 1);
 							break;
 						case ClassFileConstants.CHAR_ARRAY :
-							constantPoolName = new char[] { '[', 'C' };
+							arrayType = scope.createArrayType(TypeBinding.CHAR, 1);
 							break;
 						case ClassFileConstants.LONG_ARRAY :
-							constantPoolName = new char[] { '[', 'J' };
+							arrayType = scope.createArrayType(TypeBinding.LONG, 1);
 							break;
 						case ClassFileConstants.FLOAT_ARRAY :
-							constantPoolName = new char[] { '[', 'F' };
+							arrayType = scope.createArrayType(TypeBinding.FLOAT, 1);
 							break;
 						case ClassFileConstants.DOUBLE_ARRAY :
-							constantPoolName = new char[] { '[', 'D' };
+							arrayType = scope.createArrayType(TypeBinding.DOUBLE, 1);
 							break;
 					}
-					frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeIds.T_JavaLangObject, constantPoolName);
+					frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(arrayType);
 					pc += 2;
 					break;
 				case Opcodes.OPC_anewarray:
@@ -7160,19 +7120,16 @@
 							constantPoolOffsets[utf8index] + 3, u2At(
 									poolContents, 1,
 									constantPoolOffsets[utf8index]));
-					int classNameLength = className.length;
-					if (className[0] != '[') {
-						// this is a type name (class or interface). So we add appropriate '[', 'L' and ';'.
-						System.arraycopy(className, 0, (constantPoolName = new char[classNameLength + 3]), 2, classNameLength);
-						constantPoolName[0] = '[';
-						constantPoolName[1] = 'L';
-						constantPoolName[classNameLength + 2] = ';';
-					} else {
-						// if class name is already an array, we just need to add one dimension
-						System.arraycopy(className, 0, (constantPoolName = new char[classNameLength + 1]), 1, classNameLength);
-						constantPoolName[0] = '[';
+					frame.numberOfStackItems--;
+					typeBinding = getANewArrayTypeBinding(className, scope);
+					if (typeBinding != null) {
+						if (typeBinding.isArrayType()) {
+							ArrayBinding arrayBinding = (ArrayBinding) typeBinding;
+							frame.addStackItem(new VerificationTypeInfo(scope.createArrayType(arrayBinding.leafComponentType(), arrayBinding.dimensions + 1)));
+						} else {
+							frame.addStackItem(new VerificationTypeInfo(scope.createArrayType(typeBinding, 1)));
+						}
 					}
-					frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(0, constantPoolName);
 					pc += 3;
 					break;
 				case Opcodes.OPC_arraylength:
@@ -7192,7 +7149,10 @@
 							constantPoolOffsets[utf8index] + 3, u2At(
 									poolContents, 1,
 									constantPoolOffsets[utf8index]));
-					frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(0, className);
+					typeBinding = getTypeBinding(className, scope, true);
+					if (typeBinding != null) {
+						frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(typeBinding);
+					}
 					pc += 3;
 					break;
 				case Opcodes.OPC_instanceof:
@@ -7217,10 +7177,10 @@
 						// need to handle iload, fload, aload, lload, dload, istore, fstore, astore, lstore or dstore
 						switch(opcode) {
 							case Opcodes.OPC_iload :
-								frame.addStackItem(TypeBinding.INT);
+								frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT));
 								break;
 							case Opcodes.OPC_fload :
-								frame.addStackItem(TypeBinding.FLOAT);
+								frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT));
 								break;
 							case Opcodes.OPC_aload :
 								localsN = frame.locals[index];
@@ -7230,10 +7190,10 @@
 								frame.addStackItem(localsN);
 								break;
 							case Opcodes.OPC_lload :
-								frame.addStackItem(TypeBinding.LONG);
+								frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG));
 								break;
 							case Opcodes.OPC_dload :
-								frame.addStackItem(TypeBinding.DOUBLE);
+								frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE));
 								break;
 							case Opcodes.OPC_istore :
 								frame.numberOfStackItems--;
@@ -7265,21 +7225,23 @@
 									constantPoolOffsets[utf8index]));
 					int dimensions = u1At(bytecodes, 3, pc); // dimensions
 					frame.numberOfStackItems -= dimensions;
-					classNameLength = className.length;
 					// class name is already the name of the right array type with all dimensions
-					constantPoolName = new char[classNameLength];
-					System.arraycopy(className, 0, constantPoolName, 0, classNameLength);
-					frame.addStackItem(new VerificationTypeInfo(0, constantPoolName));
+					typeBinding = getTypeBinding(className, scope, false);
+					if (typeBinding != null) {
+						frame.addStackItem(new VerificationTypeInfo(typeBinding));
+					}
 					pc += 4;
 					break;
 				case Opcodes.OPC_ifnull:
 				case Opcodes.OPC_ifnonnull:
 					frame.numberOfStackItems--;
-					addRealJumpTarget(realJumpTarget, currentPC + i2At(bytecodes, 1, pc));
+					jumpPC =  currentPC + i2At(bytecodes, 1, pc);
+					addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope);
 					pc += 3;
 					break;
 				case Opcodes.OPC_goto_w:
-					addRealJumpTarget(realJumpTarget, currentPC + i4At(bytecodes, 1, pc));
+					jumpPC =  currentPC + i4At(bytecodes, 1, pc);
+					addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope);
 					pc += 5;
 					addRealJumpTarget(realJumpTarget, pc - codeOffset); // handle infinite loop
 					break;
@@ -7314,12 +7276,42 @@
 		return filterFakeFrames(realJumpTarget, frames, codeLength);
 	}
 
+	private StackMapFrame createNewFrame(int currentPC, StackMapFrame frame, boolean isClinit, MethodBinding methodBinding) {
+		StackMapFrame newFrame = frame.duplicate();
+		newFrame.pc = currentPC;
+		// initialize locals
+		initializeLocals(isClinit ? true : methodBinding.isStatic(), currentPC, newFrame);
+		return newFrame;
+	}
+
+	private int getDimensions(char[] returnType) {
+		int dimensions = 0;
+		while (returnType[dimensions] == '[') {
+			dimensions++;
+		}
+		return dimensions;
+	}
+
 	private void addRealJumpTarget(Set realJumpTarget, int pc) {
 		realJumpTarget.add(Integer.valueOf(pc));
 	}
-	private void add(Map frames, StackMapFrame frame) {
-		frames.put(Integer.valueOf(frame.pc), frame);
+
+	private void addRealJumpTarget(Set realJumpTarget, int pc, Map frames, StackMapFrame frame, Scope scope) {
+		realJumpTarget.add(Integer.valueOf(pc));
+		add(frames, frame, scope);
 	}
+
+	private void add(Map<Integer, StackMapFrame> frames, StackMapFrame frame, Scope scope) {
+		Integer key = Integer.valueOf(frame.pc);
+		StackMapFrame existingFrame = frames.get(key);
+		if(existingFrame == null) {
+			frames.put(key, frame);
+		} else {
+			// we need to merge
+			frames.put(key, existingFrame.merge(frame, scope));
+		}
+	}
+
 	private final int u1At(byte[] reference, int relativeOffset,
 			int structOffset) {
 		return (reference[relativeOffset + structOffset] & 0xFF);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
index 6693e6b..6581ff4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
@@ -581,7 +581,7 @@
 				syntheticArgumentBinding.recordInitializationEndPC(classFile.codeStream.position);
 // SH}
 			try {
-				classFile.completeCodeAttribute(codeAttributeOffset);
+				classFile.completeCodeAttribute(codeAttributeOffset,this.scope);
 			} catch(NegativeArraySizeException e) {
 				throw new AbortMethod(this.scope.referenceCompilationUnit().compilationResult, null);
 			}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java
index b57896b..ac36c80 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java
@@ -99,7 +99,7 @@
 
 		// in interface case, no caching occurs, since cannot make a cache field for interface
 		if (valueRequired) {
-			codeStream.generateClassLiteralAccessForType(this.type.resolvedType, this.syntheticField);
+			codeStream.generateClassLiteralAccessForType(currentScope, this.type.resolvedType, this.syntheticField);
 			codeStream.generateImplicitConversion(this.implicitConversion);
 		}
 		codeStream.recordPositionsFrom(pc, this.sourceStart);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Clinit.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Clinit.java
index db6cf9c..377683b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Clinit.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Clinit.java
@@ -212,6 +212,7 @@
 		if (this.assertionSyntheticFieldBinding != null) {
 			// generate code related to the activation of assertion for this class
 			codeStream.generateClassLiteralAccessForType(
+					classScope,
 					classScope.outerMostClassScope().enclosingSourceType(),
 					this.classLiteralSyntheticField);
 			codeStream.invokeJavaLangClassDesiredAssertionStatus();
@@ -385,7 +386,7 @@
 			}
 			// Record the end of the clinit: point to the declaration of the class
 			codeStream.recordPositionsFrom(0, declaringType.sourceStart);
-			classFile.completeCodeAttributeForClinit(codeAttributeOffset);
+			classFile.completeCodeAttributeForClinit(codeAttributeOffset, classScope);
 		}
 	}
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
index a312f3e..1210f0a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
@@ -251,8 +251,12 @@
 			return;
 		}
 		Constant cst = this.condition.optimizedBooleanConstant();
+		if (cst == Constant.NotAConstant) {
+			cst = this.condition.optimizedNullComparisonConstant();
+		}
 		boolean needTruePart = !(cst != Constant.NotAConstant && cst.booleanValue() == false);
-		boolean needFalsePart = 	!(cst != Constant.NotAConstant && cst.booleanValue() == true);
+		boolean needFalsePart = !(cst != Constant.NotAConstant && cst.booleanValue() == true);
+
 		endifLabel = new BranchLabel(codeStream);
 
 		// Generate code for the condition
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
index a9be73b..729123a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
@@ -667,7 +667,7 @@
 		codeStream.exitUserScope(this.scope);
 		codeStream.recordPositionsFrom(0, this.bodyEnd > 0 ? this.bodyEnd : this.sourceStart);
 		try {
-			classFile.completeCodeAttribute(codeAttributeOffset);
+			classFile.completeCodeAttribute(codeAttributeOffset, this.scope);
 		} catch(NegativeArraySizeException e) {
 			throw new AbortMethod(this.scope.referenceCompilationUnit().compilationResult, null);
 		}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
index 140108d..d14d153 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
@@ -853,6 +853,22 @@
 	public boolean isCompactableOperation() {
 		return false;
 	}
+
+	@Override
+	protected Constant optimizedNullComparisonConstant() {
+		int operator = (this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT;
+		if (operator == OperatorIds.EQUAL_EQUAL) {
+			if (this.left instanceof NullLiteral && this.right instanceof NullLiteral) {
+				return BooleanConstant.fromValue(true);
+			}
+		} else if (operator == OperatorIds.NOT_EQUAL) {
+			if (this.left instanceof NullLiteral && this.right instanceof NullLiteral) {
+				return BooleanConstant.fromValue(false);
+			}
+		}
+		return Constant.NotAConstant;
+	}
+
 	@Override
 	public TypeBinding resolveType(BlockScope scope) {
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
index 0b35dd2..4216220 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
@@ -1512,4 +1512,8 @@
 public boolean isPotentiallyCompatibleWith(TypeBinding targetType, Scope scope) {
 	return isCompatibleWith(targetType, scope); // for all but functional expressions, potential compatibility is the same as compatibility.
 }
+
+protected Constant optimizedNullComparisonConstant() {
+	return Constant.NotAConstant;
+}
 }
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java
index ad3013d..5b07ed6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java
@@ -1326,7 +1326,7 @@
 		codeStream.exitUserScope(this.scope);
 		codeStream.recordPositionsFrom(0, this.sourceEnd); // WAS declarationSourceEnd.
 		try {
-			classFile.completeCodeAttribute(codeAttributeOffset);
+			classFile.completeCodeAttribute(codeAttributeOffset, this.scope);
 		} catch(NegativeArraySizeException e) {
 			throw new AbortMethod(this.scope.referenceCompilationUnit().compilationResult, null);
 		}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java
index ebc5320..beb8b61 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java
@@ -215,7 +215,7 @@
 	if (needValueStore()) {
 		alreadyGeneratedExpression = true;
 		this.expression.generateCode(currentScope, codeStream, needValue()); // no value needed if non-returning subroutine
-		generateStoreSaveValueIfNecessary(codeStream);
+		generateStoreSaveValueIfNecessary(currentScope, codeStream);
 	}
 
 	// generation of code responsible for invoking the finally blocks in sequence
@@ -237,7 +237,7 @@
 	if (this.expression != null && !alreadyGeneratedExpression) {
 		this.expression.generateCode(currentScope, codeStream, true);
 		// hook necessary for Code Snippet
-		generateStoreSaveValueIfNecessary(codeStream);
+		generateStoreSaveValueIfNecessary(currentScope, codeStream);
 	}
 	// output the suitable return bytecode or wrap the value inside a descriptor for doits
 	generateReturnBytecode(codeStream);
@@ -260,7 +260,7 @@
 	codeStream.generateReturnBytecode(this.expression);
 }
 
-public void generateStoreSaveValueIfNecessary(CodeStream codeStream){
+public void generateStoreSaveValueIfNecessary(Scope scope, CodeStream codeStream){
 	if (this.saveValueVariable != null) {
 		codeStream.store(this.saveValueVariable, false);
 		// the variable is visible as soon as the local is stored
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
index 1a26e6b..aa65304 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
@@ -1787,7 +1787,7 @@
 /**
  * Macro for building a class descriptor object
  */
-public void generateClassLiteralAccessForType(TypeBinding accessedType, FieldBinding syntheticFieldBinding) {
+public void generateClassLiteralAccessForType(Scope scope, TypeBinding accessedType, FieldBinding syntheticFieldBinding) {
 	if (accessedType.isBaseType() && accessedType != TypeBinding.NULL) {
 		getTYPE(accessedType.id);
 		return;
@@ -1851,7 +1851,7 @@
 		on the stack, which means that the stack may not be empty at this point in the
 		above code gen. So we save its state and restart it from 1. */
 
-		pushExceptionOnStack(TypeBinding.NULL);/*represents ClassNotFoundException*/
+		pushExceptionOnStack(scope.getJavaLangClassNotFoundException());
 		classNotFoundExceptionHandler.place();
 
 		// Transform the current exception, and repush and throw a
@@ -2577,7 +2577,7 @@
 public void generateSyntheticBodyForEnumValueOf(SyntheticMethodBinding methodBinding) {
 	initializeMaxLocals(methodBinding);
 	final ReferenceBinding declaringClass = methodBinding.declaringClass;
-	generateClassLiteralAccessForType(declaringClass, null);
+	generateClassLiteralAccessForType(((SourceTypeBinding) methodBinding.declaringClass).scope, declaringClass, null);
 	aload_0();
 	invokeJavaLangEnumvalueOf(declaringClass);
 	this.checkcast(declaringClass);
@@ -3164,7 +3164,7 @@
 				anyExceptionHandler.placeEnd();
 				goto_(endLabel);
 				// Generate the body of the exception handler
-				pushExceptionOnStack(TypeBinding.LONG /*represents NoSuchFieldError*/);
+				pushExceptionOnStack(scope.getJavaLangNoSuchFieldError());
 				anyExceptionHandler.place();
 				pop(); // we don't use it so we can pop it
 				endLabel.place();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrame.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrame.java
index a646ac8..c2ef996 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrame.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrame.java
@@ -14,8 +14,10 @@
 package org.eclipse.jdt.internal.compiler.codegen;
 
 import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Map;
 
-import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Scope;
 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
 
 public class StackMapFrame {
@@ -37,127 +39,156 @@
 	private int numberOfDifferentLocals = -1;
 	public int tagBits;
 
-public StackMapFrame(int initialLocalSize) {
-	this.locals = new VerificationTypeInfo[initialLocalSize];
-	this.numberOfLocals = -1;
-	this.numberOfDifferentLocals = -1;
-}
-public int getFrameType(StackMapFrame prevFrame) {
-	final int offsetDelta = getOffsetDelta(prevFrame);
-	switch(this.numberOfStackItems) {
-		case 0 :
-			switch(numberOfDifferentLocals(prevFrame)) {
-				case 0 :
-					return offsetDelta <= 63 ? SAME_FRAME : SAME_FRAME_EXTENDED;
-				case 1 :
-				case 2 :
-				case 3 :
-					return APPEND_FRAME;
-				case -1 :
-				case -2 :
-				case -3 :
-					return CHOP_FRAME;
-			}
-			break;
-		case 1 :
-			switch(numberOfDifferentLocals(prevFrame)) {
-				case 0 :
-					return offsetDelta <= 63 ? SAME_LOCALS_1_STACK_ITEMS : SAME_LOCALS_1_STACK_ITEMS_EXTENDED;
-			}
+	public StackMapFrame(int initialLocalSize) {
+		this.locals = new VerificationTypeInfo[initialLocalSize];
+		this.numberOfLocals = -1;
+		this.numberOfDifferentLocals = -1;
 	}
-	return FULL_FRAME;
-}
-public void addLocal(int resolvedPosition, VerificationTypeInfo info) {
-	if (this.locals == null) {
-		this.locals = new VerificationTypeInfo[resolvedPosition + 1];
-		this.locals[resolvedPosition] = info;
-	} else {
-		final int length = this.locals.length;
-		if (resolvedPosition >= length) {
-			System.arraycopy(this.locals, 0, this.locals = new VerificationTypeInfo[resolvedPosition + 1], 0, length);
-		}
-		this.locals[resolvedPosition] = info;
-	}
-}
-public void addStackItem(VerificationTypeInfo info) {
-	if (info == null) {
-		throw new IllegalArgumentException("info cannot be null"); //$NON-NLS-1$
-	}
-	if (this.stackItems == null) {
-		this.stackItems = new VerificationTypeInfo[1];
-		this.stackItems[0] = info;
-		this.numberOfStackItems = 1;
-	} else {
-		final int length = this.stackItems.length;
-		if (this.numberOfStackItems == length) {
-			System.arraycopy(this.stackItems, 0, this.stackItems = new VerificationTypeInfo[length + 1], 0, length);
-		}
-		this.stackItems[this.numberOfStackItems++] = info;
-	}
-}
-public void addStackItem(TypeBinding binding) {
-	if (this.stackItems == null) {
-		this.stackItems = new VerificationTypeInfo[1];
-		this.stackItems[0] = new VerificationTypeInfo(binding);
-		this.numberOfStackItems = 1;
-	} else {
-		final int length = this.stackItems.length;
-		if (this.numberOfStackItems == length) {
-			System.arraycopy(this.stackItems, 0, this.stackItems = new VerificationTypeInfo[length + 1], 0, length);
-		}
-		this.stackItems[this.numberOfStackItems++] = new VerificationTypeInfo(binding);
-	}
-}
-public StackMapFrame duplicate() {
-	int length = this.locals.length;
-	StackMapFrame result = new StackMapFrame(length);
-	result.numberOfLocals = -1;
-	result.numberOfDifferentLocals = -1;
-	result.pc = this.pc;
-	result.numberOfStackItems = this.numberOfStackItems;
 
-	if (length != 0) {
-		result.locals = new VerificationTypeInfo[length];
-		for (int i = 0; i < length; i++) {
-			final VerificationTypeInfo verificationTypeInfo = this.locals[i];
-			if (verificationTypeInfo != null) {
-				result.locals[i] = verificationTypeInfo.duplicate();
+	public int getFrameType(StackMapFrame prevFrame) {
+		final int offsetDelta = getOffsetDelta(prevFrame);
+		switch (this.numberOfStackItems) {
+			case 0:
+				switch (numberOfDifferentLocals(prevFrame)) {
+					case 0:
+						return offsetDelta <= 63 ? SAME_FRAME : SAME_FRAME_EXTENDED;
+					case 1:
+					case 2:
+					case 3:
+						return APPEND_FRAME;
+					case -1:
+					case -2:
+					case -3:
+						return CHOP_FRAME;
+				}
+				break;
+			case 1:
+				switch (numberOfDifferentLocals(prevFrame)) {
+					case 0:
+						return offsetDelta <= 63 ? SAME_LOCALS_1_STACK_ITEMS : SAME_LOCALS_1_STACK_ITEMS_EXTENDED;
+				}
+		}
+		return FULL_FRAME;
+	}
+
+	public void addLocal(int resolvedPosition, VerificationTypeInfo info) {
+		if (this.locals == null) {
+			this.locals = new VerificationTypeInfo[resolvedPosition + 1];
+			this.locals[resolvedPosition] = info;
+		} else {
+			final int length = this.locals.length;
+			if (resolvedPosition >= length) {
+				System.arraycopy(this.locals, 0, this.locals = new VerificationTypeInfo[resolvedPosition + 1], 0,
+						length);
+			}
+			this.locals[resolvedPosition] = info;
+		}
+	}
+
+	public void addStackItem(VerificationTypeInfo info) {
+		if (info == null) {
+			throw new IllegalArgumentException("info cannot be null"); //$NON-NLS-1$
+		}
+		if (this.stackItems == null) {
+			this.stackItems = new VerificationTypeInfo[1];
+			this.stackItems[0] = info;
+			this.numberOfStackItems = 1;
+		} else {
+			final int length = this.stackItems.length;
+			if (this.numberOfStackItems == length) {
+				System.arraycopy(this.stackItems, 0, this.stackItems = new VerificationTypeInfo[length + 1], 0, length);
+			}
+			this.stackItems[this.numberOfStackItems++] = info;
+		}
+	}
+
+	public StackMapFrame duplicate() {
+		Map<VerificationTypeInfo, VerificationTypeInfo> cache = new HashMap<VerificationTypeInfo, VerificationTypeInfo>();
+		int length = this.locals.length;
+		StackMapFrame result = new StackMapFrame(length);
+		result.numberOfLocals = -1;
+		result.numberOfDifferentLocals = -1;
+		result.pc = this.pc;
+		result.numberOfStackItems = this.numberOfStackItems;
+
+		if (length != 0) {
+			result.locals = new VerificationTypeInfo[length];
+			for (int i = 0; i < length; i++) {
+				final VerificationTypeInfo verificationTypeInfo = this.locals[i];
+				result.locals[i] = getCachedValue(cache, verificationTypeInfo);
 			}
 		}
-	}
-	length = this.numberOfStackItems;
-	if (length != 0) {
-		result.stackItems = new VerificationTypeInfo[length];
-		for (int i = 0; i < length; i++) {
-			result.stackItems[i] = this.stackItems[i].duplicate();
+		length = this.numberOfStackItems;
+		if (length != 0) {
+			result.stackItems = new VerificationTypeInfo[length];
+			for (int i = 0; i < length; i++) {
+				final VerificationTypeInfo verificationTypeInfo = this.stackItems[i];
+				result.stackItems[i] = getCachedValue(cache, verificationTypeInfo);
+			}
 		}
+		return result;
 	}
-	return result;
-}
-public int numberOfDifferentLocals(StackMapFrame prevFrame) {
-	if (this.numberOfDifferentLocals != -1) return this.numberOfDifferentLocals;
-	if (prevFrame == null) {
-		this.numberOfDifferentLocals = 0;
-		return 0;
-	}
-	VerificationTypeInfo[] prevLocals = prevFrame.locals;
-	VerificationTypeInfo[] currentLocals = this.locals;
-	int prevLocalsLength = prevLocals == null ? 0 : prevLocals.length;
-	int currentLocalsLength = currentLocals == null ? 0 : currentLocals.length;
-	int prevNumberOfLocals = prevFrame.getNumberOfLocals();
-	int currentNumberOfLocals = getNumberOfLocals();
 
-	int result = 0;
-	if (prevNumberOfLocals == 0) {
-		if (currentNumberOfLocals != 0) {
-			// need to check if there is a hole in the locals
-			result = currentNumberOfLocals; // append if no hole and currentNumberOfLocals <= 3
+	private VerificationTypeInfo getCachedValue(Map<VerificationTypeInfo, VerificationTypeInfo> cache, VerificationTypeInfo value) {
+		VerificationTypeInfo cachedValue = value;
+		if (value != null) {
+			if (value.tag == VerificationTypeInfo.ITEM_UNINITIALIZED || value.tag == VerificationTypeInfo.ITEM_UNINITIALIZED_THIS) {
+				// we use the cache only for uninitialized info
+				cachedValue = cache.get(value);
+				if (cachedValue == null) {
+					cachedValue = value.duplicate();
+					cache.put(value, cachedValue);
+				}
+			} else {
+				cachedValue = value.duplicate();
+			}
+		}
+		return cachedValue;
+	}
+	public int numberOfDifferentLocals(StackMapFrame prevFrame) {
+		if (this.numberOfDifferentLocals != -1)
+			return this.numberOfDifferentLocals;
+		if (prevFrame == null) {
+			this.numberOfDifferentLocals = 0;
+			return 0;
+		}
+		VerificationTypeInfo[] prevLocals = prevFrame.locals;
+		VerificationTypeInfo[] currentLocals = this.locals;
+		int prevLocalsLength = prevLocals == null ? 0 : prevLocals.length;
+		int currentLocalsLength = currentLocals == null ? 0 : currentLocals.length;
+		int prevNumberOfLocals = prevFrame.getNumberOfLocals();
+		int currentNumberOfLocals = getNumberOfLocals();
+
+		int result = 0;
+		if (prevNumberOfLocals == 0) {
+			if (currentNumberOfLocals != 0) {
+				// need to check if there is a hole in the locals
+				result = currentNumberOfLocals; // append if no hole and currentNumberOfLocals <= 3
+				int counter = 0;
+				for (int i = 0; i < currentLocalsLength && counter < currentNumberOfLocals; i++) {
+					if (currentLocals[i] != null) {
+						switch (currentLocals[i].id()) {
+							case TypeIds.T_double:
+							case TypeIds.T_long:
+								i++;
+						}
+						counter++;
+					} else {
+						result = Integer.MAX_VALUE;
+						this.numberOfDifferentLocals = result;
+						return result;
+					}
+				}
+			}
+		} else if (currentNumberOfLocals == 0) {
+			// need to check if there is a hole in the prev locals
 			int counter = 0;
-			for(int i = 0; i < currentLocalsLength && counter < currentNumberOfLocals; i++) {
-				if (currentLocals[i] != null) {
-					switch(currentLocals[i].id()) {
-						case TypeIds.T_double :
-						case TypeIds.T_long :
+			result = -prevNumberOfLocals; // chop frame if no hole and prevNumberOfLocals <= 3
+			for (int i = 0; i < prevLocalsLength && counter < prevNumberOfLocals; i++) {
+				if (prevLocals[i] != null) {
+					switch (prevLocals[i].id()) {
+						case TypeIds.T_double:
+						case TypeIds.T_long:
 							i++;
 					}
 					counter++;
@@ -167,216 +198,220 @@
 					return result;
 				}
 			}
-		}
-	} else if (currentNumberOfLocals == 0) {
-		// need to check if there is a hole in the prev locals
-		int counter = 0;
-		result = -prevNumberOfLocals; // chop frame if no hole and prevNumberOfLocals <= 3
-		for(int i = 0; i < prevLocalsLength && counter < prevNumberOfLocals; i++) {
-			if (prevLocals[i] != null) {
-				switch(prevLocals[i].id()) {
-					case TypeIds.T_double :
-					case TypeIds.T_long :
-						i++;
-				}
-				counter++;
-			} else {
-				result = Integer.MAX_VALUE;
-				this.numberOfDifferentLocals = result;
-				return result;
-			}
-		}
-	} else {
-		// need to see if prevLocals matches with currentLocals
-		int indexInPrevLocals = 0;
-		int indexInCurrentLocals = 0;
-		int currentLocalsCounter = 0;
-		int prevLocalsCounter = 0;
-		currentLocalsLoop: for (;indexInCurrentLocals < currentLocalsLength && currentLocalsCounter < currentNumberOfLocals; indexInCurrentLocals++) {
-			VerificationTypeInfo currentLocal = currentLocals[indexInCurrentLocals];
-			if (currentLocal != null) {
-				currentLocalsCounter++;
-				switch(currentLocal.id()) {
-					case TypeIds.T_double :
-					case TypeIds.T_long :
-						indexInCurrentLocals++; // next entry  is null
-				}
-			}
-			if (indexInPrevLocals < prevLocalsLength && prevLocalsCounter < prevNumberOfLocals) {
-				VerificationTypeInfo prevLocal = prevLocals[indexInPrevLocals];
-				if (prevLocal != null) {
-					prevLocalsCounter++;
-					switch(prevLocal.id()) {
-						case TypeIds.T_double :
-						case TypeIds.T_long :
-							indexInPrevLocals++; // next entry  is null
+		} else {
+			// need to see if prevLocals matches with currentLocals
+			int indexInPrevLocals = 0;
+			int indexInCurrentLocals = 0;
+			int currentLocalsCounter = 0;
+			int prevLocalsCounter = 0;
+			currentLocalsLoop: for (; indexInCurrentLocals < currentLocalsLength
+					&& currentLocalsCounter < currentNumberOfLocals; indexInCurrentLocals++) {
+				VerificationTypeInfo currentLocal = currentLocals[indexInCurrentLocals];
+				if (currentLocal != null) {
+					currentLocalsCounter++;
+					switch (currentLocal.id()) {
+						case TypeIds.T_double:
+						case TypeIds.T_long:
+							indexInCurrentLocals++; // next entry is null
 					}
 				}
-				// now we need to check if prevLocal matches with currentLocal
-				// the index must be the same
-				if (equals(prevLocal, currentLocal) && indexInPrevLocals == indexInCurrentLocals) {
-					if (result != 0) {
+				if (indexInPrevLocals < prevLocalsLength && prevLocalsCounter < prevNumberOfLocals) {
+					VerificationTypeInfo prevLocal = prevLocals[indexInPrevLocals];
+					if (prevLocal != null) {
+						prevLocalsCounter++;
+						switch (prevLocal.id()) {
+							case TypeIds.T_double:
+							case TypeIds.T_long:
+								indexInPrevLocals++; // next entry is null
+						}
+					}
+					// now we need to check if prevLocal matches with currentLocal
+					// the index must be the same
+					if (equals(prevLocal, currentLocal) && indexInPrevLocals == indexInCurrentLocals) {
+						if (result != 0) {
+							result = Integer.MAX_VALUE;
+							this.numberOfDifferentLocals = result;
+							return result;
+						}
+					} else {
+						// locals at the same location are not equals - this has to be a full frame
 						result = Integer.MAX_VALUE;
 						this.numberOfDifferentLocals = result;
 						return result;
 					}
+					indexInPrevLocals++;
+					continue currentLocalsLoop;
+				}
+				// process remaining current locals
+				if (currentLocal != null) {
+					result++;
 				} else {
-					// locals at the same location are not equals - this has to be a full frame
 					result = Integer.MAX_VALUE;
 					this.numberOfDifferentLocals = result;
 					return result;
 				}
-				indexInPrevLocals++;
-				continue currentLocalsLoop;
+				indexInCurrentLocals++;
+				break currentLocalsLoop;
 			}
-			// process remaining current locals
-			if (currentLocal != null) {
-				result++;
-			} else {
-				result = Integer.MAX_VALUE;
-				this.numberOfDifferentLocals = result;
-				return result;
-			}
-			indexInCurrentLocals++;
-			break currentLocalsLoop;
-		}
-		if (currentLocalsCounter < currentNumberOfLocals) {
-			for(;indexInCurrentLocals < currentLocalsLength && currentLocalsCounter < currentNumberOfLocals; indexInCurrentLocals++) {
-				VerificationTypeInfo currentLocal = currentLocals[indexInCurrentLocals];
-				if (currentLocal == null) {
-					result = Integer.MAX_VALUE;
-					this.numberOfDifferentLocals = result;
-					return result;
+			if (currentLocalsCounter < currentNumberOfLocals) {
+				for (; indexInCurrentLocals < currentLocalsLength
+						&& currentLocalsCounter < currentNumberOfLocals; indexInCurrentLocals++) {
+					VerificationTypeInfo currentLocal = currentLocals[indexInCurrentLocals];
+					if (currentLocal == null) {
+						result = Integer.MAX_VALUE;
+						this.numberOfDifferentLocals = result;
+						return result;
+					}
+					result++;
+					currentLocalsCounter++;
+					switch (currentLocal.id()) {
+						case TypeIds.T_double:
+						case TypeIds.T_long:
+							indexInCurrentLocals++; // next entry is null
+					}
 				}
-				result++;
-				currentLocalsCounter++;
-				switch(currentLocal.id()) {
-					case TypeIds.T_double :
-					case TypeIds.T_long :
-						indexInCurrentLocals++; // next entry  is null
-				}
-			}
-		} else if (prevLocalsCounter < prevNumberOfLocals) {
-			result = -result;
-			// process possible remaining prev locals
-			for(; indexInPrevLocals < prevLocalsLength && prevLocalsCounter < prevNumberOfLocals; indexInPrevLocals++) {
-				VerificationTypeInfo prevLocal = prevLocals[indexInPrevLocals];
-				if (prevLocal == null) {
-					result = Integer.MAX_VALUE;
-					this.numberOfDifferentLocals = result;
-					return result;
-				}
-				result--;
-				prevLocalsCounter++;
-				switch(prevLocal.id()) {
-					case TypeIds.T_double :
-					case TypeIds.T_long :
-						indexInPrevLocals++; // next entry  is null
+			} else if (prevLocalsCounter < prevNumberOfLocals) {
+				result = -result;
+				// process possible remaining prev locals
+				for (; indexInPrevLocals < prevLocalsLength
+						&& prevLocalsCounter < prevNumberOfLocals; indexInPrevLocals++) {
+					VerificationTypeInfo prevLocal = prevLocals[indexInPrevLocals];
+					if (prevLocal == null) {
+						result = Integer.MAX_VALUE;
+						this.numberOfDifferentLocals = result;
+						return result;
+					}
+					result--;
+					prevLocalsCounter++;
+					switch (prevLocal.id()) {
+						case TypeIds.T_double:
+						case TypeIds.T_long:
+							indexInPrevLocals++; // next entry is null
+					}
 				}
 			}
 		}
+		this.numberOfDifferentLocals = result;
+		return result;
 	}
-	this.numberOfDifferentLocals = result;
-	return result;
-}
-public int getNumberOfLocals() {
-	if (this.numberOfLocals != -1) {
-		return this.numberOfLocals;
-	}
-	int result = 0;
-	final int length = this.locals == null ? 0 : this.locals.length;
-	for(int i = 0; i < length; i++) {
-		if (this.locals[i] != null) {
-			switch(this.locals[i].id()) {
-				case TypeIds.T_double :
-				case TypeIds.T_long :
-					i++;
-			}
-			result++;
+
+	public int getNumberOfLocals() {
+		if (this.numberOfLocals != -1) {
+			return this.numberOfLocals;
 		}
-	}
-	this.numberOfLocals = result;
-	return result;
-}
-public int getOffsetDelta(StackMapFrame prevFrame) {
-	if (prevFrame == null) return this.pc;
-	return prevFrame.pc == -1 ? this.pc : this.pc - prevFrame.pc - 1;
-}
-@Override
-public String toString() {
-	StringBuffer buffer = new StringBuffer();
-	printFrame(buffer, this);
-	return String.valueOf(buffer);
-}
-private void printFrame(StringBuffer buffer, StackMapFrame frame) {
-	String pattern = "[pc : {0} locals: {1} stack items: {2}\nlocals: {3}\nstack: {4}\n]"; //$NON-NLS-1$
-	int localsLength = frame.locals == null ? 0 : frame.locals.length;
-	buffer.append(MessageFormat.format(
-		pattern,
-		new Object[] {
-			Integer.toString(frame.pc),
-			Integer.toString(frame.getNumberOfLocals()),
-			Integer.toString(frame.numberOfStackItems),
-			print(frame.locals, localsLength),
-			print(frame.stackItems, frame.numberOfStackItems)
-		}
-	));
-}
-private String print(VerificationTypeInfo[] infos, int length) {
-	StringBuffer buffer = new StringBuffer();
-	buffer.append('[');
-	if (infos != null) {
+		int result = 0;
+		final int length = this.locals == null ? 0 : this.locals.length;
 		for (int i = 0; i < length; i++) {
-			if (i != 0) buffer.append(',');
-			VerificationTypeInfo verificationTypeInfo = infos[i];
-			if (verificationTypeInfo == null) {
-				buffer.append("top"); //$NON-NLS-1$
-				continue;
+			if (this.locals[i] != null) {
+				switch (this.locals[i].id()) {
+					case TypeIds.T_double:
+					case TypeIds.T_long:
+						i++;
+				}
+				result++;
 			}
-			buffer.append(verificationTypeInfo);
 		}
+		this.numberOfLocals = result;
+		return result;
 	}
-	buffer.append(']');
-	return String.valueOf(buffer);
-}
-public void putLocal(int resolvedPosition, VerificationTypeInfo info) {
-	if (this.locals == null) {
-		this.locals = new VerificationTypeInfo[resolvedPosition + 1];
-		this.locals[resolvedPosition] = info;
-	} else {
-		final int length = this.locals.length;
-		if (resolvedPosition >= length) {
-			System.arraycopy(this.locals, 0, this.locals = new VerificationTypeInfo[resolvedPosition + 1], 0, length);
+
+	public int getOffsetDelta(StackMapFrame prevFrame) {
+		if (prevFrame == null)
+			return this.pc;
+		return prevFrame.pc == -1 ? this.pc : this.pc - prevFrame.pc - 1;
+	}
+
+	@Override
+	public String toString() {
+		StringBuffer buffer = new StringBuffer();
+		printFrame(buffer, this);
+		return String.valueOf(buffer);
+	}
+
+	private void printFrame(StringBuffer buffer, StackMapFrame frame) {
+		String pattern = "[pc : {0} locals: {1} stack items: {2}\nlocals: {3}\nstack: {4}\n]"; //$NON-NLS-1$
+		int localsLength = frame.locals == null ? 0 : frame.locals.length;
+		buffer.append(MessageFormat.format(pattern,
+				new Object[] { Integer.toString(frame.pc), Integer.toString(frame.getNumberOfLocals()),
+						Integer.toString(frame.numberOfStackItems), print(frame.locals, localsLength),
+						print(frame.stackItems, frame.numberOfStackItems) }));
+	}
+
+	private String print(VerificationTypeInfo[] infos, int length) {
+		StringBuffer buffer = new StringBuffer();
+		buffer.append('[');
+		if (infos != null) {
+			for (int i = 0; i < length; i++) {
+				if (i != 0)
+					buffer.append(',');
+				VerificationTypeInfo verificationTypeInfo = infos[i];
+				if (verificationTypeInfo == null) {
+					buffer.append("top"); //$NON-NLS-1$
+					continue;
+				}
+				buffer.append(verificationTypeInfo);
+			}
 		}
-		this.locals[resolvedPosition] = info;
+		buffer.append(']');
+		return String.valueOf(buffer);
 	}
-}
-public void replaceWithElementType() {
-	VerificationTypeInfo info = this.stackItems[this.numberOfStackItems - 1];
-	VerificationTypeInfo info2 = info.duplicate();
-	info2.replaceWithElementType();
-	this.stackItems[this.numberOfStackItems - 1] = info2;
-}
-public int getIndexOfDifferentLocals(int differentLocalsCount) {
-	for (int i = this.locals.length - 1; i >= 0; i--) {
-		VerificationTypeInfo currentLocal = this.locals[i];
-		if (currentLocal == null) {
-			// check the previous slot
-			continue;
+
+	public void putLocal(int resolvedPosition, VerificationTypeInfo info) {
+		if (this.locals == null) {
+			this.locals = new VerificationTypeInfo[resolvedPosition + 1];
+			this.locals[resolvedPosition] = info;
 		} else {
-			differentLocalsCount--;
-		}
-		if (differentLocalsCount == 0) {
-			return i;
+			final int length = this.locals.length;
+			if (resolvedPosition >= length) {
+				System.arraycopy(this.locals, 0, this.locals = new VerificationTypeInfo[resolvedPosition + 1], 0,
+						length);
+			}
+			this.locals[resolvedPosition] = info;
 		}
 	}
-	return 0;
-}
-private boolean equals(VerificationTypeInfo info, VerificationTypeInfo info2) {
-	if (info == null) {
-		return info2 == null;
+
+	public void replaceWithElementType() {
+		VerificationTypeInfo info = this.stackItems[this.numberOfStackItems - 1];
+		VerificationTypeInfo info2 = info.duplicate();
+		info2.replaceWithElementType();
+		this.stackItems[this.numberOfStackItems - 1] = info2;
 	}
-	if (info2 == null) return false;
-	return info.equals(info2);
-}
+
+	public int getIndexOfDifferentLocals(int differentLocalsCount) {
+		for (int i = this.locals.length - 1; i >= 0; i--) {
+			VerificationTypeInfo currentLocal = this.locals[i];
+			if (currentLocal == null) {
+				// check the previous slot
+				continue;
+			} else {
+				differentLocalsCount--;
+			}
+			if (differentLocalsCount == 0) {
+				return i;
+			}
+		}
+		return 0;
+	}
+
+	private boolean equals(VerificationTypeInfo info, VerificationTypeInfo info2) {
+		if (info == null) {
+			return info2 == null;
+		}
+		if (info2 == null)
+			return false;
+		return info.equals(info2);
+	}
+
+	public StackMapFrame merge(StackMapFrame frame, Scope scope) {
+		if (frame.pc == -1) {
+			// branching
+			return this;
+		}
+		if (this.numberOfStackItems == frame.numberOfStackItems) {
+			for (int i = 0, max = this.numberOfStackItems; i < max; i++) {
+				this.stackItems[i] = this.stackItems[i].merge(frame.stackItems[i], scope);
+			}
+		}
+		return this;
+	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrameCodeStream.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrameCodeStream.java
index 8d0fffe..3e44c49 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrameCodeStream.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrameCodeStream.java
@@ -33,16 +33,17 @@
 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
 import org.eclipse.jdt.internal.compiler.problem.AbortMethod;
 
-@SuppressWarnings({"rawtypes", "unchecked"})
+@SuppressWarnings({ "rawtypes", "unchecked" })
 public class StackMapFrameCodeStream extends CodeStream {
 	public static class ExceptionMarker implements Comparable {
-		public char[] constantPoolName;
+		private TypeBinding binding;
 		public int pc;
 
-		public ExceptionMarker(int pc, char[] constantPoolName) {
+		public ExceptionMarker(int pc, TypeBinding typeBinding) {
 			this.pc = pc;
-			this.constantPoolName = constantPoolName;
+			this.binding = typeBinding;
 		}
+
 		@Override
 		public int compareTo(Object o) {
 			if (o instanceof ExceptionMarker) {
@@ -50,93 +51,29 @@
 			}
 			return 0;
 		}
+
 		@Override
 		public boolean equals(Object obj) {
 			if (obj instanceof ExceptionMarker) {
 				ExceptionMarker marker = (ExceptionMarker) obj;
-				return this.pc == marker.pc && CharOperation.equals(this.constantPoolName, marker.constantPoolName);
+				return this.pc == marker.pc && this.binding.equals(marker.binding);
 			}
 			return false;
 		}
+
+		public TypeBinding getBinding() {
+			return this.binding;
+		}
+
 		@Override
 		public int hashCode() {
-			return this.pc + CharOperation.hashCode(this.constantPoolName);
-		}
-		@Override
-		public String toString() {
-			StringBuffer buffer = new StringBuffer();
-			buffer.append('(').append(this.pc).append(',').append(this.constantPoolName).append(')');
-			return String.valueOf(buffer);
-		}
-	}
-
-	public static class StackDepthMarker {
-		public int pc;
-		public int delta;
-		public TypeBinding typeBinding;
-
-		public StackDepthMarker(int pc, int delta, TypeBinding typeBinding) {
-			this.pc = pc;
-			this.typeBinding = typeBinding;
-			this.delta = delta;
-		}
-
-		public StackDepthMarker(int pc, int delta) {
-			this.pc = pc;
-			this.delta = delta;
+			return this.pc + CharOperation.hashCode(this.binding.constantPoolName());
 		}
 
 		@Override
 		public String toString() {
 			StringBuffer buffer = new StringBuffer();
-			buffer.append('(').append(this.pc).append(',').append(this.delta);
-			if (this.typeBinding != null) {
-				if (this.typeBinding.isBaseType()) {
-					buffer
-						.append(',')
-						.append(this.typeBinding.qualifiedSourceName());
-				} else {
-					buffer
-						.append(',')
-						.append(this.typeBinding.qualifiedPackageName())
-						.append('.')
-						.append(this.typeBinding.qualifiedSourceName());
-				}
-			}
-			buffer.append(')');
-			return String.valueOf(buffer);
-		}
-	}
-
-	public static class StackMarker {
-		public int pc;
-		public int destinationPC;
-		public VerificationTypeInfo[] infos;
-
-		public StackMarker(int pc, int destinationPC) {
-			this.pc = pc;
-			this.destinationPC = destinationPC;
-		}
-
-		public void setInfos(VerificationTypeInfo[] infos) {
-			this.infos = infos;
-		}
-
-		@Override
-		public String toString() {
-			StringBuffer buffer = new StringBuffer();
-			buffer
-				.append("[copy stack items from ") //$NON-NLS-1$
-				.append(this.pc)
-				.append(" to ") //$NON-NLS-1$
-				.append(this.destinationPC);
-			if (this.infos!= null) {
-				for (int i = 0, max = this.infos.length; i < max; i++) {
-					if (i > 0) buffer.append(',');
-					buffer.append(this.infos[i]);
-				}
-			}
-			buffer.append(']');
+			buffer.append('(').append(this.pc).append(',').append(this.binding.constantPoolName()).append(')');
 			return String.valueOf(buffer);
 		}
 	}
@@ -152,483 +89,434 @@
 	public ArrayList stackDepthMarkers;
 	public ArrayList stackMarkers;
 
-public StackMapFrameCodeStream(ClassFile givenClassFile) {
-	super(givenClassFile);
-	this.generateAttributes |= ClassFileConstants.ATTR_STACK_MAP;
-}
-@Override
-public void addDefinitelyAssignedVariables(Scope scope, int initStateIndex) {
-	// Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect
-	for (int i = 0; i < this.visibleLocalsCount; i++) {
-		LocalVariableBinding localBinding = this.visibleLocals[i];
-		if (localBinding != null) {
-			// Check if the local is definitely assigned
-			boolean isDefinitelyAssigned = isDefinitelyAssigned(scope, initStateIndex, localBinding);
-			if (!isDefinitelyAssigned) {
-				continue;
-			} else {
-				if ((localBinding.initializationCount == 0) || (localBinding.initializationPCs[((localBinding.initializationCount - 1) << 1) + 1] != -1)) {
-					/* There are two cases:
-					 * 1) there is no initialization interval opened ==> add an opened interval
-					 * 2) there is already some initialization intervals but the last one is closed ==> add an opened interval
-					 * An opened interval means that the value at localBinding.initializationPCs[localBinding.initializationCount - 1][1]
-					 * is equals to -1.
-					 * initializationPCs is a collection of pairs of int:
-					 * 	first value is the startPC and second value is the endPC. -1 one for the last value means that the interval
-					 * 	is not closed yet.
-					 */
-					localBinding.recordInitializationStartPC(this.position);
-				}
-			}
-		}
-	}
-}
-public void addExceptionMarker(int pc, TypeBinding typeBinding) {
-	if (this.exceptionMarkers == null) {
-		this.exceptionMarkers = new HashSet();
-	}
-	if (typeBinding == null) {
-		this.exceptionMarkers.add(new ExceptionMarker(pc, ConstantPool.JavaLangThrowableConstantPoolName));
-	} else {
-		switch(typeBinding.id) {
-			case TypeIds.T_null :
-				this.exceptionMarkers.add(new ExceptionMarker(pc, ConstantPool.JavaLangClassNotFoundExceptionConstantPoolName));
-				break;
-			case TypeIds.T_long :
-				this.exceptionMarkers.add(new ExceptionMarker(pc, ConstantPool.JavaLangNoSuchFieldErrorConstantPoolName));
-				break;
-			default:
-				this.exceptionMarkers.add(new ExceptionMarker(pc, typeBinding.constantPoolName()));
-		}
-	}
-}
-public void addFramePosition(int pc) {
-	Integer newEntry = Integer.valueOf(pc);
-	FramePosition value;
-	if ((value = (FramePosition) this.framePositions.get(newEntry)) != null) {
-		value.counter++;
-	} else {
-		this.framePositions.put(newEntry, new FramePosition());
-	}
-}
-@Override
-public void optimizeBranch(int oldPosition, BranchLabel lbl) {
-	super.optimizeBranch(oldPosition, lbl);
-	removeFramePosition(oldPosition);
-	removeStackMapMarkers(oldPosition);
-}
-public void removeFramePosition(int pc) {
-	Integer entry = Integer.valueOf(pc);
-	FramePosition value;
-	if ((value = (FramePosition) this.framePositions.get(entry)) != null) {
-		value.counter--;
-		if (value.counter <= 0) {
-			this.framePositions.remove(entry);
-		}
-	}
-}
-public void removeStackMapMarkers(int markerOldPosition) {
-	if (this.stackDepthMarkers != null) {
-		for (int i = this.stackDepthMarkers.size() - 1; i >= 0; i--) {
-			StackDepthMarker marker = (StackDepthMarker) this.stackDepthMarkers.get(i);
-			if (marker.pc == markerOldPosition) {
-				this.stackDepthMarkers.remove(i);
-				break;
-			}
-		}
-	}
-}
-@Override
-public void addVariable(LocalVariableBinding localBinding) {
-	if (localBinding.initializationPCs == null) {
-		record(localBinding);
-	}
-	localBinding.recordInitializationStartPC(this.position);
-}
-private void addStackMarker(int pc, int destinationPC) {
-	if (this.stackMarkers == null) {
-		this.stackMarkers = new ArrayList();
-		this.stackMarkers.add(new StackMarker(pc, destinationPC));
-	} else {
-		int size = this.stackMarkers.size();
-		if (size == 0 || ((StackMarker) this.stackMarkers.get(size - 1)).pc != this.position) {
-			this.stackMarkers.add(new StackMarker(pc, destinationPC));
-		}
-	}
-}
-private void addStackDepthMarker(int pc, int delta, TypeBinding typeBinding) {
-	if (this.stackDepthMarkers == null) {
-		this.stackDepthMarkers = new ArrayList();
-		this.stackDepthMarkers.add(new StackDepthMarker(pc, delta, typeBinding));
-	} else {
-		int size = this.stackDepthMarkers.size();
-		if (size == 0) {
-			this.stackDepthMarkers.add(new StackDepthMarker(pc, delta, typeBinding));
-		} else {
-			StackDepthMarker stackDepthMarker = (StackDepthMarker) this.stackDepthMarkers.get(size - 1);
-			if (stackDepthMarker.pc != this.position) {
-				this.stackDepthMarkers.add(new StackDepthMarker(pc, delta, typeBinding));
-			} else {
-				// We replace the recorded stack depth marker with a new value that contains the given typeBinding
-				// This case can happen when multiple conditional expression are nested see bug 362591
-				this.stackDepthMarkers.set(size - 1, new StackDepthMarker(pc, delta, typeBinding));
-			}
-		}
-	}
-}
-@Override
-public void decrStackSize(int offset) {
-	super.decrStackSize(offset);
-	addStackDepthMarker(this.position, -1, null);
-}
-@Override
-public void recordExpressionType(TypeBinding typeBinding) {
-	addStackDepthMarker(this.position, 0, typeBinding);
-}
-@Override
-public void recordExpressionType(TypeBinding typeBinding, int delta, boolean adjustStackDepth) {
-	addStackDepthMarker(this.position, delta, typeBinding);
-	if (adjustStackDepth) {
-		// optimized goto
-		// the break label already adjusted the stack depth (-1 or -2 depending on the return type)
-		// we need to adjust back to what it was
-		switch(typeBinding.id) {
-			case TypeIds.T_long :
-			case TypeIds.T_double :
-				this.stackDepth+=2;
-				break;
-			case TypeIds.T_void :
-				break;
-			default :
-				this.stackDepth++;
-				break;
-		}
-	}
-}
-/**
- * Macro for building a class descriptor object
- */
-@Override
-public void generateClassLiteralAccessForType(TypeBinding accessedType, FieldBinding syntheticFieldBinding) {
-	if (accessedType.isBaseType() && accessedType != TypeBinding.NULL) {
-		getTYPE(accessedType.id);
-		return;
+	public StackMapFrameCodeStream(ClassFile givenClassFile) {
+		super(givenClassFile);
+		this.generateAttributes |= ClassFileConstants.ATTR_STACK_MAP;
 	}
 
-	if (this.targetLevel >= ClassFileConstants.JDK1_5) {
-		// generation using the new ldc_w bytecode
-		this.ldc(accessedType);
-	} else {
-		// use in CLDC mode
-		BranchLabel endLabel = new BranchLabel(this);
-		if (syntheticFieldBinding != null) { // non interface case
-			fieldAccess(Opcodes.OPC_getstatic, syntheticFieldBinding, null /* default declaringClass */);
-			dup();
-			ifnonnull(endLabel);
-			pop();
-		}
-
-		/* Macro for building a class descriptor object... using or not a field cache to store it into...
-		this sequence is responsible for building the actual class descriptor.
-
-		If the fieldCache is set, then it is supposed to be the body of a synthetic access method
-		factoring the actual descriptor creation out of the invocation site (saving space).
-		If the fieldCache is nil, then we are dumping the bytecode on the invocation site, since
-		we have no way to get a hand on the field cache to do better. */
-
-
-		// Wrap the code in an exception handler to convert a ClassNotFoundException into a NoClassDefError
-
-		ExceptionLabel classNotFoundExceptionHandler = new ExceptionLabel(this, TypeBinding.NULL /*represents ClassNotFoundException*/);
-		classNotFoundExceptionHandler.placeStart();
-		this.ldc(accessedType == TypeBinding.NULL ? "java.lang.Object" : String.valueOf(accessedType.constantPoolName()).replace('/', '.')); //$NON-NLS-1$
-		invokeClassForName();
-
-		/* See https://bugs.eclipse.org/bugs/show_bug.cgi?id=37565
-		if (accessedType == BaseTypes.NullBinding) {
-			this.ldc("java.lang.Object"); //$NON-NLS-1$
-		} else if (accessedType.isArrayType()) {
-			this.ldc(String.valueOf(accessedType.constantPoolName()).replace('/', '.'));
-		} else {
-			// we make it an array type (to avoid class initialization)
-			this.ldc("[L" + String.valueOf(accessedType.constantPoolName()).replace('/', '.') + ";"); //$NON-NLS-1$//$NON-NLS-2$
-		}
-		this.invokeClassForName();
-		if (!accessedType.isArrayType()) { // extract the component type, which doesn't initialize the class
-			this.invokeJavaLangClassGetComponentType();
-		}
-		*/
-		/* We need to protect the runtime code from binary inconsistencies
-		in case the accessedType is missing, the ClassNotFoundException has to be converted
-		into a NoClassDefError(old ex message), we thus need to build an exception handler for this one. */
-		classNotFoundExceptionHandler.placeEnd();
-
-		if (syntheticFieldBinding != null) { // non interface case
-			dup();
-			fieldAccess(Opcodes.OPC_putstatic, syntheticFieldBinding, null /* default declaringClass */);
-		}
-		int fromPC = this.position;
-		goto_(endLabel);
-		int savedStackDepth = this.stackDepth;
-		// Generate the body of the exception handler
-		/* ClassNotFoundException on stack -- the class literal could be doing more things
-		on the stack, which means that the stack may not be empty at this point in the
-		above code gen. So we save its state and restart it from 1. */
-
-		pushExceptionOnStack(TypeBinding.NULL);/*represents ClassNotFoundException*/
-		classNotFoundExceptionHandler.place();
-
-		// Transform the current exception, and repush and throw a
-		// NoClassDefFoundError(ClassNotFound.getMessage())
-
-		newNoClassDefFoundError();
-		dup_x1();
-		swap();
-
-		// Retrieve the message from the old exception
-		invokeThrowableGetMessage();
-
-		// Send the constructor taking a message string as an argument
-		invokeNoClassDefFoundErrorStringConstructor();
-		athrow();
-		endLabel.place();
-		addStackMarker(fromPC, this.position);
-		this.stackDepth = savedStackDepth;
-	}
-}
-@Override
-public void generateOuterAccess(Object[] mappingSequence, ASTNode invocationSite, Binding target, Scope scope) {
-	int currentPosition = this.position;
-	super.generateOuterAccess(mappingSequence, invocationSite, target, scope);
-	if (currentPosition == this.position) {
-		// no code has been generate during outer access => no enclosing instance is available
-		throw new AbortMethod(scope.referenceCompilationUnit().compilationResult, null);
-	}
-}
-public ExceptionMarker[] getExceptionMarkers() {
-	Set exceptionMarkerSet = this.exceptionMarkers;
-	if (this.exceptionMarkers == null) return null;
-	int size = exceptionMarkerSet.size();
-	ExceptionMarker[] markers = new ExceptionMarker[size];
-	int n = 0;
-	for (Iterator iterator = exceptionMarkerSet.iterator(); iterator.hasNext(); ) {
-		markers[n++] = (ExceptionMarker) iterator.next();
-	}
-	Arrays.sort(markers);
-//  System.out.print('[');
-//  for (int n = 0; n < size; n++) {
-//  	if (n != 0) System.out.print(',');
-//  	System.out.print(positions[n]);
-//  }
-//  System.out.println(']');
-	return markers;
-}
-public int[] getFramePositions() {
-	Set set = this.framePositions.keySet();
-	int size = set.size();
-	int[] positions = new int[size];
-	int n = 0;
-	for (Iterator iterator = set.iterator(); iterator.hasNext(); ) {
-		positions[n++] = ((Integer) iterator.next()).intValue();
-	}
-	Arrays.sort(positions);
-//  System.out.print('[');
-//  for (int n = 0; n < size; n++) {
-//  	if (n != 0) System.out.print(',');
-//  	System.out.print(positions[n]);
-//  }
-//  System.out.println(']');
-	return positions;
-}
-public StackDepthMarker[] getStackDepthMarkers() {
-	if (this.stackDepthMarkers == null) return null;
-	int length = this.stackDepthMarkers.size();
-	if (length == 0) return null;
-	StackDepthMarker[] result = new StackDepthMarker[length];
-	this.stackDepthMarkers.toArray(result);
-	return result;
-}
-public StackMarker[] getStackMarkers() {
-	if (this.stackMarkers == null) return null;
-	int length = this.stackMarkers.size();
-	if (length == 0) return null;
-	StackMarker[] result = new StackMarker[length];
-	this.stackMarkers.toArray(result);
-	return result;
-}
-public boolean hasFramePositions() {
-	return this.framePositions.size() != 0;
-}
-@Override
-public void init(ClassFile targetClassFile) {
-	super.init(targetClassFile);
-	this.stateIndexesCounter = 0;
-	if (this.framePositions != null) {
-		this.framePositions.clear();
-	}
-	if (this.exceptionMarkers != null) {
-		this.exceptionMarkers.clear();
-	}
-	if (this.stackDepthMarkers != null) {
-		this.stackDepthMarkers.clear();
-	}
-	if (this.stackMarkers != null) {
-		this.stackMarkers.clear();
-	}
-}
-
-@Override
-public void initializeMaxLocals(MethodBinding methodBinding) {
-	super.initializeMaxLocals(methodBinding);
-	if (this.framePositions == null) {
-		this.framePositions = new HashMap();
-	} else {
-		this.framePositions.clear();
-	}
-}
-public void popStateIndex() {
-	this.stateIndexesCounter--;
-}
-public void pushStateIndex(int naturalExitMergeInitStateIndex) {
-	if (this.stateIndexes == null) {
-		this.stateIndexes = new int[3];
-	}
-	int length = this.stateIndexes.length;
-	if (length == this.stateIndexesCounter) {
-		// resize
-		System.arraycopy(this.stateIndexes, 0, (this.stateIndexes = new int[length * 2]), 0, length);
-	}
-	this.stateIndexes[this.stateIndexesCounter++] = naturalExitMergeInitStateIndex;
-}
-@Override
-public void removeNotDefinitelyAssignedVariables(Scope scope, int initStateIndex) {
-	int index = this.visibleLocalsCount;
-	loop : for (int i = 0; i < index; i++) {
-		LocalVariableBinding localBinding = this.visibleLocals[i];
-		if (localBinding != null && localBinding.initializationCount > 0) {
-			boolean isDefinitelyAssigned = isDefinitelyAssigned(scope, initStateIndex, localBinding);
-			if (!isDefinitelyAssigned) {
-				if (this.stateIndexes != null) {
-					for (int j = 0, max = this.stateIndexesCounter; j < max; j++) {
-						if (isDefinitelyAssigned(scope, this.stateIndexes[j], localBinding)) {
-							continue loop;
-						}
+	@Override
+	public void addDefinitelyAssignedVariables(Scope scope, int initStateIndex) {
+		// Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect
+		for (int i = 0; i < this.visibleLocalsCount; i++) {
+			LocalVariableBinding localBinding = this.visibleLocals[i];
+			if (localBinding != null) {
+				// Check if the local is definitely assigned
+				boolean isDefinitelyAssigned = isDefinitelyAssigned(scope, initStateIndex, localBinding);
+				if (!isDefinitelyAssigned) {
+					continue;
+				} else {
+					if ((localBinding.initializationCount == 0)
+							|| (localBinding.initializationPCs[((localBinding.initializationCount - 1) << 1)
+									+ 1] != -1)) {
+						/*
+						 * There are two cases: 1) there is no initialization interval opened ==> add an opened interval
+						 * 2) there is already some initialization intervals but the last one is closed ==> add an
+						 * opened interval An opened interval means that the value at
+						 * localBinding.initializationPCs[localBinding.initializationCount - 1][1] is equals to -1.
+						 * initializationPCs is a collection of pairs of int: first value is the startPC and second
+						 * value is the endPC. -1 one for the last value means that the interval is not closed yet.
+						 */
+						localBinding.recordInitializationStartPC(this.position);
 					}
 				}
-				localBinding.recordInitializationEndPC(this.position);
 			}
 		}
 	}
-}
-@Override
-public void reset(ClassFile givenClassFile) {
-	super.reset(givenClassFile);
-	this.stateIndexesCounter = 0;
-	if (this.framePositions != null) {
-		this.framePositions.clear();
+
+	public void addExceptionMarker(int pc, TypeBinding typeBinding) {
+		if (this.exceptionMarkers == null) {
+			this.exceptionMarkers = new HashSet();
+		}
+
+		this.exceptionMarkers.add(new ExceptionMarker(pc, typeBinding));
 	}
-	if (this.exceptionMarkers != null) {
-		this.exceptionMarkers.clear();
-	}
-	if (this.stackDepthMarkers != null) {
-		this.stackDepthMarkers.clear();
-	}
-	if (this.stackMarkers != null) {
-		this.stackMarkers.clear();
-	}
-}
-@Override
-protected void writePosition(BranchLabel label) {
-	super.writePosition(label);
-	addFramePosition(label.position);
-}
-@Override
-protected void writePosition(BranchLabel label, int forwardReference) {
-	super.writePosition(label, forwardReference);
-	addFramePosition(label.position);
-}
-@Override
-protected void writeSignedWord(int pos, int value) {
-	super.writeSignedWord(pos, value);
-	addFramePosition(this.position);
-}
-@Override
-protected void writeWidePosition(BranchLabel label) {
-	super.writeWidePosition(label);
-	addFramePosition(label.position);
-}
-@Override
-public void areturn() {
-	super.areturn();
-	addFramePosition(this.position);
-}
-@Override
-public void ireturn() {
-	super.ireturn();
-	addFramePosition(this.position);
-}
-@Override
-public void lreturn() {
-	super.lreturn();
-	addFramePosition(this.position);
-}
-@Override
-public void freturn() {
-	super.freturn();
-	addFramePosition(this.position);
-}
-@Override
-public void dreturn() {
-	super.dreturn();
-	addFramePosition(this.position);
-}
-@Override
-public void return_() {
-	super.return_();
-	addFramePosition(this.position);
-}
-@Override
-public void athrow() {
-	super.athrow();
-	addFramePosition(this.position);
-}
-@Override
-public void pushOnStack(TypeBinding binding) {
-	super.pushOnStack(binding);
-	addStackDepthMarker(this.position, 1, binding);
-}
-@Override
-public void pushExceptionOnStack(TypeBinding binding) {
-	super.pushExceptionOnStack(binding);
-	addExceptionMarker(this.position, binding);
-}
-@Override
-public void goto_(BranchLabel label) {
-	super.goto_(label);
-	addFramePosition(this.position);
-}
-@Override
-public void goto_w(BranchLabel label) {
-	super.goto_w(label);
-	addFramePosition(this.position);
-}
-@Override
-public void resetInWideMode() {
-	this.resetSecretLocals();
-	super.resetInWideMode();
-}
-@Override
-public void resetForCodeGenUnusedLocals() {
-	this.resetSecretLocals();
-	super.resetForCodeGenUnusedLocals();
-}
-public void resetSecretLocals() {
-	for (int i = 0, max = this.locals.length; i < max; i++) {
-		LocalVariableBinding localVariableBinding = this.locals[i];
-		if (localVariableBinding != null && localVariableBinding.isSecret()) {
-			// all other locals are reinitialized inside the computation of their resolved positions
-			localVariableBinding.resetInitializations();
+
+	public void addFramePosition(int pc) {
+		Integer newEntry = Integer.valueOf(pc);
+		FramePosition value;
+		if ((value = (FramePosition) this.framePositions.get(newEntry)) != null) {
+			value.counter++;
+		} else {
+			this.framePositions.put(newEntry, new FramePosition());
 		}
 	}
-}
+
+	@Override
+	public void optimizeBranch(int oldPosition, BranchLabel lbl) {
+		super.optimizeBranch(oldPosition, lbl);
+		removeFramePosition(oldPosition);
+	}
+
+	public void removeFramePosition(int pc) {
+		Integer entry = Integer.valueOf(pc);
+		FramePosition value;
+		if ((value = (FramePosition) this.framePositions.get(entry)) != null) {
+			value.counter--;
+			if (value.counter <= 0) {
+				this.framePositions.remove(entry);
+			}
+		}
+	}
+
+	@Override
+	public void addVariable(LocalVariableBinding localBinding) {
+		if (localBinding.initializationPCs == null) {
+			record(localBinding);
+		}
+		localBinding.recordInitializationStartPC(this.position);
+	}
+
+	@Override
+	public void recordExpressionType(TypeBinding typeBinding, int delta, boolean adjustStackDepth) {
+		if (adjustStackDepth) {
+			// optimized goto
+			// the break label already adjusted the stack depth (-1 or -2 depending on the return type)
+			// we need to adjust back to what it was
+			switch (typeBinding.id) {
+				case TypeIds.T_long:
+				case TypeIds.T_double:
+					this.stackDepth += 2;
+					break;
+				case TypeIds.T_void:
+					break;
+				default:
+					this.stackDepth++;
+					break;
+			}
+		}
+	}
+
+	/**
+	 * Macro for building a class descriptor object
+	 */
+	@Override
+	public void generateClassLiteralAccessForType(Scope scope, TypeBinding accessedType,
+			FieldBinding syntheticFieldBinding) {
+		if (accessedType.isBaseType() && accessedType != TypeBinding.NULL) {
+			getTYPE(accessedType.id);
+			return;
+		}
+
+		if (this.targetLevel >= ClassFileConstants.JDK1_5) {
+			// generation using the new ldc_w bytecode
+			this.ldc(accessedType);
+		} else {
+			// use in CLDC mode
+			BranchLabel endLabel = new BranchLabel(this);
+			if (syntheticFieldBinding != null) { // non interface case
+				fieldAccess(Opcodes.OPC_getstatic, syntheticFieldBinding, null /* default declaringClass */);
+				dup();
+				ifnonnull(endLabel);
+				pop();
+			}
+
+			/*
+			 * Macro for building a class descriptor object... using or not a field cache to store it into... this
+			 * sequence is responsible for building the actual class descriptor.
+			 * 
+			 * If the fieldCache is set, then it is supposed to be the body of a synthetic access method factoring the
+			 * actual descriptor creation out of the invocation site (saving space). If the fieldCache is nil, then we
+			 * are dumping the bytecode on the invocation site, since we have no way to get a hand on the field cache to
+			 * do better.
+			 */
+
+			// Wrap the code in an exception handler to convert a ClassNotFoundException into a NoClassDefError
+
+			ExceptionLabel classNotFoundExceptionHandler = new ExceptionLabel(this,
+					TypeBinding.NULL /* represents ClassNotFoundException */);
+			classNotFoundExceptionHandler.placeStart();
+			this.ldc(accessedType == TypeBinding.NULL ? "java.lang.Object" //$NON-NLS-1$
+					: String.valueOf(accessedType.constantPoolName()).replace('/', '.'));
+			invokeClassForName();
+
+			/*
+			 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=37565 if (accessedType == BaseTypes.NullBinding) {
+			 * this.ldc("java.lang.Object"); //$NON-NLS-1$ } else if (accessedType.isArrayType()) {
+			 * this.ldc(String.valueOf(accessedType.constantPoolName()).replace('/', '.')); } else { // we make it an
+			 * array type (to avoid class initialization) this.ldc("[L" +
+			 * String.valueOf(accessedType.constantPoolName()).replace('/', '.') + ";"); //$NON-NLS-1$//$NON-NLS-2$ }
+			 * this.invokeClassForName(); if (!accessedType.isArrayType()) { // extract the component type, which
+			 * doesn't initialize the class this.invokeJavaLangClassGetComponentType(); }
+			 */
+			/*
+			 * We need to protect the runtime code from binary inconsistencies in case the accessedType is missing, the
+			 * ClassNotFoundException has to be converted into a NoClassDefError(old ex message), we thus need to build
+			 * an exception handler for this one.
+			 */
+			classNotFoundExceptionHandler.placeEnd();
+
+			if (syntheticFieldBinding != null) { // non interface case
+				dup();
+				fieldAccess(Opcodes.OPC_putstatic, syntheticFieldBinding, null /* default declaringClass */);
+			}
+			goto_(endLabel);
+			int savedStackDepth = this.stackDepth;
+			// Generate the body of the exception handler
+			/*
+			 * ClassNotFoundException on stack -- the class literal could be doing more things on the stack, which means
+			 * that the stack may not be empty at this point in the above code gen. So we save its state and restart it
+			 * from 1.
+			 */
+
+			pushExceptionOnStack(scope.getJavaLangClassNotFoundException());
+			classNotFoundExceptionHandler.place();
+
+			// Transform the current exception, and repush and throw a
+			// NoClassDefFoundError(ClassNotFound.getMessage())
+
+			newNoClassDefFoundError();
+			dup_x1();
+			swap();
+
+			// Retrieve the message from the old exception
+			invokeThrowableGetMessage();
+
+			// Send the constructor taking a message string as an argument
+			invokeNoClassDefFoundErrorStringConstructor();
+			athrow();
+			endLabel.place();
+			this.stackDepth = savedStackDepth;
+		}
+	}
+
+	@Override
+	public void generateOuterAccess(Object[] mappingSequence, ASTNode invocationSite, Binding target, Scope scope) {
+		int currentPosition = this.position;
+		super.generateOuterAccess(mappingSequence, invocationSite, target, scope);
+		if (currentPosition == this.position) {
+			// no code has been generate during outer access => no enclosing instance is available
+			throw new AbortMethod(scope.referenceCompilationUnit().compilationResult, null);
+		}
+	}
+
+	public ExceptionMarker[] getExceptionMarkers() {
+		Set exceptionMarkerSet = this.exceptionMarkers;
+		if (this.exceptionMarkers == null)
+			return null;
+		int size = exceptionMarkerSet.size();
+		ExceptionMarker[] markers = new ExceptionMarker[size];
+		int n = 0;
+		for (Iterator iterator = exceptionMarkerSet.iterator(); iterator.hasNext();) {
+			markers[n++] = (ExceptionMarker) iterator.next();
+		}
+		Arrays.sort(markers);
+//  System.out.print('[');
+//  for (int n = 0; n < size; n++) {
+//  	if (n != 0) System.out.print(',');
+//  	System.out.print(positions[n]);
+//  }
+//  System.out.println(']');
+		return markers;
+	}
+
+	public int[] getFramePositions() {
+		Set set = this.framePositions.keySet();
+		int size = set.size();
+		int[] positions = new int[size];
+		int n = 0;
+		for (Iterator iterator = set.iterator(); iterator.hasNext();) {
+			positions[n++] = ((Integer) iterator.next()).intValue();
+		}
+		Arrays.sort(positions);
+//  System.out.print('[');
+//  for (int n = 0; n < size; n++) {
+//  	if (n != 0) System.out.print(',');
+//  	System.out.print(positions[n]);
+//  }
+//  System.out.println(']');
+		return positions;
+	}
+
+	public boolean hasFramePositions() {
+		return this.framePositions.size() != 0;
+	}
+
+	@Override
+	public void init(ClassFile targetClassFile) {
+		super.init(targetClassFile);
+		this.stateIndexesCounter = 0;
+		if (this.framePositions != null) {
+			this.framePositions.clear();
+		}
+		if (this.exceptionMarkers != null) {
+			this.exceptionMarkers.clear();
+		}
+		if (this.stackDepthMarkers != null) {
+			this.stackDepthMarkers.clear();
+		}
+		if (this.stackMarkers != null) {
+			this.stackMarkers.clear();
+		}
+	}
+
+	@Override
+	public void initializeMaxLocals(MethodBinding methodBinding) {
+		super.initializeMaxLocals(methodBinding);
+		if (this.framePositions == null) {
+			this.framePositions = new HashMap();
+		} else {
+			this.framePositions.clear();
+		}
+	}
+
+	public void popStateIndex() {
+		this.stateIndexesCounter--;
+	}
+
+	public void pushStateIndex(int naturalExitMergeInitStateIndex) {
+		if (this.stateIndexes == null) {
+			this.stateIndexes = new int[3];
+		}
+		int length = this.stateIndexes.length;
+		if (length == this.stateIndexesCounter) {
+			// resize
+			System.arraycopy(this.stateIndexes, 0, (this.stateIndexes = new int[length * 2]), 0, length);
+		}
+		this.stateIndexes[this.stateIndexesCounter++] = naturalExitMergeInitStateIndex;
+	}
+
+	@Override
+	public void removeNotDefinitelyAssignedVariables(Scope scope, int initStateIndex) {
+		int index = this.visibleLocalsCount;
+		loop: for (int i = 0; i < index; i++) {
+			LocalVariableBinding localBinding = this.visibleLocals[i];
+			if (localBinding != null && localBinding.initializationCount > 0) {
+				boolean isDefinitelyAssigned = isDefinitelyAssigned(scope, initStateIndex, localBinding);
+				if (!isDefinitelyAssigned) {
+					if (this.stateIndexes != null) {
+						for (int j = 0, max = this.stateIndexesCounter; j < max; j++) {
+							if (isDefinitelyAssigned(scope, this.stateIndexes[j], localBinding)) {
+								continue loop;
+							}
+						}
+					}
+					localBinding.recordInitializationEndPC(this.position);
+				}
+			}
+		}
+	}
+
+	@Override
+	public void reset(ClassFile givenClassFile) {
+		super.reset(givenClassFile);
+		this.stateIndexesCounter = 0;
+		if (this.framePositions != null) {
+			this.framePositions.clear();
+		}
+		if (this.exceptionMarkers != null) {
+			this.exceptionMarkers.clear();
+		}
+		if (this.stackDepthMarkers != null) {
+			this.stackDepthMarkers.clear();
+		}
+		if (this.stackMarkers != null) {
+			this.stackMarkers.clear();
+		}
+	}
+
+	@Override
+	protected void writePosition(BranchLabel label) {
+		super.writePosition(label);
+		addFramePosition(label.position);
+	}
+
+	@Override
+	protected void writePosition(BranchLabel label, int forwardReference) {
+		super.writePosition(label, forwardReference);
+		addFramePosition(label.position);
+	}
+
+	@Override
+	protected void writeSignedWord(int pos, int value) {
+		super.writeSignedWord(pos, value);
+		addFramePosition(this.position);
+	}
+
+	@Override
+	protected void writeWidePosition(BranchLabel label) {
+		super.writeWidePosition(label);
+		addFramePosition(label.position);
+	}
+
+	@Override
+	public void areturn() {
+		super.areturn();
+		addFramePosition(this.position);
+	}
+
+	@Override
+	public void ireturn() {
+		super.ireturn();
+		addFramePosition(this.position);
+	}
+
+	@Override
+	public void lreturn() {
+		super.lreturn();
+		addFramePosition(this.position);
+	}
+
+	@Override
+	public void freturn() {
+		super.freturn();
+		addFramePosition(this.position);
+	}
+
+	@Override
+	public void dreturn() {
+		super.dreturn();
+		addFramePosition(this.position);
+	}
+
+	@Override
+	public void return_() {
+		super.return_();
+		addFramePosition(this.position);
+	}
+
+	@Override
+	public void athrow() {
+		super.athrow();
+		addFramePosition(this.position);
+	}
+
+	@Override
+	public void pushExceptionOnStack(TypeBinding binding) {
+		super.pushExceptionOnStack(binding);
+		addExceptionMarker(this.position, binding);
+	}
+
+	@Override
+	public void goto_(BranchLabel label) {
+		super.goto_(label);
+		addFramePosition(this.position);
+	}
+
+	@Override
+	public void goto_w(BranchLabel label) {
+		super.goto_w(label);
+		addFramePosition(this.position);
+	}
+
+	@Override
+	public void resetInWideMode() {
+		this.resetSecretLocals();
+		super.resetInWideMode();
+	}
+
+	@Override
+	public void resetForCodeGenUnusedLocals() {
+		this.resetSecretLocals();
+		super.resetForCodeGenUnusedLocals();
+	}
+
+	public void resetSecretLocals() {
+		for (int i = 0, max = this.locals.length; i < max; i++) {
+			LocalVariableBinding localVariableBinding = this.locals[i];
+			if (localVariableBinding != null && localVariableBinding.isSecret()) {
+				// all other locals are reinitialized inside the computation of their resolved positions
+				localVariableBinding.resetInitializations();
+			}
+		}
+	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/VerificationTypeInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/VerificationTypeInfo.java
index 38c24a3..d3afd5b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/VerificationTypeInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/VerificationTypeInfo.java
@@ -13,234 +13,237 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.codegen;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
+import org.eclipse.jdt.internal.compiler.lookup.Scope;
 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
 
 public class VerificationTypeInfo {
 	/**
 	 * The tag value representing top variable info
+	 * 
 	 * @since 3.2
 	 */
 	public static final int ITEM_TOP = 0;
 	/**
 	 * The tag value representing integer variable info
+	 * 
 	 * @since 3.2
 	 */
 	public static final int ITEM_INTEGER = 1;
 	/**
 	 * The tag value representing float variable info
+	 * 
 	 * @since 3.2
 	 */
 	public static final int ITEM_FLOAT = 2;
 	/**
 	 * The tag value representing double variable info
+	 * 
 	 * @since 3.2
 	 */
 	public static final int ITEM_DOUBLE = 3;
 	/**
 	 * The tag value representing long variable info
+	 * 
 	 * @since 3.2
 	 */
 	public static final int ITEM_LONG = 4;
 	/**
 	 * The tag value representing null variable info
+	 * 
 	 * @since 3.2
 	 */
 	public static final int ITEM_NULL = 5;
 	/**
 	 * The tag value representing uninitialized this variable info
+	 * 
 	 * @since 3.2
 	 */
 	public static final int ITEM_UNINITIALIZED_THIS = 6;
 	/**
 	 * The tag value representing object variable info
+	 * 
 	 * @since 3.2
 	 */
 	public static final int ITEM_OBJECT = 7;
 	/**
 	 * The tag value representing uninitialized variable info
+	 * 
 	 * @since 3.2
 	 */
 	public static final int ITEM_UNINITIALIZED = 8;
 
 	public int tag;
 	private int id;
-	private char[] constantPoolName;
-	public int offset;
+	private TypeBinding binding;
+	public int offset; // where the new opcode is used
+	private List<TypeBinding> bindings;
 
-private VerificationTypeInfo() {
-	// for duplication
-}
-public VerificationTypeInfo(int id, char[] constantPoolName) {
-	this(id, VerificationTypeInfo.ITEM_OBJECT, constantPoolName);
-}
-public VerificationTypeInfo(int id, int tag, char[] constantPoolName) {
-	this.id = id;
-	this.tag = tag;
-	this.constantPoolName = constantPoolName;
-}
-public VerificationTypeInfo(int tag, TypeBinding binding) {
-	this(binding);
-	this.tag = tag;
-}
-public VerificationTypeInfo(TypeBinding binding) {
-	this.id = binding.id;
-	switch(binding.id) {
-		case TypeIds.T_boolean :
-		case TypeIds.T_byte :
-		case TypeIds.T_char :
-		case TypeIds.T_int :
-		case TypeIds.T_short :
-			this.tag = VerificationTypeInfo.ITEM_INTEGER;
-			break;
-		case TypeIds.T_float :
-			this.tag = VerificationTypeInfo.ITEM_FLOAT;
-			break;
-		case TypeIds.T_long :
-			this.tag = VerificationTypeInfo.ITEM_LONG;
-			break;
-		case TypeIds.T_double :
-			this.tag = VerificationTypeInfo.ITEM_DOUBLE;
-			break;
-		case TypeIds.T_null :
-			this.tag = VerificationTypeInfo.ITEM_NULL;
-			break;
-		default:
-			this.tag =  VerificationTypeInfo.ITEM_OBJECT;
-			this.constantPoolName = binding.constantPoolName();
+	public VerificationTypeInfo(int tag, TypeBinding binding) {
+		this(binding);
+		this.tag = tag;
 	}
-}
-public void setBinding(TypeBinding binding) {
-	this.constantPoolName = binding.constantPoolName();
-	final int typeBindingId = binding.id;
-	this.id = typeBindingId;
-	switch(typeBindingId) {
-		case TypeIds.T_boolean :
-		case TypeIds.T_byte :
-		case TypeIds.T_char :
-		case TypeIds.T_int :
-		case TypeIds.T_short :
-			this.tag = VerificationTypeInfo.ITEM_INTEGER;
-			break;
-		case TypeIds.T_float :
-			this.tag = VerificationTypeInfo.ITEM_FLOAT;
-			break;
-		case TypeIds.T_long :
-			this.tag = VerificationTypeInfo.ITEM_LONG;
-			break;
-		case TypeIds.T_double :
-			this.tag = VerificationTypeInfo.ITEM_DOUBLE;
-			break;
-		case TypeIds.T_null :
-			this.tag = VerificationTypeInfo.ITEM_NULL;
-			break;
-		default:
-			this.tag =  VerificationTypeInfo.ITEM_OBJECT;
-	}
-}
-public int id() {
-	return this.id;
-}
-@Override
-public String toString() {
-	StringBuffer buffer = new StringBuffer();
-	switch(this.tag) {
-		case VerificationTypeInfo.ITEM_UNINITIALIZED_THIS :
-			buffer.append("uninitialized_this(").append(readableName()).append(")"); //$NON-NLS-1$//$NON-NLS-2$
-			break;
-		case VerificationTypeInfo.ITEM_UNINITIALIZED :
-			buffer.append("uninitialized(").append(readableName()).append(")"); //$NON-NLS-1$//$NON-NLS-2$
-			break;
-		case VerificationTypeInfo.ITEM_OBJECT :
-			buffer.append(readableName());
-			break;
-		case VerificationTypeInfo.ITEM_DOUBLE :
-			buffer.append('D');
-			break;
-		case VerificationTypeInfo.ITEM_FLOAT :
-			buffer.append('F');
-			break;
-		case VerificationTypeInfo.ITEM_INTEGER :
-			buffer.append('I');
-			break;
-		case VerificationTypeInfo.ITEM_LONG :
-			buffer.append('J');
-			break;
-		case VerificationTypeInfo.ITEM_NULL :
-			buffer.append("null"); //$NON-NLS-1$
-			break;
-		case VerificationTypeInfo.ITEM_TOP :
-			buffer.append("top"); //$NON-NLS-1$
-			break;
-	}
-	return String.valueOf(buffer);
-}
-public VerificationTypeInfo duplicate() {
-	final VerificationTypeInfo verificationTypeInfo = new VerificationTypeInfo();
-	verificationTypeInfo.id = this.id;
-	verificationTypeInfo.tag = this.tag;
-	verificationTypeInfo.constantPoolName = this.constantPoolName;
-	verificationTypeInfo.offset = this.offset;
-	return verificationTypeInfo;
-}
-@Override
-public boolean equals(Object obj) {
-	if (obj instanceof VerificationTypeInfo) {
-		VerificationTypeInfo info1 = (VerificationTypeInfo) obj;
-		return info1.tag == this.tag && CharOperation.equals(info1.constantPoolName(), constantPoolName());
-	}
-	return false;
-}
-@Override
-public int hashCode() {
-	return this.tag + this.id + this.constantPoolName.length + this.offset;
-}
-public char[] constantPoolName() {
-	return this.constantPoolName;
-}
-public char[] readableName() {
-	return this.constantPoolName;
-}
-public void replaceWithElementType() {
-	if (this.constantPoolName[1] == 'L') {
-		this.constantPoolName = CharOperation.subarray(this.constantPoolName, 2,  this.constantPoolName.length - 1);
-	} else {
-		this.constantPoolName = CharOperation.subarray(this.constantPoolName, 1, this.constantPoolName.length);
-		if (this.constantPoolName.length == 1) {
-			switch(this.constantPoolName[0]) {
-				case 'I' :
-					this.id = TypeIds.T_int;
-					break;
-				case 'B' :
-					this.id = TypeIds.T_byte;
-					break;
-				case 'S' :
-					this.id = TypeIds.T_short;
-					break;
-				case 'C' :
-					this.id = TypeIds.T_char;
-					break;
-				case 'J' :
-					this.id = TypeIds.T_long;
-					break;
-				case 'F' :
-					this.id = TypeIds.T_float;
-					break;
-				case 'D' :
-					this.id = TypeIds.T_double;
-					break;
-				case 'Z' :
-					this.id = TypeIds.T_boolean;
-					break;
-				case 'N' :
-					this.id = TypeIds.T_null;
-					break;
-				case 'V' :
-					this.id = TypeIds.T_void;
-					break;
-			}
+
+	public VerificationTypeInfo(TypeBinding binding) {
+		if (binding == null) return;
+		this.id = binding.id;
+		this.binding = binding;
+		switch (binding.id) {
+			case TypeIds.T_boolean:
+			case TypeIds.T_byte:
+			case TypeIds.T_char:
+			case TypeIds.T_int:
+			case TypeIds.T_short:
+				this.tag = VerificationTypeInfo.ITEM_INTEGER;
+				break;
+			case TypeIds.T_float:
+				this.tag = VerificationTypeInfo.ITEM_FLOAT;
+				break;
+			case TypeIds.T_long:
+				this.tag = VerificationTypeInfo.ITEM_LONG;
+				break;
+			case TypeIds.T_double:
+				this.tag = VerificationTypeInfo.ITEM_DOUBLE;
+				break;
+			case TypeIds.T_null:
+				this.tag = VerificationTypeInfo.ITEM_NULL;
+				break;
+			default:
+				this.tag = VerificationTypeInfo.ITEM_OBJECT;
 		}
 	}
-}
+
+	public void setBinding(TypeBinding binding) {
+		final int typeBindingId = binding.id;
+		this.id = typeBindingId;
+		switch (typeBindingId) {
+			case TypeIds.T_boolean:
+			case TypeIds.T_byte:
+			case TypeIds.T_char:
+			case TypeIds.T_int:
+			case TypeIds.T_short:
+				this.tag = VerificationTypeInfo.ITEM_INTEGER;
+				break;
+			case TypeIds.T_float:
+				this.tag = VerificationTypeInfo.ITEM_FLOAT;
+				break;
+			case TypeIds.T_long:
+				this.tag = VerificationTypeInfo.ITEM_LONG;
+				break;
+			case TypeIds.T_double:
+				this.tag = VerificationTypeInfo.ITEM_DOUBLE;
+				break;
+			case TypeIds.T_null:
+				this.tag = VerificationTypeInfo.ITEM_NULL;
+				break;
+			default:
+				this.tag = VerificationTypeInfo.ITEM_OBJECT;
+		}
+	}
+
+	public int id() {
+		return this.id;
+	}
+
+	@Override
+	public String toString() {
+		StringBuffer buffer = new StringBuffer();
+		switch (this.tag) {
+			case VerificationTypeInfo.ITEM_UNINITIALIZED_THIS:
+				buffer.append("uninitialized_this(").append(readableName()).append(")"); //$NON-NLS-1$//$NON-NLS-2$
+				break;
+			case VerificationTypeInfo.ITEM_UNINITIALIZED:
+				buffer.append("uninitialized(").append(readableName()).append(")"); //$NON-NLS-1$//$NON-NLS-2$
+				break;
+			case VerificationTypeInfo.ITEM_OBJECT:
+				buffer.append(readableName());
+				break;
+			case VerificationTypeInfo.ITEM_DOUBLE:
+				buffer.append('D');
+				break;
+			case VerificationTypeInfo.ITEM_FLOAT:
+				buffer.append('F');
+				break;
+			case VerificationTypeInfo.ITEM_INTEGER:
+				buffer.append('I');
+				break;
+			case VerificationTypeInfo.ITEM_LONG:
+				buffer.append('J');
+				break;
+			case VerificationTypeInfo.ITEM_NULL:
+				buffer.append("null"); //$NON-NLS-1$
+				break;
+			case VerificationTypeInfo.ITEM_TOP:
+				buffer.append("top"); //$NON-NLS-1$
+				break;
+		}
+		return String.valueOf(buffer);
+	}
+
+	public VerificationTypeInfo duplicate() {
+		VerificationTypeInfo verificationTypeInfo = new VerificationTypeInfo(this.tag, this.binding);
+		verificationTypeInfo.offset = this.offset;
+		return verificationTypeInfo;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (obj instanceof VerificationTypeInfo) {
+			VerificationTypeInfo info1 = (VerificationTypeInfo) obj;
+			return info1.tag == this.tag && CharOperation.equals(info1.constantPoolName(), constantPoolName());
+		}
+		return false;
+	}
+
+	@Override
+	public int hashCode() {
+		return this.tag + this.id + this.binding.constantPoolName().length;
+	}
+
+	public char[] constantPoolName() {
+		return this.binding.constantPoolName();
+	}
+
+	public char[] readableName() {
+		return this.constantPoolName();
+	}
+
+	public void replaceWithElementType() {
+		ArrayBinding arrayBinding = (ArrayBinding) this.binding;
+		this.binding = arrayBinding.elementsType();
+		this.id = this.binding.id;
+	}
+
+	public VerificationTypeInfo merge(VerificationTypeInfo verificationTypeInfo, Scope scope) {
+		if (this.binding.isBaseType() && verificationTypeInfo.binding.isBaseType()) {
+			return this;
+		}
+		if (!this.binding.equals(verificationTypeInfo.binding)) {
+			if (this.bindings == null) {
+				this.bindings = new ArrayList<TypeBinding>();
+				this.bindings.add(this.binding);
+			}
+			this.bindings.add(verificationTypeInfo.binding);
+			this.binding = scope.lowerUpperBound(this.bindings.toArray(new TypeBinding[this.bindings.size()]));
+			if (this.binding != null) {
+				this.id = this.binding.id;
+				switch (this.id) {
+					case TypeIds.T_null:
+						this.tag = VerificationTypeInfo.ITEM_NULL;
+						break;
+					default:
+						this.tag = VerificationTypeInfo.ITEM_OBJECT;
+				}
+			} else {
+				this.binding = scope.getJavaLangObject();
+				this.tag = VerificationTypeInfo.ITEM_OBJECT;
+			}
+		}
+		return this;
+	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
index 7d9fa4f..a9f41fb 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
@@ -1292,18 +1292,18 @@
 				return "dep-ann"; //$NON-NLS-1$
 			case RawTypeReference :
 				return "rawtypes"; //$NON-NLS-1$
-			case UnusedLabel :
-			case UnusedTypeArguments :
+			case DeadCode :
 			case RedundantSuperinterface :
-			case UnusedLocalVariable :
-			case UnusedArgument :
+			case RedundantSpecificationOfTypeArguments :
+			case UnusedDeclaredThrownException :
 			case UnusedExceptionParameter :
 			case UnusedImport :
-			case UnusedPrivateMember :
-			case UnusedDeclaredThrownException :
-			case DeadCode :
+			case UnusedLabel :
+			case UnusedLocalVariable :
 			case UnusedObjectAllocation :
-			case RedundantSpecificationOfTypeArguments :
+			case UnusedArgument : 		// OPTION_ReportUnusedParameter
+			case UnusedPrivateMember :
+			case UnusedTypeArguments : 	// OPTION_ReportUnusedTypeArgumentsForMethodInvocation
 			case UnusedTypeParameter:
 				return "unused"; //$NON-NLS-1$
 			case DiscouragedReference :
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
index 1542692..9e2aebf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
@@ -2021,6 +2021,10 @@
 	this.tagBits |= TagBits.AreMethodsComplete;
 	return this.methods;
 }
+@Override
+public void setHierarchyCheckDone() {
+	this.tagBits |= TagBits.BeginHierarchyCheck | TagBits.EndHierarchyCheck;
+}
 
 @Override
 public TypeBinding prototype() {
@@ -2545,8 +2549,60 @@
 	this.typeBits |= (this.superclass.typeBits & TypeIds.InheritableBits);
 	if ((this.typeBits & (TypeIds.BitAutoCloseable|TypeIds.BitCloseable)) != 0) // avoid the side-effects of hasTypeBit()! 
 		this.typeBits |= applyCloseableClassWhitelists();
+	detectCircularHierarchy();
 	return this.superclass;
 }
+
+private void breakLoop() {
+	ReferenceBinding currentSuper = this.superclass;
+	ReferenceBinding prevSuper = null;
+	while (currentSuper != null) {
+		if ((currentSuper.tagBits & TagBits.EndHierarchyCheck) != 0 && prevSuper instanceof BinaryTypeBinding) {
+			((BinaryTypeBinding)prevSuper).superclass = this.environment.getResolvedType(TypeConstants.JAVA_LANG_OBJECT, null);
+			break;
+		}
+		currentSuper.tagBits |= TagBits.EndHierarchyCheck;
+		prevSuper = currentSuper;
+		currentSuper = currentSuper.superclass();
+	}	
+}
+
+private void detectCircularHierarchy() {
+	ReferenceBinding currentSuper = this.superclass;
+	ReferenceBinding tempSuper = null;
+	int count = 0;
+	int skipCount = 20;
+	while (currentSuper != null) {		
+		if (currentSuper.hasHierarchyCheckStarted())
+			break;
+		if (TypeBinding.equalsEquals(currentSuper, this) || TypeBinding.equalsEquals(currentSuper, tempSuper)) {
+			currentSuper.tagBits |= TagBits.HierarchyHasProblems;
+			if (currentSuper.isBinaryBinding())
+				breakLoop();
+			
+			return;
+		}
+		if (count == skipCount) {
+			tempSuper = currentSuper; // for finding loops that only start after a linear chain
+			skipCount *= 2;
+			count = 0;
+		}
+		//Ignore if the super is not yet resolved..
+		if (!currentSuper.isHierarchyConnected()) 
+			return;
+		currentSuper = currentSuper.superclass();	
+		count++;
+	}
+	/* No loop detected and completely found that there is no loop
+	 * So, set that info for all the classes 
+	 */
+	tempSuper = this;
+	while (TypeBinding.notEquals(currentSuper, tempSuper)) {
+		tempSuper.setHierarchyCheckDone();
+		tempSuper=tempSuper.superclass();
+	}	
+}
+
 //{ObjectTeams:
 @Override
 public ReferenceBinding baseclass () {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
index 7c3f8cd..b7c11f4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
@@ -440,6 +440,15 @@
 	return methods();
 }
 
+public boolean hasHierarchyCheckStarted() {
+	return  (this.tagBits & TagBits.BeginHierarchyCheck) != 0;
+}
+
+public void setHierarchyCheckDone() {
+	return;
+}
+
+
 /**
  * Answer true if the receiver can be instantiated
  */
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
index 7dc9404..6a83d2f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
@@ -3106,6 +3106,16 @@
 		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_CLONEABLE);
 		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_CLONEABLE, this);
 	}
+	public final ReferenceBinding getJavaLangClassNotFoundException() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_CLASSNOTFOUNDEXCEPTION);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_CLASSNOTFOUNDEXCEPTION, this);
+	}
+	public final ReferenceBinding getJavaLangNoSuchFieldError() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_NOSUCHFIELDERROR);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_NOSUCHFIELDERROR, this);
+	}
 	public final ReferenceBinding getJavaLangEnum() {
 		CompilationUnitScope unitScope = compilationUnitScope();
 		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_ENUM);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
index 8fd55e7..e096688 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
@@ -144,6 +144,7 @@
 	char[][] JAVA_LANG_ASSERTIONERROR = {JAVA, LANG, "AssertionError".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_LANG_CLASS = {JAVA, LANG, "Class".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_LANG_CLASSNOTFOUNDEXCEPTION = {JAVA, LANG, "ClassNotFoundException".toCharArray()}; //$NON-NLS-1$
+	char[][] JAVA_LANG_NOSUCHFIELDERROR = {JAVA, LANG, "NoSuchFieldError".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_LANG_CLONEABLE = {JAVA, LANG, "Cloneable".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_LANG_ENUM = {JAVA, LANG, "Enum".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_LANG_EXCEPTION = {JAVA, LANG, "Exception".toCharArray()}; //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
index e89f9fb..83f1800 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
@@ -2022,14 +2022,14 @@
 						if (isTextBlock) {
 							if (lastQuotePos > 0)
 								this.currentPosition = lastQuotePos;
+							this.currentPosition = (lastQuotePos > 0) ? lastQuotePos : this.startPosition + this.rawStart;
 							throw new InvalidInputException(UNTERMINATED_TEXT_BLOCK);
 						} else {
 							throw new InvalidInputException(UNTERMINATED_STRING);
 						}
 					} catch (IndexOutOfBoundsException e) {
 						if (isTextBlock) {
-							if (lastQuotePos > 0)
-								this.currentPosition = lastQuotePos;
+							this.currentPosition = (lastQuotePos > 0) ? lastQuotePos : this.startPosition + this.rawStart;
 							throw new InvalidInputException(UNTERMINATED_TEXT_BLOCK);
 						} else {
 							this.currentPosition--;
@@ -2462,32 +2462,61 @@
 						break NextToken;
 					}
 				case '"' :
+					boolean isTextBlock = false;
+					int firstClosingBrace = 0;
 					try {
 						try { // consume next character
-							this.unicodeAsBackSlash = false;
-							if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
-									&& (this.source[this.currentPosition] == 'u')) {
-								getNextUnicodeChar();
-							} else {
-								if (this.withoutUnicodePtr != 0) {
-									unicodeStore();
+							isTextBlock = scanForTextBlockBeginning();
+							if (!isTextBlock) {
+								this.unicodeAsBackSlash = false;
+								if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+										&& (this.source[this.currentPosition] == 'u')) {
+									getNextUnicodeChar();
+								} else {
+									if (this.withoutUnicodePtr != 0) {
+										unicodeStore();
+									}
 								}
 							}
 						} catch (InvalidInputException ex) {
 								// ignore
 						}
-						while (this.currentCharacter != '"') {
-							if (this.currentPosition >= this.eofPosition) {
-								return;
+						
+						Inner: while (this.currentPosition <= this.eofPosition) {
+							if (isTextBlock) {
+								switch (this.currentCharacter) {
+									case '"':
+										// look for text block delimiter
+										if (scanForTextBlockClose()) {
+											this.currentPosition += 2;
+											this.currentCharacter = this.source[this.currentPosition];
+											isTextBlock = false;
+											break Inner;
+										}
+										break;
+									case '}':
+										if (firstClosingBrace == 0)
+											firstClosingBrace = this.currentPosition;
+										break;
+									case '\r' :
+										if (this.source[this.currentPosition] == '\n') 
+											this.currentPosition++;
+										//$FALL-THROUGH$
+									case '\n' :
+										pushLineSeparator();
+										//$FALL-THROUGH$
+									default: 
+										this.currentCharacter = this.source[this.currentPosition++];
+										continue Inner;
+								}
+							} else if (this.currentCharacter == '"') {
+								break Inner;
 							}
 							if (this.currentCharacter == '\r'){
-								// For text block, we don't want to overlook \n. Hence, don't advance past \n
-								//if (this.source[this.currentPosition] == '\n') this.currentPosition++;
+								if (this.source[this.currentPosition] == '\n') this.currentPosition++;
 								break NextToken; // the string cannot go further that the line
 							}
 							if (this.currentCharacter == '\n'){
-								// For text block, we don't want to overlook \n. Hence, go back one char
-								this.currentPosition--;
 								break; // the string cannot go further that the line
 							}
 							if (this.currentCharacter == '\\') {
@@ -2525,7 +2554,13 @@
 							}
 						}
 					} catch (IndexOutOfBoundsException e) {
-						return;
+						if(isTextBlock) {
+							// Pull it back to the first closing brace after the beginning
+							// of the unclosed text block and let recovery take over.
+							if (firstClosingBrace > 0) {
+								this.currentPosition = firstClosingBrace - 1;
+							}
+						}
 					}
 					break NextToken;
 				case '/' :
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java
index 22aee8f..8bf8ff2 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java
@@ -479,7 +479,6 @@
 
 	/**
 	 * Creates a new Java abstract syntax tree
-	 * <p>
 	 * Following option keys are significant:
 	 * <ul>
 	 * <li><code>"org.eclipse.jdt.core.compiler.source"</code>
@@ -489,18 +488,17 @@
 	 *    	<code>"1.3"</code> means the source code is as per JDK 1.3 and api level {@link #JLS3}.</li>
 	 *    	<li><code>"1.4", "1.5", "1.6", "1.7" "1.8"</code> implies the respective source JDK levels 1.4, 1.5, 1.6, 1.7 and api level {@link #JLS4}.</li>
 	 *    	<li><code>"1.8"</code> implies the respective source JDK level 1.8 and api level {@link #JLS8}.</li>
-	 *    	<li><code>"9", "10", "11" "12"</code> implies the respective JDK levels 9, 10, 11 and 12
-	 *     	and api levels {@link #JLS9}, {@link #JLS10}, {@link #JLS11}, and {@link #JLS12}.</li>
-	 *    	Additional legal values may be added later.
-	 *    	</li>
+	 *    	<li><code>"9", "10", "11", "12" and "13"</code> implies the respective JDK levels 9, 10, 11, 12 and 13
+	 *     	and api levels {@link #JLS9}, {@link #JLS10}, {@link #JLS11}, {@link #JLS12} and {@link #JLS13}.</li>
+	 *    	<li>Additional legal values may be added later.</li>
 	 *    </ul>
+	 * </li>
 	 * <li><code>"org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures"</code> -
 	 *    indicates whether the preview is enabled or disabled
 	 *    legal values are <code>"enabled"</code> and  <code>"disabled"</code> implying preview enabled and disabled respectively.
 	 *    preview enabling has an effect only with the latest ast level.
+	 * </li>
 	 * </ul>
-	 * <p>
-	 * </p>
 	 *
 	 * @param options the table of options
 	 * @see JavaCore#getDefaultOptions()
@@ -1014,7 +1012,6 @@
 
 	/**
 	 * Creates a new Java abstract syntax tree
-	 * <p>
 	 * Following option keys are significant:
 	 * <ul>
 	 * <li><code>"org.eclipse.jdt.core.compiler.source"</code>
@@ -1024,18 +1021,16 @@
 	 *    	<code>"1.3"</code> means the source code is as per JDK 1.3 and api level {@link #JLS3}.</li>
 	 *    	<li><code>"1.4", "1.5", "1.6", "1.7" "1.8"</code> implies the respective source JDK levels 1.4, 1.5, 1.6, 1.7 and api level {@link #JLS4}.</li>
 	 *    	<li><code>"1.8"</code> implies the respective source JDK level 1.8 and api level {@link #JLS8}.</li>
-	 *    	<li><code>"9", "10", "11" "12"</code> implies the respective JDK levels 9, 10, 11 and 12
-	 *     	and api levels {@link #JLS9}, {@link #JLS10}, {@link #JLS11}, and {@link #JLS12}.</li>
-	 *    	Additional legal values may be added later.
-	 *    	</li>
+	 *    	<li><code>"9", "10", "11", "12" and "13"</code> implies the respective JDK levels 9, 10, 11, 12 and 13
+	 *     	and api levels {@link #JLS9}, {@link #JLS10}, {@link #JLS11}, {@link #JLS12} and {@link #JLS13}.</li>
+	 *    	<li>Additional legal values may be added later.</li>
 	 *    </ul>
-	 * <li><code>"org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures"</code> -
-	 *    indicates whether the preview is enabled or disabled
-	 *    legal values are <code>"enabled"</code> and  <code>"disabled"</code> implying preview enabled and disabled respectively.
-	 *    preview enabling has an effect only with the latest ast level.
-	 * </ul>
-	 * <p>
-	 * </p>
+	 * 	<li><code>"org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures"</code> -
+	 *    	indicates whether the preview is enabled or disabled
+	 *    	legal values are <code>"enabled"</code> and  <code>"disabled"</code> implying preview enabled and disabled respectively.
+	 *    	preview enabling has an effect only with the latest ast level.
+	 *  </li>
+	 * 	</ul>
 	 *
 	 * @param options the table of options (key type: <code>String</code>;
 	 *    value type: <code>String</code>)
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java
index 52ddf5c..f257a1a 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -32,6 +32,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding;
+import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding18;
 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
 import org.eclipse.jdt.internal.compiler.lookup.IntersectionTypeBinding18;
 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
@@ -596,7 +597,7 @@
 		if (length != 0) {
 //{ObjectTeams: make synth role ifc transparent by transitively fetching it's super interfaces:
 //          accumulate into list not array because we may exceed length:
-			List/*<ITypeBinding>*/ interfacesList = new ArrayList(length);
+			List<ITypeBinding> interfacesList = new ArrayList<>(length);
 /* orig:
 			ITypeBinding[] newInterfaces = new ITypeBinding[length];
 			int interfacesCounter = 0;
@@ -631,7 +632,7 @@
 //  OT: collect into list instead of array:
 				interfacesList.add(typeBinding);
 			}
-			ITypeBinding[] newInterfaces = (ITypeBinding[]) interfacesList.toArray(new ITypeBinding[interfacesList.size()]);
+			ITypeBinding[] newInterfaces = interfacesList.toArray(new ITypeBinding[interfacesList.size()]);
 /*    orig:
 				newInterfaces[interfacesCounter++] = typeBinding;
 			}
@@ -1210,7 +1211,7 @@
 
 	@Override
 	public boolean isCapture() {
-		return this.binding.isCapture();
+		return this.binding.isCapture() && !(this.binding instanceof CaptureBinding18);
 	}
 
 	@Override
@@ -1551,13 +1552,22 @@
 				return ((WildcardBinding) this.binding).boundKind == Wildcard.EXTENDS;
 			case Binding.INTERSECTION_TYPE :
 				return true;
+			case Binding.TYPE_PARAMETER:
+				if (this.binding instanceof CaptureBinding18) {
+					CaptureBinding18 captureBinding18 = (CaptureBinding18) this.binding;
+					org.eclipse.jdt.internal.compiler.lookup.TypeBinding upperBound = captureBinding18.upperBound();
+					if (upperBound != null && upperBound.id != TypeIds.T_JavaLangObject) {
+						return true;
+					}
+				}
+				return false;
 		}
 		return false;
 	}
 
 	@Override
 	public boolean isWildcardType() {
-		return this.binding.isWildcard();
+		return this.binding.isWildcard() || this.binding instanceof CaptureBinding18;
 	}
 
 //{ObjectTeams: additional queries based on this.binding:
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetReturnStatement.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetReturnStatement.java
index 96052a9..ccd04ea 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetReturnStatement.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetReturnStatement.java
@@ -62,7 +62,7 @@
 	codeStream.return_();
 }
 @Override
-public void generateStoreSaveValueIfNecessary(CodeStream codeStream){
+public void generateStoreSaveValueIfNecessary(Scope scope, CodeStream codeStream){
 
 	// push receiver
 	codeStream.aload_0();
@@ -73,7 +73,7 @@
 		codeStream.aconst_null();
 
 		// void.class
-		codeStream.generateClassLiteralAccessForType(TypeBinding.VOID, null);
+		codeStream.generateClassLiteralAccessForType(scope, TypeBinding.VOID, null);
 	} else {
 		// swap with expression
 		int valueTypeID = this.expression.resolvedType.id;
@@ -90,7 +90,7 @@
 		}
 
 		// generate the expression type
-		codeStream.generateClassLiteralAccessForType(this.expression.resolvedType, null);
+		codeStream.generateClassLiteralAccessForType(scope, this.expression.resolvedType, null);
 	}
 
 	// generate the invoke virtual to "setResult(Object,Class)"
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
index 1481eac..31f10d7 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
@@ -1893,6 +1893,21 @@
 
 	/**
 	 * <pre>
+	 * FORMATTER / Option to specify how text blocks are indented
+	 *     - option id:         "org.eclipse.jdt.core.formatter.text_block_indentation"
+	 *     - possible values:   { INDENT_PRESERVE, INDENT_BY_ONE, INDENT_DEFAULT, INDENT_ON_COLUMN }
+	 *     - default:           INDENT_DEFAULT
+	 * </pre>
+	 * @see #INDENT_PRESERVE
+	 * @see #INDENT_BY_ONE
+	 * @see #INDENT_DEFAULT
+	 * @see #INDENT_ON_COLUMN
+	 * @since 3.19
+	 */
+	public static final String FORMATTER_TEXT_BLOCK_INDENTATION = JavaCore.PLUGIN_ID + ".formatter.text_block_indentation"; //$NON-NLS-1$
+
+	/**
+	 * <pre>
 	 * FORMATTER / Option to insert a new line after an annotation
 	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_new_line_after_annotation"
 	 *     - possible values:   { INSERT, DO_NOT_INSERT }
@@ -5060,6 +5075,13 @@
 	 * @since 3.0
 	 */
 	public static final int INDENT_ON_COLUMN = 1;
+	/**
+	 * <pre>
+	 * FORMATTER / Indentation is not touched, it's preserved from original source.
+	 * </pre>
+	 * @since 3.19
+	 */
+	public static final int INDENT_PRESERVE = 3;
 
 	/**
 	 * <pre>
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java
index 3788db3..6a4156c 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java
@@ -313,7 +313,7 @@
 		resultBuilder.setAlignChar(DefaultCodeFormatterOptions.SPACE);
 		for (Token token : this.tokens) {
 			List<Token> structure = token.getInternalStructure();
-			if (structure != null && !structure.isEmpty())
+			if (token.isComment() && structure != null && !structure.isEmpty())
 				resultBuilder.processComment(token);
 		}
 
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
index 5c86ffd..7dad994 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
@@ -49,6 +49,8 @@
 		public static final int M_FORCE = 1; // if bit set, then alignment will be non-optional (default is optional)
 		public static final int M_INDENT_ON_COLUMN = 2; // if bit set, broken fragments will be aligned on current location column (default is to break at current indentation level)
 		public static final int	M_INDENT_BY_ONE = 4; // if bit set, broken fragments will be indented one level below current (not using continuation indentation)
+		public static final int M_INDENT_DEFAULT = 0;
+		public static final int M_INDENT_PRESERVE = 8;
 
 		// split modes can be combined either with M_FORCE or M_INDENT_ON_COLUMN
 
@@ -486,6 +488,7 @@
 	public int page_width;
 	public int tab_char;
 	public boolean use_tabs_only_for_leading_indentations;
+	public int text_block_indentation;
 	public boolean wrap_before_multiplicative_operator;
 	public boolean wrap_before_additive_operator;
 	public boolean wrap_before_string_concatenation;
@@ -877,6 +880,26 @@
 		}
 		options.put(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, Integer.toString(this.tab_char == SPACE ? this.indentation_size : this.tab_size)); // reverse values swapping performed by IndentationTabPage
 		options.put(DefaultCodeFormatterConstants.FORMATTER_USE_TABS_ONLY_FOR_LEADING_INDENTATIONS, this.use_tabs_only_for_leading_indentations ?  DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
+
+		int textBlockIndentation;
+		switch (this.text_block_indentation) {
+			case Alignment.M_INDENT_PRESERVE:
+				textBlockIndentation = DefaultCodeFormatterConstants.INDENT_PRESERVE;
+				break;
+			case Alignment.M_INDENT_BY_ONE:
+				textBlockIndentation = DefaultCodeFormatterConstants.INDENT_BY_ONE;
+				break;
+			case Alignment.M_INDENT_DEFAULT:
+				textBlockIndentation = DefaultCodeFormatterConstants.INDENT_DEFAULT;
+				break;
+			case Alignment.M_INDENT_ON_COLUMN:
+				textBlockIndentation = DefaultCodeFormatterConstants.INDENT_ON_COLUMN;
+				break;
+			default:
+				throw new IllegalArgumentException("Invalid text block indentation: " + this.text_block_indentation); //$NON-NLS-1$
+		}
+		options.put(DefaultCodeFormatterConstants.FORMATTER_TEXT_BLOCK_INDENTATION, Integer.toString(textBlockIndentation));
+
 		options.put(DefaultCodeFormatterConstants.FORMATTER_WRAP_BEFORE_MULTIPLICATIVE_OPERATOR, this.wrap_before_multiplicative_operator ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_WRAP_BEFORE_ADDITIVE_OPERATOR, this.wrap_before_additive_operator ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_WRAP_BEFORE_STRING_CONCATENATION, this.wrap_before_string_concatenation ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
@@ -2370,6 +2393,19 @@
 		if (useTabsOnlyForLeadingIndentationsOption != null) {
 			this.use_tabs_only_for_leading_indentations = DefaultCodeFormatterConstants.TRUE.equals(useTabsOnlyForLeadingIndentationsOption);
 		}
+		setInt(settings, DefaultCodeFormatterConstants.FORMATTER_TEXT_BLOCK_INDENTATION, v -> {
+			if (DefaultCodeFormatterConstants.INDENT_PRESERVE == v) {
+				this.text_block_indentation = Alignment.M_INDENT_PRESERVE;
+			} else if (DefaultCodeFormatterConstants.INDENT_BY_ONE == v) {
+				this.text_block_indentation = Alignment.M_INDENT_BY_ONE;
+			} else if (DefaultCodeFormatterConstants.INDENT_DEFAULT == v) {
+				this.text_block_indentation = Alignment.M_INDENT_DEFAULT;
+			} else if (DefaultCodeFormatterConstants.INDENT_ON_COLUMN == v) {
+				this.text_block_indentation = Alignment.M_INDENT_ON_COLUMN;
+			} else {
+				throw new IllegalArgumentException("invalid text block setting: " + v); //$NON-NLS-1$
+			}
+		});
 		final Object pageWidthOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_LINE_SPLIT);
 		if (pageWidthOption != null) {
 			try {
@@ -3112,6 +3148,7 @@
 		this.page_width = 120;
 		this.tab_char = TAB; // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=49081
 		this.use_tabs_only_for_leading_indentations = false;
+		this.text_block_indentation = Alignment.M_INDENT_DEFAULT;
 		this.wrap_before_multiplicative_operator = true;
 		this.wrap_before_additive_operator = true;
 		this.wrap_before_string_concatenation = true;
@@ -3478,6 +3515,7 @@
 		this.page_width = 120;
 		this.tab_char = MIXED;
 		this.use_tabs_only_for_leading_indentations = false;
+		this.text_block_indentation = Alignment.M_INDENT_DEFAULT;
 		this.wrap_before_multiplicative_operator = true;
 		this.wrap_before_additive_operator = true;
 		this.wrap_before_string_concatenation = true;
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/LineBreaksPreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/LineBreaksPreparator.java
index c143a01..18026f7 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/LineBreaksPreparator.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/LineBreaksPreparator.java
@@ -23,6 +23,7 @@
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameLBRACE;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameRBRACE;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameSEMICOLON;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameTextBlock;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamebase;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameelse;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNamefinally;
@@ -76,6 +77,7 @@
 import org.eclipse.jdt.core.dom.SwitchCase;
 import org.eclipse.jdt.core.dom.SwitchExpression;
 import org.eclipse.jdt.core.dom.SwitchStatement;
+import org.eclipse.jdt.core.dom.TextBlock;
 import org.eclipse.jdt.core.dom.ThrowStatement;
 import org.eclipse.jdt.core.dom.TryStatement;
 import org.eclipse.jdt.core.dom.TypeDeclaration;
@@ -86,6 +88,9 @@
 import org.eclipse.jdt.core.dom.YieldStatement;
 import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
 import org.eclipse.jdt.core.dom.AbstractMethodMappingDeclaration;
+import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions.Alignment;
+import org.eclipse.jdt.internal.formatter.Token.WrapMode;
+import org.eclipse.jdt.internal.formatter.Token.WrapPolicy;
 
 public class LineBreaksPreparator extends ASTVisitor {
 	final private TokenManager tm;
@@ -711,6 +716,56 @@
 		return true;
 	}
 
+	@Override
+	public boolean visit(TextBlock node) {
+		int indentOption = this.options.text_block_indentation;
+		if (indentOption == Alignment.M_INDENT_PRESERVE)
+			return true;
+		Token block = this.tm.firstTokenIn(node, TokenNameTextBlock);
+		ArrayList<Token> lines = new ArrayList<>();
+		lines.add(new Token(block.originalStart, block.originalStart + 2, 0)); // first line; """
+		int incidentalWhitespace = Integer.MAX_VALUE;
+		int blankLines = -1; // will go to 0 on line break after first line
+		int i = block.originalStart + 3;
+		while (i <= block.originalEnd) {
+			int lineStart = i;
+			int firstNonBlank = -1;
+			int lastNonBlank = -1;
+			while (i <= block.originalEnd) {
+				char c = this.tm.charAt(i++);
+				if (c == '\r' || c == '\n') {
+					char c2 = this.tm.charAt(i);
+					if ((c2 == '\r' || c2 == '\n') && c2 != c)
+						i++;
+					break;
+				}
+				if (c != ' ' && c != '\t') {
+					if (firstNonBlank == -1)
+						firstNonBlank = i - 1;
+					lastNonBlank = i - 1;
+				}
+			}
+			if (firstNonBlank != -1) {
+				Token line = new Token(lineStart, lastNonBlank, 0);
+				line.putLineBreaksBefore(blankLines + 1);
+				blankLines = 0;
+				lines.add(line);
+				incidentalWhitespace = Math.min(incidentalWhitespace, firstNonBlank - lineStart);
+			} else {
+				blankLines++;
+			}
+		}
+		WrapPolicy wrapPolicy = new WrapPolicy(WrapMode.DISABLED, 0, -1, 0, 0, 1, false, false);
+		for (i = 1; i < lines.size(); i++) {
+			Token t = lines.get(i);
+			Token line = new Token(t, t.originalStart + incidentalWhitespace, t.originalEnd, TokenNameTextBlock);
+			line.setWrapPolicy(wrapPolicy);
+			lines.set(i, line);
+		}
+		block.setInternalStructure(lines);
+		return true;
+	}
+
 	private void breakLineBefore(ASTNode node) {
 		this.tm.firstTokenIn(node, -1).breakBefore();
 	}
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/OneLineEnforcer.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/OneLineEnforcer.java
index 9d9763f..9b2671a 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/OneLineEnforcer.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/OneLineEnforcer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2014, 2018 Mateusz Matela and others.
+ * Copyright (c) 2018, 2019 Mateusz Matela and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -59,6 +59,12 @@
 	}
 
 	@Override
+	public boolean preVisit2(ASTNode node) {
+		boolean isMalformed = (node.getFlags() & ASTNode.MALFORMED) != 0;
+		return !isMalformed;
+	}
+
+	@Override
 	public void endVisit(TypeDeclaration node) {
 		if (node.getParent().getLength() == 0)
 			return; // this is a fake block created by parsing in statements mode
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TextEditsBuilder.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TextEditsBuilder.java
index ef25771..b822e77 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TextEditsBuilder.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TextEditsBuilder.java
@@ -18,6 +18,7 @@
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_JAVADOC;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameNotAToken;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameStringLiteral;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameTextBlock;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameWHITESPACE;
 
 import java.util.ArrayList;
@@ -124,7 +125,7 @@
 		if (token.tokenType == TokenNameCOMMENT_LINE) {
 			handleSingleLineComment(token, index);
 		} else if (structure != null && !structure.isEmpty()) {
-			handleMultiLineComment(token, index);
+			handleStructuredToken(token, index);
 		} else {
 			flushBuffer(token.originalStart);
 			if (token.isToEscape()) {
@@ -187,14 +188,17 @@
 			return;
 		}
 
+		boolean isTextBlock = token != null && token.tokenType == TokenNameTextBlock;
 		this.parent.counter = this.counter;
 		this.parent.bufferLineSeparator(null, false);
-		this.parent.bufferIndent(this.parent.tm.get(this.parentTokenIndex), this.parentTokenIndex);
+		if (!(isTextBlock && emptyLine && !this.options.indent_empty_lines))
+			this.parent.bufferIndent(this.parent.tm.get(this.parentTokenIndex), this.parentTokenIndex);
 		this.counter = this.parent.counter;
 
+		if (isTextBlock)
+			return;
 		if (token != null && token.tokenType == TokenNameNotAToken)
 			return; // this is an unformatted block comment, don't force asterisk
-
 		if (getNext() == null && !emptyLine)
 			return; // this is the last token of block comment, asterisk is included
 
@@ -511,7 +515,7 @@
 			flushBuffer(lineComment.originalEnd + 1);
 	}
 
-	private void handleMultiLineComment(Token comment, int index) {
+	private void handleStructuredToken(Token comment, int index) {
 		flushBuffer(comment.originalStart);
 		if (this.childBuilder == null) {
 			this.childBuilder = new TextEditsBuilder(this);
@@ -538,7 +542,7 @@
 		if (commentToken.tokenType == TokenNameCOMMENT_LINE) {
 			handleSingleLineComment(commentToken, this.tm.indexOf(commentToken));
 		} else {
-			handleMultiLineComment(commentToken, this.tm.indexOf(commentToken));
+			handleStructuredToken(commentToken, this.tm.indexOf(commentToken));
 		}
 	}
 
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TokenManager.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TokenManager.java
index f054629..071f282 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TokenManager.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TokenManager.java
@@ -13,10 +13,10 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.formatter;
 
-import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_BLOCK;
-import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_JAVADOC;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_LINE;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameNotAToken;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameStringLiteral;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameTextBlock;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -252,9 +252,16 @@
 			}
 			if (traversed.getAlign() > 0)
 				this.counter = traversed.getAlign();
-			List<Token> internalStructure = traversed.getInternalStructure();
-			if (internalStructure != null && !internalStructure.isEmpty()) {
-				assert traversed.tokenType == TokenNameCOMMENT_BLOCK || traversed.tokenType == TokenNameCOMMENT_JAVADOC;
+			if (traversed.tokenType == TokenNameTextBlock) {
+				List<Token> lines = traversed.getInternalStructure();
+				if (lines == null) {
+					this.counter = getLength(traversed, 0);
+				} else {
+					this.counter = traversed.getIndent() + lines.get(1).getIndent();
+					this.counter += getLength(lines.get(lines.size() - 1), this.counter);
+				}
+			} else if (traversed.isComment()) {
+				assert traversed.tokenType != TokenNameCOMMENT_LINE;
 				this.counter = TokenManager.this.commentWrapper.wrapMultiLineComment(traversed, this.counter, true,
 						this.isNLSTagInLine);
 			} else {
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java
index 4da2d1a..2fb28a1 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2014, 2018 Mateusz Matela and others.
+ * Copyright (c) 2014, 2019 Mateusz Matela and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -18,6 +18,7 @@
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_BLOCK;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_JAVADOC;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_LINE;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameTextBlock;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameWHITESPACE;
 
 import java.util.ArrayDeque;
@@ -28,6 +29,7 @@
 
 import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
 import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions;
+import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions.Alignment;
 import org.eclipse.jdt.internal.formatter.Token;
 import org.eclipse.jdt.internal.formatter.TokenManager;
 import org.eclipse.jdt.internal.formatter.TokenTraverser;
@@ -99,13 +101,14 @@
 
 	private class LineAnalyzer extends TokenTraverser {
 
+		private final TokenManager tm2 = WrapExecutor.this.tm;
 		private final CommentWrapExecutor commentWrapper;
 		private int lineIndent;
 		int firstPotentialWrap;
 		int activeTopPriorityWrap;
 		int minStructureDepth;
 		int extraLines;
-		boolean lineExceeded;
+		int lineWidthExtent;
 		boolean isNextLineWrapped;
 		final List<Integer> extraLinesPerComment = new ArrayList<Integer>();
 		final List<Integer> topPriorityGroupStarts = new ArrayList<Integer>();
@@ -120,25 +123,28 @@
 		 * @return index of the last token in line
 		 */
 		public int analyzeLine(int startIndex, int indent) {
-			Token startToken = WrapExecutor.this.tm.get(startIndex);
+			Token startToken = this.tm2.get(startIndex);
 			assert startToken.getLineBreaksBefore() > 0;
-			this.counter = WrapExecutor.this.tm.toIndent(indent, startToken.isWrappable());
+			this.counter = this.tm2.toIndent(indent, startToken.isWrappable());
 			this.lineIndent = indent;
 			this.firstPotentialWrap = -1;
 			this.activeTopPriorityWrap = -1;
 			this.minStructureDepth = Integer.MAX_VALUE;
 			this.extraLines = 0;
+			this.lineWidthExtent = 0;
 			this.isNextLineWrapped = false;
 			this.extraLinesPerComment.clear();
 			this.topPriorityGroupStarts.clear();
 			this.currentTopPriorityGroupEnd = -1;
 			this.isNLSTagInLine = false;
-			int lastIndex = WrapExecutor.this.tm.traverse(startIndex, this);
+			int lastIndex = this.tm2.traverse(startIndex, this);
 			return lastIndex + (this.isNextLineWrapped ? 1 : 0);
 		}
 
 		@Override
 		protected boolean token(Token token, int index) {
+			setIndent(token, this.lineIndent);
+
 			if (token.hasNLSTag())
 				this.isNLSTagInLine = true;
 
@@ -167,19 +173,30 @@
 				this.counter++;
 			}
 
-			if (!token.isComment()) {
-				this.counter += WrapExecutor.this.tm.getLength(token, this.counter);
+			if (token.tokenType == TokenNameTextBlock) {
+				List<Token> lines = token.getInternalStructure();
+				if (lines == null) {
+					this.counter = this.tm2.getLength(token, 0);
+				} else {
+					this.lineWidthExtent = Math.max(this.lineWidthExtent,
+							this.counter + this.tm2.getLength(lines.get(0), this.counter));
+					this.counter = this.lineIndent + lines.get(1).getIndent();
+					lines.stream().skip(1).forEach(e -> this.lineWidthExtent = Math.max(this.lineWidthExtent,
+							this.counter + this.tm2.getLength(e, this.counter)));
+					this.counter += this.tm2.getLength(lines.get(lines.size() - 1), this.counter);
+				}
+			} else if (!token.isComment()) {
+				this.counter += this.tm2.getLength(token, this.counter);
 			} else if (token.tokenType != TokenNameCOMMENT_LINE) {
 				this.counter = this.commentWrapper.wrapMultiLineComment(token, this.counter, true, this.isNLSTagInLine);
 				this.extraLines += this.commentWrapper.getLinesCount() - 1;
 				this.extraLinesPerComment.add(this.commentWrapper.getLinesCount() - 1);
 			}
 
-			this.lineExceeded = this.counter > WrapExecutor.this.options.page_width;
-			if (this.lineExceeded && this.firstPotentialWrap >= 0) {
+			this.lineWidthExtent = Math.max(this.lineWidthExtent, this.counter);
+			if (this.lineWidthExtent > WrapExecutor.this.options.page_width && this.firstPotentialWrap >= 0) {
 				return false;
 			}
-			token.setIndent(this.lineIndent);
 
 			if (getNext() != null && getNext().isWrappable() && getLineBreaksAfter() > 0) {
 				this.isNextLineWrapped = true;
@@ -188,9 +205,8 @@
 				return false; 
 			}
 
-			boolean isLineEnd = getLineBreaksAfter() > 0 || getNext() == null
-					|| (getNext().isNextLineOnWrap() && WrapExecutor.this.tm
-							.get(WrapExecutor.this.tm.findFirstTokenInLine(index)).isWrappable());
+			boolean isLineEnd = getLineBreaksAfter() > 0 || getNext() == null || (getNext().isNextLineOnWrap()
+					&& this.tm2.get(this.tm2.findFirstTokenInLine(index)).isWrappable());
 			return !isLineEnd;
 		}
 
@@ -199,18 +215,14 @@
 				return false;
 
 			for (int i = index - 1; i > wrapPolicy.wrapParentIndex; i--) {
-				Token token = WrapExecutor.this.tm.get(i);
+				Token token = this.tm2.get(i);
 				if (token.isWrappable() && token.getWrapPolicy().wrapParentIndex == wrapPolicy.wrapParentIndex
-					&& (token.getLineBreaksBefore() > 0 || WrapExecutor.this.tm.get(i - 1).getLineBreaksAfter() > 0)) {
+					&& (token.getLineBreaksBefore() > 0 || this.tm2.get(i - 1).getLineBreaksAfter() > 0)) {
 						return true;
 				}
 			}
 			return false;
 		}
-
-		public int getLastPosition() {
-			return this.counter;
-		}
 	}
 
 	private class WrapsApplier extends TokenTraverser {
@@ -235,7 +247,7 @@
 				token.breakBefore();
 				newLine(token, index);
 			} else {
-				token.setIndent(this.currentIndent);
+				setIndent(token, this.currentIndent);
 			}
 			return true;
 		}
@@ -244,7 +256,7 @@
 			while (!this.stack.isEmpty() && index > this.stack.peek().getWrapPolicy().groupEndIndex)
 				this.stack.pop();
 			if (token.getWrapPolicy() != null) {
-				token.setIndent(getWrapIndent(token));
+				setIndent(token, getWrapIndent(token));
 				handleOnColumnIndent(index, token.getWrapPolicy());
 				this.stack.push(token);
 			} else if (this.stack.isEmpty()) {
@@ -253,7 +265,7 @@
 			}
 
 			this.currentIndent = this.stack.isEmpty() ? this.initialIndent : this.stack.peek().getIndent();
-			token.setIndent(this.currentIndent);
+			setIndent(token, this.currentIndent);
 			this.nextWrap = findWrapsCached(index, this.currentIndent).nextWrap;
 		}
 	}
@@ -437,8 +449,8 @@
 	private WrapResult findWraps(int wrapTokenIndex, int indent) {
 		final int lastIndex = this.lineAnalyzer.analyzeLine(wrapTokenIndex, indent);
 		final boolean nextLineWrapped = this.lineAnalyzer.isNextLineWrapped;
-		final boolean wrapRequired = this.lineAnalyzer.lineExceeded || nextLineWrapped;
-		int lineOverflow = Math.max(0, this.lineAnalyzer.getLastPosition() - this.options.page_width);
+		int lineOverflow = Math.max(0, this.lineAnalyzer.lineWidthExtent - this.options.page_width);
+		final boolean wrapRequired = lineOverflow > 0 || nextLineWrapped;
 		int extraLines = this.lineAnalyzer.extraLines;
 		final int firstPotentialWrap = this.lineAnalyzer.firstPotentialWrap;
 		final int activeTopPriorityWrap = this.lineAnalyzer.activeTopPriorityWrap;
@@ -662,4 +674,25 @@
 		wrapIndent += policy.extraIndent;
 		return this.tm.toIndent(wrapIndent, true);
 	}
+
+	void setIndent(Token token, int indent) {
+		token.setIndent(indent);
+
+		List<Token> structure = token.getInternalStructure();
+		if (token.tokenType == TokenNameTextBlock && structure != null) {
+			int lineIndent;
+			int indentOption = this.options.text_block_indentation;
+			if (indentOption == Alignment.M_INDENT_BY_ONE) {
+				lineIndent = 1 * this.options.indentation_size;
+			} else if (indentOption == Alignment.M_INDENT_DEFAULT) {
+				lineIndent = this.options.continuation_indentation * this.options.indentation_size;
+			} else if (indentOption == Alignment.M_INDENT_ON_COLUMN) {
+				lineIndent = this.tm.toIndent(this.tm.getPositionInLine(this.tm.indexOf(token)), true) - indent;
+			} else {
+				assert false;
+				lineIndent = 0;
+			}
+			structure.stream().skip(1).forEach(t -> t.setIndent(lineIndent));
+		}
+	}
 }
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
index 678cc88..6e10134 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
@@ -1416,7 +1416,7 @@
 				isNLSTagInLine = true;
 			}
 			List<Token> structure = token.getInternalStructure();
-			if (structure != null && !structure.isEmpty() && !isNLSTagInLine) {
+			if (token.isComment() && structure != null && !structure.isEmpty() && !isNLSTagInLine) {
 				int startPosition = this.tm.getPositionInLine(i);
 				if (token.tokenType == TokenNameCOMMENT_LINE) {
 					commentWrapper.wrapLineComment(token, startPosition);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IModuleDescription.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IModuleDescription.java
index 5455e73..bf5eed5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IModuleDescription.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IModuleDescription.java
@@ -83,4 +83,12 @@
 	default boolean isAutoModule() {
 		return false;
 	}
+
+	/**
+	 * @return true if this module is a system module, else false
+	 * @since 3.20
+	 */
+	default boolean isSystemModule() {
+		return false;
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/provisional/JavaModelAccess.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/provisional/JavaModelAccess.java
index 73e7644..0bdc298 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/provisional/JavaModelAccess.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/provisional/JavaModelAccess.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2017, 2018 GK Software SE, and others.
+ * Copyright (c) 2017, 2019 GK Software SE, and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -71,7 +71,9 @@
 	 * @param module the module being queried about
 	 * @return {@code true} iff the module is defined in the system library (also known as JRE).
 	 * @since 3.18
+	 * @deprecated please use {@link IModuleDescription#isSystemModule()}
 	 */
+	@Deprecated
 	public static boolean isSystemModule(IModuleDescription module) {
 		IPackageFragmentRoot pfr = (IPackageFragmentRoot) module.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
 		return pfr instanceof JrtPackageFragmentRoot;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryModule.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryModule.java
index 2d6bffd..e2bb12e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryModule.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryModule.java
@@ -19,6 +19,7 @@
 import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.jdt.core.IAnnotation;
 import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
 import org.eclipse.jdt.core.ISourceRange;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
@@ -65,6 +66,11 @@
 		return true;
 	}
 	@Override
+	public boolean isSystemModule() {
+		IPackageFragmentRoot pfr = (IPackageFragmentRoot) getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
+		return pfr instanceof JrtPackageFragmentRoot;
+	}
+	@Override
 	public int getFlags() throws JavaModelException {
 		if (getModuleInfo().isOpen())
 			return ClassFileConstants.ACC_OPEN;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java
index 784cee9..8ae86f7 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java
@@ -1291,6 +1291,13 @@
 					this.projectCachesToReset.add(project);
 
 					break;
+
+				case IJavaElement.COMPILATION_UNIT :
+					if (element.getElementName().equals(new String(TypeConstants.MODULE_INFO_FILE_NAME))) {
+						this.projectCachesToReset.add(element.getJavaProject()); // change unnamed -> named
+					}
+
+					break;
 			}
 		}
 	}
@@ -1387,6 +1394,13 @@
 				this.projectCachesToReset.add(project);
 
 				break;
+
+			case IJavaElement.COMPILATION_UNIT :
+				if (element.getElementName().equals(new String(TypeConstants.MODULE_INFO_FILE_NAME))) {
+					this.projectCachesToReset.add(element.getJavaProject()); // change named -> unnamed
+				}
+
+				break;
 		}
 	}
 	/*
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
index 9f1a666..6e692e0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
@@ -23,6 +23,7 @@
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -31,6 +32,7 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.function.Function;
 import java.util.jar.Manifest;
@@ -403,30 +405,35 @@
 		HashSet traversed = new HashSet();
 
 		// compute cycle participants
-		ArrayList prereqChain = new ArrayList();
+		List<IPath> prereqChain = new ArrayList<>();
+		Map<IPath,List<CycleInfo>> cyclesPerProject = new HashMap<>();
 		for (int i = 0; i < length; i++){
 			if (hasJavaNature(rscProjects[i])) {
 				JavaProject project = (projects[i] = (JavaProject)JavaCore.create(rscProjects[i]));
 				if (!traversed.contains(project.getPath())){
 					prereqChain.clear();
-					project.updateCycleParticipants(prereqChain, cycleParticipants, workspaceRoot, traversed, preferredClasspaths);
+					project.updateCycleParticipants(prereqChain, cycleParticipants, cyclesPerProject, workspaceRoot, traversed, preferredClasspaths);
 				}
 			}
 		}
 		//System.out.println("updateAllCycleMarkers: " + (System.currentTimeMillis() - start) + " ms");
 
-		String cycleString = cycleParticipants.stream()
-			.map(path -> workspaceRoot.findMember(path))
-			.filter(r -> r != null)
-			.map(r -> JavaCore.create((IProject)r))
-			.filter(p -> p != null)
-			.map(p -> p.getElementName())
-			.collect(Collectors.joining(", ")); //$NON-NLS-1$
-
 		for (int i = 0; i < length; i++){
 			JavaProject project = projects[i];
 			if (project != null) {
-				if (cycleParticipants.contains(project.getPath())) {
+				List<CycleInfo> cycles = cyclesPerProject.get(project.getPath());
+				if (cycles != null) {
+					StringBuilder cycleString = new StringBuilder();
+					boolean first = true;
+					for (CycleInfo cycleInfo : cycles) {
+						if (!first) cycleString.append('\n');
+						cycleString.append(cycleInfo.pathToCycleAsString());
+						cycleString.append("->{"); //$NON-NLS-1$
+						cycleString.append(cycleInfo.cycleAsString());
+						cycleString.append('}');
+						first = false;
+					}
+					
 					IMarker cycleMarker = project.getCycleMarker();
 					String circularCPOption = project.getOption(JavaCore.CORE_CIRCULAR_CLASSPATH, true);
 					int circularCPSeverity = JavaCore.ERROR.equals(circularCPOption) ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING;
@@ -439,7 +446,7 @@
 							}
 							String existingMessage = cycleMarker.getAttribute(IMarker.MESSAGE, ""); //$NON-NLS-1$
 							String newMessage = new JavaModelStatus(IJavaModelStatusConstants.CLASSPATH_CYCLE,
-									project, cycleString).getMessage();
+									project, cycleString.toString()).getMessage();
 							if (!newMessage.equals(existingMessage)) {
 								cycleMarker.setAttribute(IMarker.MESSAGE, newMessage);
 							}
@@ -449,7 +456,7 @@
 					} else {
 						// create new marker
 						project.createClasspathProblemMarker(
-							new JavaModelStatus(IJavaModelStatusConstants.CLASSPATH_CYCLE, project, cycleString));
+							new JavaModelStatus(IJavaModelStatusConstants.CLASSPATH_CYCLE, project, cycleString.toString()));
 					}
 				} else {
 					project.flushClasspathProblemMarkers(true, false, false);
@@ -2045,12 +2052,11 @@
 						}
 						continue;
 					} else if (token == MementoTokenizer.CLASSPATH_ATTRIBUTE) {
-						// PFR memento is optionally trailed by all extra classpath attributes ("=/name=/value"):
-						String name = memento.nextToken();
-						String separator = memento.nextToken();
-						assert separator == MementoTokenizer.CLASSPATH_ATTRIBUTE;
-						String value = memento.nextToken();
+						// PFR memento is optionally trailed by all extra classpath attributes ("=/name=/value=/"):
+						String name = memento.getStringDelimitedBy(MementoTokenizer.CLASSPATH_ATTRIBUTE);
+						String value = memento.getStringDelimitedBy(MementoTokenizer.CLASSPATH_ATTRIBUTE);
 						attributes.add(new ClasspathAttribute(name, value));
+						token = null; // consumed
 						continue;
 					}
 					rootPath += token;
@@ -2613,7 +2619,7 @@
 		LinkedHashSet cycleParticipants = new LinkedHashSet();
 		HashMap preferredClasspaths = new HashMap(1);
 		preferredClasspaths.put(this, preferredClasspath);
-		updateCycleParticipants(new ArrayList(2), cycleParticipants, ResourcesPlugin.getWorkspace().getRoot(), new HashSet(2), preferredClasspaths);
+		updateCycleParticipants(new ArrayList(2), cycleParticipants, new HashMap<>(), ResourcesPlugin.getWorkspace().getRoot(), new HashSet(2), preferredClasspaths);
 		return !cycleParticipants.isEmpty();
 	}
 
@@ -3684,6 +3690,48 @@
 		}
 	}
 
+	/** internal structure for detected build path cycles. */
+	static class CycleInfo {
+
+		private List<IPath> pathToCycle;
+		public final List<IPath> cycle;
+		
+		public CycleInfo(List<IPath> pathToCycle, List<IPath> cycle) {
+			this.pathToCycle = new ArrayList<>(pathToCycle);
+			this.cycle = new ArrayList<>(cycle);
+		}
+		
+		public static Optional<CycleInfo> findCycleContaining(Collection<List<CycleInfo>> infos, IPath path) {
+			return infos.stream().flatMap(l -> l.stream()).filter(c -> c.cycle.contains(path)).findAny();
+		}
+		
+		public static void add(IPath project, List<IPath> prefix, List<IPath> cycle, Map<IPath, List<CycleInfo>> cyclesPerProject) {
+			List<CycleInfo> list = cyclesPerProject.get(project);
+			if (list == null) {
+				cyclesPerProject.put(project, list = new ArrayList<>());
+			} else {
+				for (CycleInfo cycleInfo: list) {
+					if (cycleInfo.cycle.equals(cycle)) {
+						// same cycle: use the shorter prefix:
+						if (cycleInfo.pathToCycle.size() > prefix.size()) {
+							cycleInfo.pathToCycle.clear();
+							cycleInfo.pathToCycle.addAll(prefix);
+						}
+						return;
+					}
+				}
+			}
+			list.add(new CycleInfo(prefix, cycle));
+		}
+		
+		public String pathToCycleAsString() {
+			return this.pathToCycle.stream().map(IPath::lastSegment).collect(Collectors.joining(", ")); //$NON-NLS-1$
+		}
+		
+		public String cycleAsString() {
+			return this.cycle.stream().map(IPath::lastSegment).collect(Collectors.joining(", ")); //$NON-NLS-1$
+		}
+	}
 	/**
 	 * If a cycle is detected, then cycleParticipants contains all the paths of projects involved in this cycle (directly and indirectly),
 	 * no cycle if the set is empty (and started empty)
@@ -3694,8 +3742,9 @@
 	 * @param preferredClasspaths Map
 	 */
 	public void updateCycleParticipants(
-			ArrayList prereqChain,
+			List<IPath> prereqChain,
 			LinkedHashSet cycleParticipants,
+			Map<IPath,List<CycleInfo>> cyclesPerProject,
 			IWorkspaceRoot workspaceRoot,
 			HashSet traversed,
 			Map preferredClasspaths){
@@ -3712,19 +3761,60 @@
 
 				if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT){
 					IPath prereqProjectPath = entry.getPath();
-					int index = cycleParticipants.contains(prereqProjectPath) ? 0 : prereqChain.indexOf(prereqProjectPath);
-					if (index >= 0) { // refer to cycle, or in cycle itself
-						for (int size = prereqChain.size(); index < size; index++) {
-							cycleParticipants.add(prereqChain.get(index));
+					int prereqIndex = prereqChain.indexOf(prereqProjectPath);
+					if (prereqIndex > -1) {
+						// record a new cycle:
+						List<IPath> cycle = prereqChain.subList(prereqIndex, prereqChain.size());
+						// empty-prefix CycleInfo for all members of the cycle:
+						List<IPath> prefix = Collections.emptyList();
+						for (IPath prjInCycle : cycle) {
+							CycleInfo.add(prjInCycle, prefix, cycle, cyclesPerProject);
 						}
+						// also record with all members of the prereqChain with transitive dependency on the cycle:
+						for (int j = 0; j < prereqIndex; j++) {
+							CycleInfo.add(prereqChain.get(j), prereqChain.subList(j, prereqIndex), cycle, cyclesPerProject);
+						}
+					} else if (cycleParticipants.contains(prereqProjectPath)) {
+						// record existing cycle as dependency of each project in prereqChain:
+						Optional<CycleInfo> cycle = CycleInfo.findCycleContaining(cyclesPerProject.values(), prereqProjectPath);
+						if (cycle.isPresent()) {
+							List<IPath> theCycle = cycle.get().cycle;
+							for (int j = 0; j < prereqChain.size(); j++) {
+								IPath prereq = prereqChain.get(j);
+								List<IPath> prereqSubList = prereqChain.subList(j, prereqChain.size());
+								int joinIndex1 = theCycle.indexOf(prereq);
+								if (joinIndex1 != -1) {
+									// prereqSubList -> prereqProjectPath + theCycle create a new cycle
+									List<IPath> newCycle = new ArrayList<>(prereqSubList);
+									int joinIndex2 = theCycle.indexOf(prereqProjectPath); // always != -1 since that's how we found 'cycle'
+									while (joinIndex2 != joinIndex1) {
+										newCycle.add(theCycle.get(joinIndex2++));
+										if (joinIndex2 == theCycle.size())
+											joinIndex2 = 0; // it's a cycle :)
+									}
+									for (IPath newMember : newCycle) {
+										CycleInfo.add(newMember, Collections.emptyList(), newCycle, cyclesPerProject);
+									}
+									break; // the rest of prereqChain is already included via newCycle
+								} else {
+									CycleInfo.add(prereq, prereqSubList, theCycle, cyclesPerProject);
+								}
+							}
+						}
+						prereqIndex = 0;
 					} else {
 						if (!traversed.contains(prereqProjectPath)) {
 							IResource member = workspaceRoot.findMember(prereqProjectPath);
 							if (member != null && member.getType() == IResource.PROJECT){
 								JavaProject javaProject = (JavaProject)JavaCore.create((IProject)member);
-								javaProject.updateCycleParticipants(prereqChain, cycleParticipants, workspaceRoot, traversed, preferredClasspaths);
+								javaProject.updateCycleParticipants(prereqChain, cycleParticipants, cyclesPerProject, workspaceRoot, traversed, preferredClasspaths);
 							}
 						}
+						continue;
+					}
+					// fall through from both positive branches above
+					for (int index = prereqIndex, size = prereqChain.size(); index < size; index++) {
+						cycleParticipants.add(prereqChain.get(index));
 					}
 				}
 			}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
index 1d8f9c8..8a93a53 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -515,6 +515,7 @@
 				escapeMementoName(buff, attribute.getName());
 				appendEscapedDelimiter(buff, JavaElement.JEM_PACKAGEFRAGMENTROOT);
 				escapeMementoName(buff, attribute.getValue());
+				appendEscapedDelimiter(buff, JavaElement.JEM_PACKAGEFRAGMENTROOT);
 			}
 		}
 	} catch (JavaModelException e) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java
index f210573..dc6fce9 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java
@@ -796,7 +796,7 @@
  */
 void mustPropagateStructuralChanges() {
 	LinkedHashSet cycleParticipants = new LinkedHashSet(3);
-	this.javaProject.updateCycleParticipants(new ArrayList(), cycleParticipants, this.workspaceRoot, new HashSet(3), null);
+	this.javaProject.updateCycleParticipants(new ArrayList(), cycleParticipants, new HashMap<>(), this.workspaceRoot, new HashSet(3), null);
 	IPath currentPath = this.javaProject.getPath();
 	Iterator i= cycleParticipants.iterator();
 	while (i.hasNext()) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MementoTokenizer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MementoTokenizer.java
index b610afd..1c53ce6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MementoTokenizer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MementoTokenizer.java
@@ -161,4 +161,12 @@
 		}
 	}
 
+	public String getStringDelimitedBy(String delimiter) {
+		String token = nextToken();
+		if (token == delimiter)
+			return ""; //$NON-NLS-1$
+		String separator = nextToken();
+		assert separator == delimiter;
+		return token;
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties
index ec02740..725a1cc 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties
@@ -150,7 +150,7 @@
 classpath_cannotUseLibraryAsOutput = Source folder ''{0}'' in project ''{2}'' cannot output to library ''{1}''
 classpath_closedProject = Required project ''{0}'' needs to be open
 classpath_couldNotWriteClasspathFile = Could not write ''.classpath'' file of project ''{0}'': {1}
-classpath_cycle = A cycle was detected in the build path of project ''{0}''. The cycle consists of projects '{'{1}'}'
+classpath_cycle = One or more cycles were detected in the build path of project ''{0}''. The paths towards the cycle and cycle are:\n{1}
 classpath_duplicateEntryPath = Build path contains duplicate entry: ''{0}'' for project ''{1}''
 classpath_illegalContainerPath = Illegal classpath container path: ''{0}'' in project ''{1}'', must have at least one segment (containerID+hints)
 classpath_illegalEntryInClasspathFile = Illegal entry in ''.classpath'' of project ''{0}'' file: {1}