< prev index next >

src/hotspot/cpu/ppc/templateTable_ppc_64.cpp

Print this page
*** 1,8 ***
  /*
   * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved.
!  * Copyright (c) 2013, 2025 SAP SE. 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.
--- 1,8 ---
  /*
   * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved.
!  * Copyright (c) 2013, 2026 SAP SE. 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.

*** 100,10 ***
--- 100,11 ---
    // With sharing on, may need to test method flag.
    if (!RewriteBytecodes) return;
    Label L_patch_done;
  
    switch (new_bc) {
+     case Bytecodes::_fast_vputfield:
      case Bytecodes::_fast_aputfield:
      case Bytecodes::_fast_bputfield:
      case Bytecodes::_fast_zputfield:
      case Bytecodes::_fast_cputfield:
      case Bytecodes::_fast_dputfield:

*** 682,13 ***
    const Register Rload_addr = R3_ARG1,
                   Rarray     = R4_ARG2,
                   Rtemp      = R5_ARG3,
                   Rtemp2     = R31;
    __ index_check(Rarray, R17_tos /* index */, UseCompressedOops ? 2 : LogBytesPerWord, Rtemp, Rload_addr);
!   do_oop_load(_masm, Rload_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), R17_tos, Rtemp, Rtemp2,
!               IS_ARRAY);
!   __ verify_oop(R17_tos);
    //__ dcbt(R17_tos); // prefetch
  }
  
  void TemplateTable::baload() {
    transition(itos, itos);
--- 683,30 ---
    const Register Rload_addr = R3_ARG1,
                   Rarray     = R4_ARG2,
                   Rtemp      = R5_ARG3,
                   Rtemp2     = R31;
    __ index_check(Rarray, R17_tos /* index */, UseCompressedOops ? 2 : LogBytesPerWord, Rtemp, Rload_addr);
!   __ profile_array_type<ArrayLoadData>(Rarray, R11_scratch1, R12_scratch2);
!   if (UseArrayFlattening) {
!     Label is_flat_array, cont;
+ 
+     __ test_flat_array_oop(Rarray, Rtemp, is_flat_array);
+     do_oop_load(_masm, Rload_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), R17_tos, Rtemp, Rtemp2,
+                 IS_ARRAY);
+     __ verify_oop(R17_tos);
+     __ b(cont);
+ 
+     __ bind(is_flat_array);
+     __ call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::flat_array_load), Rarray, R17_tos);
+     __ bind(cont);
+   } else {
+     do_oop_load(_masm, Rload_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), R17_tos, Rtemp, Rtemp2,
+                 IS_ARRAY);
+     __ verify_oop(R17_tos);
+   }
+   __ profile_element_type(R17_tos, Rtemp, Rtemp2);
+ 
    //__ dcbt(R17_tos); // prefetch
  }
  
  void TemplateTable::baload() {
    transition(itos, itos);

*** 971,54 ***
  
  // Pop 3 values from the stack and...
  void TemplateTable::aastore() {
    transition(vtos, vtos);
  
!   Label Lstore_ok, Lis_null, Ldone;
!   const Register Rindex    = R3_ARG1,
!                  Rarray    = R4_ARG2,
                   Rscratch  = R11_scratch1,
                   Rscratch2 = R12_scratch2,
!                  Rarray_klass = R5_ARG3,
                   Rarray_element_klass = Rarray_klass,
!                  Rvalue_klass = R6_ARG4,
                   Rstore_addr = R31;    // Use register which survives VM call.
  
    __ ld(R17_tos, Interpreter::expr_offset_in_bytes(0), R15_esp); // Get value to store.
    __ lwz(Rindex, Interpreter::expr_offset_in_bytes(1), R15_esp); // Get index.
    __ ld(Rarray, Interpreter::expr_offset_in_bytes(2), R15_esp);  // Get array.
  
    __ verify_oop(R17_tos);
    __ index_check_without_pop(Rarray, Rindex, UseCompressedOops ? 2 : LogBytesPerWord, Rscratch, Rstore_addr);
!   // Rindex is dead!
!   Register Rscratch3 = Rindex;
  
    // Do array store check - check for null value first.
    __ cmpdi(CR0, R17_tos, 0);
    __ beq(CR0, Lis_null);
  
!   __ load_klass(Rarray_klass, Rarray);
    __ load_klass(Rvalue_klass, R17_tos);
  
    // Do fast instanceof cache test.
    __ ld(Rarray_element_klass, in_bytes(ObjArrayKlass::element_klass_offset()), Rarray_klass);
  
    // Generate a fast subtype check. Branch to store_ok if no failure. Throw if failure.
!   __ gen_subtype_check(Rvalue_klass /*subklass*/, Rarray_element_klass /*superklass*/, Rscratch, Rscratch2, Rscratch3, Lstore_ok);
  
    // Fell through: subtype check failed => throw an exception.
    __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ArrayStoreException_entry);
    __ mtctr(R11_scratch1);
    __ bctr();
  
    __ bind(Lis_null);
    do_oop_store(_masm, Rstore_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), noreg /* 0 */,
                 Rscratch, Rscratch2, Rscratch3, IS_ARRAY);
