• 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 "ecma-alloc.h"
17 #include "ecma-literal-storage.h"
18 #include "ecma-helpers.h"
19 #include "jcontext.h"
20 
21 /** \addtogroup ecma ECMA
22  * @{
23  *
24  * \addtogroup ecmalitstorage Literal storage
25  * @{
26  */
27 
28 #if ENABLED (JERRY_ES2015)
29 /**
30  * Free symbol list
31  */
32 static void
ecma_free_symbol_list(jmem_cpointer_t symbol_list_cp)33 ecma_free_symbol_list (jmem_cpointer_t symbol_list_cp) /**< symbol list */
34 {
35   while (symbol_list_cp != JMEM_CP_NULL)
36   {
37     ecma_lit_storage_item_t *symbol_list_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_lit_storage_item_t, symbol_list_cp);
38 
39     for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
40     {
41       if (symbol_list_p->values[i] != JMEM_CP_NULL)
42       {
43         ecma_string_t *string_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t,
44                                                                 symbol_list_p->values[i]);
45 
46         JERRY_ASSERT (ECMA_STRING_IS_REF_EQUALS_TO_ONE (string_p));
47         ecma_deref_ecma_string (string_p);
48       }
49     }
50 
51     jmem_cpointer_t next_item_cp = symbol_list_p->next_cp;
52     jmem_pools_free (symbol_list_p, sizeof (ecma_lit_storage_item_t));
53     symbol_list_cp = next_item_cp;
54   }
55 } /* ecma_free_symbol_list */
56 #endif /* ENABLED (JERRY_ES2015) */
57 
58 /**
59  * Free string list
60  */
61 static void
ecma_free_string_list(jmem_cpointer_t string_list_cp)62 ecma_free_string_list (jmem_cpointer_t string_list_cp) /**< string list */
63 {
64   while (string_list_cp != JMEM_CP_NULL)
65   {
66     ecma_lit_storage_item_t *string_list_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_lit_storage_item_t, string_list_cp);
67 
68     for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
69     {
70       if (string_list_p->values[i] != JMEM_CP_NULL)
71       {
72         ecma_string_t *string_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t,
73                                                                 string_list_p->values[i]);
74 
75         JERRY_ASSERT (ECMA_STRING_IS_REF_EQUALS_TO_ONE (string_p));
76         ecma_destroy_ecma_string (string_p);
77       }
78     }
79 
80     jmem_cpointer_t next_item_cp = string_list_p->next_cp;
81     jmem_pools_free (string_list_p, sizeof (ecma_lit_storage_item_t));
82     string_list_cp = next_item_cp;
83   }
84 } /* ecma_free_string_list */
85 
86 /**
87  * Free number list
88  */
89 static void
ecma_free_number_list(jmem_cpointer_t number_list_cp)90 ecma_free_number_list (jmem_cpointer_t number_list_cp) /**< string list */
91 {
92   while (number_list_cp != JMEM_CP_NULL)
93   {
94     ecma_number_storage_item_t *number_list_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_number_storage_item_t,
95                                                                               number_list_cp);
96 
97     for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
98     {
99       if (number_list_p->values[i] != JMEM_CP_NULL)
100       {
101         ecma_number_t *num_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_number_t, number_list_p->values[i]);
102         ecma_dealloc_number (num_p);
103       }
104     }
105 
106     jmem_cpointer_t next_item_cp = number_list_p->next_cp;
107     jmem_pools_free (number_list_p, sizeof (ecma_number_storage_item_t));
108     number_list_cp = next_item_cp;
109   }
110 } /* ecma_free_number_list */
111 
112 /**
113  * Finalize literal storage
114  */
115 void
ecma_finalize_lit_storage(void)116 ecma_finalize_lit_storage (void)
117 {
118 #if ENABLED (JERRY_ES2015)
119   ecma_free_symbol_list (JERRY_CONTEXT (symbol_list_first_cp));
120 #endif /* ENABLED (JERRY_ES2015) */
121   ecma_free_string_list (JERRY_CONTEXT (string_list_first_cp));
122   ecma_free_number_list (JERRY_CONTEXT (number_list_first_cp));
123 } /* ecma_finalize_lit_storage */
124 
125 /**
126  * Find or create a literal string.
127  *
128  * @return ecma_string_t compressed pointer
129  */
130 ecma_value_t
ecma_find_or_create_literal_string(const lit_utf8_byte_t * chars_p,lit_utf8_size_t size)131 ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, /**< string to be searched */
132                                     lit_utf8_size_t size) /**< size of the string */
133 {
134   ecma_string_t *string_p = ecma_new_ecma_string_from_utf8 (chars_p, size);
135 
136   if (ECMA_IS_DIRECT_STRING (string_p))
137   {
138     return ecma_make_string_value (string_p);
139   }
140 
141   jmem_cpointer_t string_list_cp = JERRY_CONTEXT (string_list_first_cp);
142   jmem_cpointer_t *empty_cpointer_p = NULL;
143 
144   while (string_list_cp != JMEM_CP_NULL)
145   {
146     ecma_lit_storage_item_t *string_list_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_lit_storage_item_t, string_list_cp);
147 
148     for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
149     {
150       if (string_list_p->values[i] == JMEM_CP_NULL)
151       {
152         if (empty_cpointer_p == NULL)
153         {
154           empty_cpointer_p = string_list_p->values + i;
155         }
156       }
157       else
158       {
159         ecma_string_t *value_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t,
160                                                                string_list_p->values[i]);
161 
162         if (ecma_compare_ecma_strings (string_p, value_p))
163         {
164           /* Return with string if found in the list. */
165           ecma_deref_ecma_string (string_p);
166           return ecma_make_string_value (value_p);
167         }
168       }
169     }
170 
171     string_list_cp = string_list_p->next_cp;
172   }
173 
174   ECMA_SET_STRING_AS_STATIC (string_p);
175   jmem_cpointer_t result;
176   JMEM_CP_SET_NON_NULL_POINTER (result, string_p);
177 
178   if (empty_cpointer_p != NULL)
179   {
180     *empty_cpointer_p = result;
181     return ecma_make_string_value (string_p);
182   }
183 
184   ecma_lit_storage_item_t *new_item_p;
185   new_item_p = (ecma_lit_storage_item_t *) jmem_pools_alloc (sizeof (ecma_lit_storage_item_t));
186 
187   new_item_p->values[0] = result;
188   for (int i = 1; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
189   {
190     new_item_p->values[i] = JMEM_CP_NULL;
191   }
192 
193   new_item_p->next_cp = JERRY_CONTEXT (string_list_first_cp);
194   JMEM_CP_SET_NON_NULL_POINTER (JERRY_CONTEXT (string_list_first_cp), new_item_p);
195 
196   return ecma_make_string_value (string_p);
197 } /* ecma_find_or_create_literal_string */
198 
199 /**
200  * Find or create a literal number.
201  *
202  * @return ecma_string_t compressed pointer
203  */
204 ecma_value_t
ecma_find_or_create_literal_number(ecma_number_t number_arg)205 ecma_find_or_create_literal_number (ecma_number_t number_arg) /**< number to be searched */
206 {
207   ecma_value_t num = ecma_make_number_value (number_arg);
208 
209   if (ecma_is_value_integer_number (num))
210   {
211     return num;
212   }
213 
214   JERRY_ASSERT (ecma_is_value_float_number (num));
215 
216   jmem_cpointer_t number_list_cp = JERRY_CONTEXT (number_list_first_cp);
217   jmem_cpointer_t *empty_cpointer_p = NULL;
218 
219   while (number_list_cp != JMEM_CP_NULL)
220   {
221     ecma_number_storage_item_t *number_list_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_number_storage_item_t,
222                                                                               number_list_cp);
223 
224     for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
225     {
226       if (number_list_p->values[i] == JMEM_CP_NULL)
227       {
228         if (empty_cpointer_p == NULL)
229         {
230           empty_cpointer_p = number_list_p->values + i;
231         }
232       }
233       else
234       {
235         ecma_number_t *number_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_number_t,
236                                                                 number_list_p->values[i]);
237 
238         if (*number_p == number_arg)
239         {
240           ecma_free_value (num);
241           return ecma_make_float_value (number_p);
242         }
243       }
244     }
245 
246     number_list_cp = number_list_p->next_cp;
247   }
248 
249   ecma_number_t *num_p = ecma_get_pointer_from_float_value (num);
250 
251   jmem_cpointer_t result;
252   JMEM_CP_SET_NON_NULL_POINTER (result, num_p);
253 
254   if (empty_cpointer_p != NULL)
255   {
256     *empty_cpointer_p = result;
257     return num;
258   }
259 
260   ecma_number_storage_item_t *new_item_p;
261   new_item_p = (ecma_number_storage_item_t *) jmem_pools_alloc (sizeof (ecma_number_storage_item_t));
262 
263   new_item_p->values[0] = result;
264   for (int i = 1; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++)
265   {
266     new_item_p->values[i] = JMEM_CP_NULL;
267   }
268 
269   new_item_p->next_cp = JERRY_CONTEXT (number_list_first_cp);
270   JMEM_CP_SET_NON_NULL_POINTER (JERRY_CONTEXT (number_list_first_cp), new_item_p);
271 
272   return num;
273 } /* ecma_find_or_create_literal_number */
274 
275 /**
276  * Log2 of snapshot literal alignment.
277  */
278 #define JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG 1
279 
280 /**
281  * Snapshot literal alignment.
282  */
283 #define JERRY_SNAPSHOT_LITERAL_ALIGNMENT (1u << JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG)
284 
285 /**
286  * Literal offset shift.
287  */
288 #define JERRY_SNAPSHOT_LITERAL_SHIFT (ECMA_VALUE_SHIFT + 1)
289 
290 /**
291  * Literal value is number.
292  */
293 #define JERRY_SNAPSHOT_LITERAL_IS_NUMBER (1u << ECMA_VALUE_SHIFT)
294 
295 #if ENABLED (JERRY_SNAPSHOT_SAVE)
296 
297 /**
298  * Append the value at the end of the appropriate list if it is not present there.
299  */
ecma_save_literals_append_value(ecma_value_t value,ecma_collection_t * lit_pool_p)300 void ecma_save_literals_append_value (ecma_value_t value, /**< value to be appended */
301                                       ecma_collection_t *lit_pool_p) /**< list of known values */
302 {
303   /* Unlike direct numbers, direct strings are converted to character literals. */
304   if (!ecma_is_value_string (value) && !ecma_is_value_float_number (value))
305   {
306     return;
307   }
308 
309   ecma_value_t *buffer_p = lit_pool_p->buffer_p;
310 
311   for (uint32_t i = 0; i < lit_pool_p->item_count; i++)
312   {
313     /* Strings / numbers are direct strings or stored in the literal storage.
314      * Therefore direct comparison is enough to find the same strings / numbers. */
315     if (buffer_p[i] == value)
316     {
317       return;
318     }
319   }
320 
321   ecma_collection_push_back (lit_pool_p, value);
322 } /* ecma_save_literals_append_value */
323 
324 /**
325  * Add names from a byte-code data to a list.
326  */
327 void
ecma_save_literals_add_compiled_code(const ecma_compiled_code_t * compiled_code_p,ecma_collection_t * lit_pool_p)328 ecma_save_literals_add_compiled_code (const ecma_compiled_code_t *compiled_code_p, /**< byte-code data */
329                                       ecma_collection_t *lit_pool_p) /**< list of known values */
330 {
331   ecma_value_t *literal_p;
332   uint32_t argument_end = 0;
333   uint32_t register_end;
334   uint32_t const_literal_end;
335   uint32_t literal_end;
336 
337   JERRY_ASSERT (compiled_code_p->status_flags & CBC_CODE_FLAGS_FUNCTION);
338 
339   if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
340   {
341     cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) compiled_code_p;
342     uint8_t *byte_p = (uint8_t *) compiled_code_p;
343 
344     literal_p = (ecma_value_t *) (byte_p + sizeof (cbc_uint16_arguments_t));
345     register_end = args_p->register_end;
346     const_literal_end = args_p->const_literal_end - register_end;
347     literal_end = args_p->literal_end - register_end;
348 
349     if (compiled_code_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED)
350     {
351       argument_end = args_p->argument_end;
352     }
353   }
354   else
355   {
356     cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) compiled_code_p;
357     uint8_t *byte_p = (uint8_t *) compiled_code_p;
358 
359     literal_p = (ecma_value_t *) (byte_p + sizeof (cbc_uint8_arguments_t));
360     register_end = args_p->register_end;
361     const_literal_end = args_p->const_literal_end - register_end;
362     literal_end = args_p->literal_end - register_end;
363 
364     if (compiled_code_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED)
365     {
366       argument_end = args_p->argument_end;
367     }
368   }
369 
370   for (uint32_t i = 0; i < argument_end; i++)
371   {
372     ecma_save_literals_append_value (literal_p[i], lit_pool_p);
373   }
374 
375   for (uint32_t i = 0; i < const_literal_end; i++)
376   {
377     ecma_save_literals_append_value (literal_p[i], lit_pool_p);
378   }
379 
380   for (uint32_t i = const_literal_end; i < literal_end; i++)
381   {
382     ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t,
383                                                                         literal_p[i]);
384 
385     if ((bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION)
386         && bytecode_p != compiled_code_p)
387     {
388       ecma_save_literals_add_compiled_code (bytecode_p, lit_pool_p);
389     }
390   }
391 
392   if (argument_end != 0)
393   {
394     uint8_t *byte_p = (uint8_t *) compiled_code_p;
395     byte_p += ((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG;
396     literal_p = ((ecma_value_t *) byte_p) - argument_end;
397 
398     for (uint32_t i = 0; i < argument_end; i++)
399     {
400       ecma_save_literals_append_value (literal_p[i], lit_pool_p);
401     }
402   }
403 } /* ecma_save_literals_add_compiled_code */
404 
405 /**
406  * Save literals to specified snapshot buffer.
407  *
408  * Note:
409  *      Frees 'lit_pool_p' regardless of success.
410  *
411  * @return true - if save was performed successfully (i.e. buffer size is sufficient),
412  *         false - otherwise
413  */
414 bool
ecma_save_literals_for_snapshot(ecma_collection_t * lit_pool_p,uint32_t * buffer_p,size_t buffer_size,size_t * in_out_buffer_offset_p,lit_mem_to_snapshot_id_map_entry_t ** out_map_p,uint32_t * out_map_len_p)415 ecma_save_literals_for_snapshot (ecma_collection_t *lit_pool_p, /**< list of known values */
416                                  uint32_t *buffer_p, /**< [out] output snapshot buffer */
417                                  size_t buffer_size, /**< size of the buffer */
418                                  size_t *in_out_buffer_offset_p, /**< [in,out] write position in the buffer */
419                                  lit_mem_to_snapshot_id_map_entry_t **out_map_p, /**< [out] map from literal identifiers
420                                                                                   *   to the literal offsets
421                                                                                   *   in snapshot */
422                                  uint32_t *out_map_len_p) /**< [out] number of literals */
423 {
424   if (lit_pool_p->item_count == 0)
425   {
426     *out_map_p = NULL;
427     *out_map_len_p = 0;
428   }
429 
430   uint32_t lit_table_size = 0;
431   size_t max_lit_table_size = buffer_size - *in_out_buffer_offset_p;
432 
433   if (max_lit_table_size > (UINT32_MAX >> JERRY_SNAPSHOT_LITERAL_SHIFT))
434   {
435     max_lit_table_size = (UINT32_MAX >> JERRY_SNAPSHOT_LITERAL_SHIFT);
436   }
437 
438   ecma_value_t *lit_buffer_p = lit_pool_p->buffer_p;
439 
440   /* Compute the size of the literal pool. */
441   for (uint32_t i = 0; i < lit_pool_p->item_count; i++)
442   {
443     if (ecma_is_value_float_number (lit_buffer_p[i]))
444     {
445       lit_table_size += (uint32_t) sizeof (ecma_number_t);
446     }
447     else
448     {
449       ecma_string_t *string_p = ecma_get_string_from_value (lit_buffer_p[i]);
450 
451       lit_table_size += (uint32_t) JERRY_ALIGNUP (sizeof (uint16_t) + ecma_string_get_size (string_p),
452                                                   JERRY_SNAPSHOT_LITERAL_ALIGNMENT);
453     }
454 
455     /* Check whether enough space is available and the maximum size is not reached. */
456     if (lit_table_size > max_lit_table_size)
457     {
458       ecma_collection_destroy (lit_pool_p);
459       return false;
460     }
461   }
462 
463   lit_mem_to_snapshot_id_map_entry_t *map_p;
464   ecma_length_t total_count = lit_pool_p->item_count;
465 
466   map_p = jmem_heap_alloc_block (total_count * sizeof (lit_mem_to_snapshot_id_map_entry_t));
467 
468   /* Set return values (no error is possible from here). */
469   JERRY_ASSERT ((*in_out_buffer_offset_p % sizeof (uint32_t)) == 0);
470 
471   uint8_t *destination_p = (uint8_t *) (buffer_p + (*in_out_buffer_offset_p / sizeof (uint32_t)));
472   uint32_t literal_offset = 0;
473 
474   *in_out_buffer_offset_p += lit_table_size;
475   *out_map_p = map_p;
476   *out_map_len_p = total_count;
477 
478   lit_buffer_p = lit_pool_p->buffer_p;
479 
480   /* Generate literal pool data. */
481   for (uint32_t i = 0; i < lit_pool_p->item_count; i++)
482   {
483     map_p->literal_id = lit_buffer_p[i];
484     map_p->literal_offset = (literal_offset << JERRY_SNAPSHOT_LITERAL_SHIFT) | ECMA_TYPE_SNAPSHOT_OFFSET;
485 
486     ecma_length_t length;
487 
488     if (ecma_is_value_float_number (lit_buffer_p[i]))
489     {
490       map_p->literal_offset |= JERRY_SNAPSHOT_LITERAL_IS_NUMBER;
491 
492       ecma_number_t num = ecma_get_float_from_value (lit_buffer_p[i]);
493       memcpy (destination_p, &num, sizeof (ecma_number_t));
494 
495       length = JERRY_ALIGNUP (sizeof (ecma_number_t), JERRY_SNAPSHOT_LITERAL_ALIGNMENT);
496     }
497     else
498     {
499       ecma_string_t *string_p = ecma_get_string_from_value (lit_buffer_p[i]);
500       length = ecma_string_get_size (string_p);
501 
502       *(uint16_t *) destination_p = (uint16_t) length;
503 
504       ecma_string_to_utf8_bytes (string_p, destination_p + sizeof (uint16_t), length);
505 
506       length = JERRY_ALIGNUP (sizeof (uint16_t) + length, JERRY_SNAPSHOT_LITERAL_ALIGNMENT);
507     }
508 
509     JERRY_ASSERT ((length % sizeof (uint16_t)) == 0);
510     destination_p += length;
511     literal_offset += length;
512 
513     map_p++;
514   }
515 
516   ecma_collection_destroy (lit_pool_p);
517   return true;
518 } /* ecma_save_literals_for_snapshot */
519 
520 #endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
521 
522 #if ENABLED (JERRY_SNAPSHOT_EXEC) || ENABLED (JERRY_SNAPSHOT_SAVE)
523 
524 /**
525  * Get the compressed pointer of a given literal.
526  *
527  * @return literal compressed pointer
528  */
529 ecma_value_t
ecma_snapshot_get_literal(const uint8_t * literal_base_p,ecma_value_t literal_value)530 ecma_snapshot_get_literal (const uint8_t *literal_base_p, /**< literal start */
531                            ecma_value_t literal_value) /**< string / number offset */
532 {
533   JERRY_ASSERT ((literal_value & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET);
534 
535   const uint8_t *literal_p = literal_base_p + (literal_value >> JERRY_SNAPSHOT_LITERAL_SHIFT);
536 
537   if (literal_value & JERRY_SNAPSHOT_LITERAL_IS_NUMBER)
538   {
539     ecma_number_t num;
540     memcpy (&num, literal_p, sizeof (ecma_number_t));
541     return ecma_find_or_create_literal_number (num);
542   }
543 
544   uint16_t length = *(const uint16_t *) literal_p;
545 
546   return ecma_find_or_create_literal_string (literal_p + sizeof (uint16_t), length);
547 } /* ecma_snapshot_get_literal */
548 
549 #endif /* ENABLED (JERRY_SNAPSHOT_EXEC) || ENABLED (JERRY_SNAPSHOT_SAVE) */
550 
551 /**
552  * @}
553  * @}
554  */
555