1/* Copyright JS Foundation and other contributors, http://js.foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16/**
17 * Memory pool manager implementation
18 */
19
20#include "jcontext.h"
21#include "jmem.h"
22#include "jrt-libc-includes.h"
23
24#define JMEM_ALLOCATOR_INTERNAL
25#include "jmem-allocator-internal.h"
26
27#if ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC)
28#include "ecma-gc.h"
29#endif /* ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC) */
30
31/** \addtogroup mem Memory allocation
32 * @{
33 *
34 * \addtogroup poolman Memory pool manager
35 * @{
36 */
37
38/**
39 * Finalize pool manager
40 */
41void
42jmem_pools_finalize (void)
43{
44  jmem_pools_collect_empty ();
45
46  JERRY_ASSERT (JERRY_CONTEXT (jmem_free_8_byte_chunk_p) == NULL);
47#if ENABLED (JERRY_CPOINTER_32_BIT)
48  JERRY_ASSERT (JERRY_CONTEXT (jmem_free_16_byte_chunk_p) == NULL);
49#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
50} /* jmem_pools_finalize */
51
52/**
53 * Allocate a chunk of specified size
54 *
55 * @return pointer to allocated chunk, if allocation was successful,
56 *         or NULL - if not enough memory.
57 */
58extern inline void * JERRY_ATTR_HOT JERRY_ATTR_ALWAYS_INLINE
59jmem_pools_alloc (size_t size) /**< size of the chunk */
60{
61#if ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC)
62  ecma_free_unused_memory (JMEM_PRESSURE_LOW);
63#endif /* ENABLED (JERRY_MEM_GC_BEFORE_EACH_ALLOC) */
64
65#if ENABLED (JERRY_CPOINTER_32_BIT)
66  if (size <= 8)
67  {
68#else /* !ENABLED (JERRY_CPOINTER_32_BIT) */
69    JERRY_ASSERT (size <= 8);
70#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
71
72    if (JERRY_CONTEXT (jmem_free_8_byte_chunk_p) != NULL)
73    {
74      const jmem_pools_chunk_t *const chunk_p = JERRY_CONTEXT (jmem_free_8_byte_chunk_p);
75
76      JMEM_VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
77      JERRY_CONTEXT (jmem_free_8_byte_chunk_p) = chunk_p->next_p;
78      JMEM_VALGRIND_UNDEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
79
80      JMEM_HEAP_STAT_ALLOC (8);
81      return (void *) chunk_p;
82    }
83    else
84    {
85      void *chunk_p = jmem_heap_alloc_block_internal (8);
86      JMEM_HEAP_STAT_ALLOC (8);
87      return chunk_p;
88    }
89
90#if ENABLED (JERRY_CPOINTER_32_BIT)
91  }
92
93  JERRY_ASSERT (size <= 16);
94
95  if (JERRY_CONTEXT (jmem_free_16_byte_chunk_p) != NULL)
96  {
97    const jmem_pools_chunk_t *const chunk_p = JERRY_CONTEXT (jmem_free_16_byte_chunk_p);
98
99    JMEM_VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
100    JERRY_CONTEXT (jmem_free_16_byte_chunk_p) = chunk_p->next_p;
101    JMEM_VALGRIND_UNDEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
102
103    JMEM_HEAP_STAT_ALLOC (16);
104    return (void *) chunk_p;
105  }
106  else
107  {
108    void *chunk_p = jmem_heap_alloc_block_internal (16);
109    JMEM_HEAP_STAT_ALLOC (16);
110    return chunk_p;
111  }
112#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
113} /* jmem_pools_alloc */
114
115/**
116 * Free the chunk
117 */
118extern inline void JERRY_ATTR_HOT JERRY_ATTR_ALWAYS_INLINE
119jmem_pools_free (void *chunk_p, /**< pointer to the chunk */
120                 size_t size) /**< size of the chunk */
121{
122  JERRY_ASSERT (chunk_p != NULL);
123  JMEM_HEAP_STAT_FREE (size);
124
125  jmem_pools_chunk_t *const chunk_to_free_p = (jmem_pools_chunk_t *) chunk_p;
126
127  JMEM_VALGRIND_DEFINED_SPACE (chunk_to_free_p, size);
128
129#if ENABLED (JERRY_CPOINTER_32_BIT)
130  if (size <= 8)
131  {
132#else /* !ENABLED (JERRY_CPOINTER_32_BIT) */
133    JERRY_ASSERT (size <= 8);
134#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
135
136    chunk_to_free_p->next_p = JERRY_CONTEXT (jmem_free_8_byte_chunk_p);
137    JERRY_CONTEXT (jmem_free_8_byte_chunk_p) = chunk_to_free_p;
138
139#if ENABLED (JERRY_CPOINTER_32_BIT)
140  }
141  else
142  {
143    JERRY_ASSERT (size <= 16);
144
145    chunk_to_free_p->next_p = JERRY_CONTEXT (jmem_free_16_byte_chunk_p);
146    JERRY_CONTEXT (jmem_free_16_byte_chunk_p) = chunk_to_free_p;
147  }
148#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
149
150  JMEM_VALGRIND_NOACCESS_SPACE (chunk_to_free_p, size);
151} /* jmem_pools_free */
152
153/**
154 *  Collect empty pool chunks
155 */
156void
157jmem_pools_collect_empty (void)
158{
159  jmem_pools_chunk_t *chunk_p = JERRY_CONTEXT (jmem_free_8_byte_chunk_p);
160  JERRY_CONTEXT (jmem_free_8_byte_chunk_p) = NULL;
161
162  while (chunk_p)
163  {
164    JMEM_VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
165    jmem_pools_chunk_t *const next_p = chunk_p->next_p;
166    JMEM_VALGRIND_NOACCESS_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
167
168    jmem_heap_free_block_internal (chunk_p, 8);
169    chunk_p = next_p;
170  }
171
172#if ENABLED (JERRY_CPOINTER_32_BIT)
173  chunk_p = JERRY_CONTEXT (jmem_free_16_byte_chunk_p);
174  JERRY_CONTEXT (jmem_free_16_byte_chunk_p) = NULL;
175
176  while (chunk_p)
177  {
178    JMEM_VALGRIND_DEFINED_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
179    jmem_pools_chunk_t *const next_p = chunk_p->next_p;
180    JMEM_VALGRIND_NOACCESS_SPACE (chunk_p, sizeof (jmem_pools_chunk_t));
181
182    jmem_heap_free_block_internal (chunk_p, 16);
183    chunk_p = next_p;
184  }
185#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
186} /* jmem_pools_collect_empty */
187
188/**
189 * @}
190 * @}
191 */
192