-   __ profile_null_seen(Rscratch, Rscratch2);
    __ b(Ldone);
  
    // Store is OK.
    __ bind(Lstore_ok);
    do_oop_store(_masm, Rstore_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), R17_tos /* value */,
                 Rscratch, Rscratch2, Rscratch3, IS_ARRAY | IS_NOT_NULL);
  
    __ bind(Ldone);
--- 989,84 ---
  
  // Pop 3 values from the stack and...
  void TemplateTable::aastore() {
    transition(vtos, vtos);
  
!   Label Lstore_ok, Lis_null, Lis_flat_array, Lwrite_null_to_null_free_array, Ldone;
!   const Register Rindex    = R6_ARG4,
!                  Rarray    = R5_ARG3,
                   Rscratch  = R11_scratch1,
                   Rscratch2 = R12_scratch2,
!                  Rarray_klass = R4_ARG2,
                   Rarray_element_klass = Rarray_klass,
!                  Rvalue_klass = R3_ARG1,
                   Rstore_addr = R31;    // Use register which survives VM call.
  
    __ ld(R17_tos, Interpreter::expr_offset_in_bytes(0), R15_esp); // Get value to store.
    __ lwz(Rindex, Interpreter::expr_offset_in_bytes(1), R15_esp); // Get index.
    __ ld(Rarray, Interpreter::expr_offset_in_bytes(2), R15_esp);  // Get array.
  
    __ verify_oop(R17_tos);
    __ index_check_without_pop(Rarray, Rindex, UseCompressedOops ? 2 : LogBytesPerWord, Rscratch, Rstore_addr);
! 
!   __ profile_array_type<ArrayStoreData>(Rarray, Rscratch, Rscratch2);
+   __ profile_multiple_element_types(R17_tos, Rscratch, Rscratch2, /* temp */ Rarray_klass);
+ 
+   if (UseArrayFlattening) {
+     __ load_klass(Rarray_klass, Rarray);
+     __ lwz(Rscratch, in_bytes(Klass::layout_helper_offset()), Rarray_klass);
+     __ test_flat_array_layout(Rscratch, Lis_flat_array);
+   }
  
    // Do array store check - check for null value first.
    __ cmpdi(CR0, R17_tos, 0);
    __ beq(CR0, Lis_null);
  
!   // Rindex is dead!
+   Register Rscratch3 = Rindex;
+ 
+   if (!UseArrayFlattening) {
+     __ load_klass(Rarray_klass, Rarray); // haven't done this above
+   }
    __ load_klass(Rvalue_klass, R17_tos);
  
    // Do fast instanceof cache test.
    __ ld(Rarray_element_klass, in_bytes(ObjArrayKlass::element_klass_offset()), Rarray_klass);
  
    // Generate a fast subtype check. Branch to store_ok if no failure. Throw if failure.
!   __ gen_subtype_check(Rvalue_klass /*subklass*/, Rarray_element_klass /*superklass*/,
+                        Rscratch, Rscratch2, Rscratch3, Lstore_ok, false);
  
    // Fell through: subtype check failed => throw an exception.
    __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ArrayStoreException_entry);
    __ mtctr(R11_scratch1);
    __ bctr();
  
+   if (UseArrayFlattening) {
+     __ bind(Lis_flat_array); // Store non-null value to flat
+     __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::flat_array_store), R17_tos, Rarray, Rindex);
+     __ b(Ldone);
+   }
+ 
    __ bind(Lis_null);
+   if (Arguments::is_valhalla_enabled()) {
+     // No way to store null in null-free array
+     __ test_null_free_array_oop(Rarray, Rscratch, Lwrite_null_to_null_free_array);
+   }
    do_oop_store(_masm, Rstore_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), noreg /* 0 */,
                 Rscratch, Rscratch2, Rscratch3, IS_ARRAY);
    __ b(Ldone);
  
