diff a/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad b/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad
--- a/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad
+++ b/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad
@@ -58,17 +58,21 @@
 static void write_barrier_post(MacroAssembler* masm,
                                const MachNode* node,
                                Register store_addr,
                                Register new_val,
                                Register tmp1,
-                               Register tmp2) {
+                               Register tmp2,
+                               RegSet preserve = RegSet()) {
   if (!G1PostBarrierStubC2::needs_barrier(node)) {
     return;
   }
   Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
   G1BarrierSetAssembler* g1_asm = static_cast<G1BarrierSetAssembler*>(BarrierSet::barrier_set()->barrier_set_assembler());
   G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node);
+  for (RegSetIterator<Register> reg = preserve.begin(); *reg != noreg; ++reg) {
+    stub->preserve(*reg);
+  }
   g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, r15_thread, tmp1, tmp2, stub);
 }
 
 %}
 
@@ -99,10 +103,95 @@
                        $tmp2$$Register /* tmp2 */);
   %}
   ins_pipe(ialu_mem_reg);
 %}
 
+// TODO 8350865 (same applies to g1StoreLSpecialTwoOops)
+// - Can we use an unbound register for src?
+// - Do no set/overwrite barrier data here, also handle G1C2BarrierPostNotNull
+// - Is the zero-extend really required in all the places?
+instruct g1StoreLSpecialOneOop(memory mem, rdx_RegL src, immI off, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr)
+%{
+  predicate(UseG1GC);
+  match(Set mem (StoreLSpecial mem (Binary src off)));
+  effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, USE_KILL src, KILL cr);
+  format %{ "movq    $mem, $src\t# g1StoreLSpecialOneOop" %}
+  ins_encode %{
+    ((MachNode*)this)->set_barrier_data(G1C2BarrierPre | G1C2BarrierPost);
+
+    __ lea($tmp1$$Register, $mem$$Address);
+    // Adjust address to point to narrow oop
+    __ addq($tmp1$$Register, $off$$constant);
+    write_barrier_pre(masm, this,
+                      $tmp1$$Register /* obj */,
+                      $tmp2$$Register /* pre_val */,
+                      $tmp3$$Register /* tmp */,
+                      RegSet::of($tmp1$$Register, $src$$Register) /* preserve */);
+
+    __ movq(Address($tmp1$$Register, 0), $src$$Register);
+
+    // Shift long value to extract the narrow oop field value and zero-extend it
+    __ shrq($src$$Register, $off$$constant << LogBitsPerByte);
+    __ movl($src$$Register, $src$$Register);
+
+    write_barrier_post(masm, this,
+                       $tmp1$$Register /* store_addr */,
+                       $src$$Register /* new_val */,
+                       $tmp3$$Register /* tmp1 */,
+                       $tmp2$$Register /* tmp2 */);
+  %}
+  ins_pipe(ialu_mem_reg);
+%}
+
+instruct g1StoreLSpecialTwoOops(memory mem, rdx_RegL src, rRegP tmp1, rRegP tmp2, rRegP tmp3, rRegP tmp4, rFlagsReg cr)
+%{
+  predicate(UseG1GC);
+  match(Set mem (StoreLSpecial mem src));
+  effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, KILL cr);
+  format %{ "movq    $mem, $src\t# g1StoreLSpecialTwoOops" %}
+  ins_encode %{
+    ((MachNode*)this)->set_barrier_data(G1C2BarrierPre | G1C2BarrierPost);
+
+    __ lea($tmp1$$Register, $mem$$Address);
+    write_barrier_pre(masm, this,
+                      $tmp1$$Register /* obj */,
+                      $tmp2$$Register /* pre_val */,
+                      $tmp3$$Register /* tmp */,
+                      RegSet::of($tmp1$$Register, $src$$Register) /* preserve */);
+    // Adjust address to point to the second narrow oop in the long value
+    __ addq($tmp1$$Register, 4);
+    write_barrier_pre(masm, this,
+                      $tmp1$$Register /* obj */,
+                      $tmp2$$Register /* pre_val */,
+                      $tmp3$$Register /* tmp */,
+                      RegSet::of($tmp1$$Register, $src$$Register) /* preserve */);
+    // Adjust address again to point to the first narrow oop in the long value
+    __ subq($tmp1$$Register, 4);
+
+    __ movq(Address($tmp1$$Register, 0), $src$$Register);
+
+    // Zero-extend first narrow oop to long
+    __ movl($tmp4$$Register, $src$$Register);
+
+    // Shift long value to extract the second narrow oop field value
+    __ shrq($src$$Register, 32);
+    write_barrier_post(masm, this,
+                       $tmp1$$Register /* store_addr */,
+                       $tmp4$$Register /* new_val */,
+                       $tmp3$$Register /* tmp1 */,
+                       $tmp2$$Register /* tmp2 */,
+                       RegSet::of($tmp1$$Register, $src$$Register) /* preserve */);
+    __ addq($tmp1$$Register, 4);
+    write_barrier_post(masm, this,
+                       $tmp1$$Register /* store_addr */,
+                       $src$$Register /* new_val */,
+                       $tmp3$$Register /* tmp1 */,
+                       $tmp2$$Register /* tmp2 */);
+  %}
+  ins_pipe(ialu_mem_reg);
+%}
+
 instruct g1StoreN(memory mem, rRegN src, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr)
 %{
   predicate(UseG1GC && n->as_Store()->barrier_data() != 0);
   match(Set mem (StoreN mem src));
   effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
