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