11/*
2- * Copyright (c) 1999, 2025 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 1999, 2026 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
2626#include " c1/c1_CFGPrinter.hpp"
2727#include " c1/c1_Compilation.hpp"
2828#include " c1/c1_GraphBuilder.hpp"
29+ #include " c1/c1_Instruction.hpp"
2930#include " c1/c1_InstructionPrinter.hpp"
31+ #include " c1/c1_ValueType.hpp"
3032#include " ci/ciCallSite.hpp"
3133#include " ci/ciField.hpp"
3234#include " ci/ciFlatArrayKlass.hpp"
@@ -1983,28 +1985,28 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
19831985 // Flat field
19841986 assert (!needs_patching, " Can't patch flat inline type field access" );
19851987 ciInlineKlass* inline_klass = field->type ()->as_inline_klass ();
1986- bool is_naturally_atomic = inline_klass->nof_declared_nonstatic_fields () <= 1 ;
1987- bool needs_atomic_access = !field->is_null_free () || (field->is_volatile () && !is_naturally_atomic);
1988- if (needs_atomic_access) {
1988+ if (field->is_atomic ()) {
19891989 assert (!has_pending_field_access (), " Pending field accesses are not supported" );
19901990 LoadField* load = new LoadField (obj, offset, field, false , state_before, needs_patching);
19911991 push (type, append (load));
19921992 } else {
1993- assert (field->is_null_free (), " must be null-free" );
19941993 // Look at the next bytecode to check if we can delay the field access
19951994 bool can_delay_access = false ;
1996- ciBytecodeStream s (method ());
1997- s.force_bci (bci ());
1998- s.next ();
1999- if (s.cur_bc () == Bytecodes::_getfield && !needs_patching) {
2000- ciField* next_field = s.get_field (will_link);
2001- bool next_needs_patching = !next_field->holder ()->is_loaded () ||
2002- !next_field->will_link (method (), Bytecodes::_getfield) ||
2003- PatchALot;
2004- // We can't update the offset for atomic accesses
2005- bool next_needs_atomic_access = !next_field->is_null_free () || next_field->is_volatile ();
2006- can_delay_access = C1UseDelayedFlattenedFieldReads && !next_needs_patching && !next_needs_atomic_access;
1995+ if (field->is_null_free ()) {
1996+ ciBytecodeStream s (method ());
1997+ s.force_bci (bci ());
1998+ s.next ();
1999+ if (s.cur_bc () == Bytecodes::_getfield && !needs_patching) {
2000+ ciField* next_field = s.get_field (will_link);
2001+ bool next_needs_patching = !next_field->holder ()->is_loaded () ||
2002+ !next_field->will_link (method (), Bytecodes::_getfield) ||
2003+ PatchALot;
2004+ // We can't update the offset for atomic accesses
2005+ bool next_needs_atomic_access = next_field->is_flat () && next_field->is_atomic ();
2006+ can_delay_access = C1UseDelayedFlattenedFieldReads && !next_needs_patching && !next_needs_atomic_access && next_field->is_null_free ();
2007+ }
20072008 }
2009+
20082010 if (can_delay_access) {
20092011 if (has_pending_load_indexed ()) {
20102012 pending_load_indexed ()->update (field, offset - field->holder ()->as_inline_klass ()->payload_offset ());
@@ -2018,8 +2020,8 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
20182020 } else {
20192021 scope ()->set_wrote_final ();
20202022 scope ()->set_wrote_fields ();
2021- bool need_membar = false ;
20222023 if (has_pending_load_indexed ()) {
2024+ assert (field->is_null_free (), " nullable fields do not support delayed accesses yet" );
20232025 assert (!needs_patching, " Can't patch delayed field access" );
20242026 pending_load_indexed ()->update (field, offset - field->holder ()->as_inline_klass ()->payload_offset ());
20252027 NewInstance* vt = new NewInstance (inline_klass, pending_load_indexed ()->state_before (), false , true );
@@ -2028,34 +2030,49 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
20282030 apush (append_split (vt));
20292031 append (pending_load_indexed ()->load_instr ());
20302032 set_pending_load_indexed (nullptr );
2031- need_membar = true ;
2033+ } else if (has_pending_field_access ()) {
2034+ assert (field->is_null_free (), " nullable fields do not support delayed accesses yet" );
2035+ state_before = pending_field_access ()->state_before ();
2036+ NewInstance* new_instance = new NewInstance (inline_klass, state_before, false , true );
2037+ _memory->new_instance (new_instance);
2038+ apush (append_split (new_instance));
2039+ copy_inline_content (inline_klass, pending_field_access ()->obj (),
2040+ pending_field_access ()->offset () + field->offset_in_bytes () - field->holder ()->as_inline_klass ()->payload_offset (),
2041+ new_instance, inline_klass->payload_offset (), state_before);
2042+ set_pending_field_access (nullptr );
20322043 } else {
2033- if (has_pending_field_access ()) {
2034- state_before = pending_field_access ()->state_before ();
2044+ if (!field->is_null_free () && !inline_klass->is_initialized ()) {
2045+ // Cannot allocate an instance of inline_klass because it may have not been
2046+ // initialized, bailout for now
2047+ bailout (" load from an uninitialized nullable non-atomic flat field" );
2048+ return ;
20352049 }
2050+
20362051 NewInstance* new_instance = new NewInstance (inline_klass, state_before, false , true );
20372052 _memory->new_instance (new_instance);
2038- apush (append_split (new_instance));
2039- if (has_pending_field_access ()) {
2040- copy_inline_content (inline_klass, pending_field_access ()->obj (),
2041- pending_field_access ()->offset () + field->offset_in_bytes () - field->holder ()->as_inline_klass ()->payload_offset (),
2042- new_instance, inline_klass->payload_offset (), state_before);
2043- set_pending_field_access (nullptr );
2044- } else {
2045- if (field->type ()->as_instance_klass ()->is_initialized () && field->type ()->as_inline_klass ()->is_empty ()) {
2046- // Needs an explicit null check because below code does not perform any actual load if there are no fields
2047- null_check (obj);
2048- }
2049- copy_inline_content (inline_klass, obj, field->offset_in_bytes (), new_instance, inline_klass->payload_offset (), state_before);
2053+ append_split (new_instance);
2054+
2055+ if (inline_klass->is_initialized () && inline_klass->is_empty ()) {
2056+ // Needs an explicit null check because below code does not perform any actual load if there are no fields
2057+ null_check (obj);
20502058 }
2051- need_membar = true ;
2052- }
2053- if (need_membar) {
2054- // If we allocated a new instance ensure the stores to copy the
2055- // field contents are visible before any subsequent store that
2056- // publishes this reference.
2057- append (new MemBar (lir_membar_storestore));
2059+ copy_inline_content (inline_klass, obj, field->offset_in_bytes (), new_instance, inline_klass->payload_offset (), state_before);
2060+
2061+ Instruction* result = new_instance;
2062+ if (!field->is_null_free ()) {
2063+ Value int_zero = append (new Constant (intZero));
2064+ Value object_null = append (new Constant (objectNull));
2065+ Value nm_offset = append (new Constant (new LongConstant (offset + inline_klass->null_marker_offset_in_payload ())));
2066+ Value nm = append (new UnsafeGet (T_BOOLEAN, obj, nm_offset, false ));
2067+ result = append (new IfOp (nm, Instruction::neq, int_zero, new_instance, object_null, state_before, false ));
2068+ }
2069+ apush (result);
20582070 }
2071+
2072+ // If we allocated a new instance ensure the stores to copy the
2073+ // field contents are visible before any subsequent store that
2074+ // publishes this reference.
2075+ append (new MemBar (lir_membar_storestore));
20592076 }
20602077 }
20612078 }
@@ -2090,16 +2107,33 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
20902107 // Flat field
20912108 assert (!needs_patching, " Can't patch flat inline type field access" );
20922109 ciInlineKlass* inline_klass = field->type ()->as_inline_klass ();
2093- bool is_naturally_atomic = inline_klass->nof_declared_nonstatic_fields () <= 1 ;
2094- bool needs_atomic_access = !field->is_null_free () || (field->is_volatile () && !is_naturally_atomic);
2095- if (needs_atomic_access) {
2110+ if (field->is_atomic ()) {
20962111 if (field->is_null_free ()) {
20972112 null_check (val);
20982113 }
20992114 append (new StoreField (obj, offset, field, val, false , state_before, needs_patching));
2100- } else {
2101- assert (field-> is_null_free (), " must be null-free " );
2115+ } else if (field-> is_null_free ()) {
2116+ assert (!inline_klass-> is_empty (), " should have been handled " );
21022117 copy_inline_content (inline_klass, val, inline_klass->payload_offset (), obj, offset, state_before, field);
2118+ } else {
2119+ if (!inline_klass->is_initialized ()) {
2120+ // null_reset_value is not available, bailout for now
2121+ bailout (" store to an uninitialized nullable non-atomic flat field" );
2122+ return ;
2123+ }
2124+
2125+ // Store the subfields when field is a nullable non-atomic field
2126+ Value object_null = append (new Constant (objectNull));
2127+ Value null_reset_value = append (new Constant (new ObjectConstant (inline_klass->get_null_reset_value ().as_object ())));
2128+ Value src = append (new IfOp (val, Instruction::neq, object_null, val, null_reset_value, state_before, false ));
2129+ copy_inline_content (inline_klass, src, inline_klass->payload_offset (), obj, offset, state_before);
2130+
2131+ // Store the null marker
2132+ Value int_one = append (new Constant (new IntConstant (1 )));
2133+ Value int_zero = append (new Constant (intZero));
2134+ Value nm = append (new IfOp (val, Instruction::neq, object_null, int_one, int_zero, state_before, false ));
2135+ Value nm_offset = append (new Constant (new LongConstant (offset + inline_klass->null_marker_offset_in_payload ())));
2136+ append (new UnsafePut (T_BOOLEAN, obj, nm_offset, nm, false ));
21032137 }
21042138 }
21052139 break ;
0 commit comments