+   if (Arguments::is_valhalla_enabled()) {
+     __ bind(Lwrite_null_to_null_free_array);
+     __ load_dispatch_table(Rscratch, (address*)Interpreter::_throw_NullPointerException_entry);
+     __ mtctr(Rscratch);
+     __ bctr();
+   }
+ 
    // Store is OK.
+   __ align(32, 12);
    __ bind(Lstore_ok);
    do_oop_store(_masm, Rstore_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), R17_tos /* value */,
                 Rscratch, Rscratch2, Rscratch3, IS_ARRAY | IS_NOT_NULL);
  
    __ bind(Ldone);

*** 1751,23 ***
    __ dispatch_next(vtos, 0, true);
  }
  
  // Helper function for if_cmp* methods below.
  // Factored out common compare and branch code.
! void TemplateTable::if_cmp_common(Register Rfirst, Register Rsecond, Register Rscratch1, Register Rscratch2, Condition cc, bool is_jint, bool cmp0) {
    Label Lnot_taken;
    // Note: The condition code we get is the condition under which we
    // *fall through*! So we have to inverse the CC here.
  
    if (is_jint) {
!     if (cmp0) {
        __ cmpwi(CR0, Rfirst, 0);
      } else {
        __ cmpw(CR0, Rfirst, Rsecond);
      }
    } else {
!     if (cmp0) {
        __ cmpdi(CR0, Rfirst, 0);
      } else {
        __ cmpd(CR0, Rfirst, Rsecond);
      }
    }
--- 1799,23 ---
    __ dispatch_next(vtos, 0, true);
  }
  
  // Helper function for if_cmp* methods below.
  // Factored out common compare and branch code.
! void TemplateTable::if_cmp_common(Register Rfirst, Register Rsecond, Register Rscratch1, Register Rscratch2, Condition cc, bool is_jint, bool is_acmp) {
    Label Lnot_taken;
    // Note: The condition code we get is the condition under which we
    // *fall through*! So we have to inverse the CC here.
  
    if (is_jint) {
!     if (Rsecond == noreg) {
        __ cmpwi(CR0, Rfirst, 0);
      } else {
        __ cmpw(CR0, Rfirst, Rsecond);
      }
    } else {
!     if (Rsecond == noreg) {
        __ cmpdi(CR0, Rfirst, 0);
      } else {
        __ cmpd(CR0, Rfirst, Rsecond);
      }
    }

*** 1777,18 ***
    branch(false, false);
  
    // Condition is not true => Continue.
    __ align(32, 12);
    __ bind(Lnot_taken);
!   __ profile_not_taken_branch(Rscratch1, Rscratch2);
  }
  
  // Compare integer values with zero and fall through if CC holds, branch away otherwise.
  void TemplateTable::if_0cmp(Condition cc) {
    transition(itos, vtos);
  
!   if_cmp_common(R17_tos, noreg, R11_scratch1, R12_scratch2, cc, true, true);
  }
  
  // Compare integer values and fall through if CC holds, branch away otherwise.
  //
  // Interface:
--- 1825,18 ---
    branch(false, false);
  
    // Condition is not true => Continue.
    __ align(32, 12);
    __ bind(Lnot_taken);
!   __ profile_not_taken_branch(Rscratch1, Rscratch2, is_acmp);
  }
  
  // Compare integer values with zero and fall through if CC holds, branch away otherwise.
  void TemplateTable::if_0cmp(Condition cc) {
    transition(itos, vtos);
  
!   if_cmp_common(R17_tos, noreg, R11_scratch1, R12_scratch2, cc, true);
  }
  
  // Compare integer values and fall through if CC holds, branch away otherwise.
  //
  // Interface:

*** 1799,27 ***
  
    const Register Rfirst  = R0,
                   Rsecond = R17_tos;
  
    __ pop_i(Rfirst);
