1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5#ifndef NIBBLEMAPMACROS_H_
6#define NIBBLEMAPMACROS_H_
7
8///////////////////////////////////////////////////////////////////////
9//// some mmgr stuff for JIT, especially for jit code blocks
10///////////////////////////////////////////////////////////////////////
11//
12// In order to quickly find the start of a jit code block
13// we keep track of all those positions via a map.
14// Each entry in this map represents 32 byte (a bucket) of the code heap.
15// We make the assumption that no two code-blocks can start in
16// the same 32byte bucket;
17// Additionally we assume that every code header is DWORD aligned.
18// Because we cannot guarantee that jitblocks always start at
19// multiples of 32 bytes we cannot use a simple bitmap; instead we
20// use a nibble (4 bit) per bucket and encode the offset of the header
21// inside the bucket (in DWORDS). In order to make initialization
22// easier we add one to the real offset, a nibble-value of zero
23// means that there is no header start in the resp. bucket.
24// In order to speed up "backwards scanning" we start numbering
25// nibbles inside a DWORD from the highest bits (28..31). Because
26// of that we can scan backwards inside the DWORD with right shifts.
27
28#if defined(_WIN64)
29// TODO: bump up the windows CODE_ALIGN to 16 and iron out any nibble map bugs that exist.
30// TODO: there is something wrong with USE_INDIRECT_CODEHEADER with CODE_ALIGN=16
31# define CODE_ALIGN 4
32# define LOG2_CODE_ALIGN 2
33#else
34# define CODE_ALIGN sizeof(DWORD) // 4 byte boundry
35# define LOG2_CODE_ALIGN 2
36#endif
37#define NIBBLE_MASK 0xf
38#define NIBBLE_SIZE 4 // 4 bits
39#define LOG2_NIBBLE_SIZE 2
40#define NIBBLES_PER_DWORD ((8*sizeof(DWORD)) >> LOG2_NIBBLE_SIZE) // 8 (4-bit) nibbles per dword
41#define NIBBLES_PER_DWORD_MASK (NIBBLES_PER_DWORD - 1) // 7
42#define LOG2_NIBBLES_PER_DWORD 3
43#define BYTES_PER_BUCKET (NIBBLES_PER_DWORD * CODE_ALIGN) // 32 bytes per bucket
44#define LOG2_BYTES_PER_BUCKET (LOG2_CODE_ALIGN + LOG2_NIBBLES_PER_DWORD) // 5 bits per bucket
45#define MASK_BYTES_PER_BUCKET (BYTES_PER_BUCKET - 1) // 31
46#define HIGHEST_NIBBLE_BIT (32 - NIBBLE_SIZE) // 28 (i.e 32 - 4)
47#define HIGHEST_NIBBLE_MASK (NIBBLE_MASK << HIGHEST_NIBBLE_BIT) // 0xf0000000
48
49#define ADDR2POS(x) ((x) >> LOG2_BYTES_PER_BUCKET)
50#define ADDR2OFFS(x) (DWORD) ((((x) & MASK_BYTES_PER_BUCKET) >> LOG2_CODE_ALIGN) + 1)
51#define POSOFF2ADDR(pos, of) (size_t) (((pos) << LOG2_BYTES_PER_BUCKET) + (((of) - 1) << LOG2_CODE_ALIGN))
52#define HEAP2MAPSIZE(x) (((x) / (BYTES_PER_BUCKET * NIBBLES_PER_DWORD)) * CODE_ALIGN)
53#define POS2SHIFTCOUNT(x) (DWORD) (HIGHEST_NIBBLE_BIT - (((x) & NIBBLES_PER_DWORD_MASK) << LOG2_NIBBLE_SIZE))
54#define POS2MASK(x) (DWORD) ~(HIGHEST_NIBBLE_MASK >> (((x) & NIBBLES_PER_DWORD_MASK) << LOG2_NIBBLE_SIZE))
55
56#endif // NIBBLEMAPMACROS_H_
57