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