!   if_cmp_common(Rfirst, Rsecond, R11_scratch1, R12_scratch2, cc, true, false);
  }
  
  void TemplateTable::if_nullcmp(Condition cc) {
    transition(atos, vtos);
  
!   if_cmp_common(R17_tos, noreg, R11_scratch1, R12_scratch2, cc, false, true);
  }
  
  void TemplateTable::if_acmp(Condition cc) {
    transition(atos, vtos);
  
!   const Register Rfirst  = R0,
                   Rsecond = R17_tos;
  
    __ pop_ptr(Rfirst);
!   if_cmp_common(Rfirst, Rsecond, R11_scratch1, R12_scratch2, cc, false, false);
  }
  
  void TemplateTable::ret() {
    locals_index(R11_scratch1);
    __ load_local_ptr(R17_tos, R11_scratch1, R11_scratch1);
--- 1847,83 ---
  
    const Register Rfirst  = R0,
                   Rsecond = R17_tos;
  
    __ pop_i(Rfirst);
!   if_cmp_common(Rfirst, Rsecond, R11_scratch1, R12_scratch2, cc, true);
  }
  
  void TemplateTable::if_nullcmp(Condition cc) {
    transition(atos, vtos);
  
!   if_cmp_common(R17_tos, noreg, R11_scratch1, R12_scratch2, cc, false);
  }
  
  void TemplateTable::if_acmp(Condition cc) {
    transition(atos, vtos);
  
!   const Register Rfirst  = R31,
                   Rsecond = R17_tos;
  
    __ pop_ptr(Rfirst);
! 
+   __ profile_acmp(Rsecond, Rfirst, R11_scratch1, R12_scratch2);
+ 
+   const int is_inline_type_mask = markWord::inline_type_pattern;
+   if (Arguments::is_valhalla_enabled()) {
+     Label taken, not_taken;
+     __ cmpd(CR0, Rfirst, Rsecond);
+     __ beq(CR0, (cc == equal) ? taken : not_taken);
+ 
+     // test if any input is null
+     __ cmpdi(CR0, Rfirst, 0);
+     __ cmpdi(CR1, Rsecond, 0);
+     __ cror(CR0, Assembler::equal, CR1, Assembler::equal);
+     __ beq(CR0, (cc == equal) ? not_taken : taken);
+ 
+     // and both are values ?
+     __ ld(R11_scratch1, oopDesc::mark_offset_in_bytes(), Rfirst);
+     __ ld(R12_scratch2, oopDesc::mark_offset_in_bytes(), Rsecond);
+     __ andr(R11_scratch1, R11_scratch1, R12_scratch2);
+     __ andi(R11_scratch1, R11_scratch1, is_inline_type_mask);
+     __ cmpdi(CR0, R11_scratch1, is_inline_type_mask);
+     __ bne(CR0, (cc == equal) ? not_taken : taken);
+ 
+     // same value klass ?
+     __ load_metadata(R11_scratch1, Rfirst);
+     __ load_metadata(R12_scratch2, Rsecond);
+     __ cmpd(CR0, R11_scratch1, R12_scratch2);
+     __ bne(CR0, (cc == equal) ? not_taken : taken);
+ 
+     // Know both are the same type, let's test for substitutability...
+     if (cc == equal) {
+       invoke_is_substitutable(Rfirst, Rsecond, taken, not_taken);
+     } else {
+       invoke_is_substitutable(Rfirst, Rsecond, not_taken, taken);
+     }
+     DEBUG_ONLY( __ stop("Not reachable"); )
+ 
+     // Conition is false => Jump!
+     __ align(32, 12);
+     __ bind(taken);
+     branch(false, false);
+ 
+     // Condition is not true => Continue.
+     __ align(32, 12);
+     __ bind(not_taken);
+     __ profile_not_taken_branch(R11_scratch1, R12_scratch2, true);
+ 
+   } else {
+     if_cmp_common(Rfirst, Rsecond, R11_scratch1, R12_scratch2, cc, false, true);
+   }
+ }
+ 
+ void TemplateTable::invoke_is_substitutable(Register aobj, Register bobj, Label& is_subst, Label& not_subst) {
+   __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::is_substitutable), aobj, bobj);
+   __ cmpwi(CR0, R3_RET, 0);
+   __ beq(CR0, not_subst);
+   __ b(is_subst);
  }
  
  void TemplateTable::ret() {
    locals_index(R11_scratch1);
    __ load_local_ptr(R17_tos, R11_scratch1, R11_scratch1);

*** 2735,16 ***
    __ align(32, 28, 28); // Align load.
    // __ bind(Latos);
    __ fence(); // Volatile entry point (one instruction before non-volatile_entry point).
    assert(branch_table[atos] == nullptr, "can't compute twice");
    branch_table[atos] = __ pc(); // non-volatile_entry point
!   do_oop_load(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, /* nv temp */ Rflags, IN_HEAP);
!   __ verify_oop(R17_tos);
!   __ push(atos);
!   //__ dcbt(R17_tos); // prefetch
!   if (!is_static && rc == may_rewrite) {
!     patch_bytecode(Bytecodes::_fast_agetfield, Rbc, Rscratch);
    }
    __ beq(CR2, Lacquire); // Volatile?
    __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
  
    __ align(32, 12);
--- 2839,45 ---
    __ align(32, 28, 28); // Align load.
    // __ bind(Latos);
    __ fence(); // Volatile entry point (one instruction before non-volatile_entry point).
    assert(branch_table[atos] == nullptr, "can't compute twice");
    branch_table[atos] = __ pc(); // non-volatile_entry point
!   if (!Arguments::is_valhalla_enabled()) {
!     do_oop_load(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, /* nv temp */ Rflags, IN_HEAP);
!     __ verify_oop(R17_tos);
!     __ push(atos);
!     //__ dcbt(R17_tos); // prefetch
!     if (!is_static && rc == may_rewrite) {
+       patch_bytecode(Bytecodes::_fast_agetfield, Rbc, Rscratch);
+     }
+   } else { // Valhalla
+     if (is_static) {
+       do_oop_load(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, /* nv temp */ Rflags, IN_HEAP);
+       __ verify_oop(R17_tos);
+       __ push(atos);
+     } else {
+       Label is_flat;
+       __ test_field_is_flat(Rflags, is_flat);
+       do_oop_load(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, /* nv temp */ Rflags, IN_HEAP);
+       __ verify_oop(R17_tos);
+       __ push(atos);
+       if (rc == may_rewrite) {
+         patch_bytecode(Bytecodes::_fast_agetfield, Rbc, Rscratch);
+       }
+       __ beq(CR2, Lacquire); // Volatile?
+       __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+ 
+       __ bind(is_flat);
+       // field is flat (null-free or nullable with a null-marker)
+       __ mr(R17_tos, Rclass_or_obj);
+       __ read_flat_field(Rcache, R17_tos);
+       __ verify_oop(R17_tos);
+       __ push(atos);
+       if (rc == may_rewrite) {
+         patch_bytecode(Bytecodes::_fast_vgetfield, Rbc, Rscratch);
+       }
+     }
    }
    __ beq(CR2, Lacquire); // Volatile?
    __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
  
    __ align(32, 12);

*** 2776,11 ***
  
  // The registers cache and index expected to be set before call.
  // The function may destroy various registers, just not the cache and index registers.
  void TemplateTable::jvmti_post_field_mod(Register Rcache, Register Rscratch, bool is_static) {
  
!   assert_different_registers(Rcache, Rscratch, R6_ARG4);
  
    if (JvmtiExport::can_post_field_modification()) {
      Label Lno_field_mod_post;
  
      // Check if post field access in enabled.
--- 2909,11 ---
  
  // The registers cache and index expected to be set before call.
  // The function may destroy various registers, just not the cache and index registers.
  void TemplateTable::jvmti_post_field_mod(Register Rcache, Register Rscratch, bool is_static) {
  
!   assert_different_registers(Rcache, Rscratch);
  
    if (JvmtiExport::can_post_field_modification()) {
      Label Lno_field_mod_post;
  
      // Check if post field access in enabled.

*** 2799,10 ***
--- 2932,11 ---
      } else {
        // In case of the fast versions, value lives in registers => put it back on tos.
        int offs = Interpreter::expr_offset_in_bytes(0);
        Register base = R15_esp;
        switch(bytecode()) {
+         case Bytecodes::_fast_vputfield: // fall through
          case Bytecodes::_fast_aputfield: __ push_ptr(); offs+= Interpreter::stackElementSize; break;
          case Bytecodes::_fast_iputfield: // Fall through
          case Bytecodes::_fast_bputfield: // Fall through
          case Bytecodes::_fast_zputfield: // Fall through
          case Bytecodes::_fast_cputfield: // Fall through

*** 2833,16 ***
        }
        __ ld(Robj, offs, base);
        __ verify_oop(Robj);
      }
  
!     __ addi(R6_ARG4, R15_esp, Interpreter::expr_offset_in_bytes(0));
!     __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), Robj, Rcache, R6_ARG4);
      __ load_field_entry(Rcache, Rscratch);
  
      // In case of the fast versions, value lives in registers => put it back on tos.
      switch(bytecode()) {
        case Bytecodes::_fast_aputfield: __ pop_ptr(); break;
        case Bytecodes::_fast_iputfield: // Fall through
        case Bytecodes::_fast_bputfield: // Fall through
        case Bytecodes::_fast_zputfield: // Fall through
        case Bytecodes::_fast_cputfield: // Fall through
--- 2967,21 ---
        }
        __ ld(Robj, offs, base);
        __ verify_oop(Robj);
      }
  
!     // Pass arguments without register clashes (R16_thread passed by call_VM)
!     __ mr_if_needed(R4_ARG2, Robj);
+     assert(Rcache != R4_ARG2, "smashed argument");
+     __ mr_if_needed(R5_ARG3, Rcache);
+     __ addi(R6_ARG4, R15_esp, Interpreter::expr_offset_in_bytes(0)); // set R6_ARG4 last (may use same reg as other args)
+     __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification));
      __ load_field_entry(Rcache, Rscratch);
  
      // In case of the fast versions, value lives in registers => put it back on tos.
      switch(bytecode()) {
+       case Bytecodes::_fast_vputfield: // fall through
        case Bytecodes::_fast_aputfield: __ pop_ptr(); break;
        case Bytecodes::_fast_iputfield: // Fall through
        case Bytecodes::_fast_bputfield: // Fall through
        case Bytecodes::_fast_zputfield: // Fall through
        case Bytecodes::_fast_cputfield: // Fall through

*** 2860,19 ***
  
  // PPC64: implement volatile stores as release-store (return bytecode contains an additional release).
  void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteControl rc) {
    Label Lvolatile;
  
!   const Register Rcache        = R5_ARG3,  // Do not use ARG1/2 (causes trouble in jvmti_post_field_mod).
                   Rclass_or_obj = R31,      // Needs to survive C call.
                   Roffset       = R22_tmp2, // Needs to survive C call.
                   Rtos_state    = R23_tmp3, // Needs to survive C call.
                   Rflags        = R30,      // Needs to survive C call.
                   Rbtable       = R4_ARG2,
                   Rscratch      = R11_scratch1, // used by load_field_cp_cache_entry
                   Rscratch2     = R12_scratch2, // used by load_field_cp_cache_entry
!                  Rscratch3     = R6_ARG4,
                   Rbc           = Rscratch3;
    const ConditionRegister CR_is_vol = CR2; // Non-volatile condition register (survives runtime call in do_oop_store).
  
    static address field_rw_branch_table[number_of_states],
                   field_norw_branch_table[number_of_states],
--- 2999,19 ---
  
  // PPC64: implement volatile stores as release-store (return bytecode contains an additional release).
  void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteControl rc) {
    Label Lvolatile;
  
!   const Register Rcache        = R6_ARG4,  // Do not use ARG1-3 (causes trouble in jvmti_post_field_mod or write_flat_field).
                   Rclass_or_obj = R31,      // Needs to survive C call.
                   Roffset       = R22_tmp2, // Needs to survive C call.
                   Rtos_state    = R23_tmp3, // Needs to survive C call.
                   Rflags        = R30,      // Needs to survive C call.
                   Rbtable       = R4_ARG2,
                   Rscratch      = R11_scratch1, // used by load_field_cp_cache_entry
                   Rscratch2     = R12_scratch2, // used by load_field_cp_cache_entry
!                  Rscratch3     = R10_ARG8,
                   Rbc           = Rscratch3;
    const ConditionRegister CR_is_vol = CR2; // Non-volatile condition register (survives runtime call in do_oop_store).
  
    static address field_rw_branch_table[number_of_states],
                   field_norw_branch_table[number_of_states],

*** 3062,15 ***
    // __ bind(Latos);
    __ release(); // Volatile entry point (one instruction before non-volatile_entry point).
    assert(branch_table[atos] == nullptr, "can't compute twice");
    branch_table[atos] = __ pc(); // non-volatile_entry point
    __ pop(atos);
!   if (!is_static) { pop_and_check_object(Rclass_or_obj); } // kills R11_scratch1
!   do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, IN_HEAP);
!   if (!is_static && rc == may_rewrite) {
!     patch_bytecode(Bytecodes::_fast_aputfield, Rbc, Rscratch, true, byte_no);
!   }
    if (!support_IRIW_for_not_multiple_copy_atomic_cpu) {
      __ beq(CR_is_vol, Lvolatile); // Volatile?
      __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
  
      __ align(32, 12);
--- 3201,56 ---
    // __ bind(Latos);
    __ release(); // Volatile entry point (one instruction before non-volatile_entry point).
    assert(branch_table[atos] == nullptr, "can't compute twice");
    branch_table[atos] = __ pc(); // non-volatile_entry point
    __ pop(atos);
!   if (!Arguments::is_valhalla_enabled()) {
!     if (!is_static) { pop_and_check_object(Rclass_or_obj); } // kills R11_scratch1
!     do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, IN_HEAP);
!     if (!is_static && rc == may_rewrite) {
!       patch_bytecode(Bytecodes::_fast_aputfield, Rbc, Rscratch, true, byte_no);
+     }
+   } else { // Valhalla
+     if (is_static) {
+       Label is_nullable;
+       __ test_field_is_not_null_free_inline_type(Rflags, is_nullable);
+       __ null_check_throw(R17_tos, -1, Rscratch);
+       __ align(32, 12);
+       __ bind(is_nullable);
+       do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, IN_HEAP);
+     } else {
+       Label null_free_reference, is_flat, rewrite_inline;
+       __ test_field_is_flat(Rflags, is_flat);
+       __ test_field_is_null_free_inline_type(Rflags, null_free_reference);
+       pop_and_check_object(Rclass_or_obj);
+       // Store into the field
+       do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, IN_HEAP);
+       if (rc == may_rewrite) {
+         patch_bytecode(Bytecodes::_fast_aputfield, Rbc, Rscratch, true, byte_no);
+       }
+       if (!support_IRIW_for_not_multiple_copy_atomic_cpu) {
+         __ beq(CR_is_vol, Lvolatile); // Volatile?
+       }
+       __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+ 
+       // Implementation of the inline type semantic
+       __ bind(null_free_reference);
+       __ null_check_throw(R17_tos, -1, Rscratch);
+       pop_and_check_object(Rclass_or_obj);
+       // Store into the field
+       do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, IN_HEAP);
+       __ b(rewrite_inline);
+ 
+       __ bind(is_flat);
+       pop_and_check_object(Rclass_or_obj);
+       __ write_flat_field(Rcache, Rscratch, Rscratch2, Rclass_or_obj, Roffset, R17_tos);
+       __ bind(rewrite_inline);
+       if (rc == may_rewrite) {
+         patch_bytecode(Bytecodes::_fast_vputfield, Rbc, Rscratch, true, byte_no);
+       }
+     }
+   } // Valhalla
    if (!support_IRIW_for_not_multiple_copy_atomic_cpu) {
      __ beq(CR_is_vol, Lvolatile); // Volatile?
      __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
  
      __ align(32, 12);

*** 3106,11 ***
  }
  
  void TemplateTable::fast_storefield(TosState state) {
    transition(state, vtos);
  
!   const Register Rcache        = R5_ARG3,  // Do not use ARG1/2 (causes trouble in jvmti_post_field_mod).
                   Rclass_or_obj = R31,      // Needs to survive C call.
                   Roffset       = R22_tmp2, // Needs to survive C call.
                   Rflags        = R3_ARG1,
                   Rscratch      = R11_scratch1, // used by load_field_cp_cache_entry
                   Rscratch2     = R12_scratch2, // used by load_field_cp_cache_entry
--- 3286,11 ---
  }
  
  void TemplateTable::fast_storefield(TosState state) {
    transition(state, vtos);
  
!   const Register Rcache        = R6_ARG4,  // Do not use ARG1-3 (causes trouble in jvmti_post_field_mod or write_flat_field).
                   Rclass_or_obj = R31,      // Needs to survive C call.
                   Roffset       = R22_tmp2, // Needs to survive C call.
                   Rflags        = R3_ARG1,
                   Rscratch      = R11_scratch1, // used by load_field_cp_cache_entry
                   Rscratch2     = R12_scratch2, // used by load_field_cp_cache_entry

*** 3136,10 ***
--- 3316,23 ---
      __ bind(LnotVolatile);
    }
  
    // Do the store and fencing.
    switch(bytecode()) {
+     case Bytecodes::_fast_vputfield:
+     {
+       Label is_flat, done;
+       __ test_field_is_flat(Rflags, is_flat);
+       __ null_check_throw(Rclass_or_obj, -1, Rscratch);
+       do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, IN_HEAP);
+       __ b(done);
+       __ bind(is_flat);
+       __ write_flat_field(Rcache, Rscratch, Rscratch2, Rclass_or_obj, Roffset, R17_tos);
+       __ bind(done);
+       break;
+     }
+ 
      case Bytecodes::_fast_aputfield:
        // Store into the field.
        do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, IN_HEAP);
        break;
  

