1425bb815Sopenharmony_ci/* Copyright JS Foundation and other contributors, http://js.foundation
2425bb815Sopenharmony_ci *
3425bb815Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4425bb815Sopenharmony_ci * you may not use this file except in compliance with the License.
5425bb815Sopenharmony_ci * You may obtain a copy of the License at
6425bb815Sopenharmony_ci *
7425bb815Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8425bb815Sopenharmony_ci *
9425bb815Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10425bb815Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS
11425bb815Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12425bb815Sopenharmony_ci * See the License for the specific language governing permissions and
13425bb815Sopenharmony_ci * limitations under the License.
14425bb815Sopenharmony_ci */
15425bb815Sopenharmony_ci
16425bb815Sopenharmony_ci#include "js-parser-internal.h"
17425bb815Sopenharmony_ci
18425bb815Sopenharmony_ci#if ENABLED (JERRY_PARSER)
19425bb815Sopenharmony_ci
20425bb815Sopenharmony_ci/** \addtogroup mem Memory allocation
21425bb815Sopenharmony_ci * @{
22425bb815Sopenharmony_ci *
23425bb815Sopenharmony_ci * \addtogroup mem_parser Parser memory manager
24425bb815Sopenharmony_ci * @{
25425bb815Sopenharmony_ci */
26425bb815Sopenharmony_ci
27425bb815Sopenharmony_ci/**********************************************************************/
28425bb815Sopenharmony_ci/* Memory allocation                                                  */
29425bb815Sopenharmony_ci/**********************************************************************/
30425bb815Sopenharmony_ci
31425bb815Sopenharmony_ci/**
32425bb815Sopenharmony_ci * Allocate memory.
33425bb815Sopenharmony_ci *
34425bb815Sopenharmony_ci * @return allocated memory.
35425bb815Sopenharmony_ci */
36425bb815Sopenharmony_civoid *
37425bb815Sopenharmony_ciparser_malloc (parser_context_t *context_p, /**< context */
38425bb815Sopenharmony_ci               size_t size) /**< size of the memory block */
39425bb815Sopenharmony_ci{
40425bb815Sopenharmony_ci  void *result;
41425bb815Sopenharmony_ci
42425bb815Sopenharmony_ci  JERRY_ASSERT (size > 0);
43425bb815Sopenharmony_ci  result = jmem_heap_alloc_block_null_on_error (size);
44425bb815Sopenharmony_ci
45425bb815Sopenharmony_ci  if (result == NULL)
46425bb815Sopenharmony_ci  {
47425bb815Sopenharmony_ci    parser_raise_error (context_p, PARSER_ERR_OUT_OF_MEMORY);
48425bb815Sopenharmony_ci  }
49425bb815Sopenharmony_ci  return result;
50425bb815Sopenharmony_ci} /* parser_malloc */
51425bb815Sopenharmony_ci
52425bb815Sopenharmony_ci/**
53425bb815Sopenharmony_ci * Free memory allocated by parser_malloc.
54425bb815Sopenharmony_ci */
55425bb815Sopenharmony_ciinline void JERRY_ATTR_ALWAYS_INLINE
56425bb815Sopenharmony_ciparser_free (void *ptr, /**< pointer to free */
57425bb815Sopenharmony_ci             size_t size) /**< size of the memory block */
58425bb815Sopenharmony_ci{
59425bb815Sopenharmony_ci  jmem_heap_free_block (ptr, size);
60425bb815Sopenharmony_ci} /* parser_free */
61425bb815Sopenharmony_ci
62425bb815Sopenharmony_ci/**
63425bb815Sopenharmony_ci * Allocate local memory for short term use.
64425bb815Sopenharmony_ci *
65425bb815Sopenharmony_ci * @return allocated memory.
66425bb815Sopenharmony_ci */
67425bb815Sopenharmony_civoid *
68425bb815Sopenharmony_ciparser_malloc_local (parser_context_t *context_p, /**< context */
69425bb815Sopenharmony_ci                     size_t size) /**< size of the memory */
70425bb815Sopenharmony_ci{
71425bb815Sopenharmony_ci  void *result;
72425bb815Sopenharmony_ci
73425bb815Sopenharmony_ci  JERRY_ASSERT (size > 0);
74425bb815Sopenharmony_ci  result = jmem_heap_alloc_block (size);
75425bb815Sopenharmony_ci  if (result == 0)
76425bb815Sopenharmony_ci  {
77425bb815Sopenharmony_ci    parser_raise_error (context_p, PARSER_ERR_OUT_OF_MEMORY);
78425bb815Sopenharmony_ci  }
79425bb815Sopenharmony_ci  return result;
80425bb815Sopenharmony_ci} /* parser_malloc_local */
81425bb815Sopenharmony_ci
82425bb815Sopenharmony_ci/**
83425bb815Sopenharmony_ci * Free memory allocated by parser_malloc_local.
84425bb815Sopenharmony_ci */
85425bb815Sopenharmony_civoid
86425bb815Sopenharmony_ciparser_free_local (void *ptr, /**< pointer to free */
87425bb815Sopenharmony_ci                   size_t size) /**< size of the memory */
88425bb815Sopenharmony_ci{
89425bb815Sopenharmony_ci  jmem_heap_free_block (ptr, size);
90425bb815Sopenharmony_ci} /* parser_free_local */
91425bb815Sopenharmony_ci
92425bb815Sopenharmony_ci/**
93425bb815Sopenharmony_ci * Free the dynamically allocated buffer stored in the context
94425bb815Sopenharmony_ci */
95425bb815Sopenharmony_ciinline void JERRY_ATTR_ALWAYS_INLINE
96425bb815Sopenharmony_ciparser_free_allocated_buffer (parser_context_t *context_p) /**< context */
97425bb815Sopenharmony_ci{
98425bb815Sopenharmony_ci  if (context_p->u.allocated_buffer_p != NULL)
99425bb815Sopenharmony_ci  {
100425bb815Sopenharmony_ci    parser_free_local (context_p->u.allocated_buffer_p,
101425bb815Sopenharmony_ci                       context_p->allocated_buffer_size);
102425bb815Sopenharmony_ci    context_p->u.allocated_buffer_p = NULL;
103425bb815Sopenharmony_ci  }
104425bb815Sopenharmony_ci} /* parser_free_allocated_buffer */
105425bb815Sopenharmony_ci
106425bb815Sopenharmony_ci/**********************************************************************/
107425bb815Sopenharmony_ci/* Parser data management functions                                   */
108425bb815Sopenharmony_ci/**********************************************************************/
109425bb815Sopenharmony_ci
110425bb815Sopenharmony_ci/**
111425bb815Sopenharmony_ci * Initialize parse data.
112425bb815Sopenharmony_ci */
113425bb815Sopenharmony_cistatic void
114425bb815Sopenharmony_ciparser_data_init (parser_mem_data_t *data_p, /**< memory manager */
115425bb815Sopenharmony_ci                  uint32_t page_size) /**< size of each page */
116425bb815Sopenharmony_ci{
117425bb815Sopenharmony_ci  data_p->first_p = NULL;
118425bb815Sopenharmony_ci  data_p->last_p = NULL;
119425bb815Sopenharmony_ci  data_p->last_position = page_size;
120425bb815Sopenharmony_ci} /* parser_data_init */
121425bb815Sopenharmony_ci
122425bb815Sopenharmony_ci/**
123425bb815Sopenharmony_ci * Free parse data.
124425bb815Sopenharmony_ci */
125425bb815Sopenharmony_cistatic void
126425bb815Sopenharmony_ciparser_data_free (parser_mem_data_t *data_p, /**< memory manager */
127425bb815Sopenharmony_ci                  uint32_t page_size) /**< size of each page */
128425bb815Sopenharmony_ci{
129425bb815Sopenharmony_ci  parser_mem_page_t *page_p = data_p->first_p;
130425bb815Sopenharmony_ci
131425bb815Sopenharmony_ci  while (page_p != NULL)
132425bb815Sopenharmony_ci  {
133425bb815Sopenharmony_ci    parser_mem_page_t *next_p = page_p->next_p;
134425bb815Sopenharmony_ci
135425bb815Sopenharmony_ci    parser_free (page_p, page_size);
136425bb815Sopenharmony_ci    page_p = next_p;
137425bb815Sopenharmony_ci  }
138425bb815Sopenharmony_ci} /* parser_data_free */
139425bb815Sopenharmony_ci
140425bb815Sopenharmony_ci/**********************************************************************/
141425bb815Sopenharmony_ci/* Parser byte stream management functions                            */
142425bb815Sopenharmony_ci/**********************************************************************/
143425bb815Sopenharmony_ci
144425bb815Sopenharmony_ci/**
145425bb815Sopenharmony_ci * Initialize byte stream.
146425bb815Sopenharmony_ci */
147425bb815Sopenharmony_civoid
148425bb815Sopenharmony_ciparser_cbc_stream_init (parser_mem_data_t *data_p) /**< memory manager */
149425bb815Sopenharmony_ci{
150425bb815Sopenharmony_ci  parser_data_init (data_p, PARSER_CBC_STREAM_PAGE_SIZE);
151425bb815Sopenharmony_ci} /* parser_cbc_stream_init */
152425bb815Sopenharmony_ci
153425bb815Sopenharmony_ci/**
154425bb815Sopenharmony_ci * Free byte stream.
155425bb815Sopenharmony_ci */
156425bb815Sopenharmony_civoid
157425bb815Sopenharmony_ciparser_cbc_stream_free (parser_mem_data_t *data_p) /**< memory manager */
158425bb815Sopenharmony_ci{
159425bb815Sopenharmony_ci  parser_data_free (data_p,
160425bb815Sopenharmony_ci                    sizeof (parser_mem_page_t *) + PARSER_CBC_STREAM_PAGE_SIZE);
161425bb815Sopenharmony_ci} /* parser_cbc_stream_free */
162425bb815Sopenharmony_ci
163425bb815Sopenharmony_ci/**
164425bb815Sopenharmony_ci * Appends a byte at the end of the byte stream.
165425bb815Sopenharmony_ci */
166425bb815Sopenharmony_civoid
167425bb815Sopenharmony_ciparser_cbc_stream_alloc_page (parser_context_t *context_p, /**< context */
168425bb815Sopenharmony_ci                              parser_mem_data_t *data_p) /**< memory manager */
169425bb815Sopenharmony_ci{
170425bb815Sopenharmony_ci  size_t size = sizeof (parser_mem_page_t *) + PARSER_CBC_STREAM_PAGE_SIZE;
171425bb815Sopenharmony_ci  parser_mem_page_t *page_p = (parser_mem_page_t *) parser_malloc (context_p, size);
172425bb815Sopenharmony_ci
173425bb815Sopenharmony_ci  page_p->next_p = NULL;
174425bb815Sopenharmony_ci  data_p->last_position = 0;
175425bb815Sopenharmony_ci
176425bb815Sopenharmony_ci  if (data_p->last_p != NULL)
177425bb815Sopenharmony_ci  {
178425bb815Sopenharmony_ci    data_p->last_p->next_p = page_p;
179425bb815Sopenharmony_ci  }
180425bb815Sopenharmony_ci  else
181425bb815Sopenharmony_ci  {
182425bb815Sopenharmony_ci    data_p->first_p = page_p;
183425bb815Sopenharmony_ci  }
184425bb815Sopenharmony_ci  data_p->last_p = page_p;
185425bb815Sopenharmony_ci} /* parser_cbc_stream_alloc_page */
186425bb815Sopenharmony_ci
187425bb815Sopenharmony_ci/**********************************************************************/
188425bb815Sopenharmony_ci/* Parser list management functions                                   */
189425bb815Sopenharmony_ci/**********************************************************************/
190425bb815Sopenharmony_ci
191425bb815Sopenharmony_ci/**
192425bb815Sopenharmony_ci * Initialize parser list.
193425bb815Sopenharmony_ci */
194425bb815Sopenharmony_civoid
195425bb815Sopenharmony_ciparser_list_init (parser_list_t *list_p, /**< parser list */
196425bb815Sopenharmony_ci                  uint32_t item_size, /**< size for each page */
197425bb815Sopenharmony_ci                  uint32_t item_count) /**< number of items on each page */
198425bb815Sopenharmony_ci{
199425bb815Sopenharmony_ci  /* Align to pointer size. */
200425bb815Sopenharmony_ci  item_size = (uint32_t) (((item_size) + sizeof (void *) - 1) & ~(sizeof (void *) - 1));
201425bb815Sopenharmony_ci  parser_data_init (&list_p->data, item_size * item_count);
202425bb815Sopenharmony_ci  list_p->page_size = item_size * item_count;
203425bb815Sopenharmony_ci  list_p->item_size = item_size;
204425bb815Sopenharmony_ci  list_p->item_count = item_count;
205425bb815Sopenharmony_ci} /* parser_list_init */
206425bb815Sopenharmony_ci
207425bb815Sopenharmony_ci/**
208425bb815Sopenharmony_ci * Free parser list.
209425bb815Sopenharmony_ci */
210425bb815Sopenharmony_civoid
211425bb815Sopenharmony_ciparser_list_free (parser_list_t *list_p) /**< parser list */
212425bb815Sopenharmony_ci{
213425bb815Sopenharmony_ci  parser_data_free (&list_p->data,
214425bb815Sopenharmony_ci                    (uint32_t) (sizeof (parser_mem_page_t *) + list_p->page_size));
215425bb815Sopenharmony_ci} /* parser_list_free */
216425bb815Sopenharmony_ci
217425bb815Sopenharmony_ci/**
218425bb815Sopenharmony_ci * Reset parser list.
219425bb815Sopenharmony_ci */
220425bb815Sopenharmony_civoid
221425bb815Sopenharmony_ciparser_list_reset (parser_list_t *list_p) /**< parser list */
222425bb815Sopenharmony_ci{
223425bb815Sopenharmony_ci  parser_data_init (&list_p->data, list_p->page_size);
224425bb815Sopenharmony_ci} /* parser_list_reset */
225425bb815Sopenharmony_ci
226425bb815Sopenharmony_ci/**
227425bb815Sopenharmony_ci * Allocate space for the next item.
228425bb815Sopenharmony_ci *
229425bb815Sopenharmony_ci * @return pointer to the appended item.
230425bb815Sopenharmony_ci */
231425bb815Sopenharmony_civoid *
232425bb815Sopenharmony_ciparser_list_append (parser_context_t *context_p, /**< context */
233425bb815Sopenharmony_ci                    parser_list_t *list_p) /**< parser list */
234425bb815Sopenharmony_ci{
235425bb815Sopenharmony_ci  parser_mem_page_t *page_p = list_p->data.last_p;
236425bb815Sopenharmony_ci  void *result;
237425bb815Sopenharmony_ci
238425bb815Sopenharmony_ci  if (list_p->data.last_position + list_p->item_size > list_p->page_size)
239425bb815Sopenharmony_ci  {
240425bb815Sopenharmony_ci    size_t size = sizeof (parser_mem_page_t *) + list_p->page_size;
241425bb815Sopenharmony_ci
242425bb815Sopenharmony_ci    page_p = (parser_mem_page_t *) parser_malloc (context_p, size);
243425bb815Sopenharmony_ci
244425bb815Sopenharmony_ci    page_p->next_p = NULL;
245425bb815Sopenharmony_ci    list_p->data.last_position = 0;
246425bb815Sopenharmony_ci
247425bb815Sopenharmony_ci    if (list_p->data.last_p != NULL)
248425bb815Sopenharmony_ci    {
249425bb815Sopenharmony_ci      list_p->data.last_p->next_p = page_p;
250425bb815Sopenharmony_ci    }
251425bb815Sopenharmony_ci    else
252425bb815Sopenharmony_ci    {
253425bb815Sopenharmony_ci      list_p->data.first_p = page_p;
254425bb815Sopenharmony_ci    }
255425bb815Sopenharmony_ci    list_p->data.last_p = page_p;
256425bb815Sopenharmony_ci  }
257425bb815Sopenharmony_ci
258425bb815Sopenharmony_ci  result = page_p->bytes + list_p->data.last_position;
259425bb815Sopenharmony_ci  list_p->data.last_position += list_p->item_size;
260425bb815Sopenharmony_ci  return result;
261425bb815Sopenharmony_ci} /* parser_list_append */
262425bb815Sopenharmony_ci
263425bb815Sopenharmony_ci/**
264425bb815Sopenharmony_ci * Return the nth item of the list.
265425bb815Sopenharmony_ci *
266425bb815Sopenharmony_ci * @return pointer to the item.
267425bb815Sopenharmony_ci */
268425bb815Sopenharmony_civoid *
269425bb815Sopenharmony_ciparser_list_get (parser_list_t *list_p, /**< parser list */
270425bb815Sopenharmony_ci                 size_t index) /**< item index */
271425bb815Sopenharmony_ci{
272425bb815Sopenharmony_ci  size_t item_count = list_p->item_count;
273425bb815Sopenharmony_ci  parser_mem_page_t *page_p = list_p->data.first_p;
274425bb815Sopenharmony_ci
275425bb815Sopenharmony_ci  while (index >= item_count)
276425bb815Sopenharmony_ci  {
277425bb815Sopenharmony_ci    JERRY_ASSERT (page_p != NULL);
278425bb815Sopenharmony_ci    page_p = page_p->next_p;
279425bb815Sopenharmony_ci    index -= item_count;
280425bb815Sopenharmony_ci  }
281425bb815Sopenharmony_ci
282425bb815Sopenharmony_ci  JERRY_ASSERT (page_p != NULL);
283425bb815Sopenharmony_ci  JERRY_ASSERT (page_p != list_p->data.last_p
284425bb815Sopenharmony_ci                || (index * list_p->item_size < list_p->data.last_position));
285425bb815Sopenharmony_ci  return page_p->bytes + (index * list_p->item_size);
286425bb815Sopenharmony_ci} /* parser_list_get */
287425bb815Sopenharmony_ci
288425bb815Sopenharmony_ci/**
289425bb815Sopenharmony_ci * Initialize a parser list iterator.
290425bb815Sopenharmony_ci */
291425bb815Sopenharmony_civoid
292425bb815Sopenharmony_ciparser_list_iterator_init (parser_list_t *list_p, /**< parser list */
293425bb815Sopenharmony_ci                           parser_list_iterator_t *iterator_p) /**< iterator */
294425bb815Sopenharmony_ci{
295425bb815Sopenharmony_ci  iterator_p->list_p = list_p;
296425bb815Sopenharmony_ci  iterator_p->current_p = list_p->data.first_p;
297425bb815Sopenharmony_ci  iterator_p->current_position = 0;
298425bb815Sopenharmony_ci} /* parser_list_iterator_init */
299425bb815Sopenharmony_ci
300425bb815Sopenharmony_ci/**
301425bb815Sopenharmony_ci * Next iterator step.
302425bb815Sopenharmony_ci *
303425bb815Sopenharmony_ci * @return the address of the current item, or NULL at the end.
304425bb815Sopenharmony_ci */
305425bb815Sopenharmony_civoid *
306425bb815Sopenharmony_ciparser_list_iterator_next (parser_list_iterator_t *iterator_p) /**< iterator */
307425bb815Sopenharmony_ci{
308425bb815Sopenharmony_ci  void *result;
309425bb815Sopenharmony_ci
310425bb815Sopenharmony_ci  if (iterator_p->current_p == NULL)
311425bb815Sopenharmony_ci  {
312425bb815Sopenharmony_ci    return NULL;
313425bb815Sopenharmony_ci  }
314425bb815Sopenharmony_ci
315425bb815Sopenharmony_ci  result = iterator_p->current_p->bytes + iterator_p->current_position;
316425bb815Sopenharmony_ci  iterator_p->current_position += iterator_p->list_p->item_size;
317425bb815Sopenharmony_ci
318425bb815Sopenharmony_ci  if (iterator_p->current_p->next_p == NULL)
319425bb815Sopenharmony_ci  {
320425bb815Sopenharmony_ci    if (iterator_p->current_position >= iterator_p->list_p->data.last_position)
321425bb815Sopenharmony_ci    {
322425bb815Sopenharmony_ci      iterator_p->current_p = NULL;
323425bb815Sopenharmony_ci      iterator_p->current_position = 0;
324425bb815Sopenharmony_ci    }
325425bb815Sopenharmony_ci  }
326425bb815Sopenharmony_ci  else if (iterator_p->current_position >= iterator_p->list_p->page_size)
327425bb815Sopenharmony_ci  {
328425bb815Sopenharmony_ci    iterator_p->current_p = iterator_p->current_p->next_p;
329425bb815Sopenharmony_ci    iterator_p->current_position = 0;
330425bb815Sopenharmony_ci  }
331425bb815Sopenharmony_ci  return result;
332425bb815Sopenharmony_ci} /* parser_list_iterator_next */
333425bb815Sopenharmony_ci
334425bb815Sopenharmony_ci/**********************************************************************/
335425bb815Sopenharmony_ci/* Parser stack management functions                                  */
336425bb815Sopenharmony_ci/**********************************************************************/
337425bb815Sopenharmony_ci
338425bb815Sopenharmony_ci/* Stack is a reversed storage. */
339425bb815Sopenharmony_ci
340425bb815Sopenharmony_ci/**
341425bb815Sopenharmony_ci * Initialize parser stack.
342425bb815Sopenharmony_ci */
343425bb815Sopenharmony_civoid
344425bb815Sopenharmony_ciparser_stack_init (parser_context_t *context_p) /**< context */
345425bb815Sopenharmony_ci{
346425bb815Sopenharmony_ci  parser_data_init (&context_p->stack, PARSER_STACK_PAGE_SIZE);
347425bb815Sopenharmony_ci  context_p->free_page_p = NULL;
348425bb815Sopenharmony_ci} /* parser_stack_init */
349425bb815Sopenharmony_ci
350425bb815Sopenharmony_ci/**
351425bb815Sopenharmony_ci * Free parser stack.
352425bb815Sopenharmony_ci */
353425bb815Sopenharmony_civoid
354425bb815Sopenharmony_ciparser_stack_free (parser_context_t *context_p) /**< context */
355425bb815Sopenharmony_ci{
356425bb815Sopenharmony_ci  parser_data_free (&context_p->stack,
357425bb815Sopenharmony_ci                    sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE);
358425bb815Sopenharmony_ci
359425bb815Sopenharmony_ci  if (context_p->free_page_p != NULL)
360425bb815Sopenharmony_ci  {
361425bb815Sopenharmony_ci    parser_free (context_p->free_page_p,
362425bb815Sopenharmony_ci                 sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE);
363425bb815Sopenharmony_ci  }
364425bb815Sopenharmony_ci} /* parser_stack_free */
365425bb815Sopenharmony_ci
366425bb815Sopenharmony_ci/**
367425bb815Sopenharmony_ci * Pushes an uint8_t value onto the stack.
368425bb815Sopenharmony_ci */
369425bb815Sopenharmony_civoid
370425bb815Sopenharmony_ciparser_stack_push_uint8 (parser_context_t *context_p, /**< context */
371425bb815Sopenharmony_ci                         uint8_t uint8_value) /**< value pushed onto the stack */
372425bb815Sopenharmony_ci{
373425bb815Sopenharmony_ci  parser_mem_page_t *page_p = context_p->stack.first_p;
374425bb815Sopenharmony_ci
375425bb815Sopenharmony_ci  /* This assert might trigger false positive valgrind errors, when
376425bb815Sopenharmony_ci   * parser_stack_push() pushes not fully initialized structures.
377425bb815Sopenharmony_ci   * More precisely when the last byte of the structure is uninitialized. */
378425bb815Sopenharmony_ci  JERRY_ASSERT (page_p == NULL
379425bb815Sopenharmony_ci                || context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]);
380425bb815Sopenharmony_ci
381425bb815Sopenharmony_ci  if (context_p->stack.last_position >= PARSER_STACK_PAGE_SIZE)
382425bb815Sopenharmony_ci  {
383425bb815Sopenharmony_ci    if (context_p->free_page_p != NULL)
384425bb815Sopenharmony_ci    {
385425bb815Sopenharmony_ci      page_p = context_p->free_page_p;
386425bb815Sopenharmony_ci      context_p->free_page_p = NULL;
387425bb815Sopenharmony_ci    }
388425bb815Sopenharmony_ci    else
389425bb815Sopenharmony_ci    {
390425bb815Sopenharmony_ci      size_t size = sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE;
391425bb815Sopenharmony_ci      page_p = (parser_mem_page_t *) parser_malloc (context_p, size);
392425bb815Sopenharmony_ci    }
393425bb815Sopenharmony_ci
394425bb815Sopenharmony_ci    page_p->next_p = context_p->stack.first_p;
395425bb815Sopenharmony_ci    context_p->stack.last_position = 0;
396425bb815Sopenharmony_ci    context_p->stack.first_p = page_p;
397425bb815Sopenharmony_ci  }
398425bb815Sopenharmony_ci
399425bb815Sopenharmony_ci  page_p->bytes[context_p->stack.last_position++] = uint8_value;
400425bb815Sopenharmony_ci  context_p->stack_top_uint8 = uint8_value;
401425bb815Sopenharmony_ci} /* parser_stack_push_uint8 */
402425bb815Sopenharmony_ci
403425bb815Sopenharmony_ci/**
404425bb815Sopenharmony_ci * Pops the last uint8_t value from the stack.
405425bb815Sopenharmony_ci */
406425bb815Sopenharmony_civoid
407425bb815Sopenharmony_ciparser_stack_pop_uint8 (parser_context_t *context_p) /**< context */
408425bb815Sopenharmony_ci{
409425bb815Sopenharmony_ci  parser_mem_page_t *page_p = context_p->stack.first_p;
410425bb815Sopenharmony_ci
411425bb815Sopenharmony_ci  JERRY_ASSERT (page_p != NULL
412425bb815Sopenharmony_ci                && context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]);
413425bb815Sopenharmony_ci
414425bb815Sopenharmony_ci  context_p->stack.last_position--;
415425bb815Sopenharmony_ci
416425bb815Sopenharmony_ci  if (context_p->stack.last_position == 0)
417425bb815Sopenharmony_ci  {
418425bb815Sopenharmony_ci    context_p->stack.first_p = page_p->next_p;
419425bb815Sopenharmony_ci    context_p->stack.last_position = PARSER_STACK_PAGE_SIZE;
420425bb815Sopenharmony_ci
421425bb815Sopenharmony_ci    if (context_p->free_page_p == NULL)
422425bb815Sopenharmony_ci    {
423425bb815Sopenharmony_ci      context_p->free_page_p = page_p;
424425bb815Sopenharmony_ci    }
425425bb815Sopenharmony_ci    else
426425bb815Sopenharmony_ci    {
427425bb815Sopenharmony_ci      parser_free (page_p,
428425bb815Sopenharmony_ci                   sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE);
429425bb815Sopenharmony_ci    }
430425bb815Sopenharmony_ci
431425bb815Sopenharmony_ci    page_p = context_p->stack.first_p;
432425bb815Sopenharmony_ci
433425bb815Sopenharmony_ci    JERRY_ASSERT (page_p != NULL);
434425bb815Sopenharmony_ci  }
435425bb815Sopenharmony_ci
436425bb815Sopenharmony_ci  context_p->stack_top_uint8 = page_p->bytes[context_p->stack.last_position - 1];
437425bb815Sopenharmony_ci} /* parser_stack_pop_uint8 */
438425bb815Sopenharmony_ci
439425bb815Sopenharmony_ci/**
440425bb815Sopenharmony_ci * Pushes an uint16_t value onto the stack.
441425bb815Sopenharmony_ci */
442425bb815Sopenharmony_civoid
443425bb815Sopenharmony_ciparser_stack_push_uint16 (parser_context_t *context_p, /**< context */
444425bb815Sopenharmony_ci                          uint16_t uint16_value) /**< value pushed onto the stack */
445425bb815Sopenharmony_ci{
446425bb815Sopenharmony_ci  if (context_p->stack.last_position + 2 <= PARSER_STACK_PAGE_SIZE)
447425bb815Sopenharmony_ci  {
448425bb815Sopenharmony_ci    parser_mem_page_t *page_p = context_p->stack.first_p;
449425bb815Sopenharmony_ci
450425bb815Sopenharmony_ci    JERRY_ASSERT (page_p != NULL
451425bb815Sopenharmony_ci                  && context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]);
452425bb815Sopenharmony_ci
453425bb815Sopenharmony_ci    page_p->bytes[context_p->stack.last_position++] = (uint8_t) (uint16_value >> 8);
454425bb815Sopenharmony_ci    page_p->bytes[context_p->stack.last_position++] = (uint8_t) uint16_value;
455425bb815Sopenharmony_ci    context_p->stack_top_uint8 = (uint8_t) uint16_value;
456425bb815Sopenharmony_ci  }
457425bb815Sopenharmony_ci  else
458425bb815Sopenharmony_ci  {
459425bb815Sopenharmony_ci    parser_stack_push_uint8 (context_p, (uint8_t) (uint16_value >> 8));
460425bb815Sopenharmony_ci    parser_stack_push_uint8 (context_p, (uint8_t) uint16_value);
461425bb815Sopenharmony_ci  }
462425bb815Sopenharmony_ci} /* parser_stack_push_uint16 */
463425bb815Sopenharmony_ci
464425bb815Sopenharmony_ci/**
465425bb815Sopenharmony_ci * Pops the last uint16_t value from the stack.
466425bb815Sopenharmony_ci *
467425bb815Sopenharmony_ci * @return the value popped from the stack.
468425bb815Sopenharmony_ci */
469425bb815Sopenharmony_ciuint16_t
470425bb815Sopenharmony_ciparser_stack_pop_uint16 (parser_context_t *context_p) /**< context */
471425bb815Sopenharmony_ci{
472425bb815Sopenharmony_ci  uint32_t value = context_p->stack_top_uint8;
473425bb815Sopenharmony_ci
474425bb815Sopenharmony_ci  if (context_p->stack.last_position >= 3)
475425bb815Sopenharmony_ci  {
476425bb815Sopenharmony_ci    parser_mem_page_t *page_p = context_p->stack.first_p;
477425bb815Sopenharmony_ci
478425bb815Sopenharmony_ci    JERRY_ASSERT (page_p != NULL
479425bb815Sopenharmony_ci                  && context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]);
480425bb815Sopenharmony_ci
481425bb815Sopenharmony_ci    value |= ((uint32_t) page_p->bytes[context_p->stack.last_position - 2]) << 8;
482425bb815Sopenharmony_ci    context_p->stack_top_uint8 = page_p->bytes[context_p->stack.last_position - 3];
483425bb815Sopenharmony_ci    context_p->stack.last_position -= 2;
484425bb815Sopenharmony_ci  }
485425bb815Sopenharmony_ci  else
486425bb815Sopenharmony_ci  {
487425bb815Sopenharmony_ci    parser_stack_pop_uint8 (context_p);
488425bb815Sopenharmony_ci    value |= ((uint32_t) context_p->stack_top_uint8) << 8;
489425bb815Sopenharmony_ci    parser_stack_pop_uint8 (context_p);
490425bb815Sopenharmony_ci  }
491425bb815Sopenharmony_ci  return (uint16_t) value;
492425bb815Sopenharmony_ci} /* parser_stack_pop_uint16 */
493425bb815Sopenharmony_ci
494425bb815Sopenharmony_ci/**
495425bb815Sopenharmony_ci * Pushes a data onto the stack.
496425bb815Sopenharmony_ci */
497425bb815Sopenharmony_civoid
498425bb815Sopenharmony_ciparser_stack_push (parser_context_t *context_p, /**< context */
499425bb815Sopenharmony_ci                   const void *data_p, /**< data pushed onto the stack */
500425bb815Sopenharmony_ci                   uint32_t length) /**< length of the data */
501425bb815Sopenharmony_ci{
502425bb815Sopenharmony_ci  uint32_t fragment_length = PARSER_STACK_PAGE_SIZE - context_p->stack.last_position;
503425bb815Sopenharmony_ci  const uint8_t *bytes_p = (const uint8_t *) data_p;
504425bb815Sopenharmony_ci  parser_mem_page_t *page_p;
505425bb815Sopenharmony_ci
506425bb815Sopenharmony_ci  JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
507425bb815Sopenharmony_ci
508425bb815Sopenharmony_ci  context_p->stack_top_uint8 = bytes_p[length - 1];
509425bb815Sopenharmony_ci
510425bb815Sopenharmony_ci  if (fragment_length > 0)
511425bb815Sopenharmony_ci  {
512425bb815Sopenharmony_ci    /* Fill the remaining bytes. */
513425bb815Sopenharmony_ci    if (fragment_length > length)
514425bb815Sopenharmony_ci    {
515425bb815Sopenharmony_ci      fragment_length = length;
516425bb815Sopenharmony_ci    }
517425bb815Sopenharmony_ci
518425bb815Sopenharmony_ci    memcpy (context_p->stack.first_p->bytes + context_p->stack.last_position,
519425bb815Sopenharmony_ci            bytes_p,
520425bb815Sopenharmony_ci            fragment_length);
521425bb815Sopenharmony_ci
522425bb815Sopenharmony_ci    if (fragment_length == length)
523425bb815Sopenharmony_ci    {
524425bb815Sopenharmony_ci      context_p->stack.last_position += length;
525425bb815Sopenharmony_ci      return;
526425bb815Sopenharmony_ci    }
527425bb815Sopenharmony_ci
528425bb815Sopenharmony_ci    bytes_p += fragment_length;
529425bb815Sopenharmony_ci    length -= fragment_length;
530425bb815Sopenharmony_ci  }
531425bb815Sopenharmony_ci
532425bb815Sopenharmony_ci  if (context_p->free_page_p != NULL)
533425bb815Sopenharmony_ci  {
534425bb815Sopenharmony_ci    page_p = context_p->free_page_p;
535425bb815Sopenharmony_ci    context_p->free_page_p = NULL;
536425bb815Sopenharmony_ci  }
537425bb815Sopenharmony_ci  else
538425bb815Sopenharmony_ci  {
539425bb815Sopenharmony_ci    size_t size = sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE;
540425bb815Sopenharmony_ci
541425bb815Sopenharmony_ci    page_p = (parser_mem_page_t *) parser_malloc (context_p, size);
542425bb815Sopenharmony_ci  }
543425bb815Sopenharmony_ci
544425bb815Sopenharmony_ci  page_p->next_p = context_p->stack.first_p;
545425bb815Sopenharmony_ci
546425bb815Sopenharmony_ci  context_p->stack.first_p = page_p;
547425bb815Sopenharmony_ci
548425bb815Sopenharmony_ci  memcpy (page_p->bytes, bytes_p, length);
549425bb815Sopenharmony_ci  context_p->stack.last_position = length;
550425bb815Sopenharmony_ci} /* parser_stack_push */
551425bb815Sopenharmony_ci
552425bb815Sopenharmony_ci/**
553425bb815Sopenharmony_ci * Pop bytes from the top of the stack.
554425bb815Sopenharmony_ci */
555425bb815Sopenharmony_civoid
556425bb815Sopenharmony_ciparser_stack_pop (parser_context_t *context_p, /**< context */
557425bb815Sopenharmony_ci                  void *data_p, /**< destination buffer, can be NULL */
558425bb815Sopenharmony_ci                  uint32_t length) /**< length of the data */
559425bb815Sopenharmony_ci{
560425bb815Sopenharmony_ci  uint8_t *bytes_p = (uint8_t *) data_p;
561425bb815Sopenharmony_ci  parser_mem_page_t *page_p = context_p->stack.first_p;
562425bb815Sopenharmony_ci
563425bb815Sopenharmony_ci  JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
564425bb815Sopenharmony_ci
565425bb815Sopenharmony_ci  if (context_p->stack.last_position > length)
566425bb815Sopenharmony_ci  {
567425bb815Sopenharmony_ci    context_p->stack.last_position -= length;
568425bb815Sopenharmony_ci    context_p->stack_top_uint8 = page_p->bytes[context_p->stack.last_position - 1];
569425bb815Sopenharmony_ci
570425bb815Sopenharmony_ci    if (bytes_p != NULL)
571425bb815Sopenharmony_ci    {
572425bb815Sopenharmony_ci      memcpy (bytes_p, context_p->stack.first_p->bytes + context_p->stack.last_position, length);
573425bb815Sopenharmony_ci    }
574425bb815Sopenharmony_ci    return;
575425bb815Sopenharmony_ci  }
576425bb815Sopenharmony_ci
577425bb815Sopenharmony_ci  JERRY_ASSERT (page_p->next_p != NULL);
578425bb815Sopenharmony_ci
579425bb815Sopenharmony_ci  length -= context_p->stack.last_position;
580425bb815Sopenharmony_ci
581425bb815Sopenharmony_ci  if (bytes_p != NULL)
582425bb815Sopenharmony_ci  {
583425bb815Sopenharmony_ci    memcpy (bytes_p + length, page_p->bytes, context_p->stack.last_position);
584425bb815Sopenharmony_ci  }
585425bb815Sopenharmony_ci
586425bb815Sopenharmony_ci  context_p->stack.first_p = page_p->next_p;
587425bb815Sopenharmony_ci  context_p->stack.last_position = PARSER_STACK_PAGE_SIZE - length;
588425bb815Sopenharmony_ci  context_p->stack_top_uint8 = page_p->next_p->bytes[context_p->stack.last_position - 1];
589425bb815Sopenharmony_ci
590425bb815Sopenharmony_ci  if (bytes_p != NULL && length > 0)
591425bb815Sopenharmony_ci  {
592425bb815Sopenharmony_ci    memcpy (bytes_p, page_p->next_p->bytes + context_p->stack.last_position, length);
593425bb815Sopenharmony_ci  }
594425bb815Sopenharmony_ci
595425bb815Sopenharmony_ci  JERRY_ASSERT (context_p->stack.last_position > 0);
596425bb815Sopenharmony_ci
597425bb815Sopenharmony_ci  if (context_p->free_page_p == NULL)
598425bb815Sopenharmony_ci  {
599425bb815Sopenharmony_ci    context_p->free_page_p = page_p;
600425bb815Sopenharmony_ci  }
601425bb815Sopenharmony_ci  else
602425bb815Sopenharmony_ci  {
603425bb815Sopenharmony_ci    parser_free (page_p,
604425bb815Sopenharmony_ci                 sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE);
605425bb815Sopenharmony_ci  }
606425bb815Sopenharmony_ci} /* parser_stack_pop */
607425bb815Sopenharmony_ci
608425bb815Sopenharmony_ci/**
609425bb815Sopenharmony_ci * Skip the next n bytes of the stack.
610425bb815Sopenharmony_ci */
611425bb815Sopenharmony_civoid
612425bb815Sopenharmony_ciparser_stack_iterator_skip (parser_stack_iterator_t *iterator, /**< iterator */
613425bb815Sopenharmony_ci                            size_t length) /**< number of skipped bytes */
614425bb815Sopenharmony_ci{
615425bb815Sopenharmony_ci  JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
616425bb815Sopenharmony_ci
617425bb815Sopenharmony_ci  if (length < iterator->current_position)
618425bb815Sopenharmony_ci  {
619425bb815Sopenharmony_ci    iterator->current_position -= length;
620425bb815Sopenharmony_ci  }
621425bb815Sopenharmony_ci  else
622425bb815Sopenharmony_ci  {
623425bb815Sopenharmony_ci    iterator->current_position = PARSER_STACK_PAGE_SIZE - (length - iterator->current_position);
624425bb815Sopenharmony_ci    iterator->current_p = iterator->current_p->next_p;
625425bb815Sopenharmony_ci  }
626425bb815Sopenharmony_ci} /* parser_stack_iterator_skip */
627425bb815Sopenharmony_ci
628425bb815Sopenharmony_ci/**
629425bb815Sopenharmony_ci * Read bytes from the stack.
630425bb815Sopenharmony_ci */
631425bb815Sopenharmony_civoid
632425bb815Sopenharmony_ciparser_stack_iterator_read (parser_stack_iterator_t *iterator, /**< iterator */
633425bb815Sopenharmony_ci                            void *data_p, /**< destination buffer */
634425bb815Sopenharmony_ci                            size_t length) /**< length of the data */
635425bb815Sopenharmony_ci{
636425bb815Sopenharmony_ci  uint8_t *bytes_p = (uint8_t *) data_p;
637425bb815Sopenharmony_ci
638425bb815Sopenharmony_ci  JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
639425bb815Sopenharmony_ci
640425bb815Sopenharmony_ci  if (length <= iterator->current_position)
641425bb815Sopenharmony_ci  {
642425bb815Sopenharmony_ci    memcpy (bytes_p,
643425bb815Sopenharmony_ci            iterator->current_p->bytes + iterator->current_position - length,
644425bb815Sopenharmony_ci            length);
645425bb815Sopenharmony_ci  }
646425bb815Sopenharmony_ci  else
647425bb815Sopenharmony_ci  {
648425bb815Sopenharmony_ci    JERRY_ASSERT (iterator->current_p->next_p != NULL);
649425bb815Sopenharmony_ci
650425bb815Sopenharmony_ci    length -= iterator->current_position;
651425bb815Sopenharmony_ci    memcpy (bytes_p + length,
652425bb815Sopenharmony_ci            iterator->current_p->bytes,
653425bb815Sopenharmony_ci            iterator->current_position);
654425bb815Sopenharmony_ci    memcpy (bytes_p,
655425bb815Sopenharmony_ci            iterator->current_p->next_p->bytes + PARSER_STACK_PAGE_SIZE - length,
656425bb815Sopenharmony_ci            length);
657425bb815Sopenharmony_ci  }
658425bb815Sopenharmony_ci} /* parser_stack_iterator_read */
659425bb815Sopenharmony_ci
660425bb815Sopenharmony_ci/**
661425bb815Sopenharmony_ci * Write bytes onto the stack.
662425bb815Sopenharmony_ci */
663425bb815Sopenharmony_civoid
664425bb815Sopenharmony_ciparser_stack_iterator_write (parser_stack_iterator_t *iterator, /**< iterator */
665425bb815Sopenharmony_ci                             const void *data_p, /**< destination buffer */
666425bb815Sopenharmony_ci                             size_t length) /**< length of the data */
667425bb815Sopenharmony_ci{
668425bb815Sopenharmony_ci  const uint8_t *bytes_p = (const uint8_t *) data_p;
669425bb815Sopenharmony_ci
670425bb815Sopenharmony_ci  JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
671425bb815Sopenharmony_ci
672425bb815Sopenharmony_ci  if (length <= iterator->current_position)
673425bb815Sopenharmony_ci  {
674425bb815Sopenharmony_ci    memcpy (iterator->current_p->bytes + iterator->current_position - length,
675425bb815Sopenharmony_ci            bytes_p,
676425bb815Sopenharmony_ci            length);
677425bb815Sopenharmony_ci  }
678425bb815Sopenharmony_ci  else
679425bb815Sopenharmony_ci  {
680425bb815Sopenharmony_ci    JERRY_ASSERT (iterator->current_p->next_p != NULL);
681425bb815Sopenharmony_ci
682425bb815Sopenharmony_ci    length -= iterator->current_position;
683425bb815Sopenharmony_ci    memcpy (iterator->current_p->bytes,
684425bb815Sopenharmony_ci            bytes_p + length,
685425bb815Sopenharmony_ci            iterator->current_position);
686425bb815Sopenharmony_ci    memcpy (iterator->current_p->next_p->bytes + PARSER_STACK_PAGE_SIZE - length,
687425bb815Sopenharmony_ci            bytes_p,
688425bb815Sopenharmony_ci            length);
689425bb815Sopenharmony_ci  }
690425bb815Sopenharmony_ci} /* parser_stack_iterator_write */
691425bb815Sopenharmony_ci
692425bb815Sopenharmony_ci/**
693425bb815Sopenharmony_ci * @}
694425bb815Sopenharmony_ci * @}
695425bb815Sopenharmony_ci */
696425bb815Sopenharmony_ci
697425bb815Sopenharmony_ci#endif /* ENABLED (JERRY_PARSER) */
698