blob: 9872669138de2fe3de9145ed37fb9a8fc1bffcdc [file] [log] [blame]
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
Dimitry Ivanovbcc4da92017-02-15 15:31:13 -08003 * All rights reserved.
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -07004 *
Dimitry Ivanovbcc4da92017-02-15 15:31:13 -08005 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070014 *
Dimitry Ivanovbcc4da92017-02-15 15:31:13 -080015 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070027 */
28
Elliott Hughescbc80ba2018-02-13 14:26:29 -080029#pragma once
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070030
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070031#include <sys/cdefs.h>
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070032#include <stddef.h>
Elliott Hughes8f653f82024-05-29 22:25:37 +000033#include <stdint.h>
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070034
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070035const uint32_t kSmallObjectMaxSizeLog2 = 10;
36const uint32_t kSmallObjectMinSizeLog2 = 4;
37const uint32_t kSmallObjectAllocatorsCount = kSmallObjectMaxSizeLog2 - kSmallObjectMinSizeLog2 + 1;
38
Ryan Prichard083d8502019-01-24 13:47:13 -080039class BionicSmallObjectAllocator;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070040
41// This structure is placed at the beginning of each addressable page
42// and has all information we need to find the corresponding memory allocator.
43struct page_info {
44 char signature[4];
45 uint32_t type;
46 union {
47 // we use allocated_size for large objects allocator
48 size_t allocated_size;
49 // and allocator_addr for small ones.
Ryan Prichard083d8502019-01-24 13:47:13 -080050 BionicSmallObjectAllocator* allocator_addr;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070051 };
Vic Yang259429b2018-12-04 23:59:57 -080052};
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070053
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070054struct small_object_block_record {
55 small_object_block_record* next;
56 size_t free_blocks_cnt;
57};
58
Vic Yang54938512018-12-02 23:46:26 -080059// This structure is placed at the beginning of each page managed by
Ryan Prichard083d8502019-01-24 13:47:13 -080060// BionicSmallObjectAllocator. Note that a page_info struct is expected at the
Vic Yang54938512018-12-02 23:46:26 -080061// beginning of each page as well, and therefore this structure contains a
62// page_info as its *first* field.
63struct small_object_page_info {
64 page_info info; // Must be the first field.
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070065
Vic Yang54938512018-12-02 23:46:26 -080066 // Doubly linked list for traversing all pages allocated by a
Ryan Prichard083d8502019-01-24 13:47:13 -080067 // BionicSmallObjectAllocator.
Vic Yang54938512018-12-02 23:46:26 -080068 small_object_page_info* next_page;
69 small_object_page_info* prev_page;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070070
Vic Yang54938512018-12-02 23:46:26 -080071 // Linked list containing all free blocks in this page.
72 small_object_block_record* free_block_list;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070073
Vic Yang259429b2018-12-04 23:59:57 -080074 // Free blocks counter.
Vic Yang54938512018-12-02 23:46:26 -080075 size_t free_blocks_cnt;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070076};
77
Ryan Prichard083d8502019-01-24 13:47:13 -080078class BionicSmallObjectAllocator {
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070079 public:
Ryan Prichard083d8502019-01-24 13:47:13 -080080 BionicSmallObjectAllocator(uint32_t type, size_t block_size);
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070081 void* alloc();
82 void free(void* ptr);
83
84 size_t get_block_size() const { return block_size_; }
85 private:
86 void alloc_page();
Vic Yang54938512018-12-02 23:46:26 -080087 void free_page(small_object_page_info* page);
88 void add_to_page_list(small_object_page_info* page);
89 void remove_from_page_list(small_object_page_info* page);
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070090
Vic Yang259429b2018-12-04 23:59:57 -080091 const uint32_t type_;
92 const size_t block_size_;
93 const size_t blocks_per_page_;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070094
95 size_t free_pages_cnt_;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070096
Vic Yang54938512018-12-02 23:46:26 -080097 small_object_page_info* page_list_;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070098};
99
Ryan Prichard083d8502019-01-24 13:47:13 -0800100class BionicAllocator {
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700101 public:
Ryan Prichard083d8502019-01-24 13:47:13 -0800102 constexpr BionicAllocator() : allocators_(nullptr), allocators_buf_() {}
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700103 void* alloc(size_t size);
Ryan Prichard96773a22019-01-24 15:22:50 -0800104 void* memalign(size_t align, size_t size);
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700105
106 // Note that this implementation of realloc never shrinks allocation
107 void* realloc(void* ptr, size_t size);
108 void free(void* ptr);
Vy Nguyend5007512020-07-14 17:37:04 -0400109
110 // Returns the size of the given allocated heap chunk, if it is valid.
111 // Otherwise, this may return 0 or cause a segfault if the pointer is invalid.
112 size_t get_chunk_size(void* ptr);
113
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700114 private:
Ryan Prichard96773a22019-01-24 15:22:50 -0800115 void* alloc_mmap(size_t align, size_t size);
116 inline void* alloc_impl(size_t align, size_t size);
117 inline page_info* get_page_info_unchecked(void* ptr);
118 inline page_info* get_page_info(void* ptr);
Elliott Hughes8f653f82024-05-29 22:25:37 +0000119 BionicSmallObjectAllocator* get_small_object_allocator_unchecked(uint32_t type);
120 BionicSmallObjectAllocator* get_small_object_allocator(page_info* pi, void* ptr);
Dimitry Ivanov65707b62016-07-29 13:25:33 -0700121 void initialize_allocators();
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700122
Ryan Prichard083d8502019-01-24 13:47:13 -0800123 BionicSmallObjectAllocator* allocators_;
124 uint8_t allocators_buf_[sizeof(BionicSmallObjectAllocator)*kSmallObjectAllocatorsCount];
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700125};