*** 3211,10 ***
--- 3404,24 ---
    // Get volatile flag.
    __ rldicl_(Rscratch, Rflags, 64-ResolvedFieldEntry::is_volatile_shift, 63); // Extract volatile bit.
    __ bne(CR0, LisVolatile);
  
    switch(bytecode()) {
+     case Bytecodes::_fast_vgetfield:
+     {
+       // field is flat
+       __ read_flat_field(Rcache, R17_tos);
+       __ verify_oop(R17_tos);
+       __ dispatch_epilog(state, Bytecodes::length_for(bytecode()));
+ 
+       __ bind(LisVolatile);
+       if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); }
+       __ read_flat_field(Rcache, R17_tos);
+       __ verify_oop(R17_tos);
+       // memory barrier in read_flat_field
+       break;
+     }
      case Bytecodes::_fast_agetfield:
      {
        do_oop_load(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, /* nv temp */ Rflags, IN_HEAP);
        __ verify_oop(R17_tos);
        __ dispatch_epilog(state, Bytecodes::length_for(bytecode()));

*** 3840,16 ***
      }
  
      // --------------------------------------------------------------------------
      // Init2: Initialize the header: mark, klass
      // Init mark.
!     if (UseCompactObjectHeaders) {
        __ ld(Rscratch, in_bytes(Klass::prototype_header_offset()), RinstanceKlass);
-       __ std(Rscratch, oopDesc::mark_offset_in_bytes(), RallocatedObject);
      } else {
        __ load_const_optimized(Rscratch, markWord::prototype().value(), R0);
!       __ std(Rscratch, oopDesc::mark_offset_in_bytes(), RallocatedObject);
        __ store_klass_gap(RallocatedObject);
        __ store_klass(RallocatedObject, RinstanceKlass, Rscratch);
      }
  
      __ b(Ldone);
