Merge
authortschatzl
Wed, 27 Nov 2019 10:21:22 +0100
changeset 59289 c887851da33d
parent 59288 3b1afeb49a20 (current diff)
parent 59287 c04fa10636fd (diff)
child 59290 97d13893ec3c
Merge
--- a/make/autoconf/flags-cflags.m4	Wed Nov 27 10:19:45 2019 +0100
+++ b/make/autoconf/flags-cflags.m4	Wed Nov 27 10:21:22 2019 +0100
@@ -190,20 +190,7 @@
       WARNINGS_ENABLE_ALL_CXXFLAGS="$WARNINGS_ENABLE_ALL_CFLAGS $WARNINGS_ENABLE_ADDITIONAL_CXX"
 
       DISABLED_WARNINGS="unused-parameter unused"
-
-      # Repeate the check for the BUILD_CC and BUILD_CXX. Need to also reset
-      # CFLAGS since any target specific flags will likely not work with the
-      # build compiler
-      CC_OLD="$CC"
-      CXX_OLD="$CXX"
-      CC="$BUILD_CC"
-      CXX="$BUILD_CXX"
-      CFLAGS_OLD="$CFLAGS"
-      CFLAGS=""
       BUILD_CC_DISABLE_WARNING_PREFIX="-Wno-"
-      CC="$CC_OLD"
-      CXX="$CXX_OLD"
-      CFLAGS="$CFLAGS_OLD"
       ;;
 
     clang)
@@ -420,6 +407,17 @@
 
   FLAGS_SETUP_CFLAGS_CPU_DEP([TARGET])
 
+  # Repeat the check for the BUILD_CC and BUILD_CXX. Need to also reset CFLAGS
+  # since any target specific flags will likely not work with the build compiler.
+  CC_OLD="$CC"
+  CXX_OLD="$CXX"
+  CFLAGS_OLD="$CFLAGS"
+  CXXFLAGS_OLD="$CXXFLAGS"
+  CC="$BUILD_CC"
+  CXX="$BUILD_CXX"
+  CFLAGS=""
+  CXXFLAGS=""
+
   FLAGS_OS=$OPENJDK_BUILD_OS
   FLAGS_OS_TYPE=$OPENJDK_BUILD_OS_TYPE
   FLAGS_CPU=$OPENJDK_BUILD_CPU
@@ -430,6 +428,11 @@
   FLAGS_CPU_LEGACY_LIB=$OPENJDK_BUILD_CPU_LEGACY_LIB
 
   FLAGS_SETUP_CFLAGS_CPU_DEP([BUILD], [OPENJDK_BUILD_], [BUILD_])
+
+  CC="$CC_OLD"
+  CXX="$CXX_OLD"
+  CFLAGS="$CFLAGS_OLD"
+  CXXFLAGS="$CXXFLAGS_OLD"
 ])
 
 ################################################################################
@@ -529,6 +532,11 @@
   if test "x$TOOLCHAIN_TYPE" = xgcc; then
     TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM -fcheck-new -fstack-protector"
     TOOLCHAIN_CFLAGS_JDK="-pipe -fstack-protector"
+    # reduce lib size on s390x in link step, this needs also special compile flags
+    if test "x$OPENJDK_TARGET_CPU" = xs390x; then
+      TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM -ffunction-sections -fdata-sections"
+      TOOLCHAIN_CFLAGS_JDK="$TOOLCHAIN_CFLAGS_JDK -ffunction-sections -fdata-sections"
+    fi
     # technically NOT for CXX (but since this gives *worse* performance, use
     # no-strict-aliasing everywhere!)
     TOOLCHAIN_CFLAGS_JDK_CONLY="-fno-strict-aliasing"
--- a/make/autoconf/flags-ldflags.m4	Wed Nov 27 10:19:45 2019 +0100
+++ b/make/autoconf/flags-ldflags.m4	Wed Nov 27 10:21:22 2019 +0100
@@ -70,10 +70,14 @@
     fi
 
     # Add -z defs, to forbid undefined symbols in object files.
-    BASIC_LDFLAGS="$BASIC_LDFLAGS -Wl,-z,defs"
+    # add relro (mark relocations read only) for all libs
+    BASIC_LDFLAGS="$BASIC_LDFLAGS -Wl,-z,defs -Wl,-z,relro"
+    # s390x : remove unused code+data in link step
+    if test "x$OPENJDK_TARGET_CPU" = xs390x; then
+      BASIC_LDFLAGS="$BASIC_LDFLAGS -Wl,--gc-sections -Wl,--print-gc-sections"
+    fi
 
-    BASIC_LDFLAGS_JVM_ONLY="-Wl,-O1 -Wl,-z,relro"
-
+    BASIC_LDFLAGS_JVM_ONLY="-Wl,-O1"
 
   elif test "x$TOOLCHAIN_TYPE" = xclang; then
     BASIC_LDFLAGS_JVM_ONLY="-mno-omit-leaf-frame-pointer -mstack-alignment=16 \
@@ -120,9 +124,6 @@
     if test "x$OPENJDK_TARGET_OS" = xlinux; then
       if test x$DEBUG_LEVEL = xrelease; then
         DEBUGLEVEL_LDFLAGS_JDK_ONLY="$DEBUGLEVEL_LDFLAGS_JDK_ONLY -Wl,-O1"
-      else
-        # mark relocations read only on (fast/slow) debug builds
-        DEBUGLEVEL_LDFLAGS_JDK_ONLY="-Wl,-z,relro"
       fi
       if test x$DEBUG_LEVEL = xslowdebug; then
         # do relocations at load
--- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp	Wed Nov 27 10:21:22 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -327,24 +327,42 @@
 #endif
 }
 
+#ifdef _LP64
 void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) {
   BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
   if (bs_nm == NULL) {
     return;
   }
-#ifndef _LP64
-  ShouldNotReachHere();
-#else
   Label continuation;
-  Register thread = LP64_ONLY(r15_thread);
+  Register thread = r15_thread;
   Address disarmed_addr(thread, in_bytes(bs_nm->thread_disarmed_offset()));
   __ align(8);
   __ cmpl(disarmed_addr, 0);
   __ jcc(Assembler::equal, continuation);
   __ call(RuntimeAddress(StubRoutines::x86::method_entry_barrier()));
   __ bind(continuation);
+}
+#else
+void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) {
+  BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
+  if (bs_nm == NULL) {
+    return;
+  }
+
+  Label continuation;
+
+  Register tmp = rdi;
+  __ push(tmp);
+  __ movptr(tmp, (intptr_t)bs_nm->disarmed_value_address());
+  Address disarmed_addr(tmp, 0);
+  __ align(4);
+  __ cmpl(disarmed_addr, 0);
+  __ pop(tmp);
+  __ jcc(Assembler::equal, continuation);
+  __ call(RuntimeAddress(StubRoutines::x86::method_entry_barrier()));
+  __ bind(continuation);
+}
 #endif
-}
 
 void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) {
   BarrierSetNMethod* bs = BarrierSet::barrier_set()->barrier_set_nmethod();
--- a/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp	Wed Nov 27 10:21:22 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,6 +35,7 @@
 
 class NativeNMethodCmpBarrier: public NativeInstruction {
 public:
+#ifdef _LP64
   enum Intel_specific_constants {
     instruction_code        = 0x81,
     instruction_size        = 8,
@@ -42,6 +43,14 @@
     instruction_rex_prefix  = Assembler::REX | Assembler::REX_B,
     instruction_modrm       = 0x7f  // [r15 + offset]
   };
+#else
+  enum Intel_specific_constants {
+    instruction_code        = 0x81,
+    instruction_size        = 7,
+    imm_offset              = 2,
+    instruction_modrm       = 0x3f  // [rdi]
+  };
+#endif
 
   address instruction_address() const { return addr_at(0); }
   address immediate_address() const { return addr_at(imm_offset); }
@@ -51,6 +60,7 @@
   void verify() const;
 };
 
+#ifdef _LP64
 void NativeNMethodCmpBarrier::verify() const {
   if (((uintptr_t) instruction_address()) & 0x7) {
     fatal("Not properly aligned");
@@ -77,6 +87,27 @@
     fatal("not a cmp barrier");
   }
 }
+#else
+void NativeNMethodCmpBarrier::verify() const {
+  if (((uintptr_t) instruction_address()) & 0x3) {
+    fatal("Not properly aligned");
+  }
+
+  int inst = ubyte_at(0);
+  if (inst != instruction_code) {
+    tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", p2i(instruction_address()),
+        inst);
+    fatal("not a cmp barrier");
+  }
+
+  int modrm = ubyte_at(1);
+  if (modrm != instruction_modrm) {
+    tty->print_cr("Addr: " INTPTR_FORMAT " mod/rm: 0x%x", p2i(instruction_address()),
+        modrm);
+    fatal("not a cmp barrier");
+  }
+}
+#endif // _LP64
 
 void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
   /*
@@ -127,7 +158,7 @@
 // NativeNMethodCmpBarrier::verify() will immediately complain when it does
 // not find the expected native instruction at this offset, which needs updating.
 // Note that this offset is invariant of PreserveFramePointer.
-static const int entry_barrier_offset = -19;
+static const int entry_barrier_offset = LP64_ONLY(-19) NOT_LP64(-18);
 
 static NativeNMethodCmpBarrier* native_nmethod_barrier(nmethod* nm) {
   address barrier_address = nm->code_begin() + nm->frame_complete_offset() + entry_barrier_offset;
--- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp	Wed Nov 27 10:21:22 2019 +0100
@@ -511,6 +511,7 @@
 
   // 3: apply keep-alive barrier if needed
   if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) {
+    __ push_IU_state();
     const Register thread = NOT_LP64(tmp_thread) LP64_ONLY(r15_thread);
     assert_different_registers(dst, tmp1, tmp_thread);
     NOT_LP64(__ get_thread(thread));
@@ -523,6 +524,7 @@
                                  tmp1 /* tmp */,
                                  true /* tosca_live */,
                                  true /* expand_call */);
+    __ pop_IU_state();
   }
 }
 
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp	Wed Nov 27 10:21:22 2019 +0100
@@ -975,6 +975,9 @@
 
   address c2i_entry = __ pc();
 
+  BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+  bs->c2i_entry_barrier(masm);
+
   gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
 
   __ flush();
@@ -1886,6 +1889,10 @@
   // -2 because return address is already present and so is saved rbp
   __ subptr(rsp, stack_size - 2*wordSize);
 
+
+  BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+  bs->nmethod_entry_barrier(masm);
+
   // Frame is now completed as far as size and linkage.
   int frame_complete = ((intptr_t)__ pc()) - start;
 
@@ -1921,12 +1928,12 @@
   // if we load it once it is usable thru the entire wrapper
   const Register thread = rdi;
 
-  // We use rsi as the oop handle for the receiver/klass
-  // It is callee save so it survives the call to native
-
-  const Register oop_handle_reg = rsi;
-
-  __ get_thread(thread);
+   // We use rsi as the oop handle for the receiver/klass
+   // It is callee save so it survives the call to native
+
+   const Register oop_handle_reg = rsi;
+
+   __ get_thread(thread);
 
   if (is_critical_native && !Universe::heap()->supports_object_pinning()) {
     check_needs_gc_for_critical_native(masm, thread, stack_slots, total_c_args, total_in_args,
--- a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp	Wed Nov 27 10:21:22 2019 +0100
@@ -27,6 +27,7 @@
 #include "asm/macroAssembler.inline.hpp"
 #include "gc/shared/barrierSet.hpp"
 #include "gc/shared/barrierSetAssembler.hpp"
+#include "gc/shared/barrierSetNMethod.hpp"
 #include "interpreter/interpreter.hpp"
 #include "memory/universe.hpp"
 #include "nativeInst_x86.hpp"
@@ -3663,6 +3664,68 @@
     __ ret(0);
   }
 
+  address generate_method_entry_barrier() {
+    __ align(CodeEntryAlignment);
+    StubCodeMark mark(this, "StubRoutines", "nmethod_entry_barrier");
+
+    Label deoptimize_label;
+
+    address start = __ pc();
+
+    __ push(-1); // cookie, this is used for writing the new rsp when deoptimizing
+
+    BLOCK_COMMENT("Entry:");
+    __ enter(); // save rbp
+
+    // save rbx, because we want to use that value.
+    // We could do without it but then we depend on the number of slots used by pusha
+    __ push(rbx);
+
+    __ lea(rbx, Address(rsp, wordSize * 3)); // 1 for cookie, 1 for rbp, 1 for rbx - this should be the return address
+
+    __ pusha();
+
+    // xmm0 and xmm1 may be used for passing float/double arguments
+    const int xmm_size = wordSize * 2;
+    const int xmm_spill_size = xmm_size * 2;
+    __ subptr(rsp, xmm_spill_size);
+    __ movdqu(Address(rsp, xmm_size * 1), xmm1);
+    __ movdqu(Address(rsp, xmm_size * 0), xmm0);
+
+    __ call_VM_leaf(CAST_FROM_FN_PTR(address, static_cast<int (*)(address*)>(BarrierSetNMethod::nmethod_stub_entry_barrier)), rbx);
+
+    __ movdqu(xmm0, Address(rsp, xmm_size * 0));
+    __ movdqu(xmm1, Address(rsp, xmm_size * 1));
+    __ addptr(rsp, xmm_spill_size);
+
+    __ cmpl(rax, 1); // 1 means deoptimize
+    __ jcc(Assembler::equal, deoptimize_label);
+
+    __ popa();
+    __ pop(rbx);
+
+    __ leave();
+
+    __ addptr(rsp, 1 * wordSize); // cookie
+    __ ret(0);
+
+    __ BIND(deoptimize_label);
+
+    __ popa();
+    __ pop(rbx);
+
+    __ leave();
+
+    // this can be taken out, but is good for verification purposes. getting a SIGSEGV
+    // here while still having a correct stack is valuable
+    __ testptr(rsp, Address(rsp, 0));
+
+    __ movptr(rsp, Address(rsp, 0)); // new rsp was written in the barrier
+    __ jmp(Address(rsp, -1 * wordSize)); // jmp target should be callers verified_entry_point
+
+    return start;
+  }
+
  public:
   // Information about frame layout at time of blocking runtime call.
   // Note that we only have to preserve callee-saved registers since
@@ -3959,6 +4022,11 @@
     StubRoutines::_safefetchN_entry           = StubRoutines::_safefetch32_entry;
     StubRoutines::_safefetchN_fault_pc        = StubRoutines::_safefetch32_fault_pc;
     StubRoutines::_safefetchN_continuation_pc = StubRoutines::_safefetch32_continuation_pc;
+
+    BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
+    if (bs_nm != NULL) {
+      StubRoutines::x86::_method_entry_barrier = generate_method_entry_barrier();
+    }
   }
 
 
--- a/src/hotspot/cpu/x86/stubRoutines_x86.hpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/cpu/x86/stubRoutines_x86.hpp	Wed Nov 27 10:21:22 2019 +0100
@@ -55,14 +55,8 @@
   static address _double_sign_mask;
   static address _double_sign_flip;
 
-  static address _method_entry_barrier;
-
  public:
 
-  static address method_entry_barrier() {
-    return _method_entry_barrier;
-  }
-
   static address get_previous_fp_entry() {
     return _get_previous_fp_entry;
   }
@@ -121,6 +115,8 @@
   //shuffle mask for big-endian 128-bit integers
   static address _counter_shuffle_mask_addr;
 
+  static address _method_entry_barrier;
+
   // masks and table for CRC32
   static uint64_t _crc_by128_masks[];
   static juint    _crc_table[];
@@ -221,6 +217,7 @@
   static address upper_word_mask_addr() { return _upper_word_mask_addr; }
   static address shuffle_byte_flip_mask_addr() { return _shuffle_byte_flip_mask_addr; }
   static address k256_addr()      { return _k256_adr; }
+  static address method_entry_barrier() { return _method_entry_barrier; }
 
   static address vector_short_to_byte_mask() {
     return _vector_short_to_byte_mask;
--- a/src/hotspot/cpu/x86/stubRoutines_x86_32.cpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/cpu/x86/stubRoutines_x86_32.cpp	Wed Nov 27 10:21:22 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,3 +32,5 @@
 // a description of how to extend it, see the stubRoutines.hpp file.
 
 address StubRoutines::x86::_verify_fpu_cntrl_wrd_entry = NULL;
+address StubRoutines::x86::_method_entry_barrier = NULL;
+
--- a/src/hotspot/cpu/x86/vm_version_x86.cpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/cpu/x86/vm_version_x86.cpp	Wed Nov 27 10:21:22 2019 +0100
@@ -367,26 +367,29 @@
     //
     intx saved_useavx = UseAVX;
     intx saved_usesse = UseSSE;
-    // check _cpuid_info.sef_cpuid7_ebx.bits.avx512f
-    __ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_offset())));
-    __ movl(rax, 0x10000);
-    __ andl(rax, Address(rsi, 4)); // xcr0 bits sse | ymm
-    __ cmpl(rax, 0x10000);
-    __ jccb(Assembler::notEqual, legacy_setup); // jump if EVEX is not supported
-    // check _cpuid_info.xem_xcr0_eax.bits.opmask
-    // check _cpuid_info.xem_xcr0_eax.bits.zmm512
-    // check _cpuid_info.xem_xcr0_eax.bits.zmm32
-    __ movl(rax, 0xE0);
-    __ andl(rax, Address(rbp, in_bytes(VM_Version::xem_xcr0_offset()))); // xcr0 bits sse | ymm
-    __ cmpl(rax, 0xE0);
-    __ jccb(Assembler::notEqual, legacy_setup); // jump if EVEX is not supported
 
-    __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset())));
-    __ movl(rax, Address(rsi, 0));
-    __ cmpl(rax, 0x50654);              // If it is Skylake
-    __ jcc(Assembler::equal, legacy_setup);
     // If UseAVX is unitialized or is set by the user to include EVEX
     if (use_evex) {
+      // check _cpuid_info.sef_cpuid7_ebx.bits.avx512f
+      __ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_offset())));
+      __ movl(rax, 0x10000);
+      __ andl(rax, Address(rsi, 4)); // xcr0 bits sse | ymm
+      __ cmpl(rax, 0x10000);
+      __ jccb(Assembler::notEqual, legacy_setup); // jump if EVEX is not supported
+      // check _cpuid_info.xem_xcr0_eax.bits.opmask
+      // check _cpuid_info.xem_xcr0_eax.bits.zmm512
+      // check _cpuid_info.xem_xcr0_eax.bits.zmm32
+      __ movl(rax, 0xE0);
+      __ andl(rax, Address(rbp, in_bytes(VM_Version::xem_xcr0_offset()))); // xcr0 bits sse | ymm
+      __ cmpl(rax, 0xE0);
+      __ jccb(Assembler::notEqual, legacy_setup); // jump if EVEX is not supported
+
+      if (FLAG_IS_DEFAULT(UseAVX)) {
+        __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset())));
+        __ movl(rax, Address(rsi, 0));
+        __ cmpl(rax, 0x50654);              // If it is Skylake
+        __ jcc(Assembler::equal, legacy_setup);
+      }
       // EVEX setup: run in lowest evex mode
       VM_Version::set_evex_cpuFeatures(); // Enable temporary to pass asserts
       UseAVX = 3;
@@ -455,27 +458,28 @@
     VM_Version::set_cpuinfo_cont_addr(__ pc());
     // Returns here after signal. Save xmm0 to check it later.
 
-    // check _cpuid_info.sef_cpuid7_ebx.bits.avx512f
-    __ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_offset())));
-    __ movl(rax, 0x10000);
-    __ andl(rax, Address(rsi, 4));
-    __ cmpl(rax, 0x10000);
-    __ jcc(Assembler::notEqual, legacy_save_restore);
-    // check _cpuid_info.xem_xcr0_eax.bits.opmask
-    // check _cpuid_info.xem_xcr0_eax.bits.zmm512
-    // check _cpuid_info.xem_xcr0_eax.bits.zmm32
-    __ movl(rax, 0xE0);
-    __ andl(rax, Address(rbp, in_bytes(VM_Version::xem_xcr0_offset()))); // xcr0 bits sse | ymm
-    __ cmpl(rax, 0xE0);
-    __ jcc(Assembler::notEqual, legacy_save_restore);
-
-    __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset())));
-    __ movl(rax, Address(rsi, 0));
-    __ cmpl(rax, 0x50654);              // If it is Skylake
-    __ jcc(Assembler::equal, legacy_save_restore);
-
     // If UseAVX is unitialized or is set by the user to include EVEX
     if (use_evex) {
+      // check _cpuid_info.sef_cpuid7_ebx.bits.avx512f
+      __ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_offset())));
+      __ movl(rax, 0x10000);
+      __ andl(rax, Address(rsi, 4));
+      __ cmpl(rax, 0x10000);
+      __ jcc(Assembler::notEqual, legacy_save_restore);
+      // check _cpuid_info.xem_xcr0_eax.bits.opmask
+      // check _cpuid_info.xem_xcr0_eax.bits.zmm512
+      // check _cpuid_info.xem_xcr0_eax.bits.zmm32
+      __ movl(rax, 0xE0);
+      __ andl(rax, Address(rbp, in_bytes(VM_Version::xem_xcr0_offset()))); // xcr0 bits sse | ymm
+      __ cmpl(rax, 0xE0);
+      __ jcc(Assembler::notEqual, legacy_save_restore);
+
+      if (FLAG_IS_DEFAULT(UseAVX)) {
+        __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset())));
+        __ movl(rax, Address(rsi, 0));
+        __ cmpl(rax, 0x50654);              // If it is Skylake
+        __ jcc(Assembler::equal, legacy_save_restore);
+      }
       // EVEX check: run in lowest evex mode
       VM_Version::set_evex_cpuFeatures(); // Enable temporary to pass asserts
       UseAVX = 3;
--- a/src/hotspot/cpu/x86/x86_32.ad	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/cpu/x86/x86_32.ad	Wed Nov 27 10:21:22 2019 +0100
@@ -3917,6 +3917,13 @@
   interface(REG_INTER);
 %}
 
+operand eDXRegP(eRegP reg) %{
+  constraint(ALLOC_IN_RC(edx_reg));
+  match(reg);
+  format %{ "EDX" %}
+  interface(REG_INTER);
+%}
+
 operand eSIRegP(eRegP reg) %{
   constraint(ALLOC_IN_RC(esi_reg));
   match(reg);
@@ -8977,7 +8984,7 @@
   %}
 
   ins_pipe(ialu_reg_reg);
-%} 
+%}
 
 //----------Long Instructions------------------------------------------------
 // Add Long Register with Register
--- a/src/hotspot/cpu/x86/x86_64.ad	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/cpu/x86/x86_64.ad	Wed Nov 27 10:21:22 2019 +0100
@@ -267,6 +267,9 @@
 // Singleton class for RSI pointer register
 reg_class ptr_rsi_reg(RSI, RSI_H);
 
+// Singleton class for RBP pointer register
+reg_class ptr_rbp_reg(RBP, RBP_H);
+
 // Singleton class for RDI pointer register
 reg_class ptr_rdi_reg(RDI, RDI_H);
 
@@ -3530,6 +3533,16 @@
   interface(REG_INTER);
 %}
 
