• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "js-parser-internal.h"
17 
18 #if ENABLED (JERRY_PARSER)
19 
20 /** \addtogroup mem Memory allocation
21  * @{
22  *
23  * \addtogroup mem_parser Parser memory manager
24  * @{
25  */
26 
27 /**********************************************************************/
28 /* Memory allocation                                                  */
29 /**********************************************************************/
30 
31 /**
32  * Allocate memory.
33  *
34  * @return allocated memory.
35  */
36 void *
parser_malloc(parser_context_t * context_p,size_t size)37 parser_malloc (parser_context_t *context_p, /**< context */
38                size_t size) /**< size of the memory block */
39 {
40   void *result;
41 
42   JERRY_ASSERT (size > 0);
43   result = jmem_heap_alloc_block_null_on_error (size);
44 
45   if (result == NULL)
46   {
47     parser_raise_error (context_p, PARSER_ERR_OUT_OF_MEMORY);
48   }
49   return result;
50 } /* parser_malloc */
51 
52 /**
53  * Free memory allocated by parser_malloc.
54  */
55 inline void JERRY_ATTR_ALWAYS_INLINE
parser_free(void * ptr,size_t size)56 parser_free (void *ptr, /**< pointer to free */
57              size_t size) /**< size of the memory block */
58 {
59   jmem_heap_free_block (ptr, size);
60 } /* parser_free */
61 
62 /**
63  * Allocate local memory for short term use.
64  *
65  * @return allocated memory.
66  */
67 void *
parser_malloc_local(parser_context_t * context_p,size_t size)68 parser_malloc_local (parser_context_t *context_p, /**< context */
69                      size_t size) /**< size of the memory */
70 {
71   void *result;
72 
73   JERRY_ASSERT (size > 0);
74   result = jmem_heap_alloc_block (size);
75   if (result == 0)
76   {
77     parser_raise_error (context_p, PARSER_ERR_OUT_OF_MEMORY);
78   }
79   return result;
80 } /* parser_malloc_local */
81 
82 /**
83  * Free memory allocated by parser_malloc_local.
84  */
85 void
parser_free_local(void * ptr,size_t size)86 parser_free_local (void *ptr, /**< pointer to free */
87                    size_t size) /**< size of the memory */
88 {
89   jmem_heap_free_block (ptr, size);
90 } /* parser_free_local */
91 
92 /**
93  * Free the dynamically allocated buffer stored in the context
94  */
95 inline void JERRY_ATTR_ALWAYS_INLINE
parser_free_allocated_buffer(parser_context_t * context_p)96 parser_free_allocated_buffer (parser_context_t *context_p) /**< context */
97 {
98   if (context_p->u.allocated_buffer_p != NULL)
99   {
100     parser_free_local (context_p->u.allocated_buffer_p,
101                        context_p->allocated_buffer_size);
102     context_p->u.allocated_buffer_p = NULL;
103   }
104 } /* parser_free_allocated_buffer */
105 
106 /**********************************************************************/
107 /* Parser data management functions                                   */
108 /**********************************************************************/
109 
110 /**
111  * Initialize parse data.
112  */
113 static void
parser_data_init(parser_mem_data_t * data_p,uint32_t page_size)114 parser_data_init (parser_mem_data_t *data_p, /**< memory manager */
115                   uint32_t page_size) /**< size of each page */
116 {
117   data_p->first_p = NULL;
118   data_p->last_p = NULL;
119   data_p->last_position = page_size;
120 } /* parser_data_init */
121 
122 /**
123  * Free parse data.
124  */
125 static void
parser_data_free(parser_mem_data_t * data_p,uint32_t page_size)126 parser_data_free (parser_mem_data_t *data_p, /**< memory manager */
127                   uint32_t page_size) /**< size of each page */
128 {
129   parser_mem_page_t *page_p = data_p->first_p;
130 
131   while (page_p != NULL)
132   {
133     parser_mem_page_t *next_p = page_p->next_p;
134 
135     parser_free (page_p, page_size);
136     page_p = next_p;
137   }
138 } /* parser_data_free */
139 
140 /**********************************************************************/
141 /* Parser byte stream management functions                            */
142 /**********************************************************************/
143 
144 /**
145  * Initialize byte stream.
146  */
147 void
parser_cbc_stream_init(parser_mem_data_t * data_p)148 parser_cbc_stream_init (parser_mem_data_t *data_p) /**< memory manager */
149 {
150   parser_data_init (data_p, PARSER_CBC_STREAM_PAGE_SIZE);
151 } /* parser_cbc_stream_init */
152 
153 /**
154  * Free byte stream.
155  */
156 void
parser_cbc_stream_free(parser_mem_data_t * data_p)157 parser_cbc_stream_free (parser_mem_data_t *data_p) /**< memory manager */
158 {
159   parser_data_free (data_p,
160                     sizeof (parser_mem_page_t *) + PARSER_CBC_STREAM_PAGE_SIZE);
161 } /* parser_cbc_stream_free */
162 
163 /**
164  * Appends a byte at the end of the byte stream.
165  */
166 void
parser_cbc_stream_alloc_page(parser_context_t * context_p,parser_mem_data_t * data_p)167 parser_cbc_stream_alloc_page (parser_context_t *context_p, /**< context */
168                               parser_mem_data_t *data_p) /**< memory manager */
169 {
170   size_t size = sizeof (parser_mem_page_t *) + PARSER_CBC_STREAM_PAGE_SIZE;
171   parser_mem_page_t *page_p = (parser_mem_page_t *) parser_malloc (context_p, size);
172 
173   page_p->next_p = NULL;
174   data_p->last_position = 0;
175 
176   if (data_p->last_p != NULL)
177   {
178     data_p->last_p->next_p = page_p;
179   }
180   else
181   {
182     data_p->first_p = page_p;
183   }
184   data_p->last_p = page_p;
185 } /* parser_cbc_stream_alloc_page */
186 
187 /**********************************************************************/
188 /* Parser list management functions                                   */
189 /**********************************************************************/
190 
191 /**
192  * Initialize parser list.
193  */
194 void
parser_list_init(parser_list_t * list_p,uint32_t item_size,uint32_t item_count)195 parser_list_init (parser_list_t *list_p, /**< parser list */
196                   uint32_t item_size, /**< size for each page */
197                   uint32_t item_count) /**< number of items on each page */
198 {
199   /* Align to pointer size. */
200   item_size = (uint32_t) (((item_size) + sizeof (void *) - 1) & ~(sizeof (void *) - 1));
201   parser_data_init (&list_p->data, item_size * item_count);
202   list_p->page_size = item_size * item_count;
203   list_p->item_size = item_size;
204   list_p->item_count = item_count;
205 } /* parser_list_init */
206 
207 /**
208  * Free parser list.
209  */
210 void
parser_list_free(parser_list_t * list_p)211 parser_list_free (parser_list_t *list_p) /**< parser list */
212 {
213   parser_data_free (&list_p->data,
214                     (uint32_t) (sizeof (parser_mem_page_t *) + list_p->page_size));
215 } /* parser_list_free */
216 
217 /**
218  * Reset parser list.
219  */
220 void
parser_list_reset(parser_list_t * list_p)221 parser_list_reset (parser_list_t *list_p) /**< parser list */
222 {
223   parser_data_init (&list_p->data, list_p->page_size);
224 } /* parser_list_reset */
225 
226 /**
227  * Allocate space for the next item.
228  *
229  * @return pointer to the appended item.
230  */
231 void *
parser_list_append(parser_context_t * context_p,parser_list_t * list_p)232 parser_list_append (parser_context_t *context_p, /**< context */
233                     parser_list_t *list_p) /**< parser list */
234 {
235   parser_mem_page_t *page_p = list_p->data.last_p;
236   void *result;
237 
238   if (list_p->data.last_position + list_p->item_size > list_p->page_size)
239   {
240     size_t size = sizeof (parser_mem_page_t *) + list_p->page_size;
241 
242     page_p = (parser_mem_page_t *) parser_malloc (context_p, size);
243 
244     page_p->next_p = NULL;
245     list_p->data.last_position = 0;
246 
247     if (list_p->data.last_p != NULL)
248     {
249       list_p->data.last_p->next_p = page_p;
250     }
251     else
252     {
253       list_p->data.first_p = page_p;
254     }
255     list_p->data.last_p = page_p;
256   }
257 
258   result = page_p->bytes + list_p->data.last_position;
259   list_p->data.last_position += list_p->item_size;
260   return result;
261 } /* parser_list_append */
262 
263 /**
264  * Return the nth item of the list.
265  *
266  * @return pointer to the item.
267  */
268 void *
parser_list_get(parser_list_t * list_p,size_t index)269 parser_list_get (parser_list_t *list_p, /**< parser list */
270                  size_t index) /**< item index */
271 {
272   size_t item_count = list_p->item_count;
273   parser_mem_page_t *page_p = list_p->data.first_p;
274 
275   while (index >= item_count)
276   {
277     JERRY_ASSERT (page_p != NULL);
278     page_p = page_p->next_p;
279     index -= item_count;
280   }
281 
282   JERRY_ASSERT (page_p != NULL);
283   JERRY_ASSERT (page_p != list_p->data.last_p
284                 || (index * list_p->item_size < list_p->data.last_position));
285   return page_p->bytes + (index * list_p->item_size);
286 } /* parser_list_get */
287 
288 /**
289  * Initialize a parser list iterator.
290  */
291 void
parser_list_iterator_init(parser_list_t * list_p,parser_list_iterator_t * iterator_p)292 parser_list_iterator_init (parser_list_t *list_p, /**< parser list */
293                            parser_list_iterator_t *iterator_p) /**< iterator */
294 {
295   iterator_p->list_p = list_p;
296   iterator_p->current_p = list_p->data.first_p;
297   iterator_p->current_position = 0;
298 } /* parser_list_iterator_init */
299 
300 /**
301  * Next iterator step.
302  *
303  * @return the address of the current item, or NULL at the end.
304  */
305 void *
parser_list_iterator_next(parser_list_iterator_t * iterator_p)306 parser_list_iterator_next (parser_list_iterator_t *iterator_p) /**< iterator */
307 {
308   void *result;
309 
310   if (iterator_p->current_p == NULL)
311   {
312     return NULL;
313   }
314 
315   result = iterator_p->current_p->bytes + iterator_p->current_position;
316   iterator_p->current_position += iterator_p->list_p->item_size;
317 
318   if (iterator_p->current_p->next_p == NULL)
319   {
320     if (iterator_p->current_position >= iterator_p->list_p->data.last_position)
321     {
322       iterator_p->current_p = NULL;
323       iterator_p->current_position = 0;
324     }
325   }
326   else if (iterator_p->current_position >= iterator_p->list_p->page_size)
327   {
328     iterator_p->current_p = iterator_p->current_p->next_p;
329     iterator_p->current_position = 0;
330   }
331   return result;
332 } /* parser_list_iterator_next */
333 
334 /**********************************************************************/
335 /* Parser stack management functions                                  */
336 /**********************************************************************/
337 
338 /* Stack is a reversed storage. */
339 
340 /**
341  * Initialize parser stack.
342  */
343 void
parser_stack_init(parser_context_t * context_p)344 parser_stack_init (parser_context_t *context_p) /**< context */
345 {
346   parser_data_init (&context_p->stack, PARSER_STACK_PAGE_SIZE);
347   context_p->free_page_p = NULL;
348 } /* parser_stack_init */
349 
350 /**
351  * Free parser stack.
352  */
353 void
parser_stack_free(parser_context_t * context_p)354 parser_stack_free (parser_context_t *context_p) /**< context */
355 {
356   parser_data_free (&context_p->stack,
357                     sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE);
358 
359   if (context_p->free_page_p != NULL)
360   {
361     parser_free (context_p->free_page_p,
362                  sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE);
363   }
364 } /* parser_stack_free */
365 
366 /**
367  * Pushes an uint8_t value onto the stack.
368  */
369 void
parser_stack_push_uint8(parser_context_t * context_p,uint8_t uint8_value)370 parser_stack_push_uint8 (parser_context_t *context_p, /**< context */
371                          uint8_t uint8_value) /**< value pushed onto the stack */
372 {
373   parser_mem_page_t *page_p = context_p->stack.first_p;
374 
375   /* This assert might trigger false positive valgrind errors, when
376    * parser_stack_push() pushes not fully initialized structures.
377    * More precisely when the last byte of the structure is uninitialized. */
378   JERRY_ASSERT (page_p == NULL
379                 || context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]);
380 
381   if (context_p->stack.last_position >= PARSER_STACK_PAGE_SIZE)
382   {
383     if (context_p->free_page_p != NULL)
384     {
385       page_p = context_p->free_page_p;
386       context_p->free_page_p = NULL;
387     }
388     else
389     {
390       size_t size = sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE;
391       page_p = (parser_mem_page_t *) parser_malloc (context_p, size);
392     }
393 
394     page_p->next_p = context_p->stack.first_p;
395     context_p->stack.last_position = 0;
396     context_p->stack.first_p = page_p;
397   }
398 
399   page_p->bytes[context_p->stack.last_position++] = uint8_value;
400   context_p->stack_top_uint8 = uint8_value;
401 } /* parser_stack_push_uint8 */
402 
403 /**
404  * Pops the last uint8_t value from the stack.
405  */
406 void
parser_stack_pop_uint8(parser_context_t * context_p)407 parser_stack_pop_uint8 (parser_context_t *context_p) /**< context */
408 {
409   parser_mem_page_t *page_p = context_p->stack.first_p;
410 
411   JERRY_ASSERT (page_p != NULL
412                 && context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]);
413 
414   context_p->stack.last_position--;
415 
416   if (context_p->stack.last_position == 0)
417   {
418     context_p->stack.first_p = page_p->next_p;
419     context_p->stack.last_position = PARSER_STACK_PAGE_SIZE;
420 
421     if (context_p->free_page_p == NULL)
422     {
423       context_p->free_page_p = page_p;
424     }
425     else
426     {
427       parser_free (page_p,
428                    sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE);
429     }
430 
431     page_p = context_p->stack.first_p;
432 
433     JERRY_ASSERT (page_p != NULL);
434   }
435 
436   context_p->stack_top_uint8 = page_p->bytes[context_p->stack.last_position - 1];
437 } /* parser_stack_pop_uint8 */
438 
439 /**
440  * Pushes an uint16_t value onto the stack.
441  */
442 void
parser_stack_push_uint16(parser_context_t * context_p,uint16_t uint16_value)443 parser_stack_push_uint16 (parser_context_t *context_p, /**< context */
444                           uint16_t uint16_value) /**< value pushed onto the stack */
445 {
446   if (context_p->stack.last_position + 2 <= PARSER_STACK_PAGE_SIZE)
447   {
448     parser_mem_page_t *page_p = context_p->stack.first_p;
449 
450     JERRY_ASSERT (page_p != NULL
451                   && context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]);
452 
453     page_p->bytes[context_p->stack.last_position++] = (uint8_t) (uint16_value >> 8);
454     page_p->bytes[context_p->stack.last_position++] = (uint8_t) uint16_value;
455     context_p->stack_top_uint8 = (uint8_t) uint16_value;
456   }
457   else
458   {
459     parser_stack_push_uint8 (context_p, (uint8_t) (uint16_value >> 8));
460     parser_stack_push_uint8 (context_p, (uint8_t) uint16_value);
461   }
462 } /* parser_stack_push_uint16 */
463 
464 /**
465  * Pops the last uint16_t value from the stack.
466  *
467  * @return the value popped from the stack.
468  */
469 uint16_t
parser_stack_pop_uint16(parser_context_t * context_p)470 parser_stack_pop_uint16 (parser_context_t *context_p) /**< context */
471 {
472   uint32_t value = context_p->stack_top_uint8;
473 
474   if (context_p->stack.last_position >= 3)
475   {
476     parser_mem_page_t *page_p = context_p->stack.first_p;
477 
478     JERRY_ASSERT (page_p != NULL
479                   && context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]);
480 
481     value |= ((uint32_t) page_p->bytes[context_p->stack.last_position - 2]) << 8;
482     context_p->stack_top_uint8 = page_p->bytes[context_p->stack.last_position - 3];
483     context_p->stack.last_position -= 2;
484   }
485   else
486   {
487     parser_stack_pop_uint8 (context_p);
488     value |= ((uint32_t) context_p->stack_top_uint8) << 8;
489     parser_stack_pop_uint8 (context_p);
490   }
491   return (uint16_t) value;
492 } /* parser_stack_pop_uint16 */
493 
494 /**
495  * Pushes a data onto the stack.
496  */
497 void
parser_stack_push(parser_context_t * context_p,const void * data_p,uint32_t length)498 parser_stack_push (parser_context_t *context_p, /**< context */
499                    const void *data_p, /**< data pushed onto the stack */
500                    uint32_t length) /**< length of the data */
501 {
502   uint32_t fragment_length = PARSER_STACK_PAGE_SIZE - context_p->stack.last_position;
503   const uint8_t *bytes_p = (const uint8_t *) data_p;
504   parser_mem_page_t *page_p;
505 
506   JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
507 
508   context_p->stack_top_uint8 = bytes_p[length - 1];
509 
510   if (fragment_length > 0)
511   {
512     /* Fill the remaining bytes. */
513     if (fragment_length > length)
514     {
515       fragment_length = length;
516     }
517 
518     memcpy (context_p->stack.first_p->bytes + context_p->stack.last_position,
519             bytes_p,
520             fragment_length);
521 
522     if (fragment_length == length)
523     {
524       context_p->stack.last_position += length;
525       return;
526     }
527 
528     bytes_p += fragment_length;
529     length -= fragment_length;
530   }
531 
532   if (context_p->free_page_p != NULL)
533   {
534     page_p = context_p->free_page_p;
535     context_p->free_page_p = NULL;
536   }
537   else
538   {
539     size_t size = sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE;
540 
541     page_p = (parser_mem_page_t *) parser_malloc (context_p, size);
542   }
543 
544   page_p->next_p = context_p->stack.first_p;
545 
546   context_p->stack.first_p = page_p;
547 
548   memcpy (page_p->bytes, bytes_p, length);
549   context_p->stack.last_position = length;
550 } /* parser_stack_push */
551 
552 /**
553  * Pop bytes from the top of the stack.
554  */
555 void
parser_stack_pop(parser_context_t * context_p,void * data_p,uint32_t length)556 parser_stack_pop (parser_context_t *context_p, /**< context */
557                   void *data_p, /**< destination buffer, can be NULL */
558                   uint32_t length) /**< length of the data */
559 {
560   uint8_t *bytes_p = (uint8_t *) data_p;
561   parser_mem_page_t *page_p = context_p->stack.first_p;
562 
563   JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
564 
565   if (context_p->stack.last_position > length)
566   {
567     context_p->stack.last_position -= length;
568     context_p->stack_top_uint8 = page_p->bytes[context_p->stack.last_position - 1];
569 
570     if (bytes_p != NULL)
571     {
572       memcpy (bytes_p, context_p->stack.first_p->bytes + context_p->stack.last_position, length);
573     }
574     return;
575   }
576 
577   JERRY_ASSERT (page_p->next_p != NULL);
578 
579   length -= context_p->stack.last_position;
580 
581   if (bytes_p != NULL)
582   {
583     memcpy (bytes_p + length, page_p->bytes, context_p->stack.last_position);
584   }
585 
586   context_p->stack.first_p = page_p->next_p;
587   context_p->stack.last_position = PARSER_STACK_PAGE_SIZE - length;
588   context_p->stack_top_uint8 = page_p->next_p->bytes[context_p->stack.last_position - 1];
589 
590   if (bytes_p != NULL && length > 0)
591   {
592     memcpy (bytes_p, page_p->next_p->bytes + context_p->stack.last_position, length);
593   }
594 
595   JERRY_ASSERT (context_p->stack.last_position > 0);
596 
597   if (context_p->free_page_p == NULL)
598   {
599     context_p->free_page_p = page_p;
600   }
601   else
602   {
603     parser_free (page_p,
604                  sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE);
605   }
606 } /* parser_stack_pop */
607 
608 /**
609  * Skip the next n bytes of the stack.
610  */
611 void
parser_stack_iterator_skip(parser_stack_iterator_t * iterator,size_t length)612 parser_stack_iterator_skip (parser_stack_iterator_t *iterator, /**< iterator */
613                             size_t length) /**< number of skipped bytes */
614 {
615   JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
616 
617   if (length < iterator->current_position)
618   {
619     iterator->current_position -= length;
620   }
621   else
622   {
623     iterator->current_position = PARSER_STACK_PAGE_SIZE - (length - iterator->current_position);
624     iterator->current_p = iterator->current_p->next_p;
625   }
626 } /* parser_stack_iterator_skip */
627 
628 /**
629  * Read bytes from the stack.
630  */
631 void
parser_stack_iterator_read(parser_stack_iterator_t * iterator,void * data_p,size_t length)632 parser_stack_iterator_read (parser_stack_iterator_t *iterator, /**< iterator */
633                             void *data_p, /**< destination buffer */
634                             size_t length) /**< length of the data */
635 {
636   uint8_t *bytes_p = (uint8_t *) data_p;
637 
638   JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
639 
640   if (length <= iterator->current_position)
641   {
642     memcpy (bytes_p,
643             iterator->current_p->bytes + iterator->current_position - length,
644             length);
645   }
646   else
647   {
648     JERRY_ASSERT (iterator->current_p->next_p != NULL);
649 
650     length -= iterator->current_position;
651     memcpy (bytes_p + length,
652             iterator->current_p->bytes,
653             iterator->current_position);
654     memcpy (bytes_p,
655             iterator->current_p->next_p->bytes + PARSER_STACK_PAGE_SIZE - length,
656             length);
657   }
658 } /* parser_stack_iterator_read */
659 
660 /**
661  * Write bytes onto the stack.
662  */
663 void
parser_stack_iterator_write(parser_stack_iterator_t * iterator,const void * data_p,size_t length)664 parser_stack_iterator_write (parser_stack_iterator_t *iterator, /**< iterator */
665                              const void *data_p, /**< destination buffer */
666                              size_t length) /**< length of the data */
667 {
668   const uint8_t *bytes_p = (const uint8_t *) data_p;
669 
670   JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
671 
672   if (length <= iterator->current_position)
673   {
674     memcpy (iterator->current_p->bytes + iterator->current_position - length,
675             bytes_p,
676             length);
677   }
678   else
679   {
680     JERRY_ASSERT (iterator->current_p->next_p != NULL);
681 
682     length -= iterator->current_position;
683     memcpy (iterator->current_p->bytes,
684             bytes_p + length,
685             iterator->current_position);
686     memcpy (iterator->current_p->next_p->bytes + PARSER_STACK_PAGE_SIZE - length,
687             bytes_p,
688             length);
689   }
690 } /* parser_stack_iterator_write */
691 
692 /**
693  * @}
694  * @}
695  */
696 
697 #endif /* ENABLED (JERRY_PARSER) */
698