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#include <stdlib.h>
17#include "handle-scope-internal.h"
18#include "jext-common.h"
19
20static jerryx_handle_scope_t jerryx_handle_scope_root =
21{
22 .prelist_handle_count = 0,
23 .handle_ptr = NULL,
24};
25static jerryx_handle_scope_t *jerryx_handle_scope_current = &jerryx_handle_scope_root;
26static jerryx_handle_scope_pool_t jerryx_handle_scope_pool =
27{
28 .count = 0,
29 .start = NULL,
30};
31
32#define JERRYX_HANDLE_SCOPE_POOL_PRELIST_LAST \
33 jerryx_handle_scope_pool.prelist + JERRYX_SCOPE_PRELIST_SIZE - 1
34
35#define JERRYX_HANDLE_SCOPE_PRELIST_IDX(scope) (scope - jerryx_handle_scope_pool.prelist)
36
37/**
38 * Get current handle scope top of stack.
39 */
40jerryx_handle_scope_t *
41jerryx_handle_scope_get_current (void)
42{
43 return jerryx_handle_scope_current;
44} /* jerryx_handle_scope_get_current */
45
46/**
47 * Get root handle scope.
48 */
49jerryx_handle_scope_t *
50jerryx_handle_scope_get_root (void)
51{
52 return &jerryx_handle_scope_root;
53} /* jerryx_handle_scope_get_root */
54
55/**
56 * Determines if given handle scope is located in pre-allocated list.
57 *
58 * @param scope - the one to be determined.
59 */
60static bool
61jerryx_handle_scope_is_in_prelist (jerryx_handle_scope_t *scope)
62{
63 return (jerryx_handle_scope_pool.prelist <= scope)
64 && (scope <= (jerryx_handle_scope_pool.prelist + JERRYX_SCOPE_PRELIST_SIZE - 1));
65} /** jerryx_handle_scope_is_in_prelist */
66
67/**
68 * Get the parent of given handle scope.
69 * If given handle scope is in prelist, the parent must be in prelist too;
70 * if given is the first item of heap chain list, the parent must be the last one of prelist;
71 * the parent must be in chain list otherwise.
72 *
73 * @param scope - the one to be permformed on.
74 * @returns - the parent of the given scope.
75 */
76jerryx_handle_scope_t *
77jerryx_handle_scope_get_parent (jerryx_handle_scope_t *scope)
78{
79 if (scope == &jerryx_handle_scope_root)
80 {
81 return NULL;
82 }
83 if (!jerryx_handle_scope_is_in_prelist (scope))
84 {
85 jerryx_handle_scope_dynamic_t *dy_scope = (jerryx_handle_scope_dynamic_t *) scope;
86 if (dy_scope == jerryx_handle_scope_pool.start)
87 {
88 return JERRYX_HANDLE_SCOPE_POOL_PRELIST_LAST;
89 }
90 jerryx_handle_scope_dynamic_t *parent = dy_scope->parent;
91 return (jerryx_handle_scope_t *) parent;
92 }
93 if (scope == jerryx_handle_scope_pool.prelist)
94 {
95 return &jerryx_handle_scope_root;
96 }
97 return jerryx_handle_scope_pool.prelist + JERRYX_HANDLE_SCOPE_PRELIST_IDX (scope) - 1;
98} /** jerryx_handle_scope_get_parent */
99
100/**
101 * Get the child of given handle scope.
102 * If the given handle scope is in heap chain list, its child must be in heap chain list too;
103 * if the given handle scope is the last one of prelist, its child must be the first item of chain list;
104 * the children are in prelist otherwise.
105 *
106 * @param scope - the one to be permformed on.
107 * @returns the child of the given scope.
108 */
109jerryx_handle_scope_t *
110jerryx_handle_scope_get_child (jerryx_handle_scope_t *scope)
111{
112 if (scope == &jerryx_handle_scope_root)
113 {
114 if (jerryx_handle_scope_pool.count > 0)
115 {
116 return jerryx_handle_scope_pool.prelist;
117 }
118 return NULL;
119 }
120 if (!jerryx_handle_scope_is_in_prelist (scope))
121 {
122 jerryx_handle_scope_dynamic_t *child = ((jerryx_handle_scope_dynamic_t *) scope)->child;
123 return (jerryx_handle_scope_t *) child;
124 }
125 if (scope == JERRYX_HANDLE_SCOPE_POOL_PRELIST_LAST)
126 {
127 return (jerryx_handle_scope_t *) jerryx_handle_scope_pool.start;
128 }
129 ptrdiff_t idx = JERRYX_HANDLE_SCOPE_PRELIST_IDX (scope);
130 if (idx < 0)
131 {
132 return NULL;
133 }
134 if ((unsigned long) idx >= jerryx_handle_scope_pool.count - 1)
135 {
136 return NULL;
137 }
138 return jerryx_handle_scope_pool.prelist + idx + 1;
139} /** jerryx_handle_scope_get_child */
140
141/**
142 * Claims a handle scope either from prelist or allocating a new memory block,
143 * and increment pool's scope count by 1, and set current scope to the newly claimed one.
144 * If there are still available spaces in prelist, claims a block in prelist;
145 * otherwise allocates a new memory block from heap and sets its fields to default values,
146 * and link it to previously dynamically allocated scope, or link it to pool's start pointer.
147 *
148 * @returns the newly claimed handle scope pointer.
149 */
150jerryx_handle_scope_t *
151jerryx_handle_scope_alloc (void)
152{
153 jerryx_handle_scope_t *scope;
154 if (jerryx_handle_scope_pool.count < JERRYX_SCOPE_PRELIST_SIZE)
155 {
156 scope = jerryx_handle_scope_pool.prelist + jerryx_handle_scope_pool.count;
157 }
158 else
159 {
160 jerryx_handle_scope_dynamic_t *dy_scope;
161 dy_scope = (jerryx_handle_scope_dynamic_t *) jerry_heap_alloc (sizeof (jerryx_handle_scope_dynamic_t));
162 JERRYX_ASSERT (dy_scope != NULL);
163 dy_scope->child = NULL;
164
165 if (jerryx_handle_scope_pool.count != JERRYX_SCOPE_PRELIST_SIZE)
166 {
167 jerryx_handle_scope_dynamic_t *dy_current = (jerryx_handle_scope_dynamic_t *) jerryx_handle_scope_current;
168 dy_scope->parent = dy_current;
169 dy_current->child = dy_scope;
170 }
171 else
172 {
173 jerryx_handle_scope_pool.start = dy_scope;
174 dy_scope->parent = NULL;
175 }
176
177 scope = (jerryx_handle_scope_t *) dy_scope;
178 }
179
180 scope->prelist_handle_count = 0;
181 scope->escaped = false;
182 scope->handle_ptr = NULL;
183
184 jerryx_handle_scope_current = scope;
185 ++jerryx_handle_scope_pool.count;
186 return (jerryx_handle_scope_t *) scope;
187} /** jerryx_handle_scope_alloc */
188
189/**
190 * Deannounce a previously claimed handle scope, return it to pool
191 * or free the allocated memory block.
192 *
193 * @param scope - the one to be freed.
194 */
195void
196jerryx_handle_scope_free (jerryx_handle_scope_t *scope)
197{
198 if (scope == &jerryx_handle_scope_root)
199 {
200 return;
201 }
202
203 --jerryx_handle_scope_pool.count;
204 if (scope == jerryx_handle_scope_current)
205 {
206 jerryx_handle_scope_current = jerryx_handle_scope_get_parent (scope);
207 }
208
209 if (!jerryx_handle_scope_is_in_prelist (scope))
210 {
211 jerryx_handle_scope_dynamic_t *dy_scope = (jerryx_handle_scope_dynamic_t *) scope;
212 if (dy_scope == jerryx_handle_scope_pool.start)
213 {
214 jerryx_handle_scope_pool.start = dy_scope->child;
215 }
216 else if (dy_scope->parent != NULL)
217 {
218 dy_scope->parent->child = dy_scope->child;
219 }
220 jerry_heap_free (dy_scope, sizeof (jerryx_handle_scope_dynamic_t));
221 return;
222 }
223 /**
224 * Nothing to do with scopes in prelist
225 */
226} /** jerryx_handle_scope_free */
227