+operand rbp_RegP()
+%{
+  constraint(ALLOC_IN_RC(ptr_rbp_reg));
+  match(RegP);
+  match(rRegP);
+
+  format %{ %}
+  interface(REG_INTER);
+%}
+
 // Used in rep stosq
 operand rdi_RegP()
 %{
--- a/src/hotspot/share/adlc/adlparse.cpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/share/adlc/adlparse.cpp	Wed Nov 27 10:21:22 2019 +0100
@@ -123,6 +123,7 @@
     parse_err(SEMERR, "Did not declare 'register' definitions");
   }
   regBlock->addSpillRegClass();
+  regBlock->addDynamicRegClass();
 
   // Done with parsing, check consistency.
 
--- a/src/hotspot/share/adlc/archDesc.cpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/share/adlc/archDesc.cpp	Wed Nov 27 10:21:22 2019 +0100
@@ -245,12 +245,12 @@
     // Construct chain rules
     build_chain_rule(op);
 
-    MatchRule &mrule = *op->_matrule;
-    Predicate *pred  =  op->_predicate;
+    MatchRule *mrule = op->_matrule;
+    Predicate *pred  = op->_predicate;
 
     // Grab the machine type of the operand
     const char  *rootOp    = op->_ident;
-    mrule._machType  = rootOp;
+    mrule->_machType  = rootOp;
 
     // Check for special cases
     if (strcmp(rootOp,"Universe")==0) continue;
@@ -271,10 +271,13 @@
 
     // Find result type for match.
     const char *result      = op->reduce_result();
-    bool        has_root    = false;
 
-    // Construct a MatchList for this entry
-    buildMatchList(op->_matrule, result, rootOp, pred, cost);
+    // Construct a MatchList for this entry.
+    // Iterate over the list to enumerate all match cases for operands with multiple match rules.
+    for (; mrule != NULL; mrule = mrule->_next) {
+      mrule->_machType = rootOp;
+      buildMatchList(mrule, result, rootOp, pred, cost);
+    }
   }
 }
 
@@ -805,6 +808,8 @@
     return "RegMask::Empty";
   } else if (strcmp(reg_class_name,"stack_slots")==0) {
     return "(Compile::current()->FIRST_STACK_mask())";
+  } else if (strcmp(reg_class_name, "dynamic")==0) {
+    return "*_opnds[0]->in_RegMask(0)";
   } else {
     char       *rc_name = toUpper(reg_class_name);
     const char *mask    = "_mask";
@@ -867,7 +872,7 @@
   }
 
   // Instructions producing 'Universe' use RegMask::Empty
-  if( strcmp(result,"Universe")==0 ) {
+  if (strcmp(result,"Universe") == 0) {
     return "RegMask::Empty";
   }
 
--- a/src/hotspot/share/adlc/formsopt.cpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/share/adlc/formsopt.cpp	Wed Nov 27 10:21:22 2019 +0100
@@ -80,6 +80,15 @@
   _regClass.Insert(rc_name,reg_class);
 }
 
+// Called after parsing the Register block.  Record the register class
+// for operands which are overwritten after matching.
+void RegisterForm::addDynamicRegClass() {
+  const char *rc_name = "dynamic";
+  RegClass* reg_class = new RegClass(rc_name);
+  reg_class->set_stack_version(false);
+  _rclasses.addName(rc_name);
+  _regClass.Insert(rc_name,reg_class);
+}
 
 // Provide iteration over all register definitions
 // in the order used by the register allocator
--- a/src/hotspot/share/adlc/formsopt.hpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/share/adlc/formsopt.hpp	Wed Nov 27 10:21:22 2019 +0100
@@ -104,6 +104,7 @@
 
   AllocClass *addAllocClass(char *allocName);
   void        addSpillRegClass();
+  void        addDynamicRegClass();
 
   // Provide iteration over all register definitions
   // in the order used by the register allocator