--- 4047,18 ---
      }
  
      // --------------------------------------------------------------------------
      // Init2: Initialize the header: mark, klass
      // Init mark.
!     if (UseCompactObjectHeaders || Arguments::is_valhalla_enabled()) {
        __ ld(Rscratch, in_bytes(Klass::prototype_header_offset()), RinstanceKlass);
      } else {
        __ load_const_optimized(Rscratch, markWord::prototype().value(), R0);
!     }
+     __ std(Rscratch, oopDesc::mark_offset_in_bytes(), RallocatedObject);
+ 
+     if (!UseCompactObjectHeaders) {
        __ store_klass_gap(RallocatedObject);
        __ store_klass(RallocatedObject, RinstanceKlass, Rscratch);
      }
  
      __ b(Ldone);

*** 4108,10 ***
--- 4317,14 ---
  
    // ------------------------------------------------------------------------------
    // Null pointer exception.
    __ null_check_throw(Robj_to_lock, -1, Rscratch1);
  
+   Label is_inline_type;
+   __ ld(Rscratch1, oopDesc::mark_offset_in_bytes(), Robj_to_lock);
+   __ test_markword_is_inline_type(Rscratch1, is_inline_type);
+ 
    // Check if any slot is present => short cut to allocation if not.
    __ cmpld(CR0, Rcurrent_monitor, Rbot);
    __ beq(CR0, Lallocate_new);
  
    // ------------------------------------------------------------------------------

