xref: /php-src/ext/dom/lexbor/lexbor/core/dobject.c (revision bffab33a)
1 /*
2  * Copyright (C) 2018-2019 Alexander Borisov
3  *
4  * Author: Alexander Borisov <borisov@lexbor.com>
5  */
6 
7 #include "lexbor/core/dobject.h"
8 
9 
10 #if defined(LEXBOR_HAVE_ADDRESS_SANITIZER)
11     #include <sanitizer/asan_interface.h>
12 #endif
13 
14 
15 lexbor_dobject_t *
lexbor_dobject_create(void)16 lexbor_dobject_create(void)
17 {
18     return lexbor_calloc(1, sizeof(lexbor_dobject_t));
19 }
20 
21 lxb_status_t
lexbor_dobject_init(lexbor_dobject_t * dobject,size_t chunk_size,size_t struct_size)22 lexbor_dobject_init(lexbor_dobject_t *dobject,
23                     size_t chunk_size, size_t struct_size)
24 {
25     lxb_status_t status;
26 
27     if (dobject == NULL) {
28         return LXB_STATUS_ERROR_OBJECT_IS_NULL;
29     }
30 
31     if (chunk_size == 0 || struct_size == 0) {
32         return LXB_STATUS_ERROR_WRONG_ARGS;
33     }
34 
35     /* Set params */
36     dobject->allocated = 0UL;
37     dobject->struct_size = struct_size;
38 
39     /* Init memory */
40     dobject->mem = lexbor_mem_create();
41 
42     status = lexbor_mem_init(dobject->mem,
43                            lexbor_mem_align(chunk_size * dobject->struct_size));
44     if (status) {
45         return status;
46     }
47 
48 #if defined(LEXBOR_HAVE_ADDRESS_SANITIZER)
49     ASAN_POISON_MEMORY_REGION(dobject->mem->chunk->data,
50                               dobject->mem->chunk->size);
51 #endif
52 
53     /* Array */
54     dobject->cache = lexbor_array_create();
55 
56     status = lexbor_array_init(dobject->cache, chunk_size);
57     if (status)
58         return status;
59 
60     return LXB_STATUS_OK;
61 }
62 
63 void
lexbor_dobject_clean(lexbor_dobject_t * dobject)64 lexbor_dobject_clean(lexbor_dobject_t *dobject)
65 {
66     if (dobject != NULL) {
67         dobject->allocated = 0UL;
68 
69         lexbor_mem_clean(dobject->mem);
70         lexbor_array_clean(dobject->cache);
71     }
72 }
73 
74 lexbor_dobject_t *
lexbor_dobject_destroy(lexbor_dobject_t * dobject,bool destroy_self)75 lexbor_dobject_destroy(lexbor_dobject_t *dobject, bool destroy_self)
76 {
77     if (dobject == NULL)
78         return NULL;
79 
80     dobject->mem = lexbor_mem_destroy(dobject->mem, true);
81     dobject->cache = lexbor_array_destroy(dobject->cache, true);
82 
83     if (destroy_self == true) {
84         return lexbor_free(dobject);
85     }
86 
87     return dobject;
88 }
89 
90 void *
lexbor_dobject_alloc(lexbor_dobject_t * dobject)91 lexbor_dobject_alloc(lexbor_dobject_t *dobject)
92 {
93     void *data;
94 
95     if (lexbor_array_length(dobject->cache) != 0) {
96         dobject->allocated++;
97 
98 #if defined(LEXBOR_HAVE_ADDRESS_SANITIZER)
99         data = lexbor_array_pop(dobject->cache);
100         ASAN_UNPOISON_MEMORY_REGION(data, dobject->struct_size);
101 
102         return data;
103 #else
104         return lexbor_array_pop(dobject->cache);
105 #endif
106     }
107 
108     data = lexbor_mem_alloc(dobject->mem, dobject->struct_size);
109     if (data == NULL) {
110         return NULL;
111     }
112 
113 #if defined(LEXBOR_HAVE_ADDRESS_SANITIZER)
114     ASAN_UNPOISON_MEMORY_REGION(data, dobject->struct_size);
115 #endif
116 
117     dobject->allocated++;
118 
119     return data;
120 }
121 
122 void *
lexbor_dobject_calloc(lexbor_dobject_t * dobject)123 lexbor_dobject_calloc(lexbor_dobject_t *dobject)
124 {
125     void *data = lexbor_dobject_alloc(dobject);
126 
127     if (data != NULL) {
128         memset(data, 0, dobject->struct_size);
129     }
130 
131     return data;
132 }
133 
134 void *
lexbor_dobject_free(lexbor_dobject_t * dobject,void * data)135 lexbor_dobject_free(lexbor_dobject_t *dobject, void *data)
136 {
137     if (data == NULL) {
138         return NULL;
139     }
140 
141 #if defined(LEXBOR_HAVE_ADDRESS_SANITIZER)
142     ASAN_POISON_MEMORY_REGION(data, dobject->struct_size);
143 #endif
144 
145     if (lexbor_array_push(dobject->cache, data) == LXB_STATUS_OK) {
146         dobject->allocated--;
147         return NULL;
148     }
149 
150     return data;
151 }
152 
153 void *
lexbor_dobject_by_absolute_position(lexbor_dobject_t * dobject,size_t pos)154 lexbor_dobject_by_absolute_position(lexbor_dobject_t *dobject, size_t pos)
155 {
156     size_t chunk_idx, chunk_pos, i;
157     lexbor_mem_chunk_t *chunk;
158 
159     if (pos >= dobject->allocated) {
160         return NULL;
161     }
162 
163     chunk = dobject->mem->chunk_first;
164     chunk_pos = pos * dobject->struct_size;
165     chunk_idx = chunk_pos / dobject->mem->chunk_min_size;
166 
167     for (i = 0; i < chunk_idx; i++) {
168         chunk = chunk->next;
169     }
170 
171     return &chunk->data[chunk_pos % chunk->size];
172 }
173 
174 /*
175  * No inline functions for ABI.
176  */
177 size_t
lexbor_dobject_allocated_noi(lexbor_dobject_t * dobject)178 lexbor_dobject_allocated_noi(lexbor_dobject_t *dobject)
179 {
180     return lexbor_dobject_allocated(dobject);
181 }
182 
183 size_t
lexbor_dobject_cache_length_noi(lexbor_dobject_t * dobject)184 lexbor_dobject_cache_length_noi(lexbor_dobject_t *dobject)
185 {
186     return lexbor_dobject_cache_length(dobject);
187 }
188