--- a/src/hotspot/share/adlc/output_c.cpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/share/adlc/output_c.cpp	Wed Nov 27 10:21:22 2019 +0100
@@ -2781,6 +2781,8 @@
       // Return the sole RegMask.
       if (strcmp(first_reg_class, "stack_slots") == 0) {
         fprintf(fp,"  return &(Compile::current()->FIRST_STACK_mask());\n");
+      } else if (strcmp(first_reg_class, "dynamic") == 0) {
+        fprintf(fp,"  return &RegMask::Empty;\n");
       } else {
         const char* first_reg_class_to_upper = toUpper(first_reg_class);
         fprintf(fp,"  return &%s_mask();\n", first_reg_class_to_upper);
--- a/src/hotspot/share/gc/shared/barrierSetNMethod.cpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp	Wed Nov 27 10:21:22 2019 +0100
@@ -32,9 +32,7 @@
 #include "utilities/debug.hpp"
 
 int BarrierSetNMethod::disarmed_value() const {
-  char* disarmed_addr = reinterpret_cast<char*>(Thread::current());
-  disarmed_addr += in_bytes(thread_disarmed_offset());
-  return *reinterpret_cast<int*>(disarmed_addr);
+  return *disarmed_value_address();
 }
 
 bool BarrierSetNMethod::supports_entry_barrier(nmethod* nm) {
--- a/src/hotspot/share/gc/shared/barrierSetNMethod.hpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/share/gc/shared/barrierSetNMethod.hpp	Wed Nov 27 10:21:22 2019 +0100
@@ -34,13 +34,14 @@
 class BarrierSetNMethod: public CHeapObj<mtGC> {
   bool supports_entry_barrier(nmethod* nm);
   void deoptimize(nmethod* nm, address* return_addr_ptr);
+  int disarmed_value() const;
 
 protected:
-  virtual int disarmed_value() const;
   virtual bool nmethod_entry_barrier(nmethod* nm) = 0;
 
 public:
   virtual ByteSize thread_disarmed_offset() const = 0;
+  virtual int* disarmed_value_address() const = 0;
 
   static int nmethod_stub_entry_barrier(address* return_address_ptr);
   bool nmethod_osr_entry_barrier(nmethod* nm);
--- a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp	Wed Nov 27 10:21:22 2019 +0100
@@ -61,12 +61,10 @@
   return true;
 }
 
-int ZBarrierSetNMethod::disarmed_value() const {
-  // We override the default BarrierSetNMethod::disarmed_value() since
-  // this can be called by GC threads, which doesn't keep an up to date
-  // address_bad_mask.
-  const uintptr_t disarmed_addr = ((uintptr_t)&ZAddressBadMask) + ZNMethodDisarmedOffset;
-  return *((int*)disarmed_addr);
+int* ZBarrierSetNMethod::disarmed_value_address() const {
+  const uintptr_t mask_addr = reinterpret_cast<uintptr_t>(&ZAddressBadMask);
+  const uintptr_t disarmed_addr = mask_addr + ZNMethodDisarmedOffset;
+  return reinterpret_cast<int*>(disarmed_addr);
 }
 
 ByteSize ZBarrierSetNMethod::thread_disarmed_offset() const {
--- a/src/hotspot/share/gc/z/zBarrierSetNMethod.hpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.hpp	Wed Nov 27 10:21:22 2019 +0100
@@ -31,11 +31,11 @@
 
 class ZBarrierSetNMethod : public BarrierSetNMethod {
 protected:
-  virtual int disarmed_value() const;
   virtual bool nmethod_entry_barrier(nmethod* nm);
 
 public:
   virtual ByteSize thread_disarmed_offset() const;
+  virtual int* disarmed_value_address() const;
 };
 
 #endif // SHARE_GC_Z_ZBARRIERSETNMETHOD_HPP
--- a/src/hotspot/share/memory/filemap.cpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/share/memory/filemap.cpp	Wed Nov 27 10:21:22 2019 +0100
@@ -1385,14 +1385,6 @@
 
   }
 
-  DEBUG_ONLY(if (addr_delta == 0 && ArchiveRelocationMode == 1) {
-      // This is for simulating mmap failures at the requested address. We do it here (instead
-      // of MetaspaceShared::map_archives) so we can thoroughly test the code for failure handling
-      // (releasing all allocated resource, etc).
-      log_info(cds)("ArchiveRelocationMode == 1: always map archive(s) at an alternative address");
-      return MAP_ARCHIVE_MMAP_FAILURE;
-    });
-
   header()->set_mapped_base_address(header()->requested_base_address() + addr_delta);
   if (addr_delta != 0 && !relocate_pointers(addr_delta)) {
     return MAP_ARCHIVE_OTHER_FAILURE;
@@ -1446,12 +1438,14 @@
     MemTracker::record_virtual_memory_type((address)requested_addr, mtClassShared);
   }
 
-  if (MetaspaceShared::use_windows_memory_mapping() && addr_delta != 0) {
+  if (MetaspaceShared::use_windows_memory_mapping() && rs.is_reserved()) {
     // This is the second time we try to map the archive(s). We have already created a ReservedSpace
     // that covers all the FileMapRegions to ensure all regions can be mapped. However, Windows
     // can't mmap into a ReservedSpace, so we just os::read() the data. We're going to patch all the
     // regions anyway, so there's no benefit for mmap anyway.
     if (!read_region(i, requested_addr, size)) {
+      log_info(cds)("Failed to read %s shared space into reserved space at " INTPTR_FORMAT,
+                    shared_region_name[i], p2i(requested_addr));
       return MAP_ARCHIVE_OTHER_FAILURE; // oom or I/O error.
     }
   } else {
@@ -1459,7 +1453,8 @@
                                 requested_addr, size, si->read_only(),
                                 si->allow_exec());
     if (base != requested_addr) {
-      log_info(cds)("Unable to map %s shared space at required address.", shared_region_name[i]);
+      log_info(cds)("Unable to map %s shared space at " INTPTR_FORMAT,
+                    shared_region_name[i], p2i(requested_addr));
       _memory_mapping_failed = true;
       return MAP_ARCHIVE_MMAP_FAILURE;
     }
@@ -1468,7 +1463,7 @@
   si->set_mapped_base(requested_addr);
 
   if (!rs.is_reserved()) {
-    // When mapping on Windows with (addr_delta == 0), we don't reserve the address space for the regions
+    // When mapping on Windows for the first attempt, we don't reserve the address space for the regions
     // (Windows can't mmap into a ReservedSpace). In this case, NMT requires we call it after
     // os::map_memory has succeeded.
     assert(MetaspaceShared::use_windows_memory_mapping(), "Windows memory mapping only");
--- a/src/hotspot/share/memory/metaspaceShared.cpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/share/memory/metaspaceShared.cpp	Wed Nov 27 10:21:22 2019 +0100
@@ -2147,6 +2147,19 @@
     MapArchiveResult dynamic_result = (static_result == MAP_ARCHIVE_SUCCESS) ?
                                      map_archive(dynamic_mapinfo, mapped_base_address, archive_space_rs) : MAP_ARCHIVE_OTHER_FAILURE;
 
+    DEBUG_ONLY(if (ArchiveRelocationMode == 1 && use_requested_addr) {
+      // This is for simulating mmap failures at the requested address. In debug builds, we do it
+      // here (after all archives have possibly been mapped), so we can thoroughly test the code for
+      // failure handling (releasing all allocated resource, etc).
+      log_info(cds)("ArchiveRelocationMode == 1: always map archive(s) at an alternative address");
+      if (static_result == MAP_ARCHIVE_SUCCESS) {
+        static_result = MAP_ARCHIVE_MMAP_FAILURE;
+      }
+      if (dynamic_result == MAP_ARCHIVE_SUCCESS) {
+        dynamic_result = MAP_ARCHIVE_MMAP_FAILURE;
+      }
+    });
+
     if (static_result == MAP_ARCHIVE_SUCCESS) {
       if (dynamic_result == MAP_ARCHIVE_SUCCESS) {
         result = MAP_ARCHIVE_SUCCESS;
@@ -2298,7 +2311,7 @@
 MapArchiveResult MetaspaceShared::map_archive(FileMapInfo* mapinfo, char* mapped_base_address, ReservedSpace rs) {
   assert(UseSharedSpaces, "must be runtime");
   if (mapinfo == NULL) {
-    return MAP_ARCHIVE_SUCCESS; // no error has happeed -- trivially succeeded.
+    return MAP_ARCHIVE_SUCCESS; // The dynamic archive has not been specified. No error has happened -- trivially succeeded.
   }
 
   mapinfo->set_is_mapped(false);
--- a/src/hotspot/share/opto/parse3.cpp	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/hotspot/share/opto/parse3.cpp	Wed Nov 27 10:21:22 2019 +0100
@@ -55,8 +55,9 @@
     return;
   }
 
-  // Deoptimize on putfield writes to call site target field.
-  if (!is_get && field->is_call_site_target()) {
+  // Deoptimize on putfield writes to call site target field outside of CallSite ctor.
+  if (!is_get && field->is_call_site_target() &&
+      !(method()->holder() == field_holder && method()->is_object_initializer())) {
     uncommon_trap(Deoptimization::Reason_unhandled,
                   Deoptimization::Action_reinterpret,
                   NULL, "put to call site target field");
--- a/src/java.base/share/classes/java/lang/invoke/CallSite.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/java.base/share/classes/java/lang/invoke/CallSite.java	Wed Nov 27 10:21:22 2019 +0100
@@ -87,9 +87,10 @@
 abstract
 public class CallSite {
 
-    // The actual payload of this call site:
+    // The actual payload of this call site.
+    // Can be modified using {@link MethodHandleNatives#setCallSiteTargetNormal} or {@link MethodHandleNatives#setCallSiteTargetVolatile}.
     /*package-private*/
-    MethodHandle target;    // Note: This field is known to the JVM.  Do not change.
+    final MethodHandle target;  // Note: This field is known to the JVM.
 
     /**
      * Make a blank call site object with the given method type.
@@ -129,11 +130,11 @@
      */
     /*package-private*/
     CallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
-        this(targetType);
+        this(targetType); // need to initialize target to make CallSite.type() work in createTargetHook
         ConstantCallSite selfCCS = (ConstantCallSite) this;
         MethodHandle boundTarget = (MethodHandle) createTargetHook.invokeWithArguments(selfCCS);
-        checkTargetChange(this.target, boundTarget);
-        this.target = boundTarget;
+        setTargetNormal(boundTarget); // ConstantCallSite doesn't publish CallSite.target
+        UNSAFE.storeStoreFence(); // barrier between target and isFrozen updates
     }
 
     /**
@@ -190,11 +191,12 @@
      */
     public abstract void setTarget(MethodHandle newTarget);
 
-    void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) {
-        MethodType oldType = oldTarget.type();
+    private void checkTargetChange(MethodHandle newTarget) {
+        MethodType oldType = target.type(); // target is always present
         MethodType newType = newTarget.type();  // null check!
-        if (!newType.equals(oldType))
+        if (newType != oldType) {
             throw wrongTargetType(newTarget, oldType);
+        }
     }
 
     private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
@@ -217,7 +219,7 @@
      */
     public abstract MethodHandle dynamicInvoker();
 
-    /*non-public*/
+    /*package-private*/
     MethodHandle makeDynamicInvoker() {
         MethodHandle getTarget = getTargetHandle().bindArgumentL(0, this);
         MethodHandle invoker = MethodHandles.exactInvoker(this.type());
@@ -283,19 +285,24 @@
     }
 
     /*package-private*/
-    void setTargetNormal(MethodHandle newTarget) {
+    final void setTargetNormal(MethodHandle newTarget) {
+        checkTargetChange(newTarget);
         MethodHandleNatives.setCallSiteTargetNormal(this, newTarget);
     }
+
     /*package-private*/
-    MethodHandle getTargetVolatile() {
+    final MethodHandle getTargetVolatile() {
         return (MethodHandle) UNSAFE.getReferenceVolatile(this, getTargetOffset());
     }
+
     /*package-private*/
-    void setTargetVolatile(MethodHandle newTarget) {
+    final void setTargetVolatile(MethodHandle newTarget) {
+        checkTargetChange(newTarget);
         MethodHandleNatives.setCallSiteTargetVolatile(this, newTarget);
     }
 
     // this implements the upcall from the JVM, MethodHandleNatives.linkCallSite:
+    /*package-private*/
     static CallSite makeSite(MethodHandle bootstrapMethod,
                              // Callee information:
                              String name, MethodType type,
--- a/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java	Wed Nov 27 10:21:22 2019 +0100
@@ -25,6 +25,9 @@
 
 package java.lang.invoke;
 
+import jdk.internal.misc.Unsafe;
+import jdk.internal.vm.annotation.Stable;
+
 /**
  * A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed.
  * An {@code invokedynamic} instruction linked to a {@code ConstantCallSite} is permanently
@@ -33,7 +36,10 @@
  * @since 1.7
  */
 public class ConstantCallSite extends CallSite {
-    private final boolean isFrozen;
+    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
+    @Stable // should NOT be constant folded during instance initialization (isFrozen == false)
+    /*final*/ private boolean isFrozen;
 
     /**
      * Creates a call site with a permanent target.
@@ -43,6 +49,7 @@
     public ConstantCallSite(MethodHandle target) {
         super(target);
         isFrozen = true;
+        UNSAFE.storeStoreFence(); // properly publish isFrozen update
     }
 
     /**
@@ -79,8 +86,9 @@
      * @throws Throwable anything else thrown by the hook function
      */
     protected ConstantCallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
-        super(targetType, createTargetHook);
+        super(targetType, createTargetHook); // "this" instance leaks into createTargetHook
         isFrozen = true;
+        UNSAFE.storeStoreFence(); // properly publish isFrozen
     }
 
     /**
--- a/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java	Wed Nov 27 10:21:22 2019 +0100
@@ -152,7 +152,6 @@
      * @see #getTarget
      */
     @Override public void setTarget(MethodHandle newTarget) {
-        checkTargetChange(this.target, newTarget);
         setTargetNormal(newTarget);
     }
 
--- a/src/java.base/share/classes/java/lang/invoke/VolatileCallSite.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/java.base/share/classes/java/lang/invoke/VolatileCallSite.java	Wed Nov 27 10:21:22 2019 +0100
@@ -96,7 +96,6 @@
      * @see #getTarget
      */
     @Override public void setTarget(MethodHandle newTarget) {
-        checkTargetChange(getTargetVolatile(), newTarget);
         setTargetVolatile(newTarget);
     }
 
--- a/src/java.base/share/classes/jdk/internal/PreviewFeature.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/java.base/share/classes/jdk/internal/PreviewFeature.java	Wed Nov 27 10:21:22 2019 +0100
@@ -54,6 +54,8 @@
     public boolean essentialAPI() default false;
 
     public enum Feature {
-        TEXT_BLOCKS;
+        PATTERN_MATCHING_IN_INSTANCEOF,
+        TEXT_BLOCKS,
+        ;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/BindingPatternTree.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.source.tree;
+
+import javax.lang.model.element.Name;
+
+/**
+ * {@preview Associated with pattern matching for instanceof, a preview feature of
+ *           the Java language.
+ *
+ *           This interface is associated with <i>pattern matching for instanceof</i>, a preview
+ *           feature of the Java language. Preview features
+ *           may be removed in a future release, or upgraded to permanent
+ *           features of the Java language.}
+ *
+ * A binding pattern tree
+ *
+ * @since 14
+ */
+public interface BindingPatternTree extends PatternTree {
+
+    /**
+     * Returns the type of the bind variable.
+     * @return the type
+     */
+    Tree getType();
+
+    /**
+     * A binding variable name.
+     * @return the name of the binding variable
+     */
+    Name getBinding();
+
+}
+
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java	Wed Nov 27 10:21:22 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -51,4 +51,33 @@
      * @return the type
      */
     Tree getType();
+
+    /**
+     * {@preview Associated with pattern matching for instanceof, a preview feature of
+     *           the Java language.
+     *
+     *           This method is associated with <i>pattern matching for instanceof</i>, a preview
+     *           feature of the Java language. Preview features
+     *           may be removed in a future release, or upgraded to permanent
+     *           features of the Java language.}
+     *
+     * Returns the tested pattern, or null if this instanceof does not use
+     * a pattern.
+     *
+     * <p>For instanceof with a pattern, i.e. in the following form:
+     * <pre>
+     *   <em>expression</em> instanceof <em>type</em> <em>variable name</em>
+     * </pre>
+     * returns the pattern.
+     *
+     * <p>For instanceof without a pattern, i.e. in the following form:
+     * <pre>
+     *   <em>expression</em> instanceof <em>type</em>
+     * </pre>
+     * returns null.
+     *
+     * @return the tested pattern, or null if this instanceof does not use a pattern.
+     * @since 14
+     */
+    PatternTree getPattern();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/PatternTree.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.source.tree;
+
+/**
+ * {@preview Associated with pattern matching for instanceof, a preview feature of
+ *           the Java language.
+ *
+ *           This interface is associated with <i>pattern matching for instanceof</i>, a preview
+ *           feature of the Java language. Preview features
+ *           may be removed in a future release, or upgraded to permanent
+ *           features of the Java language.}
+ *
+ * A tree node used as the base class for the different kinds of
+ * statements.
+ *
+ * @since 14
+ */
+public interface PatternTree extends Tree {}
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java	Wed Nov 27 10:21:22 2019 +0100
@@ -220,6 +220,21 @@
         PARENTHESIZED(ParenthesizedTree.class),
 
         /**
+         * {@preview Associated with pattern matching for instanceof, a preview feature of
+         *           the Java language.
+         *
+         *           This enum constant is associated with <i>pattern matching for instanceof</i>, a preview
+         *           feature of the Java language. Preview features
+         *           may be removed in a future release, or upgraded to permanent
+         *           features of the Java language.}
+         *
+         * Used for instances of {@link BindingPatternTree}.
+         *
+         * @since 14
+         */
+        BINDING_PATTERN(BindingPatternTree.class),
+
+        /**
          * Used for instances of {@link PrimitiveTypeTree}.
          */
         PRIMITIVE_TYPE(PrimitiveTypeTree.class),
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java	Wed Nov 27 10:21:22 2019 +0100
@@ -258,6 +258,23 @@
     R visitLiteral(LiteralTree node, P p);
 
     /**
+     * {@preview Associated with pattern matching for instanceof, a preview feature of
+     *           the Java language.
+     *
+     *           This method is associated with <i>pattern matching for instanceof</i>, a preview
+     *           feature of the Java language. Preview features
+     *           may be removed in a future release, or upgraded to permanent
+     *           features of the Java language.}
+     *
+     * Visits an BindingPattern node.
+     * @param node the node being visited
+     * @param p a parameter value
+     * @return a result value
+     * @since 14
+     */
+    R visitBindingPattern(BindingPatternTree node, P p);
+
+    /**
      * Visits a MethodTree node.
      * @param node the node being visited
      * @param p a parameter value
--- a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java	Wed Nov 27 10:21:22 2019 +0100
@@ -557,6 +557,19 @@
      * @param node {@inheritDoc}
      * @param p {@inheritDoc}
      * @return  the result of {@code defaultAction}
+     * @since 14
+     */
+    @Override
+    public R visitBindingPattern(BindingPatternTree node, P p) {
+        return defaultAction(node, p);
+    }
+
+    /**
+     * {@inheritDoc} This implementation calls {@code defaultAction}.
+     *
+     * @param node {@inheritDoc}
+     * @param p {@inheritDoc}
+     * @return  the result of {@code defaultAction}
      */
     @Override
     public R visitArrayAccess(ArrayAccessTree node, P p) {
--- a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java	Wed Nov 27 10:21:22 2019 +0100
@@ -667,7 +667,11 @@
     @Override
     public R visitInstanceOf(InstanceOfTree node, P p) {
         R r = scan(node.getExpression(), p);
-        r = scanAndReduce(node.getType(), p, r);
+        if (node.getPattern() != null) {
+            r = scanAndReduce(node.getPattern(), p, r);
+        } else {
+            r = scanAndReduce(node.getType(), p, r);
+        }
         return r;
     }
 
@@ -677,6 +681,19 @@
      * @param node  {@inheritDoc}
      * @param p  {@inheritDoc}
      * @return the result of scanning
+     * @since 14
+     */
+    @Override
+    public R visitBindingPattern(BindingPatternTree node, P p) {
+        return scan(node.getType(), p);
+    }
+
+    /**
+     * {@inheritDoc} This implementation scans the children in left to right order.
+     *
+     * @param node  {@inheritDoc}
+     * @param p  {@inheritDoc}
+     * @return the result of scanning
      */
     @Override
     public R visitArrayAccess(ArrayAccessTree node, P p) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Wed Nov 27 10:21:22 2019 +0100
@@ -334,6 +334,16 @@
      */
     public static final long PREVIEW_ESSENTIAL_API = 1L<<58; //any Symbol kind
 
+    /**
+     * Flag to indicate the given variable is a match binding variable.
+     */
+    public static final long MATCH_BINDING = 1L<<59;
+
+    /**
+     * A flag to indicate a match binding variable whose scope extends after the current statement.
+     */
+    public static final long MATCH_BINDING_TO_OUTER = 1L<<60;
+
     /** Modifier masks.
      */
     public static final int
@@ -453,7 +463,9 @@
         ANONCONSTR_BASED(Flags.ANONCONSTR_BASED),
         NAME_FILLED(Flags.NAME_FILLED),
         PREVIEW_API(Flags.PREVIEW_API),
-        PREVIEW_ESSENTIAL_API(Flags.PREVIEW_ESSENTIAL_API);
+        PREVIEW_ESSENTIAL_API(Flags.PREVIEW_ESSENTIAL_API),
+        MATCH_BINDING(Flags.MATCH_BINDING),
+        MATCH_BINDING_TO_OUTER(Flags.MATCH_BINDING_TO_OUTER);
 
         Flag(long flag) {
             this.value = flag;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java	Wed Nov 27 10:21:22 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -165,7 +165,9 @@
      * @return true, if given feature is a preview feature.
      */
     public boolean isPreview(Feature feature) {
-        if (feature == Feature.TEXT_BLOCKS)
+        if (feature == Feature.PATTERN_MATCHING_IN_INSTANCEOF ||
+            feature == Feature.REIFIABLE_TYPES_INSTANCEOF ||
+            feature == Feature.TEXT_BLOCKS)
             return true;
         //Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing).
         //When real preview features will be added, this method can be implemented to return 'true'
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Wed Nov 27 10:21:22 2019 +0100
@@ -198,7 +198,10 @@
         SWITCH_MULTIPLE_CASE_LABELS(JDK14, Fragments.FeatureMultipleCaseLabels, DiagKind.PLURAL),
         SWITCH_RULE(JDK14, Fragments.FeatureSwitchRules, DiagKind.PLURAL),
         SWITCH_EXPRESSION(JDK14, Fragments.FeatureSwitchExpressions, DiagKind.PLURAL),
-        TEXT_BLOCKS(JDK14, Fragments.FeatureTextBlocks, DiagKind.PLURAL);
+        TEXT_BLOCKS(JDK14, Fragments.FeatureTextBlocks, DiagKind.PLURAL),
+        PATTERN_MATCHING_IN_INSTANCEOF(JDK14, Fragments.FeaturePatternMatchingInstanceof, DiagKind.NORMAL),
+        REIFIABLE_TYPES_INSTANCEOF(JDK14, Fragments.FeatureReifiableTypesInstanceof, DiagKind.PLURAL),
+        ;
 
         enum DiagKind {
             NORMAL,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java	Wed Nov 27 10:21:22 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -390,22 +390,26 @@
                 sym.getKind() == ElementKind.LOCAL_VARIABLE ||
                 sym.getKind() == ElementKind.RESOURCE_VARIABLE ||
                 sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
-                // Make sure all type annotations from the symbol are also
-                // on the owner. If the owner is an initializer block, propagate
-                // to the type.
-                final long ownerFlags = sym.owner.flags();
-                if ((ownerFlags & Flags.BLOCK) != 0) {
-                    // Store init and clinit type annotations with the ClassSymbol
-                    // to allow output in Gen.normalizeDefs.
-                    ClassSymbol cs = (ClassSymbol) sym.owner.owner;
-                    if ((ownerFlags & Flags.STATIC) != 0) {
-                        cs.appendClassInitTypeAttributes(typeAnnotations);
-                    } else {
-                        cs.appendInitTypeAttributes(typeAnnotations);
-                    }
+                appendTypeAnnotationsToOwner(sym, typeAnnotations);
+            }
+        }
+
+        private void appendTypeAnnotationsToOwner(Symbol sym, List<Attribute.TypeCompound> typeAnnotations) {
+            // Make sure all type annotations from the symbol are also
+            // on the owner. If the owner is an initializer block, propagate
+            // to the type.
+            final long ownerFlags = sym.owner.flags();
+            if ((ownerFlags & Flags.BLOCK) != 0) {
+                // Store init and clinit type annotations with the ClassSymbol
+                // to allow output in Gen.normalizeDefs.
+                ClassSymbol cs = (ClassSymbol) sym.owner.owner;
+                if ((ownerFlags & Flags.STATIC) != 0) {
+                    cs.appendClassInitTypeAttributes(typeAnnotations);
                 } else {
-                    sym.owner.appendUniqueTypeAttributes(sym.getRawTypeAttributes());
+                    cs.appendInitTypeAttributes(typeAnnotations);
                 }
+            } else {
+                sym.owner.appendUniqueTypeAttributes(typeAnnotations);
             }
         }
 
@@ -943,10 +947,11 @@
                                                  " within frame " + frame);
                     }
 
+                case BINDING_PATTERN:
                 case VARIABLE:
-                    VarSymbol v = ((JCVariableDecl)frame).sym;
+                    VarSymbol v = frame.hasTag(Tag.BINDINGPATTERN) ? ((JCBindingPattern) frame).symbol : ((JCVariableDecl) frame).sym;
                     if (v.getKind() != ElementKind.FIELD) {
-                        v.owner.appendUniqueTypeAttributes(v.getRawTypeAttributes());
+                        appendTypeAnnotationsToOwner(v, v.getRawTypeAttributes());
                     }
                     switch (v.getKind()) {
                         case LOCAL_VARIABLE:
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Wed Nov 27 10:21:22 2019 +0100
@@ -1122,6 +1122,13 @@
         }
 
         @Override
+        public void visitBindingPattern(JCTree.JCBindingPattern tree) {
+            //type binding pattern's type will be annotated separatelly, avoid
+            //adding its annotations into the owning method here (would clash
+            //with repeatable annotations).
+        }
+
+        @Override
         public void visitClassDef(JCClassDecl tree) {
             // We can only hit a classdef if it is declared within
             // a method. Ignore it - the class will be visited
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Nov 27 10:21:22 2019 +0100
@@ -49,6 +49,7 @@
 import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
 import com.sun.tools.javac.comp.Check.CheckContext;
 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
+import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol;
 import com.sun.tools.javac.jvm.*;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg;
@@ -110,6 +111,7 @@
     final Enter enter;
     final Target target;
     final Types types;
+    final Preview preview;
     final JCDiagnostic.Factory diags;
     final TypeAnnotations typeAnnotations;
     final DeferredLintHandler deferredLintHandler;
@@ -117,6 +119,7 @@
     final Dependencies dependencies;
     final Annotate annotate;
     final ArgumentAttr argumentAttr;
+    final MatchBindingsComputer matchBindingsComputer;
 
     public static Attr instance(Context context) {
         Attr instance = context.get(attrKey);
@@ -145,6 +148,7 @@
         cfolder = ConstFold.instance(context);
         target = Target.instance(context);
         types = Types.instance(context);
+        preview = Preview.instance(context);
         diags = JCDiagnostic.Factory.instance(context);
         annotate = Annotate.instance(context);
         typeAnnotations = TypeAnnotations.instance(context);
@@ -152,6 +156,7 @@
         typeEnvs = TypeEnvs.instance(context);
         dependencies = Dependencies.instance(context);
         argumentAttr = ArgumentAttr.instance(context);
+        matchBindingsComputer = MatchBindingsComputer.instance(context);
 
         Options options = Options.instance(context);
 
@@ -161,6 +166,9 @@
         allowLambda = Feature.LAMBDA.allowedInSource(source);
         allowDefaultMethods = Feature.DEFAULT_METHODS.allowedInSource(source);
         allowStaticInterfaceMethods = Feature.STATIC_INTERFACE_METHODS.allowedInSource(source);
+        allowReifiableTypesInInstanceof =
+                Feature.REIFIABLE_TYPES_INSTANCEOF.allowedInSource(source) &&
+                (!preview.isPreview(Feature.REIFIABLE_TYPES_INSTANCEOF) || preview.isEnabled());
         sourceName = source.name;
         useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
 
@@ -193,6 +201,10 @@
      */
     boolean allowStaticInterfaceMethods;
 
+    /** Switch: reifiable types in instanceof enabled?
+     */
+    boolean allowReifiableTypesInInstanceof;
+
     /**
      * Switch: warn about use of variable before declaration?
      * RFE: 6425594
@@ -292,6 +304,8 @@
                isAssignableAsBlankFinal(v, env)))) {
             if (v.isResourceVariable()) { //TWR resource
                 log.error(pos, Errors.TryResourceMayNotBeAssigned(v));
+            } else if ((v.flags() & MATCH_BINDING) != 0) {
+                log.error(pos, Errors.PatternBindingMayNotBeAssigned(v));
             } else {
                 log.error(pos, Errors.CantAssignValToFinalVar(v));
             }
@@ -1298,29 +1312,73 @@
     public void visitDoLoop(JCDoWhileLoop tree) {
         attribStat(tree.body, env.dup(tree));
         attribExpr(tree.cond, env, syms.booleanType);
+        if (!breaksOutOf(tree, tree.body)) {
+            //include condition's body when false after the while, if cannot get out of the loop
+            List<BindingSymbol> bindings = matchBindingsComputer.getMatchBindings(tree.cond, false);
+
+            bindings.forEach(env.info.scope::enter);
+            bindings.forEach(BindingSymbol::preserveBinding);
+        }
         result = null;
     }
 
     public void visitWhileLoop(JCWhileLoop tree) {
         attribExpr(tree.cond, env, syms.booleanType);
-        attribStat(tree.body, env.dup(tree));
+        // include condition's bindings when true in the body:
+        Env<AttrContext> whileEnv = bindingEnv(env, matchBindingsComputer.getMatchBindings(tree.cond, true));
+        try {
+            attribStat(tree.body, whileEnv.dup(tree));
+        } finally {
+            whileEnv.info.scope.leave();
+        }
+        if (!breaksOutOf(tree, tree.body)) {
+            //include condition's bindings when false after the while, if cannot get out of the loop
+            List<BindingSymbol> bindings =
+                    matchBindingsComputer.getMatchBindings(tree.cond, false);
+
+            bindings.forEach(env.info.scope::enter);
+            bindings.forEach(BindingSymbol::preserveBinding);
+        }
         result = null;
     }
 
+    private boolean breaksOutOf(JCTree loop, JCTree body) {
+        preFlow(body);
+        return flow.breaksOutOf(env, loop, body, make);
+    }
+
     public void visitForLoop(JCForLoop tree) {
         Env<AttrContext> loopEnv =
             env.dup(env.tree, env.info.dup(env.info.scope.dup()));
         try {
             attribStats(tree.init, loopEnv);
-            if (tree.cond != null) attribExpr(tree.cond, loopEnv, syms.booleanType);
-            loopEnv.tree = tree; // before, we were not in loop!
-            attribStats(tree.step, loopEnv);
-            attribStat(tree.body, loopEnv);
+            List<BindingSymbol> matchBindings = List.nil();
+            if (tree.cond != null) {
+                attribExpr(tree.cond, loopEnv, syms.booleanType);
+                // include condition's bindings when true in the body and step:
+                matchBindings = matchBindingsComputer.getMatchBindings(tree.cond, true);
+            }
+            Env<AttrContext> bodyEnv = bindingEnv(loopEnv, matchBindings);
+            try {
+                bodyEnv.tree = tree; // before, we were not in loop!
+                attribStats(tree.step, bodyEnv);
+                attribStat(tree.body, bodyEnv);
+            } finally {
+                bodyEnv.info.scope.leave();
+            }
             result = null;
         }
         finally {
             loopEnv.info.scope.leave();
         }
+        if (!breaksOutOf(tree, tree.body)) {
+            //include condition's body when false after the while, if cannot get out of the loop
+            List<BindingSymbol> bindings =
+                    matchBindingsComputer.getMatchBindings(tree.cond, false);
+
+            bindings.forEach(env.info.scope::enter);
+            bindings.forEach(BindingSymbol::preserveBinding);
+        }
     }
 
     public void visitForeachLoop(JCEnhancedForLoop tree) {
@@ -1673,8 +1731,26 @@
                 unknownExprInfo :
                 resultInfo.dup(conditionalContext(resultInfo.checkContext));
 
-        Type truetype = attribTree(tree.truepart, env, condInfo);
-        Type falsetype = attribTree(tree.falsepart, env, condInfo);
+
+        // x ? y : z
+        // include x's bindings when true in y
+        // include x's bindings when false in z
+
+        Type truetype;
+        Env<AttrContext> trueEnv = bindingEnv(env, matchBindingsComputer.getMatchBindings(tree.cond, true));
+        try {
+            truetype = attribTree(tree.truepart, trueEnv, condInfo);
+        } finally {
+            trueEnv.info.scope.leave();
+        }
+
+        Type falsetype;
+        Env<AttrContext> falseEnv = bindingEnv(env, matchBindingsComputer.getMatchBindings(tree.cond, false));
+        try {
+            falsetype = attribTree(tree.falsepart, falseEnv, condInfo);
+        } finally {
+            falseEnv.info.scope.leave();
+        }
 
         Type owntype = (tree.polyKind == PolyKind.STANDALONE) ?
                 condType(List.of(tree.truepart.pos(), tree.falsepart.pos()),
@@ -1829,15 +1905,77 @@
         BOOLEAN,
     };
 
+    Env<AttrContext> bindingEnv(Env<AttrContext> env, List<BindingSymbol> bindings) {
+        Env<AttrContext> env1 = env.dup(env.tree, env.info.dup(env.info.scope.dup()));
+        bindings.forEach(env1.info.scope::enter);
+        return env1;
+    }
+
     public void visitIf(JCIf tree) {
         attribExpr(tree.cond, env, syms.booleanType);
-        attribStat(tree.thenpart, env);
-        if (tree.elsepart != null)
-            attribStat(tree.elsepart, env);
+
+        // if (x) { y } [ else z ]
+        // include x's bindings when true in y
+        // include x's bindings when false in z
+
+        List<BindingSymbol> thenBindings = matchBindingsComputer.getMatchBindings(tree.cond, true);
+        Env<AttrContext> thenEnv = bindingEnv(env, thenBindings);
+
+        try {
+            attribStat(tree.thenpart, thenEnv);
+        } finally {
+            thenEnv.info.scope.leave();
+        }
+
+        preFlow(tree.thenpart);
+        boolean aliveAfterThen = flow.aliveAfter(env, tree.thenpart, make);
+        boolean aliveAfterElse;
+        List<BindingSymbol> elseBindings = matchBindingsComputer.getMatchBindings(tree.cond, false);
+
+        if (tree.elsepart != null) {
+            Env<AttrContext> elseEnv = bindingEnv(env, elseBindings);
+            try {
+                attribStat(tree.elsepart, elseEnv);
+            } finally {
+                elseEnv.info.scope.leave();
+            }
+            preFlow(tree.elsepart);
+            aliveAfterElse = flow.aliveAfter(env, tree.elsepart, make);
+        } else {
+            aliveAfterElse = true;
+        }
+
         chk.checkEmptyIf(tree);
+
+        List<BindingSymbol> afterIfBindings = List.nil();
+
+        if (aliveAfterThen && !aliveAfterElse) {
+            afterIfBindings = thenBindings;
+        } else if (aliveAfterElse && !aliveAfterThen) {
+            afterIfBindings = elseBindings;
+        }
+
+        afterIfBindings.forEach(env.info.scope::enter);
+        afterIfBindings.forEach(BindingSymbol::preserveBinding);
+
         result = null;
     }
 
+        void preFlow(JCTree tree) {
+            new PostAttrAnalyzer() {
+                @Override
+                public void scan(JCTree tree) {
+                    if (tree == null ||
+                            (tree.type != null &&
+                            tree.type == Type.stuckType)) {
+                        //don't touch stuck expressions!
+                        return;
+                    }
+                    super.scan(tree);
+                }
+            }.scan(tree);
+        }
+
     public void visitExec(JCExpressionStatement tree) {
         //a fresh environment is required for 292 inference to work properly ---
         //see Infer.instantiatePolymorphicSignatureInstance()
@@ -3521,7 +3659,32 @@
     public void visitBinary(JCBinary tree) {
         // Attribute arguments.
         Type left = chk.checkNonVoid(tree.lhs.pos(), attribExpr(tree.lhs, env));
-        Type right = chk.checkNonVoid(tree.rhs.pos(), attribExpr(tree.rhs, env));
+        // x && y
+        // include x's bindings when true in y
+
+        // x || y
+        // include x's bindings when false in y
+
+        List<BindingSymbol> matchBindings;
+        switch (tree.getTag()) {
+            case AND:
+                matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, true);
+                break;
+            case OR:
+                matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, false);
+                break;
+            default:
+                matchBindings = List.nil();
+                break;
+        }
+        Env<AttrContext> rhsEnv = bindingEnv(env, matchBindings);
+        Type right;
+        try {
+            right = chk.checkNonVoid(tree.rhs.pos(), attribExpr(tree.rhs, rhsEnv));
+        } finally {
+            rhsEnv.info.scope.leave();
+        }
+
         // Find operator.
         Symbol operator = tree.operator = operators.resolveBinary(tree, tree.getTag(), left, right);
         Type owntype = types.createErrorType(tree.type);
@@ -3587,19 +3750,63 @@
     public void visitTypeTest(JCInstanceOf tree) {
         Type exprtype = chk.checkNullOrRefType(
                 tree.expr.pos(), attribExpr(tree.expr, env));
-        Type clazztype = attribType(tree.clazz, env);
+        Type clazztype;
+        JCTree typeTree;
+        if (tree.pattern.getTag() == BINDINGPATTERN) {
+            attribTree(tree.pattern, env, unknownExprInfo);
+            clazztype = tree.pattern.type;
+            JCBindingPattern pattern = (JCBindingPattern) tree.pattern;
+            typeTree = pattern.vartype;
+            if (!clazztype.hasTag(TYPEVAR)) {
+                clazztype = chk.checkClassOrArrayType(pattern.vartype.pos(), clazztype);
+            }
+        } else {
+            clazztype = attribType(tree.pattern, env);
+            typeTree = tree.pattern;
+        }
         if (!clazztype.hasTag(TYPEVAR)) {
-            clazztype = chk.checkClassOrArrayType(tree.clazz.pos(), clazztype);
+            clazztype = chk.checkClassOrArrayType(typeTree.pos(), clazztype);
         }
         if (!clazztype.isErroneous() && !types.isReifiable(clazztype)) {
-            log.error(tree.clazz.pos(), Errors.IllegalGenericTypeForInstof);
-            clazztype = types.createErrorType(clazztype);
-        }
-        chk.validate(tree.clazz, env, false);
+            boolean valid = false;
+            if (allowReifiableTypesInInstanceof) {
+                if (preview.isPreview(Feature.REIFIABLE_TYPES_INSTANCEOF)) {
+                    preview.warnPreview(tree.expr.pos(), Feature.REIFIABLE_TYPES_INSTANCEOF);
+                }
+                Warner warner = new Warner();
+                if (!types.isCastable(exprtype, clazztype, warner)) {
+                    chk.basicHandler.report(tree.expr.pos(),
+                                            diags.fragment(Fragments.InconvertibleTypes(exprtype, clazztype)));
+                } else if (warner.hasLint(LintCategory.UNCHECKED)) {
+                    log.error(tree.expr.pos(),
+                              Errors.InstanceofReifiableNotSafe(exprtype, clazztype));
+                } else {
+                    valid = true;
+                }
+            } else {
+                log.error(typeTree.pos(), Errors.IllegalGenericTypeForInstof);
+            }
+            if (!valid) {
+                clazztype = types.createErrorType(clazztype);
+            }
+        }
+        chk.validate(typeTree, env, false);
         chk.checkCastable(tree.expr.pos(), exprtype, clazztype);
         result = check(tree, syms.booleanType, KindSelector.VAL, resultInfo);
     }
 
+    public void visitBindingPattern(JCBindingPattern tree) {
+        ResultInfo varInfo = new ResultInfo(KindSelector.TYP, resultInfo.pt, resultInfo.checkContext);
+        tree.type = attribTree(tree.vartype, env, varInfo);
+        VarSymbol v = tree.symbol = new BindingSymbol(tree.name, tree.vartype.type, env.info.scope.owner);
+        if (chk.checkUnique(tree.pos(), v, env.info.scope)) {
+            chk.checkTransparentVar(tree.pos(), v, env.info.scope);
+        }
+        annotate.queueScanTreeAndTypeAnnotate(tree.vartype, env, v, tree.pos());
+        annotate.flush();
+        result = tree.type;
+    }
+
     public void visitIndexed(JCArrayAccess tree) {
         Type owntype = types.createErrorType(tree.type);
         Type atype = attribExpr(tree.indexed, env);
@@ -4991,8 +5198,8 @@
             super.visitTypeCast(tree);
         }
         public void visitTypeTest(JCInstanceOf tree) {
-            if (tree.clazz != null && tree.clazz.type != null)
-                validateAnnotatedType(tree.clazz, tree.clazz.type);
+            if (tree.pattern != null && !(tree.pattern instanceof JCPattern) && tree.pattern.type != null)
+                validateAnnotatedType(tree.pattern, tree.pattern.type);
             super.visitTypeTest(tree);
         }
         public void visitNewClass(JCNewClass tree) {
@@ -5253,6 +5460,15 @@
         }
 
         @Override
+        public void visitBindingPattern(JCBindingPattern that) {
+            if (that.symbol == null) {
+                that.symbol = new BindingSymbol(that.name, that.type, syms.noSymbol);
+                that.symbol.adr = 0;
+            }
+            super.visitBindingPattern(that);
+        }
+
+        @Override
         public void visitNewClass(JCNewClass that) {
             if (that.constructor == null) {
                 that.constructor = new MethodSymbol(0, names.init,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Wed Nov 27 10:21:22 2019 +0100
@@ -3486,6 +3486,11 @@
                     duplicateErasureError(pos, sym, byName);
                     sym.flags_field |= CLASH;
                     return true;
+                } else if ((sym.flags() & MATCH_BINDING) != 0 &&
+                           (byName.flags() & MATCH_BINDING) != 0 &&
+                           (byName.flags() & MATCH_BINDING_TO_OUTER) == 0) {
+                    //this error will be reported separatelly in MatchBindingsComputer
+                    return false;
                 } else {
                     duplicateError(pos, byName);
                     return false;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/CompileStates.java	Wed Nov 27 10:21:22 2019 +0100
@@ -59,9 +59,10 @@
         ATTR(4),
         FLOW(5),
         TRANSTYPES(6),
-        UNLAMBDA(7),
-        LOWER(8),
-        GENERATE(9);
+        TRANSPATTERNS(7),
+        UNLAMBDA(8),
+        LOWER(9),
+        GENERATE(10);
 
         CompileState(int value) {
             this.value = value;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Wed Nov 27 10:21:22 2019 +0100
@@ -255,6 +255,41 @@
         }
     }
 
+    public boolean aliveAfter(Env<AttrContext> env, JCTree that, TreeMaker make) {
+        //we need to disable diagnostics temporarily; the problem is that if
+        //"that" contains e.g. an unreachable statement, an error
+        //message will be reported and will cause compilation to skip the flow analyis
+        //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
+        //related errors, which will allow for more errors to be detected
+        Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
+        try {
+            SnippetAliveAnalyzer analyzer = new SnippetAliveAnalyzer();
+
+            analyzer.analyzeTree(env, that, make);
+            return analyzer.isAlive();
+        } finally {
+            log.popDiagnosticHandler(diagHandler);
+        }
+    }
+
+    public boolean breaksOutOf(Env<AttrContext> env, JCTree loop, JCTree body, TreeMaker make) {
+        //we need to disable diagnostics temporarily; the problem is that if
+        //"that" contains e.g. an unreachable statement, an error
+        //message will be reported and will cause compilation to skip the flow analyis
+        //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
+        //related errors, which will allow for more errors to be detected
+        Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
+        try {
+            boolean[] breaksOut = new boolean[1];
+            SnippetBreakAnalyzer analyzer = new SnippetBreakAnalyzer(loop);
+
+            analyzer.analyzeTree(env, body, make);
+            return analyzer.breaksOut();
+        } finally {
+            log.popDiagnosticHandler(diagHandler);
+        }
+    }
+
     /**
      * Definite assignment scan mode
      */
@@ -1467,6 +1502,38 @@
     }
 
     /**
+     * Determine if alive after the given tree.
+     */
+    class SnippetAliveAnalyzer extends AliveAnalyzer {
+        @Override
+        public void visitClassDef(JCClassDecl tree) {
+            //skip
+        }
+        public boolean isAlive() {
+            return super.alive != Liveness.DEAD;
+        }
+    }
+
+    class SnippetBreakAnalyzer extends AliveAnalyzer {
+        private final JCTree loop;
+        private boolean breaksOut;
+
+        public SnippetBreakAnalyzer(JCTree loop) {
+            this.loop = loop;
+        }
+
+        @Override
+        public void visitBreak(JCBreak tree) {
+            breaksOut |= (super.alive == Liveness.ALIVE && tree.target == loop);
+            super.visitBreak(tree);
+        }
+
+        public boolean breaksOut() {
+            return breaksOut;
+        }
+    }
+
+    /**
      * Specialized pass that performs DA/DU on a lambda
      */
     class LambdaAssignAnalyzer extends AssignAnalyzer {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.comp;
+
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.resources.CompilerProperties.Errors;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCBinary;
+import com.sun.tools.javac.tree.JCTree.JCConditional;
+import com.sun.tools.javac.tree.JCTree.JCUnary;
+import com.sun.tools.javac.tree.JCTree.JCBindingPattern;
+import com.sun.tools.javac.tree.TreeScanner;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Name;
+
+
+public class MatchBindingsComputer extends TreeScanner {
+    protected static final Context.Key<MatchBindingsComputer> matchBindingsComputerKey = new Context.Key<>();
+
+    private final Log log;
+    private final Types types;
+    boolean whenTrue;
+    List<BindingSymbol> bindings;
+
+    public static MatchBindingsComputer instance(Context context) {
+        MatchBindingsComputer instance = context.get(matchBindingsComputerKey);
+        if (instance == null)
+            instance = new MatchBindingsComputer(context);
+        return instance;
+    }
+
+    protected MatchBindingsComputer(Context context) {
+        this.log = Log.instance(context);
+        this.types = Types.instance(context);
+    }
+
+    public List<BindingSymbol> getMatchBindings(JCTree expression, boolean whenTrue) {
+        this.whenTrue = whenTrue;
+        this.bindings = List.nil();
+        scan(expression);
+        return bindings;
+    }
+
+    @Override
+    public void visitBindingPattern(JCBindingPattern tree) {
+        bindings = whenTrue ? List.of(tree.symbol) : List.nil();
+    }
+
+    @Override
+    public void visitBinary(JCBinary tree) {
+        switch (tree.getTag()) {
+            case AND:
+                // e.T = union(x.T, y.T)
+                // e.F = intersection(x.F, y.F)
+                scan(tree.lhs);
+                List<BindingSymbol> lhsBindings = bindings;
+                scan(tree.rhs);
+                List<BindingSymbol> rhsBindings = bindings;
+                bindings = whenTrue ? union(tree, lhsBindings, rhsBindings) : intersection(tree, lhsBindings, rhsBindings);
+                break;
+            case OR:
+                // e.T = intersection(x.T, y.T)
+                // e.F = union(x.F, y.F)
+                scan(tree.lhs);
+                lhsBindings = bindings;
+                scan(tree.rhs);
+                rhsBindings = bindings;
+                bindings = whenTrue ? intersection(tree, lhsBindings, rhsBindings) : union(tree, lhsBindings, rhsBindings);
+                break;
+            default:
+                super.visitBinary(tree);
+                break;
+        }
+    }
+
+    @Override
+    public void visitUnary(JCUnary tree) {
+        switch (tree.getTag()) {
+            case NOT:
+                // e.T = x.F  // flip 'em
+                // e.F = x.T
+                whenTrue = !whenTrue;
+                scan(tree.arg);
+                whenTrue = !whenTrue;
+                break;
+            default:
+                super.visitUnary(tree);
+                break;
+        }
+    }
+
+    @Override
+    public void visitConditional(JCConditional tree) {
+        /* if e = "x ? y : z", then:
+               e.T = union(intersect(y.T, z.T), intersect(x.T, z.T), intersect(x.F, y.T))
+               e.F = union(intersect(y.F, z.F), intersect(x.T, z.F), intersect(x.F, y.F))
+        */
+        if (whenTrue) {
+            List<BindingSymbol> xT, yT, zT, xF;
+            scan(tree.cond);
+            xT = bindings;
+            scan(tree.truepart);
+            yT = bindings;
+            scan(tree.falsepart);
+            zT = bindings;
+            whenTrue = false;
+            scan(tree.cond);
+            xF = bindings;
+            whenTrue = true;
+            bindings = union(tree, intersection(tree, yT, zT), intersection(tree, xT, zT), intersection(tree, xF, yT));
+        } else {
+            List<BindingSymbol> xF, yF, zF, xT;
+            scan(tree.cond);
+            xF = bindings;
+            scan(tree.truepart);
+            yF = bindings;
+            scan(tree.falsepart);
+            zF = bindings;
+            whenTrue = true;
+            scan(tree.cond);
+            xT = bindings;
+            whenTrue = false;
+            bindings = union(tree, intersection(tree, yF, zF), intersection(tree, xT, zF), intersection(tree, xF, yF));
+        }
+    }
+
+    private List<BindingSymbol> intersection(JCTree tree, List<BindingSymbol> lhsBindings, List<BindingSymbol> rhsBindings) {
+        // It is an error if, for intersection(a,b), if a and b contain the same variable name (may be eventually relaxed to merge variables of same type)
+        List<BindingSymbol> list = List.nil();
+        for (BindingSymbol v1 : lhsBindings) {
+            for (BindingSymbol v2 : rhsBindings) {
+                if (v1.name == v2.name) {
+                    log.error(tree.pos(), Errors.MatchBindingExists);
+                    list = list.append(v2);
+                }
+            }
+        }
+        return list;
+    }
+
+    @SafeVarargs
+    private final List<BindingSymbol> union(JCTree tree, List<BindingSymbol> lhsBindings, List<BindingSymbol> ... rhsBindings_s) {
+        // It is an error if for union(a,b), a and b contain the same name (disjoint union).
+        List<BindingSymbol> list = lhsBindings;
+        for (List<BindingSymbol> rhsBindings : rhsBindings_s) {
+            for (BindingSymbol v : rhsBindings) {
+                for (BindingSymbol ov : list) {
+                    if (ov.name == v.name) {
+                        log.error(tree.pos(), Errors.MatchBindingExists);
+                    }
+                }
+                list = list.append(v);
+            }
+        }
+        return list;
+    }
+
+    @Override
+    public void scan(JCTree tree) {
+        bindings = List.nil();
+        super.scan(tree);
+    }
+
+    public static class BindingSymbol extends VarSymbol {
+
+        public BindingSymbol(Name name, Type type, Symbol owner) {
+            super(Flags.FINAL | Flags.HASINIT | Flags.MATCH_BINDING, name, type, owner);
+        }
+
+        public boolean isAliasFor(BindingSymbol b) {
+            return aliases().containsAll(b.aliases());
+        }
+
+        List<BindingSymbol> aliases() {
+            return List.of(this);
+        }
+
+        public void preserveBinding() {
+            flags_field |= Flags.MATCH_BINDING_TO_OUTER;
+        }
+
+        public boolean isPreserved() {
+            return (flags_field & Flags.MATCH_BINDING_TO_OUTER) != 0;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.comp;
+
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCAssign;
+import com.sun.tools.javac.tree.JCTree.JCBinary;
+import com.sun.tools.javac.tree.JCTree.JCConditional;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCForLoop;
+import com.sun.tools.javac.tree.JCTree.JCIdent;
+import com.sun.tools.javac.tree.JCTree.JCIf;
+import com.sun.tools.javac.tree.JCTree.JCInstanceOf;
+import com.sun.tools.javac.tree.JCTree.JCLabeledStatement;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+import com.sun.tools.javac.tree.JCTree.JCBindingPattern;
+import com.sun.tools.javac.tree.JCTree.JCWhileLoop;
+import com.sun.tools.javac.tree.JCTree.Tag;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.tree.TreeTranslator;
+import com.sun.tools.javac.util.Assert;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Names;
+import com.sun.tools.javac.util.Options;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
+import static com.sun.tools.javac.code.TypeTag.BOT;
+import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol;
+import com.sun.tools.javac.jvm.Target;
+import com.sun.tools.javac.tree.JCTree.JCBlock;
+import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
+import com.sun.tools.javac.tree.JCTree.LetExpr;
+import com.sun.tools.javac.util.List;
+
+/**
+ * This pass translates pattern-matching constructs, such as instanceof <pattern>.
+ */
+public class TransPatterns extends TreeTranslator {
+
+    protected static final Context.Key<TransPatterns> transPatternsKey = new Context.Key<>();
+
+    public static TransPatterns instance(Context context) {
+        TransPatterns instance = context.get(transPatternsKey);
+        if (instance == null)
+            instance = new TransPatterns(context);
+        return instance;
+    }
+
+    private final Symtab syms;
+    private final Types types;
+    private final Operators operators;
+    private final Log log;
+    private final ConstFold constFold;
+    private final Names names;
+    private final Target target;
+    private final MatchBindingsComputer matchBindingsComputer;
+    private TreeMaker make;
+
+    BindingContext bindingContext = new BindingContext() {
+        @Override
+        VarSymbol getBindingFor(BindingSymbol varSymbol) {
+            return null;
+        }
+
+        @Override
+        JCStatement decorateStatement(JCStatement stat) {
+            return stat;
+        }
+
+        @Override
+        JCExpression decorateExpression(JCExpression expr) {
+            return expr;
+        }
+
+        @Override
+        BindingContext pop() {
+            //do nothing
+            return this;
+        }
+
+        @Override
+        boolean tryPrepend(BindingSymbol binding, JCVariableDecl var) {
+            return false;
+        }
+    };
+
+    JCLabeledStatement pendingMatchLabel = null;
+
+    boolean debugTransPatterns;
+
+    private MethodSymbol currentMethodSym = null;
+
+    protected TransPatterns(Context context) {
+        context.put(transPatternsKey, this);
+        syms = Symtab.instance(context);
+        make = TreeMaker.instance(context);
+        types = Types.instance(context);
+        operators = Operators.instance(context);
+        log = Log.instance(context);
+        constFold = ConstFold.instance(context);
+        names = Names.instance(context);
+        target = Target.instance(context);
+        matchBindingsComputer = MatchBindingsComputer.instance(context);
+        debugTransPatterns = Options.instance(context).isSet("debug.patterns");
+    }
+
+    @Override
+    public void visitTypeTest(JCInstanceOf tree) {
+        if (tree.pattern.hasTag(Tag.BINDINGPATTERN)) {
+            //E instanceof T N
+            //=>
+            //(let T' N$temp = E; N$temp instanceof T && (N = (T) N$temp == (T) N$temp))
+            JCBindingPattern patt = (JCBindingPattern)tree.pattern;
+            VarSymbol pattSym = patt.symbol;
+            Type tempType = tree.expr.type.hasTag(BOT) ?
+                    syms.objectType
+                    : tree.expr.type;
+            VarSymbol temp = new VarSymbol(pattSym.flags() | Flags.SYNTHETIC,
+                    names.fromString(pattSym.name.toString() + target.syntheticNameChar() + "temp"),
+                    tempType,
+                    patt.symbol.owner);
+            JCExpression translatedExpr = translate(tree.expr);
+            Type castTargetType = types.boxedTypeOrType(pattSym.erasure(types));
+
+            result = makeTypeTest(make.Ident(temp), make.Type(castTargetType));
+
+            VarSymbol bindingVar = bindingContext.getBindingFor(patt.symbol);
+            if (bindingVar != null) {
+                JCAssign fakeInit = (JCAssign)make.at(tree.pos).Assign(
+                        make.Ident(bindingVar), convert(make.Ident(temp), castTargetType)).setType(bindingVar.erasure(types));
+                result = makeBinary(Tag.AND, (JCExpression)result,
+                        makeBinary(Tag.EQ, fakeInit, convert(make.Ident(temp), castTargetType)));
+            }
+            result = make.at(tree.pos).LetExpr(make.VarDef(temp, translatedExpr), (JCExpression)result).setType(syms.booleanType);
+            ((LetExpr) result).needsCond = true;
+        } else {
+            super.visitTypeTest(tree);
+        }
+    }
+
+    @Override
+    public void visitBinary(JCBinary tree) {
+        List<BindingSymbol> matchBindings;
+        switch (tree.getTag()) {
+            case AND:
+                matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, true);
+                break;
+            case OR:
+                matchBindings = matchBindingsComputer.getMatchBindings(tree.lhs, false);
+                break;
+            default:
+                matchBindings = List.nil();
+                break;
+        }
+
+        bindingContext = new BasicBindingContext(matchBindings);
+        try {
+            super.visitBinary(tree);
+            result = bindingContext.decorateExpression(tree);
+        } finally {
+            bindingContext.pop();
+        }
+    }
+
+    @Override
+    public void visitConditional(JCConditional tree) {
+        bindingContext = new BasicBindingContext(
+                matchBindingsComputer.getMatchBindings(tree.cond, true)
+                        .appendList(matchBindingsComputer.getMatchBindings(tree.cond, false)));
+        try {
+            super.visitConditional(tree);
+            result = bindingContext.decorateExpression(tree);
+        } finally {
+            bindingContext.pop();
+        }
+    }
+
+    @Override
+    public void visitIf(JCIf tree) {
+        bindingContext = new BasicBindingContext(getMatchBindings(tree.cond));
+        try {
+            super.visitIf(tree);
+            result = bindingContext.decorateStatement(tree);
+        } finally {
+            bindingContext.pop();
+        }
+    }
+
+    @Override
+    public void visitForLoop(JCForLoop tree) {
+        bindingContext = new BasicBindingContext(getMatchBindings(tree.cond));
+        try {
+            super.visitForLoop(tree);
+            result = bindingContext.decorateStatement(tree);
+        } finally {
+            bindingContext.pop();
+        }
+    }
+
+    @Override
+    public void visitWhileLoop(JCWhileLoop tree) {
+        bindingContext = new BasicBindingContext(getMatchBindings(tree.cond));
+        try {
+            super.visitWhileLoop(tree);
+            result = bindingContext.decorateStatement(tree);
+        } finally {
+            bindingContext.pop();
+        }
+    }
+
+    @Override
+    public void visitDoLoop(JCDoWhileLoop tree) {
+        bindingContext = new BasicBindingContext(getMatchBindings(tree.cond));
+        try {
+            super.visitDoLoop(tree);
+            result = bindingContext.decorateStatement(tree);
+        } finally {
+            bindingContext.pop();
+        }
+    }
+
+    @Override
+    public void visitMethodDef(JCMethodDecl tree) {
+        MethodSymbol prevMethodSym = currentMethodSym;
+        try {
+            currentMethodSym = tree.sym;
+            super.visitMethodDef(tree);
+        } finally {
+            currentMethodSym = prevMethodSym;
+        }
+    }
+
+    @Override
+    public void visitIdent(JCIdent tree) {
+        VarSymbol bindingVar = null;
+        if ((tree.sym.flags() & Flags.MATCH_BINDING) != 0) {
+            bindingVar = bindingContext.getBindingFor((BindingSymbol)tree.sym);
+        }
+        if (bindingVar == null) {
+            super.visitIdent(tree);
+        } else {
+            result = make.at(tree.pos).Ident(bindingVar);
+        }
+    }
+
+    @Override
+    public void visitBlock(JCBlock tree) {
+        ListBuffer<JCStatement> statements = new ListBuffer<>();
+        bindingContext = new BasicBindingContext(List.nil()) {
+            boolean tryPrepend(BindingSymbol binding, JCVariableDecl var) {
+                //{
+                //    if (E instanceof T N) {
+                //        return ;
+                //    }
+                //    //use of N:
+                //}
+                //=>
+                //{
+                //    T N;
+                //    if ((let T' N$temp = E; N$temp instanceof T && (N = (T) N$temp == (T) N$temp))) {
+                //        return ;
+                //    }
+                //    //use of N:
+                //}
+                hoistedVarMap.put(binding, var.sym);
+                statements.append(var);
+                return true;
+            }
+        };
+        try {
+            for (List<JCStatement> l = tree.stats; l.nonEmpty(); l = l.tail) {
+                statements.append(translate(l.head));
+            }
+
+            tree.stats = statements.toList();
+            result = tree;
+        } finally {
+            bindingContext.pop();
+        }
+    }
+
+    public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
+        try {
+            this.make = make;
+            translate(cdef);
+        } finally {
+            // note that recursive invocations of this method fail hard
+            this.make = null;
+        }
+
+        return cdef;
+    }
+
+    /** Make an instanceof expression.
+     *  @param lhs      The expression.
+     *  @param type     The type to be tested.
+     */
+
+    JCInstanceOf makeTypeTest(JCExpression lhs, JCExpression type) {
+        JCInstanceOf tree = make.TypeTest(lhs, type);
+        tree.type = syms.booleanType;
+        return tree;
+    }
+
+    /** Make an attributed binary expression (copied from Lower).
+     *  @param optag    The operators tree tag.
+     *  @param lhs      The operator's left argument.
+     *  @param rhs      The operator's right argument.
+     */
+    JCBinary makeBinary(JCTree.Tag optag, JCExpression lhs, JCExpression rhs) {
+        JCBinary tree = make.Binary(optag, lhs, rhs);
+        tree.operator = operators.resolveBinary(tree, optag, lhs.type, rhs.type);
+        tree.type = tree.operator.type.getReturnType();
+        return tree;
+    }
+
+    JCExpression convert(JCExpression expr, Type target) {
+        JCExpression result = make.at(expr.pos()).TypeCast(make.Type(target), expr);
+        result.type = target;
+        return result;
+    }
+
+    private List<BindingSymbol> getMatchBindings(JCExpression cond) {
+        return matchBindingsComputer.getMatchBindings(cond, true)
+                        .appendList(matchBindingsComputer.getMatchBindings(cond, false));
+    }
+    abstract class BindingContext {
+        abstract VarSymbol getBindingFor(BindingSymbol varSymbol);
+        abstract JCStatement decorateStatement(JCStatement stat);
+        abstract JCExpression decorateExpression(JCExpression expr);
+        abstract BindingContext pop();
+        abstract boolean tryPrepend(BindingSymbol binding, JCVariableDecl var);
+    }
+
+    class BasicBindingContext extends BindingContext {
+        List<BindingSymbol> matchBindings;
+        Map<BindingSymbol, VarSymbol> hoistedVarMap;
+        BindingContext parent;
+
+        public BasicBindingContext(List<BindingSymbol> matchBindings) {
+            this.matchBindings = matchBindings;
+            this.parent = bindingContext;
+            this.hoistedVarMap = matchBindings.stream()
+                    .filter(v -> parent.getBindingFor(v) == null)
+                    .collect(Collectors.toMap(v -> v, v -> {
+                        VarSymbol res = new VarSymbol(v.flags(), v.name, v.type, v.owner);
+                        res.setTypeAttributes(v.getRawTypeAttributes());
+                        return res;
+                    }));
+        }
+
+        @Override
+        VarSymbol getBindingFor(BindingSymbol varSymbol) {
+            VarSymbol res = parent.getBindingFor(varSymbol);
+            if (res != null) {
+                return res;
+            }
+            return hoistedVarMap.entrySet().stream()
+                    .filter(e -> e.getKey().isAliasFor(varSymbol))
+                    .findFirst()
+                    .map(e -> e.getValue()).orElse(null);
+        }
+
+        @Override
+        JCStatement decorateStatement(JCStatement stat) {
+            if (hoistedVarMap.isEmpty()) return stat;
+            //if (E instanceof T N) {
+            //     //use N
+            //}
+            //=>
+            //{
+            //    T N;
+            //    if ((let T' N$temp = E; N$temp instanceof T && (N = (T) N$temp == (T) N$temp))) {
+            //        //use N
+            //    }
+            //}
+            ListBuffer<JCStatement> stats = new ListBuffer<>();
+            for (Entry<BindingSymbol, VarSymbol> e : hoistedVarMap.entrySet()) {
+                JCVariableDecl decl = makeHoistedVarDecl(stat.pos, e.getValue());
+                if (!e.getKey().isPreserved() ||
+                    !parent.tryPrepend(e.getKey(), decl)) {
+                    stats.add(decl);
+                }
+            }
+            if (stats.nonEmpty()) {
+                stats.add(stat);
+                stat = make.at(stat.pos).Block(0, stats.toList());
+            }
+            return stat;
+        }
+
+        @Override
+        JCExpression decorateExpression(JCExpression expr) {
+            //E instanceof T N && /*use of N*/
+            //=>
+            //(let T N; (let T' N$temp = E; N$temp instanceof T && (N = (T) N$temp == (T) N$temp)) && /*use of N*/)
+            for (VarSymbol vsym : hoistedVarMap.values()) {
+                expr = make.at(expr.pos).LetExpr(makeHoistedVarDecl(expr.pos, vsym), expr).setType(expr.type);
+            }
+            return expr;
+        }
+
+        @Override
+        BindingContext pop() {
+            return bindingContext = parent;
+        }
+
+        @Override
+        boolean tryPrepend(BindingSymbol binding, JCVariableDecl var) {
+            return false;
+        }
+
+        private JCVariableDecl makeHoistedVarDecl(int pos, VarSymbol varSymbol) {
+            return make.at(pos).VarDef(varSymbol, null);
+        }
+    }
+}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Wed Nov 27 10:21:22 2019 +0100
@@ -567,6 +567,13 @@
         result = tree;
     }
 
+    public void visitBindingPattern(JCBindingPattern tree) {
+        if (tree.vartype != null) {
+            tree.vartype = translate(tree.vartype, null);
+        }
+        result = tree;
+    }
+
     public void visitSwitchExpression(JCSwitchExpression tree) {
         Type selsuper = types.supertype(tree.selector.type);
         boolean enumSwitch = selsuper != null &&
@@ -780,7 +787,7 @@
 
     public void visitTypeTest(JCInstanceOf tree) {
         tree.expr = translate(tree.expr, null);
-        tree.clazz = translate(tree.clazz, null);
+        tree.pattern = translate(tree.pattern, null);
         result = tree;
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java	Wed Nov 27 10:21:22 2019 +0100
@@ -35,6 +35,7 @@
 import com.sun.tools.javac.tree.JCTree.JCAssign;
 import com.sun.tools.javac.tree.JCTree.JCAssignOp;
 import com.sun.tools.javac.tree.JCTree.JCBinary;
+import com.sun.tools.javac.tree.JCTree.JCBindingPattern;
 import com.sun.tools.javac.tree.JCTree.JCBlock;
 import com.sun.tools.javac.tree.JCTree.JCBreak;
 import com.sun.tools.javac.tree.JCTree.JCCase;
@@ -253,6 +254,18 @@
     }
 
     @Override
+    public void visitBindingPattern(JCBindingPattern tree) {
+        JCBindingPattern that = (JCBindingPattern) parameter;
+        result =
+                scan(tree.vartype, that.vartype)
+                        && tree.name == that.name;
+        if (!result) {
+            return;
+        }
+        equiv.put(tree.symbol, that.symbol);
+    }
+
+    @Override
     public void visitBlock(JCBlock tree) {
         JCBlock that = (JCBlock) parameter;
         result = tree.flags == that.flags && scan(tree.stats, that.stats);
@@ -591,7 +604,7 @@
     @Override
     public void visitTypeTest(JCInstanceOf tree) {
         JCInstanceOf that = (JCInstanceOf) parameter;
-        result = scan(tree.expr, that.expr) && scan(tree.clazz, that.clazz);
+        result = scan(tree.expr, that.expr) && scan(tree.pattern, that.pattern);
     }
 
     @Override
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeHasher.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeHasher.java	Wed Nov 27 10:21:22 2019 +0100
@@ -106,6 +106,12 @@
     }
 
     @Override
+    public void visitBindingPattern(JCTree.JCBindingPattern tree) {
+        symbolHashes.computeIfAbsent(tree.symbol, k -> symbolHashes.size());
+        super.visitBindingPattern(tree);
+    }
+
+    @Override
     public void visitVarDef(JCVariableDecl tree) {
         symbolHashes.computeIfAbsent(tree.sym, k -> symbolHashes.size());
         super.visitVarDef(tree);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java	Wed Nov 27 10:21:22 2019 +0100
@@ -473,7 +473,7 @@
         public void visitTypeTest(JCInstanceOf tree) {
             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
             sr.mergeWith(csp(tree.expr));
-            sr.mergeWith(csp(tree.clazz));
+            sr.mergeWith(csp(tree.pattern));
             result = sr;
         }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java	Wed Nov 27 10:21:22 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -50,6 +50,7 @@
 import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String;
 import static com.sun.tools.javac.jvm.UninitializedType.*;
 import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame;
+import java.util.Arrays;
 
 /** An internal structure that corresponds to the code attribute of
  *  methods in a classfile. The class also provides some utility operations to
@@ -2075,6 +2076,7 @@
                 lvar[adr] = v.dup();
                 v.closeRange(length);
                 putVar(v);
+                fillLocalVarPosition(v);
             } else {
                 v.removeLastRange();
             }
@@ -2106,20 +2108,31 @@
     private void fillLocalVarPosition(LocalVar lv) {
         if (lv == null || lv.sym == null || lv.sym.isExceptionParameter()|| !lv.sym.hasTypeAnnotations())
             return;
-        LocalVar.Range widestRange = lv.getWidestRange();
+        LocalVar.Range[] validRanges = lv.aliveRanges.stream().filter(r -> r.closed() && r.length > 0).toArray(s -> new LocalVar.Range[s]);
+        if (validRanges.length == 0)
+            return ;
+        int[] lvarOffset = Arrays.stream(validRanges).mapToInt(r -> r.start_pc).toArray();
+        int[] lvarLength = Arrays.stream(validRanges).mapToInt(r -> r.length).toArray();
+        int[] lvarIndex = Arrays.stream(validRanges).mapToInt(r -> lv.reg).toArray();
         for (Attribute.TypeCompound ta : lv.sym.getRawTypeAttributes()) {
             TypeAnnotationPosition p = ta.position;
-            if (widestRange.closed() && widestRange.length > 0) {
-                p.lvarOffset = new int[] { (int)widestRange.start_pc };
-                p.lvarLength = new int[] { (int)widestRange.length };
-                p.lvarIndex = new int[] { (int)lv.reg };
-                p.isValidOffset = true;
-            } else {
-                p.isValidOffset = false;
-            }
+            p.lvarOffset = appendArray(p.lvarOffset, lvarOffset);
+            p.lvarLength = appendArray(p.lvarLength, lvarLength);
+            p.lvarIndex = appendArray(p.lvarIndex, lvarIndex);
+            p.isValidOffset = true;
         }
     }
 
+    private int[] appendArray(int[] source, int[] append) {
+        if (source == null || source.length == 0) return append;
+
+        int[] result = new int[source.length + append.length];
+
+        System.arraycopy(source, 0, result, 0, source.length);
+        System.arraycopy(append, 0, result, source.length, append.length);
+        return result;
+    }
+
     // Method to be called after compressCatchTable to
     // fill in the exception table index for type
     // annotations on exception parameters.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Nov 27 10:21:22 2019 +0100
@@ -2216,7 +2216,7 @@
     public void visitTypeTest(JCInstanceOf tree) {
         genExpr(tree.expr, tree.expr.type).load();
         setTypeAnnotationPositions(tree.pos);
-        code.emitop2(instanceof_, makeRef(tree.pos(), tree.clazz.type));
+        code.emitop2(instanceof_, makeRef(tree.pos(), tree.pattern.type));
         result = items.makeStackItem(syms.booleanType);
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Wed Nov 27 10:21:22 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1558,6 +1558,12 @@
             env.tree = transTypes.translateTopLevelClass(env.tree, localMake);
             compileStates.put(env, CompileState.TRANSTYPES);
 
+            if (shouldStop(CompileState.TRANSPATTERNS))
+                return;
+
+            env.tree = TransPatterns.instance(context).translateTopLevelClass(env, env.tree, localMake);
+            compileStates.put(env, CompileState.TRANSPATTERNS);
+
             if (Feature.LAMBDA.allowedInSource(source) && scanner.hasLambdas) {
                 if (shouldStop(CompileState.UNLAMBDA))
                     return;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Wed Nov 27 10:21:22 2019 +0100
@@ -893,6 +893,7 @@
 
     /*  Expression2Rest = {infixop Expression3}
      *                  | Expression3 instanceof Type
+     *                  | Expression3 instanceof Pattern
      *  infixop         = "||"
      *                  | "&&"
      *                  | "|"
@@ -915,13 +916,24 @@
         Token topOp = Tokens.DUMMY;
         while (prec(token.kind) >= minprec) {
             opStack[top] = topOp;
-            top++;
-            topOp = token;
-            nextToken();
-            odStack[top] = (topOp.kind == INSTANCEOF) ? parseType() : term3();
+
+            if (token.kind == INSTANCEOF) {
+                int pos = token.pos;
+                nextToken();
+                JCTree pattern = parseType();
+                if (token.kind == IDENTIFIER) {
+                    checkSourceLevel(token.pos, Feature.PATTERN_MATCHING_IN_INSTANCEOF);
+                    pattern = toP(F.at(token.pos).BindingPattern(ident(), pattern));
+                }
+                odStack[top] = F.at(pos).TypeTest(odStack[top], pattern);
+            } else {
+                topOp = token;
+                nextToken();
+                top++;
+                odStack[top] = term3();
+            }
             while (top > 0 && prec(topOp.kind) >= prec(token.kind)) {
-                odStack[top-1] = makeOp(topOp.pos, topOp.kind, odStack[top-1],
-                                        odStack[top]);
+                odStack[top - 1] = F.at(topOp.pos).Binary(optag(topOp.kind), odStack[top - 1], odStack[top]);
                 top--;
                 topOp = opStack[top];
             }
@@ -938,19 +950,6 @@
         return t;
     }
     //where
-        /** Construct a binary or type test node.
-         */
-        private JCExpression makeOp(int pos,
-                                    TokenKind topOp,
-                                    JCExpression od1,
-                                    JCExpression od2)
-        {
-            if (topOp == INSTANCEOF) {
-                return F.at(pos).TypeTest(od1, od2);
-            } else {
-                return F.at(pos).Binary(optag(topOp), od1, od2);
-            }
-        }
         /** If tree is a concatenation of string literals, replace it
          *  by a single literal representing the concatenated string.
          */
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Nov 27 10:21:22 2019 +0100
@@ -546,6 +546,10 @@
     auto-closeable resource {0} may not be assigned
 
 # 0: symbol
+compiler.err.pattern.binding.may.not.be.assigned=\
+    pattern binding {0} may not be assigned
+
+# 0: symbol
 compiler.err.multicatch.parameter.may.not.be.assigned=\
     multi-catch parameter {0} may not be assigned
 
@@ -1416,6 +1420,10 @@
 compiler.misc.varargs.trustme.on.reifiable.varargs=\
     Varargs element type {0} is reifiable.
 
+# 0: type, 1: type
+compiler.err.instanceof.reifiable.not.safe=\
+    {0} cannot be safely cast to {1}
+
 # 0: symbol
 compiler.misc.varargs.trustme.on.non.varargs.meth=\
     Method {0} is not a varargs method.
@@ -2909,6 +2917,12 @@
 compiler.misc.feature.var.syntax.in.implicit.lambda=\
     var syntax in implicit lambdas
 
+compiler.misc.feature.pattern.matching.instanceof=\
+    pattern matching in instanceof
+
+compiler.misc.feature.reifiable.types.instanceof=\
+    reifiable types in instanceof
+
 compiler.warn.underscore.as.identifier=\
     as of release 9, ''_'' is a keyword, and may not be used as an identifier
 
@@ -3399,6 +3413,9 @@
 compiler.err.illegal.argument.for.option=\
     illegal argument for {0}: {1}
 
+compiler.err.match.binding.exists=\
+    illegal attempt to redefine an existing match binding
+
 compiler.err.switch.null.not.allowed=\
     null label in case is not allowed
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Wed Nov 27 10:21:22 2019 +0100
@@ -38,6 +38,7 @@
 import com.sun.tools.javac.code.Directive.RequiresDirective;
 import com.sun.tools.javac.code.Scope.*;
 import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.DefinedBy.Api;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@@ -238,6 +239,10 @@
          */
         TYPETEST,
 
+        /** Patterns.
+         */
+        BINDINGPATTERN,
+
         /** Indexed array expressions, of type Indexed.
          */
         INDEXED,
@@ -2135,10 +2140,10 @@
      */
     public static class JCInstanceOf extends JCExpression implements InstanceOfTree {
         public JCExpression expr;
-        public JCTree clazz;
-        protected JCInstanceOf(JCExpression expr, JCTree clazz) {
+        public JCTree pattern;
+        protected JCInstanceOf(JCExpression expr, JCTree pattern) {
             this.expr = expr;
-            this.clazz = clazz;
+            this.pattern = pattern;
         }
         @Override
         public void accept(Visitor v) { v.visitTypeTest(this); }
@@ -2146,7 +2151,13 @@
         @DefinedBy(Api.COMPILER_TREE)
         public Kind getKind() { return Kind.INSTANCE_OF; }
         @DefinedBy(Api.COMPILER_TREE)
-        public JCTree getType() { return clazz; }
+        public JCTree getType() { return pattern instanceof JCPattern ? pattern.hasTag(BINDINGPATTERN) ? ((JCBindingPattern) pattern).vartype : null : pattern; }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public JCPattern getPattern() {
+            return pattern instanceof JCPattern ? (JCPattern) pattern : null;
+        }
+
         @DefinedBy(Api.COMPILER_TREE)
         public JCExpression getExpression() { return expr; }
         @Override @DefinedBy(Api.COMPILER_TREE)
@@ -2160,6 +2171,60 @@
     }
 
     /**
+     * Pattern matching forms.
+     */
+    public static abstract class JCPattern extends JCTree
+            implements PatternTree {
+        public JCExpression constExpression() {
+            return null;
+        }
+    }
+
+    public static class JCBindingPattern extends JCPattern
+            implements BindingPatternTree {
+        public Name name;
+        public BindingSymbol symbol;
+        public JCTree vartype;
+
+        protected JCBindingPattern(Name name, BindingSymbol symbol, JCTree vartype) {
+            this.name = name;
+            this.symbol = symbol;
+            this.vartype = vartype;
+        }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Name getBinding() {
+            return name;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public Tree getType() {
+            return vartype;
+        }
+
+        @Override
+        public void accept(Visitor v) {
+            v.visitBindingPattern(this);
+        }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            return Kind.BINDING_PATTERN;
+        }
+
+        @Override
+        @DefinedBy(Api.COMPILER_TREE)
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitBindingPattern(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return BINDINGPATTERN;
+        }
+    }
+
+    /**
      * An array selection
      */
     public static class JCArrayAccess extends JCExpression implements ArrayAccessTree {
@@ -3133,6 +3198,7 @@
         JCBinary Binary(Tag opcode, JCExpression lhs, JCExpression rhs);
         JCTypeCast TypeCast(JCTree expr, JCExpression type);
         JCInstanceOf TypeTest(JCExpression expr, JCTree clazz);
+        JCBindingPattern BindingPattern(Name name, JCTree vartype);
         JCArrayAccess Indexed(JCExpression indexed, JCExpression index);
         JCFieldAccess Select(JCExpression selected, Name selector);
         JCIdent Ident(Name idname);
@@ -3197,6 +3263,7 @@
         public void visitBinary(JCBinary that)               { visitTree(that); }
         public void visitTypeCast(JCTypeCast that)           { visitTree(that); }
         public void visitTypeTest(JCInstanceOf that)         { visitTree(that); }
+        public void visitBindingPattern(JCBindingPattern that) { visitTree(that); }
         public void visitIndexed(JCArrayAccess that)         { visitTree(that); }
         public void visitSelect(JCFieldAccess that)          { visitTree(that); }
         public void visitReference(JCMemberReference that)   { visitTree(that); }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java	Wed Nov 27 10:21:22 2019 +0100
@@ -234,6 +234,14 @@
         printExprs(trees, ", ");
     }
 
+
+    /** Derived visitor method: print pattern.
+     */
+
+    public void printPattern(JCTree tree) throws IOException {
+        printExpr(tree);
+    }
+
     /** Derived visitor method: print list of statements, each on a separate line.
      */
     public void printStats(List<? extends JCTree> trees) throws IOException {
@@ -877,6 +885,16 @@
         }
     }
 
+    public void visitBindingPattern(JCBindingPattern patt) {
+        try {
+            printExpr(patt.vartype);
+            print(" ");
+            print(patt.name);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
     public void visitSynchronized(JCSynchronized tree) {
         try {
             print("synchronized ");
@@ -1283,7 +1301,11 @@
             open(prec, TreeInfo.ordPrec);
             printExpr(tree.expr, TreeInfo.ordPrec);
             print(" instanceof ");
-            printExpr(tree.clazz, TreeInfo.ordPrec + 1);
+            if (tree.pattern instanceof JCPattern) {
+                printPattern(tree.pattern);
+            } else {
+                printExpr(tree.getType(), TreeInfo.ordPrec + 1);
+            }
             close(prec, TreeInfo.ordPrec);
         } catch (IOException e) {
             throw new UncheckedIOException(e);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Wed Nov 27 10:21:22 2019 +0100
@@ -26,7 +26,6 @@
 package com.sun.tools.javac.tree;
 
 import com.sun.source.tree.*;
-import com.sun.source.tree.Tree.Kind;
 import com.sun.tools.javac.tree.JCTree.*;
 import com.sun.tools.javac.util.DefinedBy;
 import com.sun.tools.javac.util.DefinedBy.Api;
@@ -481,8 +480,15 @@
     public JCTree visitInstanceOf(InstanceOfTree node, P p) {
         JCInstanceOf t = (JCInstanceOf) node;
         JCExpression expr = copy(t.expr, p);
-        JCTree clazz = copy(t.clazz, p);
-        return M.at(t.pos).TypeTest(expr, clazz);
+        JCTree pattern = copy(t.pattern, p);
+        return M.at(t.pos).TypeTest(expr, pattern);
+    }
+
+    @DefinedBy(Api.COMPILER_TREE)
+    public JCTree visitBindingPattern(BindingPatternTree node, P p) {
+        JCBindingPattern t = (JCBindingPattern) node;
+        JCTree vartype = copy(t.vartype, p);
+        return M.at(t.pos).BindingPattern(t.name, vartype);
     }
 
     @DefinedBy(Api.COMPILER_TREE)
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Wed Nov 27 10:21:22 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -490,6 +490,10 @@
                     return getStartPos(node.vartype);
                 }
             }
+            case BINDINGPATTERN: {
+                JCBindingPattern node = (JCBindingPattern)tree;
+                return getStartPos(node.vartype);
+            }
             case ERRONEOUS: {
                 JCErroneous node = (JCErroneous)tree;
                 if (node.errs != null && node.errs.nonEmpty())
@@ -574,7 +578,7 @@
             case TYPECAST:
                 return getEndPos(((JCTypeCast) tree).expr, endPosTable);
             case TYPETEST:
-                return getEndPos(((JCInstanceOf) tree).clazz, endPosTable);
+                return getEndPos(((JCInstanceOf) tree).pattern, endPosTable);
             case WHILELOOP:
                 return getEndPos(((JCWhileLoop) tree).body, endPosTable);
             case ANNOTATED_TYPE:
@@ -847,6 +851,8 @@
             if (node.type != null)
                 return node.type.tsym;
             return null;
+        case BINDINGPATTERN:
+            return ((JCBindingPattern) node).symbol;
         default:
             return null;
         }
@@ -1225,4 +1231,5 @@
     public static boolean isPackageInfo(JCCompilationUnit tree) {
         return tree.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE);
     }
+
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Wed Nov 27 10:21:22 2019 +0100
@@ -29,7 +29,6 @@
 
 import com.sun.source.tree.CaseTree;
 import com.sun.source.tree.ModuleTree.ModuleKind;
-import com.sun.source.tree.Tree.Kind;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Attribute.UnresolvedClass;
 import com.sun.tools.javac.code.Symbol.*;
@@ -465,6 +464,12 @@
         return tree;
     }
 
+    public JCBindingPattern BindingPattern(Name name, JCTree vartype) {
+        JCBindingPattern tree = new JCBindingPattern(name, null, vartype);
+        tree.pos = pos;
+        return tree;
+    }
+
     public JCArrayAccess Indexed(JCExpression indexed, JCExpression index) {
         JCArrayAccess tree = new JCArrayAccess(indexed, index);
         tree.pos = pos;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Wed Nov 27 10:21:22 2019 +0100
@@ -299,7 +299,12 @@
 
     public void visitTypeTest(JCInstanceOf tree) {
         scan(tree.expr);
-        scan(tree.clazz);
+        scan(tree.pattern);
+    }
+
+    public void visitBindingPattern(JCBindingPattern tree) {
+        if (tree.vartype != null)
+            scan(tree.vartype);
     }
 
     public void visitIndexed(JCArrayAccess tree) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Wed Nov 27 10:21:22 2019 +0100
@@ -354,7 +354,12 @@
 
     public void visitTypeTest(JCInstanceOf tree) {
         tree.expr = translate(tree.expr);
-        tree.clazz = translate(tree.clazz);
+        tree.pattern = translate(tree.pattern);
+        result = tree;
+    }
+
+    public void visitBindingPattern(JCBindingPattern tree) {
+        tree.vartype = translate(tree.vartype);
         result = tree;
     }
 
--- a/test/jdk/java/lang/invoke/CallSiteTest.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/test/jdk/java/lang/invoke/CallSiteTest.java	Wed Nov 27 10:21:22 2019 +0100
@@ -24,10 +24,11 @@
 /**
  * @test
  * @summary smoke tests for CallSite
+ * @library /test/lib
  *
  * @build indify.Indify
  * @compile CallSiteTest.java
- * @run main/othervm/timeout=3600 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies
+ * @run main/othervm/timeout=3600 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -Xbatch
  *      indify.Indify
  *      --expand-properties --classpath ${test.classes}
  *      --java test.java.lang.invoke.CallSiteTest
@@ -40,6 +41,7 @@
 import java.lang.invoke.*;
 import static java.lang.invoke.MethodHandles.*;
 import static java.lang.invoke.MethodType.*;
+import static jdk.test.lib.Asserts.*;
 
 public class CallSiteTest {
     private static final Class<?> CLASS = CallSiteTest.class;
@@ -51,16 +53,19 @@
 
     static {
         try {
+
             mh_foo = lookup().findStatic(CLASS, "foo", methodType(int.class, int.class, int.class));
             mh_bar = lookup().findStatic(CLASS, "bar", methodType(int.class, int.class, int.class));
             mcs = new MutableCallSite(mh_foo);
             vcs = new VolatileCallSite(mh_foo);
         } catch (Exception e) {
             e.printStackTrace();
+            throw new Error(e);
         }
     }
 
     public static void main(String... av) throws Throwable {
+        testConstantCallSite();
         testMutableCallSite();
         testVolatileCallSite();
     }
@@ -69,9 +74,61 @@
     private static final int RESULT1 = 762786192;
     private static final int RESULT2 = -21474836;
 
-    private static void assertEquals(int expected, int actual) {
-        if (expected != actual)
-            throw new AssertionError("expected: " + expected + ", actual: " + actual);
+    static final CallSite     MCS         = new MutableCallSite(methodType(void.class));
+    static final MethodHandle MCS_INVOKER = MCS.dynamicInvoker();
+
+    static void test(boolean shouldThrow) {
+        try {
+            MCS_INVOKER.invokeExact();
+            if (shouldThrow) {
+                throw new AssertionError("should throw");
+            }
+        } catch (IllegalStateException ise) {
+            if (!shouldThrow) {
+                throw new AssertionError("should not throw", ise);
+            }
+        } catch (Throwable e) {
+            throw new Error(e);
+        }
+    }
+
+    static class MyCCS extends ConstantCallSite {
+        public MyCCS(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
+            super(targetType, createTargetHook);
+        }
+    }
+
+    private static MethodHandle testConstantCallSiteHandler(CallSite cs, CallSite[] holder) throws Throwable {
+        holder[0] = cs; // capture call site instance for subsequent checks
+
+        MethodType csType = cs.type(); // should not throw on partially constructed instance
+
+        // Truly dynamic invoker for constant call site
+        MethodHandle getTarget = lookup().findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class))
+                                         .bindTo(cs);
+        MethodHandle invoker = MethodHandles.exactInvoker(csType);
+        MethodHandle target = MethodHandles.foldArguments(invoker, getTarget);
+
+        MCS.setTarget(target);
+        // warmup
+        for (int i = 0; i < 20_000; i++) {
+            test(true); // should throw IllegalStateException
+        }
+
+        return MethodHandles.empty(csType); // initialize cs with an empty method handle
+    }
+
+    private static void testConstantCallSite() throws Throwable {
+        CallSite[] holder = new CallSite[1];
+        MethodHandle handler = lookup().findStatic(CLASS, "testConstantCallSiteHandler", MethodType.methodType(MethodHandle.class, CallSite.class, CallSite[].class));
+        handler = MethodHandles.insertArguments(handler, 1, new Object[] { holder } );
+
+        CallSite ccs = new MyCCS(MCS.type(), handler); // trigger call to handler
+
+        if (ccs != holder[0]) {
+            throw new AssertionError("different call site instances");
+        }
+        test(false); // should not throw
     }
 
     private static void testMutableCallSite() throws Throwable {
@@ -83,11 +140,11 @@
         for (int n = 0; n < 2; n++) {
             mcs.setTarget(mh_foo);
             for (int i = 0; i < 5; i++) {
-                assertEquals(RESULT1, runMutableCallSite());
+                assertEQ(RESULT1, runMutableCallSite());
             }
             mcs.setTarget(mh_bar);
             for (int i = 0; i < 5; i++) {
-                assertEquals(RESULT2, runMutableCallSite());
+                assertEQ(RESULT2, runMutableCallSite());
             }
         }
     }
@@ -100,11 +157,11 @@
         for (int n = 0; n < 2; n++) {
             vcs.setTarget(mh_foo);
             for (int i = 0; i < 5; i++) {
-                assertEquals(RESULT1, runVolatileCallSite());
+                assertEQ(RESULT1, runVolatileCallSite());
             }
             vcs.setTarget(mh_bar);
             for (int i = 0; i < 5; i++) {
-                assertEquals(RESULT2, runVolatileCallSite());
+                assertEQ(RESULT2, runVolatileCallSite());
             }
         }
     }
--- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java	Wed Nov 27 10:21:22 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,12 +27,14 @@
 import java.util.List;
 
 import com.sun.tools.classfile.*;
+import java.util.ArrayList;
 
 public class ClassfileTestHelper {
     int expected_tinvisibles = 0;
     int expected_tvisibles = 0;
     int expected_invisibles = 0;
     int expected_visibles = 0;
+    List<String> extraOptions = List.of();
 
     //Makes debugging much easier. Set to 'false' for less output.
     public Boolean verbose = true;
@@ -48,8 +50,9 @@
     }
 
     File compile(File f) {
-        int rc = com.sun.tools.javac.Main.compile(new String[] {
-                "-g", f.getPath() });
+        List<String> options = new ArrayList<>(List.of("-g", f.getPath()));
+        options.addAll(extraOptions);
+        int rc = com.sun.tools.javac.Main.compile(options.toArray(new String[0]));
         if (rc != 0)
             throw new Error("compilation failed. rc=" + rc);
         String path = f.getPath();
--- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java	Wed Nov 27 10:21:22 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,9 +30,13 @@
 
 import com.sun.tools.classfile.*;
 import java.io.File;
+import java.util.List;
 
 public class CombinationsTargetTest2 extends ClassfileTestHelper {
 
+    private static final String JDK_VERSION =
+            Integer.toString(Runtime.getRuntime().version().feature());
+
     // Test count helps identify test case in event of failure.
     int testcount = 0;
 
@@ -45,7 +49,9 @@
         src5("(repeating) type annotations on field in anonymous class", false),
         src6("(repeating) type annotations on void method declaration", false),
         src7("(repeating) type annotations in use of instanceof", true),
-        src8("(repeating) type annotations in use of instanceof in method", true);
+        src7p("(repeating) type annotations in use of instanceof with type test pattern", true),
+        src8("(repeating) type annotations in use of instanceof in method", true),
+        src8p("(repeating) type annotations in use of instanceof with type test pattern in method", true);
 
         String description;
         Boolean local;
@@ -92,8 +98,12 @@
                        test( 0, 0, 0, 2, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src6);
                        test( 2, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src7);
                        test( 0, 2, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src7);
+                       test( 2, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src7p);
+                       test( 0, 2, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src7p);
                        test( 4, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src8);
                        test( 0, 4, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src8);
+                       test( 4, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src8p);
+                       test( 0, 4, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src8p);
                        break;
                    case "FIELD":
                        test( 8, 0, 0, 0, As, BDs, ABMix, "CLASS",   et, ++testrun, srce.src1);
@@ -122,6 +132,7 @@
         expected_tinvisibles = tinv;
         expected_visibles = vis;
         expected_invisibles = inv;
+        extraOptions = List.of();
         File testFile = null;
         String tname="Test" + N.toString();
         hasInnerClass=false;
@@ -385,6 +396,24 @@
                     "\n\n";
                     hasInnerClass=false;
                 break;
+            case src7p: // (repeating) type annotations in use of instanceof with type test pattern
+                    /*
+                     *   class Test10{
+                     *       String data = "test";
+                     *       boolean dataIsString = ( data instanceof @A @B @A @B String str);
+                     *   }
+                     */
+                source = new String( source +
+                    "// " + src.description + "\n" +
+                    "class "+ testname + "{\n" +
+                    "    String data = \"test\";\n" +
+                    "    boolean dataIsString = ( data instanceof _As_ _Bs_ String str && str.isEmpty());\n" +
+                    "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
+                    "\n\n";
+                extraOptions = List.of("--enable-preview",
+                                       "-source", JDK_VERSION);
+                hasInnerClass=false;
+                break;
             case src8: // (repeating) type annotations in use of instanceof
                     /*
                      *   class Test20{
@@ -411,6 +440,34 @@
                     "\n\n";
                     hasInnerClass=false;
                 break;
+            case src8p: // (repeating) type annotations in use of instanceof with type test pattern
+                   /*
+                     *   class Test20{
+                     *       String data = "test";
+                     *       Boolean isString() {
+                     *           if( data instanceof @A @B @A @B String )
+                     *               return true;
+                     *           else
+                     *               return( data instanceof @A @B @A @B String );
+                     *       }
+                     *   }
+                     */
+                source = new String( source +
+                    "// " + src.description + "\n" +
+                    "class "+ testname + "{\n" +
+                    "    String data = \"test\";\n" +
+                    "    Boolean isString() { \n" +
+                    "        if( data instanceof _As_ _Bs_ String str)\n" +
+                    "            return true;\n" +
+                    "        else\n" +
+                    "            return( data instanceof _As_ _Bs_ String str && str.isEmpty());\n" +
+                    "    }\n" +
+                    "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
+                    "\n\n";
+                extraOptions = List.of("--enable-preview",
+                                       "-source", JDK_VERSION);
+                hasInnerClass=false;
+                break;
 
         }
         return imports + source;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/Patterns.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Verify type annotation on binding patterns
+ * @library /tools/lib
+ * @modules java.compiler
+ *          jdk.jdeps/com.sun.tools.javap
+ * @build toolbox.JavapTask
+ * @compile --enable-preview -source ${jdk.version} Patterns.java
+ * @run main/othervm --enable-preview Patterns
+ */
+
+import java.lang.annotation.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import toolbox.JavapTask;
+import toolbox.Task;
+import toolbox.ToolBox;
+
+public class Patterns {
+
+    private ToolBox tb = new ToolBox();
+
+    public static void main(String[] args) throws Exception {
+        new Patterns().run();
+    }
+
+    public void run() throws Exception {
+        String out = new JavapTask(tb)
+                .options("-private",
+                         "-verbose")
+                .classpath(System.getProperty("test.classes"))
+                .classes("Patterns$SimpleBindingPattern")
+                .run()
+                .getOutputLines(Task.OutputKind.DIRECT)
+                .stream()
+                .collect(Collectors.joining("\n"));
+
+        String constantPool = out.substring(0, out.indexOf('{'));
+
+        out = out.replaceAll("(?ms) *Code:.*?\n( *RuntimeInvisibleTypeAnnotations:)", "$1");
+        out = out.substring(out.indexOf('{'));
+        out = out.substring(0, out.lastIndexOf('}') + 1);
+
+        String A = snipCPNumber(constantPool, "LPatterns$SimpleBindingPattern$A;");
+        String CA = snipCPNumber(constantPool, "LPatterns$SimpleBindingPattern$CA;");
+        String value = snipCPNumber(constantPool, "value");
+
+        String expected = """
+                          {
+                            private static final java.lang.Object o;
+                              descriptor: Ljava/lang/Object;
+                              flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL
+
+                            private static final boolean B1s;
+                              descriptor: Z
+                              flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL
+
+                            private static final boolean B1m;
+                              descriptor: Z
+                              flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL
+
+                            private final boolean B2s;
+                              descriptor: Z
+                              flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+
+                            private final boolean B2m;
+                              descriptor: Z
+                              flags: (0x0012) ACC_PRIVATE, ACC_FINAL
+
+                            public Patterns$SimpleBindingPattern();
+                              descriptor: ()V
+                              flags: (0x0001) ACC_PUBLIC
+                                RuntimeInvisibleTypeAnnotations:
+                                  0: #_A_(): LOCAL_VARIABLE, {start_pc=257, length=18, index=2}
+                                    Patterns$SimpleBindingPattern$A
+                                  1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=297, length=19, index=3}
+                                    Patterns$SimpleBindingPattern$CA(
+                                      value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+                                    )
+                                  2: #_A_(): LOCAL_VARIABLE, {start_pc=22, length=18, index=1}
+                                    Patterns$SimpleBindingPattern$A
+                                  3: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=62, length=18, index=1}
+                                    Patterns$SimpleBindingPattern$CA(
+                                      value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+                                    )
+                                  4: #_A_(): LOCAL_VARIABLE, {start_pc=101, length=18, index=2}
+                                    Patterns$SimpleBindingPattern$A
+                                  5: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=141, length=19, index=3}
+                                    Patterns$SimpleBindingPattern$CA(
+                                      value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+                                    )
+                                  6: #_A_(): LOCAL_VARIABLE, {start_pc=179, length=18, index=2}
+                                    Patterns$SimpleBindingPattern$A
+                                  7: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=219, length=19, index=3}
+                                    Patterns$SimpleBindingPattern$CA(
+                                      value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+                                    )
+
+                            void testPatterns();
+                              descriptor: ()V
+                              flags: (0x0000)
+                                RuntimeInvisibleTypeAnnotations:
+                                  0: #_A_(): LOCAL_VARIABLE, {start_pc=17, length=18, index=2}
+                                    Patterns$SimpleBindingPattern$A
+                                  1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=57, length=19, index=3}
+                                    Patterns$SimpleBindingPattern$CA(
+                                      value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+                                    )
+
+                            void testPatternsDesugared();
+                              descriptor: ()V
+                              flags: (0x0000)
+                                RuntimeInvisibleTypeAnnotations:
+                                  0: #_A_(): LOCAL_VARIABLE, {start_pc=17, length=15, index=1; start_pc=51, length=15, index=1}
+                                    Patterns$SimpleBindingPattern$A
+
+                            static {};
+                              descriptor: ()V
+                              flags: (0x0008) ACC_STATIC
+                                RuntimeInvisibleTypeAnnotations:
+                                  0: #_A_(): LOCAL_VARIABLE, {start_pc=22, length=18, index=0}
+                                    Patterns$SimpleBindingPattern$A
+                                  1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=61, length=18, index=0}
+                                    Patterns$SimpleBindingPattern$CA(
+                                      value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+                                    )
+                                  2: #_A_(): LOCAL_VARIABLE, {start_pc=100, length=18, index=1}
+                                    Patterns$SimpleBindingPattern$A
+                                  3: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=137, length=18, index=2}
+                                    Patterns$SimpleBindingPattern$CA(
+                                      value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A]
+                                    )
+                          }""".replace("_A_", A).replace("_CA_", CA).replace("_value_", value);
+
+        if (!expected.equals(out)) {
+            throw new AssertionError("Unexpected output:\n" + out + "\nexpected:\n" + expected);
+        }
+    }
+
+    private String snipCPNumber(String constantPool, String expectedConstant) {
+        Matcher m = Pattern.compile("#([0-9]+).*" + Pattern.quote(expectedConstant))
+                           .matcher(constantPool);
+        if (!m.find()) {
+            throw new AssertionError("Cannot find constant pool item");
+        }
+
+        return m.group(1);
+    }
+
+    /*********************** Test class *************************/
+    static class SimpleBindingPattern {
+        @Target(ElementType.TYPE_USE)
+        @Repeatable(CA.class)
+        @interface A {}
+        @Target(ElementType.TYPE_USE)
+        @interface CA {
+            public A[] value();
+        }
+
+        private static final Object o = "";
+        private static final boolean B1s = o instanceof @A String s && s.isEmpty();
+        private static final boolean B1m = o instanceof @A @A String s && s.isEmpty();
+        private final boolean B2s = o instanceof @A String s && s.isEmpty();
+        private final boolean B2m = o instanceof @A @A String s && s.isEmpty();
+
+        static {
+            boolean B3s = o instanceof @A String s && s.isEmpty();
+            boolean B3m = o instanceof @A @A String s && s.isEmpty();
+        }
+
+        {
+            boolean B4s = o instanceof @A String s && s.isEmpty();
+            boolean B4m = o instanceof @A @A String s && s.isEmpty();
+        }
+
+        {
+            boolean B5s = o instanceof @A String s && s.isEmpty();
+            boolean B5m = o instanceof @A @A String s && s.isEmpty();
+        }
+
+        public SimpleBindingPattern() {
+            boolean B6s = o instanceof @A String s && s.isEmpty();
+            boolean B6m = o instanceof @A @A String s && s.isEmpty();
+        }
+
+        void testPatterns() {
+            boolean B7s = o instanceof @A String s && s.isEmpty();
+            boolean B7m = o instanceof @A @A String s && s.isEmpty();
+        }
+
+        void testPatternsDesugared() {
+            @A String s;
+            boolean B8s = o instanceof String && (s = (String) o) == s && s.isEmpty();
+            boolean B8sx = o instanceof String && (s = (String) o) == s && s.isEmpty();
+        }
+    }
+}
--- a/test/langtools/tools/javac/api/TestGetElementReference.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/test/langtools/tools/javac/api/TestGetElementReference.java	Wed Nov 27 10:21:22 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -51,6 +51,9 @@
 
 public class TestGetElementReference {
 
+    private static final String JDK_VERSION =
+            Integer.toString(Runtime.getRuntime().version().feature());
+
     public static void main(String... args) throws IOException {
         analyze("TestGetElementReferenceData.java");
         analyze("mod/module-info.java", "mod/api/pkg/Api.java");
@@ -66,7 +69,10 @@
                 }
             }
             DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
-            JavacTask ct = (JavacTask) ToolProvider.getSystemJavaCompiler().getTask(null, null, diagnostics, Arrays.asList("-Xjcov"), null, files);
+            List<String> options = List.of("-Xjcov",
+                                           "--enable-preview",
+                                           "-source", JDK_VERSION);
+            JavacTask ct = (JavacTask) ToolProvider.getSystemJavaCompiler().getTask(null, null, diagnostics, options, null, files);
             Trees trees = Trees.instance(ct);
             CompilationUnitTree cut = ct.parse().iterator().next();
 
--- a/test/langtools/tools/javac/api/TestGetElementReferenceData.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/test/langtools/tools/javac/api/TestGetElementReferenceData.java	Wed Nov 27 10:21:22 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,6 +35,8 @@
         java.util.List< /*getElement:INTERFACE:java.util.List*/ String> l;
         utility/*getElement:METHOD:test.TestGetElementReferenceData.Base.utility()*/();
         target(TestGetElementReferenceData :: test/*getElement:METHOD:test.TestGetElementReferenceData.test()*/);
+        Object/*getElement:CLASS:java.lang.Object*/ o = null;
+        if (o/*getElement:LOCAL_VARIABLE:o*/ instanceof String/*getElement:CLASS:java.lang.String*/ str/*getElement:LOCAL_VARIABLE:str*/) ;
     }
     private static void target(Runnable r) { r.run(); }
     public static class Base {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/InstanceofReifiableNotSafe.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.instanceof.reifiable.not.safe
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source ${jdk.version}
+
+import java.util.List;
+
+class InstanceofReifiableNotSafe {
+    boolean test(Object o) {
+        return o instanceof List<String> l;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/MatchBindingExists.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.match.binding.exists
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source ${jdk.version}
+
+class MatchBindingExists {
+    public void test(Object o1, Object o2) {
+        if (o1 instanceof String k && o2 instanceof Integer k) {}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/PatternBindingMayNotBeAssigned.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.err.pattern.binding.may.not.be.assigned
+// key: compiler.note.preview.filename
+// key: compiler.note.preview.recompile
+// options: --enable-preview -source ${jdk.version}
+
+class ResourceMayNotBeAssigned {
+    void m(Object o) {
+        if (o instanceof String s) {
+            s = "";
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/PatternMatchingInstanceof.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.misc.feature.pattern.matching.instanceof
+// key: compiler.warn.preview.feature.use
+// options: --enable-preview -source ${jdk.version} -Xlint:preview
+
+class PatternMatchingInstanceof {
+    boolean m(Object o) {
+        return o instanceof String s && s.isEmpty();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/diags/examples/ReifiableTypesInstanceof.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// key: compiler.misc.feature.reifiable.types.instanceof
+// key: compiler.warn.preview.feature.use.plural
+// options: --enable-preview -source ${jdk.version} -Xlint:preview
+
+class PatternMatchingInstanceof {
+    boolean m(I<String> i) {
+        return i instanceof C<String>;
+    }
+    interface I<T> {}
+    class C<T> implements I<T> {}
+}
--- a/test/langtools/tools/javac/lambda/deduplication/Deduplication.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/test/langtools/tools/javac/lambda/deduplication/Deduplication.java	Wed Nov 27 10:21:22 2019 +0100
@@ -163,6 +163,9 @@
 
         group((Function<Integer, Integer>) x -> switch (x) { default: yield x; },
               (Function<Integer, Integer>) x -> switch (x) { default: yield x; });
+
+        group((Function<Object, Integer>) x -> x instanceof Integer i ? i : -1,
+              (Function<Object, Integer>) x -> x instanceof Integer i ? i : -1);
     }
 
     void f() {}
--- a/test/langtools/tools/javac/lib/DPrinter.java	Wed Nov 27 10:19:45 2019 +0100
+++ b/test/langtools/tools/javac/lib/DPrinter.java	Wed Nov 27 10:21:22 2019 +0100
@@ -880,7 +880,7 @@
         @Override
         public void visitTypeTest(JCInstanceOf tree) {
             printTree("expr", tree.expr);
-            printTree("clazz", tree.clazz);
+            printTree("pattern", tree.pattern);
         }
 
         @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsExistTest.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,30 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Clashing bindings are reported correctly
+ * @compile/fail/ref=BindingsExistTest.out -XDrawDiagnostics --enable-preview -source ${jdk.version} BindingsExistTest.java
+ */
+public class BindingsExistTest {
+    public void t(Object o1, Object o2) {
+        if (o1 instanceof String k && o2 instanceof Integer k) {}
+
+        if (o1 instanceof String k || o2 instanceof Integer k) {}
+
+        if (!(o1 instanceof String k)) {
+            return ;
+        }
+        if (o1 instanceof Integer k) {}
+
+        String s2 = "";
+        if (o1 instanceof String s2) {}
+
+        if (o1 instanceof String s3) {
+            String s3 = "";
+        }
+
+        if (!(o1 instanceof String s4)) {
+            return ;
+        }
+        String s4 = "";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsExistTest.out	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,9 @@
+BindingsExistTest.java:9:36: compiler.err.match.binding.exists
+BindingsExistTest.java:11:36: compiler.err.match.binding.exists
+BindingsExistTest.java:16:35: compiler.err.already.defined: kindname.variable, k, kindname.method, t(java.lang.Object,java.lang.Object)
+BindingsExistTest.java:19:34: compiler.err.already.defined: kindname.variable, s2, kindname.method, t(java.lang.Object,java.lang.Object)
+BindingsExistTest.java:22:20: compiler.err.already.defined: kindname.variable, s3, kindname.method, t(java.lang.Object,java.lang.Object)
+BindingsExistTest.java:28:16: compiler.err.already.defined: kindname.variable, s4, kindname.method, t(java.lang.Object,java.lang.Object)
+- compiler.note.preview.filename: BindingsExistTest.java
+- compiler.note.preview.recompile
+6 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsTest1.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8231827
+ * @summary Basic tests for bindings from instanceof
+ * @compile --enable-preview -source ${jdk.version} BindingsTest1.java
+ * @run main/othervm --enable-preview BindingsTest1
+ */
+
+public class BindingsTest1 {
+    public static boolean Ktrue() { return true; }
+    public static void main(String[] args) {
+        Object o1 = "hello";
+        Integer i = 42;
+        Object o2 = i;
+        Object o3 = "there";
+
+
+        // Test for (e matches P).T = { binding variables in P }
+        if (o1 instanceof String s) {
+            s.length();
+        }
+
+        // Test for e1 && e2.T = union(e1.T, e2.T)
+        if (o1 instanceof String s && o2 instanceof Integer in) {
+            s.length();
+            in.intValue();
+        }
+
+        // test for e1&&e2 - include e1.T in e2
+        if (o1 instanceof String s && s.length()>0) {
+            System.out.print("done");
+        }
+
+        // Test for (e1 || e2).F = union(e1.F, e2.F)
+        if (!(o1 instanceof String s) || !(o3 instanceof Integer in)){
+        } else {
+            s.length();
+            i.intValue();
+        }
+
+        // Test for e1||e2 - include e1.F in e2
+
+        if (!(o1 instanceof String s) || s.length()>0) {
+            System.out.println("done");
+        }
+
+        // Test for e1 ? e2: e3 - include e1.T in e2
+        if (o1 instanceof String s ? s.length()>0 : false) {
+            System.out.println("done");
+        }
+
+        // Test for e1 ? e2 : e3 - include e1.F in e3
+        if (!(o1 instanceof String s) ? false : s.length()>0){
+            System.out.println("done");
+        }
+
+        // Test for (!e).T = e.F
+
+        if (!(!(o1 instanceof String s) || !(o3 instanceof Integer in))){
+            s.length();
+            i.intValue();
+        }
+
+        // Test for (!e).F = e.T
+        if (!(o1 instanceof String s)) {
+
+        } else {
+            s.length();
+        }
+
+        L1: {
+            if (o1 instanceof String s) {
+                s.length();
+            } else {
+                break L1;
+            }
+            s.length();
+        }
+
+        L2: {
+            if (!(o1 instanceof String s)) {
+                break L2;
+            } else {
+                s.length();
+            }
+            s.length();
+        }
+
+        L4: {
+            if (!(o1 instanceof String s)) {
+                break L4;
+            }
+            s.length();
+        }
+
+        {
+            while (!(o1 instanceof String s)) {
+            }
+
+            s.length();
+        }
+
+        L5: {
+            while (!(o1 instanceof String s)) {
+            }
+
+            s.length();
+        }
+
+        {
+            L6: for ( ;!(o1 instanceof String s); ) {
+
+            }
+
+            s.length();
+        }
+
+        {
+            L7: do {
+
+            } while (!(o1 instanceof String s));
+
+            s.length();
+        }
+
+        if (o1 instanceof String s) {
+            Runnable r1 = new Runnable() {
+                @Override
+                public void run() {
+                    s.length();
+                }
+            };
+            r1.run();
+            Runnable r2 = () -> {
+                s.length();
+            };
+            r2.run();
+            String s2 = s;
+        }
+
+        System.out.println("BindingsTest1 complete");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsTest1Merging.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,72 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Basic tests for bindings from instanceof - tests for merging pattern variables
+ * @compile/fail/ref=BindingsTest1Merging.out -XDrawDiagnostics --enable-preview -source ${jdk.version} BindingsTest1Merging.java
+ */
+
+public class BindingsTest1Merging {
+    public static boolean Ktrue() { return true; }
+    public static void main(String[] args) {
+        Object o1 = "hello";
+        Integer i = 42;
+        Object o2 = i;
+        Object o3 = "there";
+
+        // Test for e1 && e2.F = intersect(e1.F, e2.F)
+        if (!(o1 instanceof String s) && !(o1 instanceof String s)) {
+
+        } else {
+            s.length();
+        }
+
+        // Test for (e1 || e2).T = intersect(e1.T, e2.T)
+        if (o1 instanceof String s || o3 instanceof String s){
+            System.out.println(s); // ?
+        }
+
+        // Test for (e1 ? e2 : e3).T contains intersect(e2.T, e3.T)
+        if (Ktrue() ? o2 instanceof Integer x : o2 instanceof Integer x) {
+            x.intValue();
+        }
+
+        // Test for (e1 ? e2 : e3).T contains intersect(e1.T, e3.T)
+        if (o1 instanceof String s ? true : o1 instanceof String s) {
+            s.length();
+        }
+
+        // Test for (e1 ? e2 : e3).T contains intersect(e1.F, e2.T)
+        if (!(o1 instanceof String s) ? (o1 instanceof String s) : true) {
+            s.length();
+        }
+
+        // Test for (e1 ? e2 : e3).F contains intersect(e2.F, e3.F)
+        if (Ktrue() ? !(o2 instanceof Integer x) : !(o2 instanceof Integer x)){
+        } else {
+            x.intValue();
+        }
+
+        // Test for (e1 ? e2 : e3).F contains intersect(e1.T, e3.F)
+        if (o1 instanceof String s ? true : !(o1 instanceof String s)){
+        } else {
+            s.length();
+        }
+
+        // Test for (e1 ? e2 : e3).F contains intersect(e1.F, e2.F)
+        if (!(o1 instanceof String s) ? !(o1 instanceof String s) : true){
+        } else {
+            s.length();
+        }
+
+        L3: {
+            if ((o1 instanceof String s) || (o3 instanceof String s)) {
+                s.length();
+            } else {
+                break L3;
+            }
+            s.length();
+        }
+
+        System.out.println("BindingsTest1Merging complete");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsTest1Merging.out	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,12 @@
+BindingsTest1Merging.java:17:39: compiler.err.match.binding.exists
+BindingsTest1Merging.java:24:36: compiler.err.match.binding.exists
+BindingsTest1Merging.java:29:21: compiler.err.match.binding.exists
+BindingsTest1Merging.java:34:36: compiler.err.match.binding.exists
+BindingsTest1Merging.java:39:39: compiler.err.match.binding.exists
+BindingsTest1Merging.java:44:21: compiler.err.match.binding.exists
+BindingsTest1Merging.java:50:36: compiler.err.match.binding.exists
+BindingsTest1Merging.java:56:39: compiler.err.match.binding.exists
+BindingsTest1Merging.java:62:42: compiler.err.match.binding.exists
+- compiler.note.preview.filename: BindingsTest1Merging.java
+- compiler.note.preview.recompile
+9 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsTest2.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,191 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Ensure that scopes arising from conditionalExpressions are handled corrected.
+ * @compile/fail/ref=BindingsTest2.out -XDrawDiagnostics -XDshould-stop.at=FLOW --enable-preview -source ${jdk.version} BindingsTest2.java
+ */
+public class BindingsTest2 {
+    public static boolean Ktrue() { return true; }
+    public static void main(String[] args) {
+        Object o1 = "hello";
+        Integer in = 42;
+        Object o2 = in;
+        Object o3 = "there";
+
+
+        if (Ktrue() ? o2 instanceof Integer x : o2 instanceof String x) {
+            x.intValue();
+        }
+        if (Ktrue() ? o2 instanceof Integer x : true) {
+            x.intValue();
+        }
+
+        if (o1 instanceof String s ? true : true) {
+            s.length();
+        }
+        if (o1 instanceof String s ? true : o2 instanceof Integer s) {
+            s.length();
+        }
+        if (o1 instanceof String s ? true : o2 instanceof Integer i) {
+            s.length();
+        }
+
+        // Test for (e1 ? e2 : e3).T contains intersect(e1.F, e2.T)
+        if (!(o1 instanceof String s) ? true : true) {
+            s.length();
+        }
+        if (!(o1 instanceof String s) ? (o2 instanceof Integer s) : true) {
+            s.length();
+        }
+        if (!(o1 instanceof String s) ? (o2 instanceof Integer i) : true) {
+            s.length();
+            i.intValue();
+        }
+        if (!(o1 instanceof String s) ? (o1 instanceof String s2) : true) {
+            s.length();
+            s2.length();
+        }
+
+
+        // Test for (e1 ? e2 : e3).F contains intersect(e2.F, e3.F)
+        if (Ktrue() ? !(o2 instanceof Integer x) : !(o1 instanceof String x)){
+        } else {
+            x.intValue();
+        }
+        if (Ktrue() ? !(o2 instanceof Integer x) : !(o1 instanceof String s)){
+        } else {
+            x.intValue();
+        }
+        if (Ktrue() ? !(o2 instanceof Integer x) : !(o2 instanceof Integer x1)){
+        } else {
+            x.intValue();
+            x1.intValue();
+        }
+        if (Ktrue() ? !(o2 instanceof Integer x) : false){
+        } else {
+            x.intValue();
+        }
+
+        // Test for (e1 ? e2 : e3).F contains intersect(e1.T, e3.F)
+        if (o1 instanceof String s ? true : !(o2 instanceof Integer s)){
+        } else {
+            s.length();
+        }
+        if (o1 instanceof String s ? true : !(o2 instanceof Integer i)){
+        } else {
+            s.length();
+            i.intValue();
+        }
+        if (o1 instanceof String s ? true : !(o2 instanceof String s1)){
+        } else {
+            s.length();
+            s1.length();
+        }
+        // Test for (e1 ? e2 : e3).F contains intersect(e1.F, e2.F)
+        if (!(o1 instanceof String s) ? !(o1 instanceof String s1) : true){
+        } else {
+            s.length();
+            s1.length();
+        }
+        if (!(o1 instanceof String s) ? !(o2 instanceof Integer s) : true){
+        } else {
+            s.length();
+        }
+        if (!(o1 instanceof String s) ? !(o2 instanceof Integer i) : true){
+        } else {
+            s.length();
+            i.intValue();
+        }
+
+        // Test for e1 ? e2: e3 - include e1.T in e2
+        if (o1 instanceof String s ? false : s.length()>0) {
+            System.out.println("done");
+        }
+        if (o1 instanceof String s ? false : s.intValue!=0) {
+            System.out.println("done");
+        }
+
+        // Test for e1 ? e2 : e3 - include e1.F in e3
+        if (!(o1 instanceof String s) ? s.length()>0 : false){
+            System.out.println("done");
+        }
+        if (!(o1 instanceof String s) ? s.intValue>0 : false){
+            System.out.println("done");
+        }
+
+        {
+            while (!(o1 instanceof String s)) {
+                break;
+            }
+
+            s.length();
+        }
+
+        {
+            while (!(o1 instanceof String s)) {
+                if (false) break;
+            }
+
+            s.length();
+        }
+
+        {
+            while (!(o1 instanceof String s)) {
+                while (true);
+                break;
+            }
+
+            s.length();
+        }
+
+        {
+            for (; !(o1 instanceof String s); ) {
+                break;
+            }
+
+            s.length();
+        }
+
+        {
+            for (; !(o1 instanceof String s); ) {
+                if (false) break;
+            }
+
+            s.length();
+        }
+
+        {
+            for (; !(o1 instanceof String s); ) {
+                while (true);
+                break;
+            }
+
+            s.length();
+        }
+
+        {
+            do {
+                break;
+            } while (!(o1 instanceof String s));
+
+            s.length();
+        }
+
+        {
+            do {
+                if (false) break;
+            } while (!(o1 instanceof String s));
+
+            s.length();
+        }
+
+        {
+            do {
+                while (true);
+                break;
+            } while (!(o1 instanceof String s));
+
+            s.length();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/BindingsTest2.out	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,48 @@
+BindingsTest2.java:16:21: compiler.err.match.binding.exists
+BindingsTest2.java:17:14: compiler.err.cant.resolve.location.args: kindname.method, intValue, , , (compiler.misc.location.1: kindname.variable, x, java.lang.String)
+BindingsTest2.java:20:13: compiler.err.cant.resolve.location: kindname.variable, x, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:24:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:26:36: compiler.err.match.binding.exists
+BindingsTest2.java:27:14: compiler.err.cant.resolve.location.args: kindname.method, length, , , (compiler.misc.location.1: kindname.variable, s, java.lang.Integer)
+BindingsTest2.java:30:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:35:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:37:39: compiler.err.match.binding.exists
+BindingsTest2.java:38:14: compiler.err.cant.resolve.location.args: kindname.method, length, , , (compiler.misc.location.1: kindname.variable, s, java.lang.Integer)
+BindingsTest2.java:41:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:42:13: compiler.err.cant.resolve.location: kindname.variable, i, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:45:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:46:13: compiler.err.cant.resolve.location: kindname.variable, s2, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:51:21: compiler.err.match.binding.exists
+BindingsTest2.java:53:14: compiler.err.cant.resolve.location.args: kindname.method, intValue, , , (compiler.misc.location.1: kindname.variable, x, java.lang.String)
+BindingsTest2.java:57:13: compiler.err.cant.resolve.location: kindname.variable, x, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:61:13: compiler.err.cant.resolve.location: kindname.variable, x, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:62:13: compiler.err.cant.resolve.location: kindname.variable, x1, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:66:13: compiler.err.cant.resolve.location: kindname.variable, x, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:70:36: compiler.err.match.binding.exists
+BindingsTest2.java:72:14: compiler.err.cant.resolve.location.args: kindname.method, length, , , (compiler.misc.location.1: kindname.variable, s, java.lang.Integer)
+BindingsTest2.java:76:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:77:13: compiler.err.cant.resolve.location: kindname.variable, i, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:81:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:82:13: compiler.err.cant.resolve.location: kindname.variable, s1, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:87:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:88:13: compiler.err.cant.resolve.location: kindname.variable, s1, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:90:39: compiler.err.match.binding.exists
+BindingsTest2.java:92:14: compiler.err.cant.resolve.location.args: kindname.method, length, , , (compiler.misc.location.1: kindname.variable, s, java.lang.Integer)
+BindingsTest2.java:96:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:97:13: compiler.err.cant.resolve.location: kindname.variable, i, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:101:46: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:104:46: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:109:41: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:112:41: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:121:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:129:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:146:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:154:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:171:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:179:13: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, BindingsTest2, null)
+BindingsTest2.java:135:17: compiler.err.unreachable.stmt
+BindingsTest2.java:160:17: compiler.err.unreachable.stmt
+BindingsTest2.java:185:17: compiler.err.unreachable.stmt
+- compiler.note.preview.filename: BindingsTest2.java
+- compiler.note.preview.recompile
+45 errors
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/CastConversionMatch.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,18 @@
+/*
+ * @test /nodynamicopyright/
+ * @bug 8231827
+ * @summary Match which involves a cast conversion
+ * @compile/fail/ref=CastConversionMatch.out -XDrawDiagnostics --enable-preview -source ${jdk.version} CastConversionMatch.java
+ */
+
+public class CastConversionMatch {
+    public static void main(String [] args) {
+        Object o = 42;
+        if (o instanceof int s) {
+            System.out.println("Okay");
+        } else {
+            throw new AssertionError("broken");
+        }
+        System.out.println(">Test complete");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/CastConversionMatch.out	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,4 @@
+CastConversionMatch.java:11:26: compiler.err.type.found.req: int, (compiler.misc.type.req.class.array)
+- compiler.note.preview.filename: CastConversionMatch.java
+- compiler.note.preview.recompile
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/DuplicateBindingTest.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,22 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Basic pattern bindings scope test
+ * @compile/fail/ref=DuplicateBindingTest.out -XDrawDiagnostics --enable-preview -source ${jdk.version} DuplicateBindingTest.java
+ */
+
+public class DuplicateBindingTest {
+
+    int f;
+
+    public static void main(String[] args) {
+
+        if (args != null) {
+            int s;
+            if (args[0] instanceof String s) { // NOT OK. Redef same scope.
+            }
+            if (args[0] instanceof String f) { // OK to redef field.
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/DuplicateBindingTest.out	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,4 @@
+DuplicateBindingTest.java:16:43: compiler.err.already.defined: kindname.variable, s, kindname.method, main(java.lang.String[])
+- compiler.note.preview.filename: DuplicateBindingTest.java
+- compiler.note.preview.recompile
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/EnsureTypesOrderTest.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,13 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8187420 8231827
+ * @summary Error message mentions relevant types transposed
+ * @compile/fail/ref=EnsureTypesOrderTest.out -XDrawDiagnostics --enable-preview -source ${jdk.version} EnsureTypesOrderTest.java
+ */
+public class EnsureTypesOrderTest {
+    public static void main(String [] args) {
+        if (args instanceof String s) {
+            System.out.println("Broken");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/EnsureTypesOrderTest.out	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,4 @@
+EnsureTypesOrderTest.java:9:13: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String[], java.lang.String)
+- compiler.note.preview.filename: EnsureTypesOrderTest.java
+- compiler.note.preview.recompile
+1 error
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ExamplesFromProposal.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8231827
+ * @summary All example code from "Pattern Matching for Java" document, released April 2017, adjusted to current state (no switches, etc)
+ * @compile --enable-preview -source ${jdk.version} ExamplesFromProposal.java
+ * @run main/othervm --enable-preview ExamplesFromProposal
+ */
+
+interface Node {
+}
+
+class IntNode implements Node {
+    int value;
+
+    IntNode(int value) {
+        this.value = value;
+    }
+}
+
+class NegNode implements Node {
+    Node node;
+
+    NegNode(Node node) {
+        this.node = node;
+    }
+}
+
+class MulNode implements Node {
+    Node left, right;
+
+    MulNode(Node left, Node right) {
+        this.left = left;
+        this.right = right;
+    }
+}
+
+class AddNode implements Node {
+    Node left, right;
+
+    AddNode(Node left, Node right) {
+        this.left = left;
+        this.right = right;
+    }
+}
+
+public class ExamplesFromProposal {
+
+    public static Object getSomething() {
+        return new Long(42);
+    }
+
+    public static int eval(Node n) {
+        if (n instanceof IntNode in) return in.value;
+        else if (n instanceof NegNode nn) return -eval(nn.node);
+        else if (n instanceof AddNode an) return eval(an.left) + eval(an.right);
+        else if (n instanceof MulNode mn) return eval(mn.left) * eval(mn.right);
+        else {
+            // should never happen
+            throw new AssertionError("broken");
+        }
+    }
+
+    public static String toString(Node n) {
+        if (n instanceof IntNode in) return String.valueOf(in.value);
+        else if (n instanceof NegNode nn) return "-"+eval(nn.node);
+        else if (n instanceof AddNode an) return eval(an.left) + " + " + eval(an.right);
+        else if (n instanceof MulNode mn) return eval(mn.left) + " * " + eval(mn.right);
+        else {
+            // should never happen
+            throw new AssertionError("broken");
+        }
+    }
+
+    public static Node simplify(Node n) {
+        if (n instanceof IntNode in) {
+            return n;
+        } else if (n instanceof NegNode nn) {
+            return new NegNode(simplify(nn.node));
+        } else if (n instanceof AddNode ad) {
+            n = simplify(ad.left);
+            if (n instanceof IntNode intn) {
+                if (intn.value == 0)
+                    return simplify(ad.right);
+                else
+                    return new AddNode(intn, simplify(ad.right));
+            } else {
+                return new AddNode(simplify(ad.left), simplify(ad.right));
+            }
+        } else if (n instanceof MulNode mn) {
+            return new MulNode(simplify(mn.left), simplify(mn.right));
+        } else {
+            //should never happen
+            throw new AssertionError("broken");
+        }
+    }
+
+    public static void testNode(Node n, int expected) {
+        if (eval(n) != expected)
+            throw new AssertionError("broken");
+    }
+
+    public static void main(String[] args) {
+        Object x = new Integer(42);
+
+        if (x instanceof Integer i) {
+            // can use i here
+            System.out.println(i.intValue());
+        }
+
+        Object obj = getSomething();
+
+        String formatted = "unknown";
+        if (obj instanceof Integer i) {
+            formatted = String.format("int %d", i);
+        }
+        else if (obj instanceof Byte b) {
+            formatted = String.format("byte %d", b);
+        }
+        else if (obj instanceof Long l) {
+            formatted = String.format("long %d", l);
+        }
+        else if (obj instanceof Double d) {
+            formatted = String.format("double %f", d);
+        }
+        else if (obj instanceof String s) {
+            formatted = String.format("String %s", s);
+        }
+        System.out.println(formatted);
+
+        if (obj instanceof Integer i) formatted = String.format("int %d", i);
+        else if (obj instanceof Byte b) formatted = String.format("byte %d", b);
+        else if (obj instanceof Long l) formatted = String.format("long %d", l);
+        else if (obj instanceof Double d) formatted = String.format("double %f", d);
+        else if (obj instanceof String s) formatted = String.format("String %s", s);
+        else formatted = String.format("Something else "+ obj.toString());
+        System.out.println(formatted);
+
+        Node zero = new IntNode(0);
+        Node one = new IntNode(1);
+        Node ft = new IntNode(42);
+
+        Node temp = new AddNode(zero,ft);
+
+        testNode(temp,42);
+
+
+
+        if (toString(simplify(temp)).equals(toString(ft)))
+            System.out.println("Simplify worked!");
+        else
+            throw new AssertionError("broken");
+
+
+        if (toString(simplify(new AddNode(zero,temp))).equals(toString(ft)))
+            System.out.println("Simplify worked!");
+        else
+            throw new AssertionError("broken");
+
+
+        temp = new AddNode(zero,ft);
+        temp = new AddNode(one,temp);
+        temp = new AddNode(zero,temp);
+
+        Node fortythree = new AddNode(one,ft);
+
+        if (toString(simplify(temp)).equals(toString(fortythree)))
+            System.out.println("Simplify worked!");
+        else
+            throw new AssertionError("broken");
+
+
+        x = "Hello";
+
+        if (x instanceof String s1) {
+            System.out.println(s1);
+        }
+        if (x instanceof String s1 && s1.length() > 0) {
+            System.out.println(s1);
+        }
+        if (x instanceof String s1) {
+            System.out.println(s1 + " is a string");
+        } else {
+            System.out.println("not a string");
+        }
+
+        if (!(x instanceof String s1)) {
+            System.out.println("not a string");
+        } else {
+            System.out.println(s1 + " is a string");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ImpossibleTypeTest.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,21 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Ensure that in type test patterns, the predicate is not trivially provable false.
+ * @compile/fail/ref=ImpossibleTypeTest.out -XDrawDiagnostics --enable-preview -source ${jdk.version} ImpossibleTypeTest.java
+ */
+public class ImpossibleTypeTest {
+
+    public static void main(String[] args) {
+
+        int in = 42;
+        Integer i = 42;
+
+        if (i instanceof String s ) {
+            System.out.println("Broken");
+        }
+        if (i instanceof Undefined u ) {
+            System.out.println("Broken");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ImpossibleTypeTest.out	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,5 @@
+ImpossibleTypeTest.java:14:13: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Integer, java.lang.String)
+ImpossibleTypeTest.java:17:26: compiler.err.cant.resolve.location: kindname.class, Undefined, , , (compiler.misc.location: kindname.class, ImpossibleTypeTest, null)
+- compiler.note.preview.filename: ImpossibleTypeTest.java
+- compiler.note.preview.recompile
+2 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/LocalVariableTable.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8231827
+ * @summary Ensure the LV table entries are generated for bindings
+ * @modules jdk.jdeps/com.sun.tools.classfile
+ * @compile -g --enable-preview -source ${jdk.version} LocalVariableTable.java
+ * @run main/othervm --enable-preview LocalVariableTable
+ */
+
+import java.io.*;
+import java.lang.annotation.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+
+/*
+ * The test checks that a LocalVariableTable attribute is generated for the
+ * method bodies containing patterns, and checks that the expected
+ * set of entries is found in the attribute.
+ *
+ * The test looks for test cases represented by nested classes whose
+ * name begins with "Pattern".  Each such class contains a method
+ * with patterns, and because the test is compiled
+ * with -g, these methods should have a LocalVariableTable.  The set of
+ * expected names in the LVT is provided in an annotation on the class for
+ * the test case.
+ */
+//Copied from: test/langtools/tools/javac/lambda/LocalVariableTable.java
+public class LocalVariableTable {
+    public static void main(String... args) throws Exception {
+        new LocalVariableTable().run();
+    }
+
+    void run() throws Exception {
+        // the declared classes are returned in an unspecified order,
+        // so for neatness, sort them by name before processing them
+        Class<?>[] classes = getClass().getDeclaredClasses();
+        Arrays.sort(classes, (c1, c2) -> c1.getName().compareTo(c2.getName()));
+
+        for (Class<?> c : classes) {
+            if (c.getSimpleName().startsWith("Pattern"))
+                check(c);
+        }
+        if (errors > 0)
+            throw new Exception(errors + " errors found");
+    }
+
+    /** Check an individual test case. */
+    void check(Class<?> c) throws Exception {
+        System.err.println("Checking " + c.getSimpleName());
+
+        Expect expect = c.getAnnotation(Expect.class);
+        if (expect == null) {
+            error("@Expect not found for class " + c.getSimpleName());
+            return;
+        }
+
+        ClassFile cf = ClassFile.read(getClass().getResource(c.getName() + ".class").openStream());
+        Method m = getMethodByName(cf, c.getSimpleName().contains("Lambda") ? "lambda$" : "test");
+        if (m == null) {
+            error("test method not found");
+            return;
+        }
+
+        Code_attribute code = (Code_attribute) m.attributes.get(Attribute.Code);
+        if (code == null) {
+            error("Code attribute not found");
+            return;
+        }
+
+        LocalVariableTable_attribute lvt =
+                (LocalVariableTable_attribute) code.attributes.get(Attribute.LocalVariableTable);
+        if (lvt == null) {
+            error("LocalVariableTable attribute not found");
+            return;
+        }
+
+        Set<String> foundNames = new LinkedHashSet<>();
+        for (LocalVariableTable_attribute.Entry e: lvt.local_variable_table) {
+            foundNames.add(cf.constant_pool.getUTF8Value(e.name_index));
+        }
+
+        Set<String> expectNames = new LinkedHashSet<>(Arrays.asList(expect.value()));
+        if (!foundNames.equals(expectNames)) {
+            Set<String> foundOnly = new LinkedHashSet<>(foundNames);
+            foundOnly.removeAll(expectNames);
+            for (String s: foundOnly)
+                error("Unexpected name found: " + s);
+            Set<String> expectOnly = new LinkedHashSet<>(expectNames);
+            expectOnly.removeAll(foundNames);
+            for (String s: expectOnly)
+                error("Expected name not found: " + s);
+        }
+    }
+
+    Method getMethodByName(ClassFile cf, String name) throws ConstantPoolException {
+        for (Method m: cf.methods) {
+            if (m.getName(cf.constant_pool).startsWith(name))
+                return m;
+        }
+        return null;
+    }
+
+    /** Report an error. */
+    void error(String msg) {
+        System.err.println("Error: " + msg);
+        errors++;
+    }
+
+    int errors;
+
+    /**
+     * Annotation used to provide the set of names expected in the LVT attribute.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface Expect {
+        String[] value();
+    }
+
+    /*
+     * ---------- Test cases ---------------------------------------------------
+     */
+
+    @Expect({ "o", "s" })
+    static class Pattern_Simple {
+        public static void test(Object o) {
+            if (o instanceof String s) {}
+        }
+    }
+
+    @Expect({ "s" })
+    static class Pattern_Lambda {
+        public static void test(Object o) {
+            if (o instanceof String s) {
+                Runnable r = () -> {
+                    s.length();
+                };
+            }
+        }
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/MatchBindingScopeTest.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,68 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Basic pattern bindings scope test
+ * @compile/fail/ref=MatchBindingScopeTest.out -XDrawDiagnostics --enable-preview -source ${jdk.version} MatchBindingScopeTest.java
+ */
+public class MatchBindingScopeTest {
+
+    static Integer i = 42;
+    static String s = "Hello";
+    static Object o1 = s;
+    static Object o2 = i;
+
+    public static void main(String[] args) {
+
+        if (o1 instanceof String j && j.length() == 5) { // OK
+            System.out.println(j); // OK
+        } else {
+            System.out.println(j); // NOT OK
+        }
+
+        // NOT OK, name reused.
+        if (o1 instanceof String j && o2 instanceof Integer j) {
+        }
+
+        if (o1 instanceof String j && j.length() == 5 && o2 instanceof Integer k && k == 42) { // OK
+            System.out.println(j); // OK
+            System.out.println(k); // OK
+        } else {
+            System.out.println(j); // NOT OK
+            System.out.println(k); // NOT OK
+        }
+
+        if (o1 instanceof String j || j.length() == 5) { // NOT OK
+            System.out.println(j); // NOT OK
+        }
+
+        if (o1 instanceof String j || o2 instanceof Integer j) { // NOT OK, types differ
+            System.out.println(j);
+        } else {
+            System.out.println(j); // NOT OK.
+        }
+
+        while (o1 instanceof String j && j.length() == 5) { // OK
+            System.out.println(j); // OK
+        }
+
+        while (o1 instanceof String j || true) {
+            System.out.println(j); // Not OK
+        }
+
+        for (; o1 instanceof String j; j.length()) { // OK
+            System.out.println(j); // OK
+        }
+
+        for (; o1 instanceof String j || true; j.length()) { // NOT OK
+            System.out.println(j); // Not OK
+        }
+
+        int x = o1 instanceof String j ?
+                      j.length() : // OK.
+                      j.length();  // NOT OK.
+
+        x = !(o1 instanceof String j) ?
+                      j.length() : // NOT OK.
+                      j.length();  // OK.
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/MatchBindingScopeTest.out	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,16 @@
+MatchBindingScopeTest.java:19:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:23:36: compiler.err.match.binding.exists
+MatchBindingScopeTest.java:30:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:31:32: compiler.err.cant.resolve.location: kindname.variable, k, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:34:39: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:35:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:38:36: compiler.err.match.binding.exists
+MatchBindingScopeTest.java:41:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:49:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:56:48: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:57:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:62:23: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+MatchBindingScopeTest.java:65:23: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null)
+- compiler.note.preview.filename: MatchBindingScopeTest.java
+- compiler.note.preview.recompile
+13 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/NullsInPatterns.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8231827
+ * @summary Testing pattern matching against the null constant
+ * @compile --enable-preview -source ${jdk.version} NullsInPatterns.java
+ * @run main/othervm --enable-preview NullsInPatterns
+ */
+import java.util.List;
+
+public class NullsInPatterns {
+
+    public static void main(String[] args) {
+        if (null instanceof List t) {
+            throw new AssertionError("broken");
+        } else {
+            System.out.println("null does not match List type pattern");
+        }
+        //reifiable types not allowed in type test patterns in instanceof:
+//        if (null instanceof List<Integer> l) {
+//            throw new AssertionError("broken");
+//        } else {
+//            System.out.println("null does not match List<Integer> type pattern");
+//        }
+        if (null instanceof List<?> l) {
+            throw new AssertionError("broken");
+        } else {
+            System.out.println("null does not match List<?> type pattern");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternMatchPosTest.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8231827
+ * @summary Check proper positions.
+ * @build PatternMatchPosTest
+ * @compile/ref=PatternMatchPosTest.out -processor PatternMatchPosTest -Xlint:unchecked -XDrawDiagnostics --enable-preview -source ${jdk.version} PatternMatchPosTestData.java
+ */
+
+import java.io.IOException;
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.TypeElement;
+
+import com.sun.source.tree.IfTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.SourcePositions;
+import com.sun.source.util.TreePath;
+import com.sun.source.util.TreeScanner;
+import com.sun.source.util.Trees;
+import javax.tools.Diagnostic;
+
+@SupportedAnnotationTypes("*")
+public class PatternMatchPosTest extends AbstractProcessor {
+
+    int round;
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (round++ != 0)
+            return false;
+
+        try {
+            TypeElement data = processingEnv.getElementUtils().getTypeElement("PatternMatchPosTestData");
+            Trees trees = Trees.instance(processingEnv);
+            SourcePositions sp = trees.getSourcePositions();
+            TreePath dataPath = trees.getPath(data);
+            String text = dataPath.getCompilationUnit().getSourceFile().getCharContent(true).toString();
+
+            new TreeScanner<Void, Void>() {
+                boolean print;
+                @Override
+                public Void visitIf(IfTree node, Void p) {
+                    boolean prevPrint = print;
+                    try {
+                        print = true;
+                        scan(node.getCondition(), p);
+                    } finally {
+                        print = prevPrint;
+                    }
+                    scan(node.getThenStatement(), p);
+                    scan(node.getElseStatement(), p);
+                    return null;
+                }
+                @Override
+                public Void scan(Tree tree, Void p) {
+                    if (tree == null)
+                        return null;
+                    if (print) {
+                        int start = (int) sp.getStartPosition(dataPath.getCompilationUnit(), tree);
+                        int end = (int) sp.getEndPosition(dataPath.getCompilationUnit(), tree);
+                        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
+                                                                 text.substring(start, end));
+                    }
+                    return super.scan(tree, p);
+                }
+            }.scan(dataPath.getLeaf(), null);
+            return false;
+        } catch (IOException ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latestSupported();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternMatchPosTest.out	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,14 @@
+- compiler.note.proc.messager: (o instanceof String s)
+- compiler.note.proc.messager: o instanceof String s
+- compiler.note.proc.messager: o
+- compiler.note.proc.messager: String s
+- compiler.note.proc.messager: String
+- compiler.note.proc.messager: (o instanceof java.lang.String s)
+- compiler.note.proc.messager: o instanceof java.lang.String s
+- compiler.note.proc.messager: o
+- compiler.note.proc.messager: java.lang.String s
+- compiler.note.proc.messager: java.lang.String
+- compiler.note.proc.messager: java.lang
+- compiler.note.proc.messager: java
+- compiler.note.preview.filename: PatternMatchPosTestData.java
+- compiler.note.preview.recompile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternMatchPosTestData.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+class PatternMatchPosTestData {
+    void data(Object o) {
+        if (o instanceof String s) { }
+        if (o instanceof java.lang.String s) { }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternTypeTest2.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8231827
+ * @summary Basic pattern test
+ * @compile --enable-preview -source ${jdk.version} PatternTypeTest2.java
+ * @run main/othervm --enable-preview PatternTypeTest2
+ */
+public class PatternTypeTest2 {
+
+    public static void main(String[] args) {
+
+        Integer i = 42;
+        String s = "Hello";
+        Object o = i;
+
+        if (o instanceof Integer j) {
+            System.out.println("It's an Integer");
+        } else {
+            throw new AssertionError("Broken");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternVariablesAreFinal.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,16 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Ensure that in type test patterns, the predicate is not trivially provable false.
+ * @compile/fail/ref=PatternVariablesAreFinal.out -XDrawDiagnostics --enable-preview -source ${jdk.version} PatternVariablesAreFinal.java
+ */
+public class PatternVariablesAreFinal {
+    public static void main(String[] args) {
+        Object o = 32;
+        if (o instanceof String s) {
+            s = "hello again";
+            System.out.println(s);
+        }
+        System.out.println("test complete");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternVariablesAreFinal.out	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,4 @@
+PatternVariablesAreFinal.java:11:13: compiler.err.pattern.binding.may.not.be.assigned: s
+- compiler.note.preview.filename: PatternVariablesAreFinal.java
+- compiler.note.preview.recompile
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternVariablesAreFinal2.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8231827
+ * @summary Pattern variables are final so should be allowed to be referenced in an inner class
+ * @compile --enable-preview -source ${jdk.version} PatternVariablesAreFinal2.java
+ * @run main/othervm --enable-preview PatternVariablesAreFinal2
+ */
+public class PatternVariablesAreFinal2 {
+    public static void main(String[] args) {
+        Object o = "42";
+        if (o instanceof String s) {
+            new Object() {
+                void run() { System.err.println(s); }
+            }.run();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/PatternsSimpleVisitorTest.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8231827
+ * @summary Ensure SimpleTreeVisitor.visitBindingPattern and visitInstanceOf behaves as it should
+ * @modules jdk.compiler
+ */
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.tools.*;
+
+import com.sun.source.tree.BindingPatternTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.InstanceOfTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.SimpleTreeVisitor;
+import com.sun.source.util.TreePathScanner;
+
+public class PatternsSimpleVisitorTest {
+
+    public static void main(String[] args) throws Exception {
+        new PatternsSimpleVisitorTest().run();
+    }
+
+    void run() throws Exception {
+        String code = "class Test {\n" +
+                      "    boolean t(Object o) {\n" +
+                      "         return o instanceof String s ? s.isEmpty() : false;\n" +
+                      "    }\n" +
+                      "}\n";
+        int[] callCount = new int[1];
+        int[] instanceOfNodeCount = new int[1];
+        int[] bindingPatternNodeCount = new int[1];
+        new TreePathScanner<Void, Void>() {
+            @Override
+            public Void visitInstanceOf(InstanceOfTree node, Void p) {
+                node.accept(new SimpleTreeVisitor<Void, Void>() {
+                    @Override
+                    protected Void defaultAction(Tree defaultActionNode, Void p) {
+                        callCount[0]++;
+                        if (node == defaultActionNode) {
+                            instanceOfNodeCount[0]++;
+                        }
+                        return null;
+                    }
+                }, null);
+                return super.visitInstanceOf(node, p);
+            }
+            @Override
+            public Void visitBindingPattern(BindingPatternTree node, Void p) {
+                node.accept(new SimpleTreeVisitor<Void, Void>() {
+                    @Override
+                    protected Void defaultAction(Tree defaultActionNode, Void p) {
+                        callCount[0]++;
+                        if (node == defaultActionNode) {
+                            bindingPatternNodeCount[0]++;
+                        }
+                        return null;
+                    }
+                }, null);
+                return super.visitBindingPattern(node, p);
+            }
+        }.scan(parse(code), null);
+
+        if (callCount[0] != 2 || instanceOfNodeCount[0] != 1 ||
+            bindingPatternNodeCount[0] != 1) {
+            throw new AssertionError("Unexpected counts; callCount=" + callCount[0] +
+                                     ", switchExprNodeCount=" + instanceOfNodeCount[0] +
+                                     ", yieldNodeCount=" + bindingPatternNodeCount[0]);
+        }
+    }
+
+    private CompilationUnitTree parse(String code) throws IOException {
+        final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
+        assert tool != null;
+        DiagnosticListener<JavaFileObject> noErrors = d -> {};
+
+        StringWriter out = new StringWriter();
+        JavacTask ct = (JavacTask) tool.getTask(out, null, noErrors,
+            List.of("--enable-preview", "-source", Integer.toString(Runtime.version().feature())), null,
+            Arrays.asList(new MyFileObject(code)));
+        return ct.parse().iterator().next();
+    }
+
+    static class MyFileObject extends SimpleJavaFileObject {
+        private String text;
+
+        public MyFileObject(String text) {
+            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+            this.text = text;
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return text;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/Reifiable.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,22 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Verify behavior w.r.t. non-reifiable types and type test patterns in instanceof
+ * @compile/fail/ref=Reifiable.out --enable-preview -source ${jdk.version} -XDrawDiagnostics Reifiable.java
+ */
+
+public class Reifiable implements ReifiableI {
+    private static boolean test(Object o, List<Reifiable> l1, List<String> l2) {
+        return o instanceof ListImpl<Reifiable> li1 &&
+               l1 instanceof ListImpl<Reifiable> li2 &&
+               l2 instanceof ListImpl<Reifiable> li3 &&
+               l2 instanceof ListImpl<String> li4 &&
+               l1 instanceof Unrelated<Reifiable> li5;
+    }
+
+    public class List<T> {}
+    public class ListImpl<T extends ReifiableI> extends List<T> {}
+    public class Unrelated<T> {}
+}
+
+interface ReifiableI {}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/Reifiable.out	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,7 @@
+Reifiable.java:10:16: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, Reifiable.ListImpl<Reifiable>
+Reifiable.java:12:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Reifiable.List<java.lang.String>, Reifiable.ListImpl<Reifiable>)
+Reifiable.java:13:39: compiler.err.not.within.bounds: java.lang.String, T
+Reifiable.java:14:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Reifiable.List<Reifiable>, Reifiable.Unrelated<Reifiable>)
+- compiler.note.preview.filename: Reifiable.java
+- compiler.note.preview.recompile
+4 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ReifiableOld-old.out	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,7 @@
+ReifiableOld.java:12:37: compiler.err.illegal.generic.type.for.instof
+ReifiableOld.java:13:38: compiler.err.illegal.generic.type.for.instof
+ReifiableOld.java:14:38: compiler.err.illegal.generic.type.for.instof
+ReifiableOld.java:15:38: compiler.err.illegal.generic.type.for.instof
+ReifiableOld.java:15:39: compiler.err.not.within.bounds: java.lang.String, T
+ReifiableOld.java:16:39: compiler.err.illegal.generic.type.for.instof
+6 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ReifiableOld.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,24 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8231827
+ * @summary Verify behavior w.r.t. non-reifiable types in instanceof
+ * @compile/fail/ref=ReifiableOld-old.out -source 13 -Xlint:-options -XDrawDiagnostics ReifiableOld.java
+ * @compile/fail/ref=ReifiableOld-old.out -source ${jdk.version} -XDrawDiagnostics ReifiableOld.java
+ * @compile/fail/ref=ReifiableOld.out --enable-preview -source ${jdk.version} -XDrawDiagnostics ReifiableOld.java
+ */
+
+public class ReifiableOld implements ReifiableOldI {
+    private static boolean test(Object o, List<ReifiableOld> l1, List<String> l2) {
+        return o instanceof ListImpl<ReifiableOld> &&
+               l1 instanceof ListImpl<ReifiableOld> &&
+               l2 instanceof ListImpl<ReifiableOld> &&
+               l2 instanceof ListImpl<String> &&
+               l1 instanceof Unrelated<ReifiableOld>;
+    }
+
+    public class List<T> {}
+    public class ListImpl<T extends ReifiableOldI> extends List<T> {}
+    public class Unrelated<T> {}
+}
+
+interface ReifiableOldI {}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/ReifiableOld.out	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,7 @@
+ReifiableOld.java:12:16: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, ReifiableOld.ListImpl<ReifiableOld>
+ReifiableOld.java:14:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: ReifiableOld.List<java.lang.String>, ReifiableOld.ListImpl<ReifiableOld>)
+ReifiableOld.java:15:39: compiler.err.not.within.bounds: java.lang.String, T
+ReifiableOld.java:16:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: ReifiableOld.List<ReifiableOld>, ReifiableOld.Unrelated<ReifiableOld>)
+- compiler.note.preview.filename: ReifiableOld.java
+- compiler.note.preview.recompile
+4 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/UncheckedWarningOnMatchesTest.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,18 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8187429 8231827
+ * @summary Missing unchecked conversion warning
+ * @compile/fail/ref=UncheckedWarningOnMatchesTest.out -Xlint:unchecked -Werror -XDrawDiagnostics --enable-preview -source ${jdk.version} UncheckedWarningOnMatchesTest.java
+ */
+import java.util.ArrayList;
+
+public class UncheckedWarningOnMatchesTest {
+
+    public static void main(String [] args) {
+
+        Object o = new ArrayList<UncheckedWarningOnMatchesTest>();
+        if (o instanceof ArrayList<Integer> ai) {  // unchecked conversion
+            System.out.println("Blah");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/UncheckedWarningOnMatchesTest.out	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,4 @@
+UncheckedWarningOnMatchesTest.java:14:13: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, java.util.ArrayList<java.lang.Integer>
+- compiler.note.preview.filename: UncheckedWarningOnMatchesTest.java
+- compiler.note.preview.recompile
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/scope/ScopeTest.java	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.testng.ITestResult;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+import tools.javac.combo.JavacTemplateTestBase;
+
+import static java.util.stream.Collectors.toList;
+
+@Test
+public class ScopeTest extends JavacTemplateTestBase {
+
+    private static String st_block(String... statements) {
+        return Arrays.stream(statements).collect(Collectors.joining("", "{", "}"));
+    }
+
+    private static String st_if(String condition, String then, String els) {
+        return "if (" + condition + ") " + then + " else " + els;
+    }
+
+    private static String st_while(String condition, String body) {
+        return "while (" + condition + ") " + body;
+    }
+
+    private static String st_do_while(String body, String condition) {
+        return "do " + body + " while (" + condition + ");";
+    }
+
+    private static String st_for(String init, String condition, String update, String body) {
+        return "for (" + init + "; " + condition + "; " + update + ") " + body;
+    }
+
+    private static String st_s_use() {
+        return "s.length();";
+    }
+
+    private static String st_break() {
+        return "break;";
+    }
+
+    private static String st_return() {
+        return "return;";
+    }
+
+    private static String st_noop() {
+        return ";";
+    }
+
+    private static String expr_empty() {
+        return "";
+    }
+
+    private static String expr_o_match_str() {
+        return "o instanceof String s";
+    }
+
+    private static String expr_not(String expr) {
+        return "!(" + expr + ")";
+    }
+
+    @AfterMethod
+    public void dumpTemplateIfError(ITestResult result) {
+        // Make sure offending template ends up in log file on failure
+        if (!result.isSuccess()) {
+            System.err.printf("Diagnostics: %s%nTemplate: %s%n", diags.errorKeys(), sourceFiles.stream().map(p -> p.snd).collect(toList()));
+        }
+    }
+
+    private void program(String block) {
+        String s = "class C { void m(Object o) " + block + "}";
+        addSourceFile("C.java", new StringTemplate(s));
+    }
+
+    private void assertOK(String block) {
+        String sourceVersion = Integer.toString(Runtime.version().feature());
+
+        reset();
+        addCompileOptions("--enable-preview", "-source", sourceVersion);
+        program(block);
+        try {
+            compile();
+        }
+        catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        assertCompileSucceeded();
+    }
+
+    private void assertFail(String expectedDiag, String block) {
+        String sourceVersion = Integer.toString(Runtime.version().feature());
+
+        reset();
+        addCompileOptions("--enable-preview", "-source", sourceVersion);
+        program(block);
+        try {
+            compile();
+        }
+        catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        assertCompileFailed(expectedDiag);
+    }
+
+    public void testIf() {
+        assertOK(st_block(st_if(expr_o_match_str(), st_s_use(), st_return()), st_s_use()));
+        assertOK(st_block(st_if(expr_not(expr_o_match_str()), st_return(), st_s_use()), st_s_use()));
+        assertFail("compiler.err.cant.resolve.location", st_block(st_if(expr_o_match_str(), st_s_use(), st_noop()), st_s_use()));
+        assertFail("compiler.err.cant.resolve.location", st_block(st_if(expr_not(expr_o_match_str()), st_noop(), st_s_use()), st_s_use()));
+    }
+
+    public void testWhile() {
+        assertOK(st_block(st_while(expr_not(expr_o_match_str()), st_noop()), st_s_use()));
+        assertFail("compiler.err.cant.resolve.location", st_block(st_while(expr_not(expr_o_match_str()), st_break()), st_s_use()));
+    }
+
+    public void testDoWhile() {
+        assertOK(st_block(st_do_while(st_noop(), expr_not(expr_o_match_str())), st_s_use()));
+        assertFail("compiler.err.cant.resolve.location", st_block(st_do_while(st_break(), expr_not(expr_o_match_str())), st_s_use()));
+    }
+
+    public void testFor() {
+        assertOK(st_block(st_for(expr_empty(), expr_not(expr_o_match_str()), expr_empty(), st_noop()), st_s_use()));
+        assertFail("compiler.err.cant.resolve.location", st_block(st_for(expr_empty(), expr_not(expr_o_match_str()), expr_empty(), st_break()), st_s_use()));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/scope/TEST.properties	Wed Nov 27 10:21:22 2019 +0100
@@ -0,0 +1,6 @@
+TestNG.dirs = .
+
+lib.dirs = /lib/combo
+
+modules = \
+        jdk.compiler/com.sun.tools.javac.util