*** 4164,10 ***
--- 4377,15 ---
    // This emits a single store.
    __ generate_stack_overflow_check(0);
  
    // The bcp has already been incremented. Just need to dispatch to next instruction.
    __ dispatch_next(vtos);
+ 
+   __ bind(is_inline_type);
+   __ call_VM(noreg, CAST_FROM_FN_PTR(address,
+                     InterpreterRuntime::throw_identity_exception), Robj_to_lock);
+   __ should_not_reach_here();
  }
  
  void TemplateTable::monitorexit() {
    transition(atos, vtos);
    __ verify_oop(R17_tos);

*** 4187,10 ***
--- 4405,16 ---
    __ addi(Rbot, Rscratch, -frame::ijava_state_size);
  
    // Null pointer check.
    __ null_check_throw(Robj_to_lock, -1, Rscratch);
  
+   const int is_inline_type_mask = markWord::inline_type_pattern;
+   __ ld(Rscratch, oopDesc::mark_offset_in_bytes(), Robj_to_lock);
+   __ andi(Rscratch, Rscratch, is_inline_type_mask);
+   __ cmpwi(CR0, Rscratch, is_inline_type_mask);
+   __ beq(CR0, Lillegal_monitor_state);
+ 
    // Check corner case: unbalanced monitorEnter / Exit.
    __ cmpld(CR0, Rcurrent_monitor, Rbot);
    __ beq(CR0, Lillegal_monitor_state);
  
    // Find the corresponding slot in the monitors stack section.
< prev index next >