blob: 86b9550c04374fff380166d5258bc86dcb697670 [file] [log] [blame]
/*
* Copyright (c) 2015, 2023, 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.
*/
#ifndef SHARE_GC_Z_ZADDRESS_HPP
#define SHARE_GC_Z_ZADDRESS_HPP
#include "memory/allStatic.hpp"
#include "utilities/globalDefinitions.hpp"
#include CPU_HEADER(gc/z/zAddress)
// One bit that denotes where the heap start. All uncolored
// oops have this bit set, plus an offset within the heap.
extern uintptr_t ZAddressHeapBase;
extern uintptr_t ZAddressHeapBaseShift;
// Describes the maximal offset inside the heap.
extern size_t ZAddressOffsetBits;
const size_t ZAddressOffsetShift = 0;
extern uintptr_t ZAddressOffsetMask;
extern size_t ZAddressOffsetMax;
// Layout of metadata bits in colored pointer / zpointer.
//
// A zpointer is a combination of the address bits (heap base bit + offset)
// and two low-order metadata bytes, with the following layout:
//
// RRRRMMmmFFrr0000
// **** : Used by load barrier
// ********** : Used by mark barrier
// ************ : Used by store barrier
// **** : Reserved bits
//
// The table below describes what each color does.
//
// +-------------+-------------------+--------------------------+
// | Bit pattern | Description | Included colors |
// +-------------+-------------------+--------------------------+
// | rr | Remembered bits | Remembered[0, 1] |
// +-------------+-------------------+--------------------------+
// | FF | Finalizable bits | Finalizable[0, 1] |
// +-------------+-------------------+--------------------------+
// | mm | Marked young bits | MarkedYoung[0, 1] |
// +-------------+-------------------+--------------------------+
// | MM | Marked old bits | MarkedOld[0, 1] |
// +-------------+-------------------+--------------------------+
// | RRRR | Remapped bits | Remapped[00, 01, 10, 11] |
// +-------------+-------------------+--------------------------+
//
// The low order zero address bits sometimes overlap with the high order zero metadata
// bits, depending on the remapped bit being set.
//
// vvv- overlapping address and metadata zeros
// aaa...aaa0001MMmmFFrr0000 = Remapped00 zpointer
//
// vv-- overlapping address and metadata zeros
// aaa...aaa00010MMmmFFrr0000 = Remapped01 zpointer
//
// v--- overlapping address and metadata zero
// aaa...aaa000100MMmmFFrr0000 = Remapped10 zpointer
//
// ---- no overlapping address and metadata zeros
// aaa...aaa0001000MMmmFFrr0000 = Remapped11 zpointer
//
// The overlapping is performed because the x86 JIT-compiled load barriers expect the
// address bits to start right after the load-good bit. It allows combining the good
// bit check and unmasking into a single speculative shift instruction. On AArch64 we
// don't do this, and hence there are no overlapping address and metadata zeros there.
//
// The remapped bits are notably not grouped into two sets of bits, one for the young
// collection and one for the old collection, like the other bits. The reason is that
// the load barrier is only compatible with bit patterns where there is a single zero in
// its bits of operation (the load metadata bit mask). Instead, the single bit that we
// set encodes the combined state of a conceptual RemappedYoung[0, 1] and
// RemappedOld[0, 1] pair. The encoding scheme is that the shift of the load good bit,
// minus the shift of the load metadata bit start encodes the numbers 0, 1, 2 and 3.
// These numbers in binary correspond to 00, 01, 10 and 11. The low order bit in said
// numbers correspond to the simulated RemappedYoung[0, 1] value, and the high order bit
// corresponds to the simulated RemappedOld[0, 1] value. On AArch64, the remap bits
// of zpointers are the complement of this bit. So there are 3 good bits and one bad bit
// instead. This lends itself better to AArch64 instructions.
//
// We decide the bit to be taken by having the RemappedYoungMask and RemappedOldMask
// variables, which alternate between what two bits they accept for their corresponding
// old and young phase. The Remapped bit is chosen by taking the intersection of those
// two variables.
//
// RemappedOldMask alternates between these two bit patterns:
//
// RemappedOld0 => 0011
// RemappedOld1 => 1100
//
// RemappedYoungMask alternates between these two bit patterns:
//
// RemappedYoung0 => 0101
// RemappedYoung1 => 1010
//
// The corresponding intersections look like this:
//
// RemappedOld0 & RemappedYoung0 = 0001 = Remapped00
// RemappedOld0 & RemappedYoung1 = 0010 = Remapped01
// RemappedOld1 & RemappedYoung0 = 0100 = Remapped10
// RemappedOld1 & RemappedYoung1 = 1000 = Remapped11
constexpr uintptr_t z_pointer_mask(size_t shift, size_t bits) {
return (((uintptr_t)1 << bits) - 1) << shift;
}
constexpr uintptr_t z_pointer_bit(size_t shift, size_t offset) {
return (uintptr_t)1 << (shift + offset);
}
// Reserved bits
const size_t ZPointerReservedShift = 0;
const size_t ZPointerReservedBits = 4;
const uintptr_t ZPointerReservedMask = z_pointer_mask(ZPointerReservedShift, ZPointerReservedBits);
const uintptr_t ZPointerReserved0 = z_pointer_bit(ZPointerReservedShift, 0);
const uintptr_t ZPointerReserved1 = z_pointer_bit(ZPointerReservedShift, 1);
const uintptr_t ZPointerReserved2 = z_pointer_bit(ZPointerReservedShift, 2);
const uintptr_t ZPointerReserved3 = z_pointer_bit(ZPointerReservedShift, 3);
// Remembered set bits
const size_t ZPointerRememberedShift = ZPointerReservedShift + ZPointerReservedBits;
const size_t ZPointerRememberedBits = 2;
const uintptr_t ZPointerRememberedMask = z_pointer_mask(ZPointerRememberedShift, ZPointerRememberedBits);
const uintptr_t ZPointerRemembered0 = z_pointer_bit(ZPointerRememberedShift, 0);
const uintptr_t ZPointerRemembered1 = z_pointer_bit(ZPointerRememberedShift, 1);
// Marked bits
const size_t ZPointerMarkedShift = ZPointerRememberedShift + ZPointerRememberedBits;
const size_t ZPointerMarkedBits = 6;
const uintptr_t ZPointerMarkedMask = z_pointer_mask(ZPointerMarkedShift, ZPointerMarkedBits);
const uintptr_t ZPointerFinalizable0 = z_pointer_bit(ZPointerMarkedShift, 0);
const uintptr_t ZPointerFinalizable1 = z_pointer_bit(ZPointerMarkedShift, 1);
const uintptr_t ZPointerMarkedYoung0 = z_pointer_bit(ZPointerMarkedShift, 2);
const uintptr_t ZPointerMarkedYoung1 = z_pointer_bit(ZPointerMarkedShift, 3);
const uintptr_t ZPointerMarkedOld0 = z_pointer_bit(ZPointerMarkedShift, 4);
const uintptr_t ZPointerMarkedOld1 = z_pointer_bit(ZPointerMarkedShift, 5);
// Remapped bits
const size_t ZPointerRemappedShift = ZPointerMarkedShift + ZPointerMarkedBits;
const size_t ZPointerRemappedBits = 4;
const uintptr_t ZPointerRemappedMask = z_pointer_mask(ZPointerRemappedShift, ZPointerRemappedBits);
const uintptr_t ZPointerRemapped00 = z_pointer_bit(ZPointerRemappedShift, 0);
const uintptr_t ZPointerRemapped01 = z_pointer_bit(ZPointerRemappedShift, 1);
const uintptr_t ZPointerRemapped10 = z_pointer_bit(ZPointerRemappedShift, 2);
const uintptr_t ZPointerRemapped11 = z_pointer_bit(ZPointerRemappedShift, 3);
// The shift table is tightly coupled with the zpointer layout given above
constexpr int ZPointerLoadShiftTable[] = {
ZPointerRemappedShift + ZPointerRemappedShift, // [0] Null
ZPointerRemappedShift + 1, // [1] Remapped00
ZPointerRemappedShift + 2, // [2] Remapped01
0,
ZPointerRemappedShift + 3, // [4] Remapped10
0,
0,
0,
ZPointerRemappedShift + 4 // [8] Remapped11
};
// Barrier metadata masks
const uintptr_t ZPointerLoadMetadataMask = ZPointerRemappedMask;
const uintptr_t ZPointerMarkMetadataMask = ZPointerLoadMetadataMask | ZPointerMarkedMask;
const uintptr_t ZPointerStoreMetadataMask = ZPointerMarkMetadataMask | ZPointerRememberedMask;
const uintptr_t ZPointerAllMetadataMask = ZPointerStoreMetadataMask;
// The current expected bit
extern uintptr_t ZPointerRemapped;
extern uintptr_t ZPointerMarkedOld;
extern uintptr_t ZPointerMarkedYoung;
extern uintptr_t ZPointerFinalizable;
extern uintptr_t ZPointerRemembered;
// The current expected remap bit for the young (or old) collection is either of two bits.
// The other collection alternates the bits, so we need to use a mask.
extern uintptr_t ZPointerRemappedYoungMask;
extern uintptr_t ZPointerRemappedOldMask;
// Good/bad masks
extern uintptr_t ZPointerLoadGoodMask;
extern uintptr_t ZPointerLoadBadMask;
extern uintptr_t ZPointerMarkGoodMask;
extern uintptr_t ZPointerMarkBadMask;
extern uintptr_t ZPointerStoreGoodMask;
extern uintptr_t ZPointerStoreBadMask;
extern uintptr_t ZPointerVectorLoadBadMask[8];
extern uintptr_t ZPointerVectorStoreBadMask[8];
extern uintptr_t ZPointerVectorStoreGoodMask[8];
// The bad mask is 64 bit. Its low order 32 bits contain all possible value combinations
// that this mask will have. Therefore, the memory where the 32 low order bits are stored
// can be used as a 32 bit GC epoch counter, that has a different bit pattern every time
// the bad mask is flipped. This provides a pointer to such 32 bits.
extern uint32_t* ZPointerStoreGoodMaskLowOrderBitsAddr;
const int ZPointerStoreGoodMaskLowOrderBitsOffset = LITTLE_ENDIAN_ONLY(0) BIG_ENDIAN_ONLY(4);
// Offsets
// - Virtual address range offsets
// - Physical memory offsets
enum class zoffset : uintptr_t {};
// Offsets including end of offset range
enum class zoffset_end : uintptr_t {};
// Colored oop
enum class zpointer : uintptr_t { null = 0 };
// Uncolored oop - safe to dereference
enum class zaddress : uintptr_t { null = 0 };
// Uncolored oop - not safe to dereference, could point uncommitted memory
enum class zaddress_unsafe : uintptr_t { null = 0 };
class ZOffset : public AllStatic {
public:
static zaddress address(zoffset offset);
static zaddress_unsafe address_unsafe(zoffset offset);
};
class ZPointer : public AllStatic {
public:
static zaddress uncolor(zpointer ptr);
static zaddress uncolor_store_good(zpointer ptr);
static zaddress_unsafe uncolor_unsafe(zpointer ptr);
static zpointer set_remset_bits(zpointer ptr);
static bool is_load_bad(zpointer ptr);
static bool is_load_good(zpointer ptr);
static bool is_load_good_or_null(zpointer ptr);
static bool is_old_load_good(zpointer ptr);
static bool is_young_load_good(zpointer ptr);
static bool is_mark_bad(zpointer ptr);
static bool is_mark_good(zpointer ptr);
static bool is_mark_good_or_null(zpointer ptr);
static bool is_store_bad(zpointer ptr);
static bool is_store_good(zpointer ptr);
static bool is_store_good_or_null(zpointer ptr);
static bool is_marked_finalizable(zpointer ptr);
static bool is_marked_old(zpointer ptr);
static bool is_marked_young(zpointer ptr);
static bool is_marked_any_old(zpointer ptr);
static bool is_remapped(zpointer ptr);
static bool is_remembered_exact(zpointer ptr);
static constexpr int load_shift_lookup_index(uintptr_t value);
static constexpr int load_shift_lookup(uintptr_t value);
static uintptr_t remap_bits(uintptr_t colored);
};
class ZAddress : public AllStatic {
public:
static zpointer color(zaddress addr, uintptr_t color);
static zpointer color(zaddress_unsafe addr, uintptr_t color);
static zoffset offset(zaddress addr);
static zoffset offset(zaddress_unsafe addr);
static zpointer load_good(zaddress addr, zpointer prev);
static zpointer finalizable_good(zaddress addr, zpointer prev);
static zpointer mark_good(zaddress addr, zpointer prev);
static zpointer mark_old_good(zaddress addr, zpointer prev);
static zpointer mark_young_good(zaddress addr, zpointer prev);
static zpointer store_good(zaddress addr);
static zpointer store_good_or_null(zaddress addr);
};
class ZGlobalsPointers : public AllStatic {
friend class ZAddressTest;
private:
static void set_good_masks();
static void pd_set_good_masks();
public:
static void initialize();
static void flip_young_mark_start();
static void flip_young_relocate_start();
static void flip_old_mark_start();
static void flip_old_relocate_start();
};
#endif // SHARE_GC_Z_ZADDRESS_HPP