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-conversion.h"
17#include "ecma-exceptions.h"
18#include "ecma-function-object.h"
19#include "ecma-helpers.h"
20#include "ecma-lex-env.h"
21#include "ecma-literal-storage.h"
22#include "jcontext.h"
23#include "jerryscript.h"
24#include "jerry-snapshot.h"
25#include "js-parser.h"
26#include "lit-char-helpers.h"
27#include "js-parser-internal.h"
28#include "re-compiler.h"
29
30#if ENABLED (JERRY_SNAPSHOT_SAVE) || ENABLED (JERRY_SNAPSHOT_EXEC)
31
32/**
33 * Get snapshot configuration flags.
34 *
35 * @return configuration flags
36 */
37static inline uint32_t JERRY_ATTR_ALWAYS_INLINE
38snapshot_get_global_flags (bool has_regex, /**< regex literal is present */
39 bool has_class) /**< class literal is present */
40{
41 JERRY_UNUSED (has_regex);
42 JERRY_UNUSED (has_class);
43
44 uint32_t flags = 0;
45
46#if ENABLED (JERRY_BUILTIN_REGEXP)
47 flags |= (has_regex ? JERRY_SNAPSHOT_HAS_REGEX_LITERAL : 0);
48#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
49#if ENABLED (JERRY_ESNEXT)
50 flags |= (has_class ? JERRY_SNAPSHOT_HAS_CLASS_LITERAL : 0);
51#endif /* ENABLED (JERRY_ESNEXT) */
52#if ENABLED (JERRY_BUILTIN_REALMS)
53 flags |= JERRY_SNAPSHOT_HAS_REALM_VALUE;
54#endif /* ENABLED (JERRY_BUILTIN_REALMS) */
55
56 return flags;
57} /* snapshot_get_global_flags */
58
59/**
60 * Checks whether the global_flags argument matches to the current feature set.
61 *
62 * @return true if global_flags accepted, false otherwise
63 */
64static inline bool JERRY_ATTR_ALWAYS_INLINE
65snapshot_check_global_flags (uint32_t global_flags) /**< global flags */
66{
67#if ENABLED (JERRY_BUILTIN_REGEXP)
68 global_flags &= (uint32_t) ~JERRY_SNAPSHOT_HAS_REGEX_LITERAL;
69#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
70#if ENABLED (JERRY_ESNEXT)
71 global_flags &= (uint32_t) ~JERRY_SNAPSHOT_HAS_CLASS_LITERAL;
72#endif /* ENABLED (JERRY_ESNEXT) */
73#if ENABLED (JERRY_BUILTIN_REALMS)
74 global_flags |= JERRY_SNAPSHOT_HAS_REALM_VALUE;
75#endif /* ENABLED (JERRY_BUILTIN_REALMS) */
76
77 return global_flags == snapshot_get_global_flags (false, false);
78} /* snapshot_check_global_flags */
79
80#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) || ENABLED (JERRY_SNAPSHOT_EXEC) */
81
82#if ENABLED (JERRY_SNAPSHOT_SAVE)
83
84/**
85 * Variables required to take a snapshot.
86 */
87typedef struct
88{
89 size_t snapshot_buffer_write_offset;
90 ecma_value_t snapshot_error;
91 bool regex_found;
92 bool class_found;
93} snapshot_globals_t;
94
95/** \addtogroup jerrysnapshot Jerry snapshot operations
96 * @{
97 */
98
99/**
100 * Write data into the specified buffer.
101 *
102 * Note:
103 * Offset is in-out and is incremented if the write operation completes successfully.
104 *
105 * @return true - if write was successful, i.e. offset + data_size doesn't exceed buffer size,
106 * false - otherwise
107 */
108static inline bool JERRY_ATTR_ALWAYS_INLINE
109snapshot_write_to_buffer_by_offset (uint8_t *buffer_p, /**< buffer */
110 size_t buffer_size, /**< size of buffer */
111 size_t *in_out_buffer_offset_p, /**< [in,out] offset to write to
112 * incremented with data_size */
113 const void *data_p, /**< data */
114 size_t data_size) /**< size of the writable data */
115{
116 if (*in_out_buffer_offset_p + data_size > buffer_size)
117 {
118 return false;
119 }
120
121 memcpy (buffer_p + *in_out_buffer_offset_p, data_p, data_size);
122 *in_out_buffer_offset_p += data_size;
123
124 return true;
125} /* snapshot_write_to_buffer_by_offset */
126
127/**
128 * Maximum snapshot write buffer offset.
129 */
130#if !ENABLED (JERRY_NUMBER_TYPE_FLOAT64)
131#define JERRY_SNAPSHOT_MAXIMUM_WRITE_OFFSET (0x7fffff >> 1)
132#else /* ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */
133#define JERRY_SNAPSHOT_MAXIMUM_WRITE_OFFSET (UINT32_MAX >> 1)
134#endif /* !ENABLED (JERRY_NUMBER_TYPE_FLOAT64) */
135
136/**
137 * Save snapshot helper.
138 *
139 * @return start offset
140 */
141static uint32_t
142snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled code */
143 uint8_t *snapshot_buffer_p, /**< snapshot buffer */
144 size_t snapshot_buffer_size, /**< snapshot buffer size */
145 snapshot_globals_t *globals_p) /**< snapshot globals */
146{
147 const jerry_char_t *error_buffer_too_small_p = (const jerry_char_t *) "Snapshot buffer too small.";
148
149 if (!ecma_is_value_empty (globals_p->snapshot_error))
150 {
151 return 0;
152 }
153
154 JERRY_ASSERT ((globals_p->snapshot_buffer_write_offset & (JMEM_ALIGNMENT - 1)) == 0);
155
156 if (globals_p->snapshot_buffer_write_offset > JERRY_SNAPSHOT_MAXIMUM_WRITE_OFFSET)
157 {
158 const char * const error_message_p = "Maximum snapshot size reached.";
159 globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
160 return 0;
161 }
162
163 /* The snapshot generator always parses a single file,
164 * so the base always starts right after the snapshot header. */
165 uint32_t start_offset = (uint32_t) (globals_p->snapshot_buffer_write_offset - sizeof (jerry_snapshot_header_t));
166
167 uint8_t *copied_code_start_p = snapshot_buffer_p + globals_p->snapshot_buffer_write_offset;
168 ecma_compiled_code_t *copied_code_p = (ecma_compiled_code_t *) copied_code_start_p;
169
170#if ENABLED (JERRY_ESNEXT)
171 if (compiled_code_p->status_flags & CBC_CODE_FLAGS_HAS_TAGGED_LITERALS)
172 {
173 const char * const error_message_p = "Unsupported feature: tagged template literals.";
174 globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
175 return 0;
176 }
177
178 if (CBC_FUNCTION_GET_TYPE (compiled_code_p->status_flags) == CBC_FUNCTION_CONSTRUCTOR)
179 {
180 globals_p->class_found = true;
181 }
182#endif /* ENABLED (JERRY_ESNEXT) */
183
184#if ENABLED (JERRY_BUILTIN_REGEXP)
185 if (!CBC_IS_FUNCTION (compiled_code_p->status_flags))
186 {
187 /* Regular expression. */
188 if (globals_p->snapshot_buffer_write_offset + sizeof (ecma_compiled_code_t) > snapshot_buffer_size)
189 {
190 globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, error_buffer_too_small_p);
191 return 0;
192 }
193
194 globals_p->snapshot_buffer_write_offset += sizeof (ecma_compiled_code_t);
195
196 ecma_value_t pattern = ((re_compiled_code_t *) compiled_code_p)->source;
197 ecma_string_t *pattern_string_p = ecma_get_string_from_value (pattern);
198
199 lit_utf8_size_t pattern_size = 0;
200
201 ECMA_STRING_TO_UTF8_STRING (pattern_string_p, buffer_p, buffer_size);
202
203 pattern_size = buffer_size;
204
205 if (!snapshot_write_to_buffer_by_offset (snapshot_buffer_p,
206 snapshot_buffer_size,
207 &globals_p->snapshot_buffer_write_offset,
208 buffer_p,
209 buffer_size))
210 {
211 globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, error_buffer_too_small_p);
212 /* cannot return inside ECMA_FINALIZE_UTF8_STRING */
213 }
214
215 ECMA_FINALIZE_UTF8_STRING (buffer_p, buffer_size);
216
217 if (!ecma_is_value_empty (globals_p->snapshot_error))
218 {
219 return 0;
220 }
221
222 globals_p->regex_found = true;
223 globals_p->snapshot_buffer_write_offset = JERRY_ALIGNUP (globals_p->snapshot_buffer_write_offset,
224 JMEM_ALIGNMENT);
225
226 /* Regexp character size is stored in refs. */
227 copied_code_p->refs = (uint16_t) pattern_size;
228
229 pattern_size += (lit_utf8_size_t) sizeof (ecma_compiled_code_t);
230 copied_code_p->size = (uint16_t) ((pattern_size + JMEM_ALIGNMENT - 1) >> JMEM_ALIGNMENT_LOG);
231
232 copied_code_p->status_flags = compiled_code_p->status_flags;
233
234 return start_offset;
235 }
236#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
237
238 JERRY_ASSERT (CBC_IS_FUNCTION (compiled_code_p->status_flags));
239
240 if (!snapshot_write_to_buffer_by_offset (snapshot_buffer_p,
241 snapshot_buffer_size,
242 &globals_p->snapshot_buffer_write_offset,
243 compiled_code_p,
244 ((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG))
245 {
246 globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, error_buffer_too_small_p);
247 return 0;
248 }
249
250 /* Sub-functions and regular expressions are stored recursively. */
251 uint8_t *buffer_p = (uint8_t *) copied_code_p;
252 ecma_value_t *literal_start_p;
253 uint32_t const_literal_end;
254 uint32_t literal_end;
255
256 if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
257 {
258 literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint16_arguments_t));
259
260 cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p;
261 literal_end = (uint32_t) (args_p->literal_end - args_p->register_end);
262 const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
263 }
264 else
265 {
266 literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint8_arguments_t));
267
268 cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p;
269 literal_end = (uint32_t) (args_p->literal_end - args_p->register_end);
270 const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
271 }
272
273 for (uint32_t i = const_literal_end; i < literal_end; i++)
274 {
275 ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t,
276 literal_start_p[i]);
277
278 if (bytecode_p == compiled_code_p)
279 {
280 literal_start_p[i] = 0;
281 }
282 else
283 {
284 uint32_t offset = snapshot_add_compiled_code (bytecode_p,
285 snapshot_buffer_p,
286 snapshot_buffer_size,
287 globals_p);
288
289 JERRY_ASSERT (!ecma_is_value_empty (globals_p->snapshot_error) || offset > start_offset);
290
291 literal_start_p[i] = offset - start_offset;
292 }
293 }
294
295 return start_offset;
296} /* snapshot_add_compiled_code */
297
298/**
299 * Create unsupported literal error.
300 */
301static void
302static_snapshot_error_unsupported_literal (snapshot_globals_t *globals_p, /**< snapshot globals */
303 ecma_value_t literal) /**< literal form the literal pool */
304{
305 lit_utf8_byte_t *str_p = (lit_utf8_byte_t *) "Unsupported static snapshot literal: ";
306 ecma_stringbuilder_t builder = ecma_stringbuilder_create_raw (str_p, 37);
307
308 JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (literal));
309
310 ecma_string_t *literal_string_p = ecma_op_to_string (literal);
311 JERRY_ASSERT (literal_string_p != NULL);
312
313 ecma_stringbuilder_append (&builder, literal_string_p);
314
315 ecma_deref_ecma_string (literal_string_p);
316
317 ecma_object_t *error_object_p = ecma_new_standard_error (ECMA_ERROR_RANGE,
318 ecma_stringbuilder_finalize (&builder));
319
320 globals_p->snapshot_error = ecma_create_error_object_reference (error_object_p);
321} /* static_snapshot_error_unsupported_literal */
322
323/**
324 * Save static snapshot helper.
325 *
326 * @return start offset
327 */
328static uint32_t
329static_snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled code */
330 uint8_t *snapshot_buffer_p, /**< snapshot buffer */
331 size_t snapshot_buffer_size, /**< snapshot buffer size */
332 snapshot_globals_t *globals_p) /**< snapshot globals */
333{
334 if (!ecma_is_value_empty (globals_p->snapshot_error))
335 {
336 return 0;
337 }
338
339 JERRY_ASSERT ((globals_p->snapshot_buffer_write_offset & (JMEM_ALIGNMENT - 1)) == 0);
340
341 if (globals_p->snapshot_buffer_write_offset >= JERRY_SNAPSHOT_MAXIMUM_WRITE_OFFSET)
342 {
343 const char * const error_message_p = "Maximum snapshot size reached.";
344 globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
345 return 0;
346 }
347
348 /* The snapshot generator always parses a single file,
349 * so the base always starts right after the snapshot header. */
350 uint32_t start_offset = (uint32_t) (globals_p->snapshot_buffer_write_offset - sizeof (jerry_snapshot_header_t));
351
352 uint8_t *copied_code_start_p = snapshot_buffer_p + globals_p->snapshot_buffer_write_offset;
353 ecma_compiled_code_t *copied_code_p = (ecma_compiled_code_t *) copied_code_start_p;
354
355 if (!CBC_IS_FUNCTION (compiled_code_p->status_flags))
356 {
357 /* Regular expression literals are not supported. */
358 const char * const error_message_p = "Regular expression literals are not supported.";
359 globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
360 return 0;
361 }
362
363 if (!snapshot_write_to_buffer_by_offset (snapshot_buffer_p,
364 snapshot_buffer_size,
365 &globals_p->snapshot_buffer_write_offset,
366 compiled_code_p,
367 ((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG))
368 {
369 const char * const error_message_p = "Snapshot buffer too small.";
370 globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
371 return 0;
372 }
373
374 /* Sub-functions and regular expressions are stored recursively. */
375 uint8_t *buffer_p = (uint8_t *) copied_code_p;
376 ecma_value_t *literal_start_p;
377 uint32_t const_literal_end;
378 uint32_t literal_end;
379
380 ((ecma_compiled_code_t *) copied_code_p)->status_flags |= CBC_CODE_FLAGS_STATIC_FUNCTION;
381
382 if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
383 {
384 literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint16_arguments_t));
385
386 cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p;
387 literal_end = (uint32_t) (args_p->literal_end - args_p->register_end);
388 const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
389
390#if ENABLED (JERRY_BUILTIN_REALMS)
391 args_p->realm_value = JMEM_CP_NULL;
392#endif /* ENABLED (JERRY_BUILTIN_REALMS) */
393 }
394 else
395 {
396 literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint8_arguments_t));
397
398 cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p;
399 literal_end = (uint32_t) (args_p->literal_end - args_p->register_end);
400 const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
401
402#if ENABLED (JERRY_BUILTIN_REALMS)
403 args_p->realm_value = JMEM_CP_NULL;
404#endif /* ENABLED (JERRY_BUILTIN_REALMS) */
405 }
406
407 for (uint32_t i = 0; i < const_literal_end; i++)
408 {
409 if (!ecma_is_value_direct (literal_start_p[i])
410 && !ecma_is_value_direct_string (literal_start_p[i]))
411 {
412 static_snapshot_error_unsupported_literal (globals_p, literal_start_p[i]);
413 return 0;
414 }
415 }
416
417 for (uint32_t i = const_literal_end; i < literal_end; i++)
418 {
419 ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t,
420 literal_start_p[i]);
421
422 if (bytecode_p == compiled_code_p)
423 {
424 literal_start_p[i] = 0;
425 }
426 else
427 {
428 uint32_t offset = static_snapshot_add_compiled_code (bytecode_p,
429 snapshot_buffer_p,
430 snapshot_buffer_size,
431 globals_p);
432
433 JERRY_ASSERT (!ecma_is_value_empty (globals_p->snapshot_error) || offset > start_offset);
434
435 literal_start_p[i] = offset - start_offset;
436 }
437 }
438
439 buffer_p += ((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG;
440 literal_start_p = ecma_snapshot_resolve_serializable_values (compiled_code_p, buffer_p);
441
442 while (literal_start_p < (ecma_value_t *) buffer_p)
443 {
444 if (!ecma_is_value_direct_string (*literal_start_p)
445 && !ecma_is_value_empty (*literal_start_p))
446 {
447 static_snapshot_error_unsupported_literal (globals_p, *literal_start_p);
448 return 0;
449 }
450
451 literal_start_p++;
452 }
453
454 return start_offset;
455} /* static_snapshot_add_compiled_code */
456
457/**
458 * Set the uint16_t offsets in the code area.
459 */
460static void
461jerry_snapshot_set_offsets (uint32_t *buffer_p, /**< buffer */
462 uint32_t size, /**< buffer size */
463 lit_mem_to_snapshot_id_map_entry_t *lit_map_p) /**< literal map */
464{
465 JERRY_ASSERT (size > 0);
466
467 do
468 {
469 ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) buffer_p;
470 uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG;
471
472 if (CBC_IS_FUNCTION (bytecode_p->status_flags))
473 {
474 ecma_value_t *literal_start_p;
475 uint32_t const_literal_end;
476
477 if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
478 {
479 literal_start_p = (ecma_value_t *) (((uint8_t *) buffer_p) + sizeof (cbc_uint16_arguments_t));
480
481 cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p;
482 const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
483 }
484 else
485 {
486 literal_start_p = (ecma_value_t *) (((uint8_t *) buffer_p) + sizeof (cbc_uint8_arguments_t));
487
488 cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p;
489 const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
490 }
491
492 for (uint32_t i = 0; i < const_literal_end; i++)
493 {
494 if (ecma_is_value_string (literal_start_p[i])
495#if ENABLED (JERRY_BUILTIN_BIGINT)
496 || ecma_is_value_bigint (literal_start_p[i])
497#endif /* ENABLED (JERRY_BUILTIN_BIGINT) */
498 || ecma_is_value_float_number (literal_start_p[i]))
499 {
500 lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
501
502 while (current_p->literal_id != literal_start_p[i])
503 {
504 current_p++;
505 }
506
507 literal_start_p[i] = current_p->literal_offset;
508 }
509 }
510
511 uint8_t *byte_p = (uint8_t *) bytecode_p + (((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG);
512 literal_start_p = ecma_snapshot_resolve_serializable_values (bytecode_p, byte_p);
513
514 while (literal_start_p < (ecma_value_t *) byte_p)
515 {
516 if (*literal_start_p != ECMA_VALUE_EMPTY)
517 {
518 JERRY_ASSERT (ecma_is_value_string (*literal_start_p));
519
520 lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
521
522 while (current_p->literal_id != *literal_start_p)
523 {
524 current_p++;
525 }
526
527 *literal_start_p = current_p->literal_offset;
528 }
529
530 literal_start_p++;
531 }
532
533 /* Set reference counter to 1. */
534 bytecode_p->refs = 1;
535 }
536
537 JERRY_ASSERT ((code_size % sizeof (uint32_t)) == 0);
538 buffer_p += code_size / sizeof (uint32_t);
539 size -= code_size;
540 }
541 while (size > 0);
542} /* jerry_snapshot_set_offsets */
543
544#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
545
546#if ENABLED (JERRY_SNAPSHOT_EXEC)
547
548/**
549 * Byte code blocks shorter than this threshold are always copied into the memory.
550 * The memory / performance trade-of of byte code redirection does not worth
551 * in such cases.
552 */
553#define BYTECODE_NO_COPY_THRESHOLD 8
554
555/**
556 * Load byte code from snapshot.
557 *
558 * @return byte code
559 */
560static ecma_compiled_code_t *
561snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of the
562 * current primary function */
563 const uint8_t *literal_base_p, /**< literal start */
564 bool copy_bytecode) /**< byte code should be copied to memory */
565{
566 ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) base_addr_p;
567 uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG;
568
569#if ENABLED (JERRY_BUILTIN_REGEXP)
570 if (!CBC_IS_FUNCTION (bytecode_p->status_flags))
571 {
572 const uint8_t *regex_start_p = ((const uint8_t *) bytecode_p) + sizeof (ecma_compiled_code_t);
573
574 /* Real size is stored in refs. */
575 ecma_string_t *pattern_str_p = ecma_new_ecma_string_from_utf8 (regex_start_p,
576 bytecode_p->refs);
577
578 const re_compiled_code_t *re_bytecode_p = re_compile_bytecode (pattern_str_p,
579 bytecode_p->status_flags);
580 ecma_deref_ecma_string (pattern_str_p);
581
582 return (ecma_compiled_code_t *) re_bytecode_p;
583 }
584#else /* !ENABLED (JERRY_BUILTIN_REGEXP) */
585 JERRY_ASSERT (CBC_IS_FUNCTION (bytecode_p->status_flags));
586#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
587
588 size_t header_size;
589 uint32_t argument_end;
590 uint32_t const_literal_end;
591 uint32_t literal_end;
592
593 if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
594 {
595 uint8_t *byte_p = (uint8_t *) bytecode_p;
596 cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) byte_p;
597
598 argument_end = args_p->argument_end;
599 const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
600 literal_end = (uint32_t) (args_p->literal_end - args_p->register_end);
601 header_size = sizeof (cbc_uint16_arguments_t);
602
603#if ENABLED (JERRY_BUILTIN_REALMS)
604 ECMA_SET_INTERNAL_VALUE_POINTER (args_p->realm_value, ecma_builtin_get_global ());
605#endif /* ENABLED (JERRY_BUILTIN_REALMS) */
606 }
607 else
608 {
609 uint8_t *byte_p = (uint8_t *) bytecode_p;
610 cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) byte_p;
611
612 argument_end = args_p->argument_end;
613 const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
614 literal_end = (uint32_t) (args_p->literal_end - args_p->register_end);
615 header_size = sizeof (cbc_uint8_arguments_t);
616
617#if ENABLED (JERRY_BUILTIN_REALMS)
618 ECMA_SET_INTERNAL_VALUE_POINTER (args_p->realm_value, ecma_builtin_get_global ());
619#endif /* ENABLED (JERRY_BUILTIN_REALMS) */
620 }
621
622 if (copy_bytecode
623 || (header_size + (literal_end * sizeof (uint16_t)) + BYTECODE_NO_COPY_THRESHOLD > code_size))
624 {
625 bytecode_p = (ecma_compiled_code_t *) jmem_heap_alloc_block (code_size);
626
627#if ENABLED (JERRY_MEM_STATS)
628 jmem_stats_allocate_byte_code_bytes (code_size);
629#endif /* ENABLED (JERRY_MEM_STATS) */
630
631 memcpy (bytecode_p, base_addr_p, code_size);
632 }
633 else
634 {
635 uint32_t start_offset = (uint32_t) (header_size + literal_end * sizeof (ecma_value_t));
636
637 uint8_t *real_bytecode_p = ((uint8_t *) bytecode_p) + start_offset;
638 uint32_t new_code_size = (uint32_t) (start_offset + 1 + sizeof (uint8_t *));
639 uint32_t extra_bytes = 0;
640
641 if (bytecode_p->status_flags & CBC_CODE_FLAGS_MAPPED_ARGUMENTS_NEEDED)
642 {
643 extra_bytes += (uint32_t) (argument_end * sizeof (ecma_value_t));
644 }
645
646#if ENABLED (JERRY_ESNEXT)
647 /* function name */
648 if (CBC_FUNCTION_GET_TYPE (bytecode_p->status_flags) != CBC_FUNCTION_CONSTRUCTOR)
649 {
650 extra_bytes += (uint32_t) sizeof (ecma_value_t);
651 }
652
653 /* tagged template literals */
654 if (bytecode_p->status_flags & CBC_CODE_FLAGS_HAS_TAGGED_LITERALS)
655 {
656 extra_bytes += (uint32_t) sizeof (ecma_value_t);
657 }
658#endif /* ENABLED (JERRY_ESNEXT) */
659
660#if ENABLED (JERRY_RESOURCE_NAME)
661 /* resource name */
662 extra_bytes += (uint32_t) sizeof (ecma_value_t);
663#endif /* ENABLED (JERRY_RESOURCE_NAME) */
664
665 new_code_size = JERRY_ALIGNUP (new_code_size + extra_bytes, JMEM_ALIGNMENT);
666
667 bytecode_p = (ecma_compiled_code_t *) jmem_heap_alloc_block (new_code_size);
668
669#if ENABLED (JERRY_MEM_STATS)
670 jmem_stats_allocate_byte_code_bytes (new_code_size);
671#endif /* ENABLED (JERRY_MEM_STATS) */
672
673 memcpy (bytecode_p, base_addr_p, start_offset);
674
675 bytecode_p->size = (uint16_t) (new_code_size >> JMEM_ALIGNMENT_LOG);
676
677 uint8_t *byte_p = (uint8_t *) bytecode_p;
678
679 uint8_t *new_base_p = byte_p + new_code_size - extra_bytes;
680 const uint8_t *base_p = base_addr_p + code_size - extra_bytes;
681
682 if (extra_bytes != 0)
683 {
684 memcpy (new_base_p, base_p, extra_bytes);
685 }
686
687 byte_p[start_offset] = CBC_SET_BYTECODE_PTR;
688 memcpy (byte_p + start_offset + 1, &real_bytecode_p, sizeof (uint8_t *));
689
690 code_size = new_code_size;
691 }
692
693 JERRY_ASSERT (bytecode_p->refs == 1);
694
695#if ENABLED (JERRY_DEBUGGER)
696 bytecode_p->status_flags = (uint16_t) (bytecode_p->status_flags | CBC_CODE_FLAGS_DEBUGGER_IGNORE);
697#endif /* ENABLED (JERRY_DEBUGGER) */
698
699 ecma_value_t *literal_start_p = (ecma_value_t *) (((uint8_t *) bytecode_p) + header_size);
700
701 for (uint32_t i = 0; i < const_literal_end; i++)
702 {
703 if ((literal_start_p[i] & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET)
704 {
705 literal_start_p[i] = ecma_snapshot_get_literal (literal_base_p, literal_start_p[i]);
706 }
707 }
708
709 for (uint32_t i = const_literal_end; i < literal_end; i++)
710 {
711 size_t literal_offset = (size_t) literal_start_p[i];
712
713 if (literal_offset == 0)
714 {
715 /* Self reference */
716 ECMA_SET_INTERNAL_VALUE_POINTER (literal_start_p[i],
717 bytecode_p);
718 }
719 else
720 {
721 ecma_compiled_code_t *literal_bytecode_p;
722 literal_bytecode_p = snapshot_load_compiled_code (base_addr_p + literal_offset,
723 literal_base_p,
724 copy_bytecode);
725
726 ECMA_SET_INTERNAL_VALUE_POINTER (literal_start_p[i],
727 literal_bytecode_p);
728 }
729 }
730
731 uint8_t *byte_p = ((uint8_t *) bytecode_p) + code_size;
732 literal_start_p = ecma_snapshot_resolve_serializable_values (bytecode_p, byte_p);
733
734 while (literal_start_p < (ecma_value_t *) byte_p)
735 {
736 if ((*literal_start_p & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET)
737 {
738 *literal_start_p = ecma_snapshot_get_literal (literal_base_p, *literal_start_p);
739 }
740
741 literal_start_p++;
742 }
743
744 return bytecode_p;
745} /* snapshot_load_compiled_code */
746
747#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */
748
749#if ENABLED (JERRY_SNAPSHOT_SAVE)
750
751/**
752 * Generate snapshot from specified source and arguments
753 *
754 * @return size of snapshot (a number value), if it was generated succesfully
755 * (i.e. there are no syntax errors in source code, buffer size is sufficient,
756 * and snapshot support is enabled in current configuration through JERRY_SNAPSHOT_SAVE),
757 * error object otherwise
758 */
759static jerry_value_t
760jerry_generate_snapshot_with_args (const jerry_char_t *resource_name_p, /**< script resource name */
761 size_t resource_name_length, /**< script resource name length */
762 const jerry_char_t *source_p, /**< script source */
763 size_t source_size, /**< script source size */
764 const jerry_char_t *args_p, /**< arguments string */
765 size_t args_size, /**< arguments string size */
766 uint32_t generate_snapshot_opts, /**< jerry_generate_snapshot_opts_t option bits */
767 uint32_t *buffer_p, /**< buffer to save snapshot to */
768 size_t buffer_size) /**< the buffer's size */
769{
770 /* Currently unused arguments. */
771 JERRY_UNUSED (resource_name_p);
772 JERRY_UNUSED (resource_name_length);
773
774 ecma_value_t resource_name = ecma_make_magic_string_value (LIT_MAGIC_STRING_RESOURCE_ANON);
775
776#if ENABLED (JERRY_RESOURCE_NAME)
777 if (resource_name_length > 0)
778 {
779 resource_name = ecma_find_or_create_literal_string (resource_name_p, (lit_utf8_size_t) resource_name_length);
780 }
781#endif /* ENABLED (JERRY_RESOURCE_NAME) */
782
783 snapshot_globals_t globals;
784 const uint32_t aligned_header_size = JERRY_ALIGNUP (sizeof (jerry_snapshot_header_t),
785 JMEM_ALIGNMENT);
786
787 globals.snapshot_buffer_write_offset = aligned_header_size;
788 globals.snapshot_error = ECMA_VALUE_EMPTY;
789 globals.regex_found = false;
790 globals.class_found = false;
791
792 uint32_t status_flags = ((generate_snapshot_opts & JERRY_SNAPSHOT_SAVE_STRICT) ? ECMA_PARSE_STRICT_MODE
793 : ECMA_PARSE_NO_OPTS);
794
795 ecma_compiled_code_t *bytecode_data_p = parser_parse_script (args_p,
796 args_size,
797 source_p,
798 source_size,
799 resource_name,
800 status_flags);
801
802 if (JERRY_UNLIKELY (bytecode_data_p == NULL))
803 {
804 return ecma_create_error_reference_from_context ();
805 }
806
807 if (generate_snapshot_opts & JERRY_SNAPSHOT_SAVE_STATIC)
808 {
809 static_snapshot_add_compiled_code (bytecode_data_p, (uint8_t *) buffer_p, buffer_size, &globals);
810 }
811 else
812 {
813 snapshot_add_compiled_code (bytecode_data_p, (uint8_t *) buffer_p, buffer_size, &globals);
814 }
815
816 if (!ecma_is_value_empty (globals.snapshot_error))
817 {
818 ecma_bytecode_deref (bytecode_data_p);
819 return globals.snapshot_error;
820 }
821
822 jerry_snapshot_header_t header;
823 header.magic = JERRY_SNAPSHOT_MAGIC;
824 header.version = JERRY_SNAPSHOT_VERSION;
825 header.global_flags = snapshot_get_global_flags (globals.regex_found, globals.class_found);
826 header.lit_table_offset = (uint32_t) globals.snapshot_buffer_write_offset;
827 header.number_of_funcs = 1;
828 header.func_offsets[0] = aligned_header_size;
829
830 lit_mem_to_snapshot_id_map_entry_t *lit_map_p = NULL;
831 uint32_t literals_num = 0;
832
833 if (!(generate_snapshot_opts & JERRY_SNAPSHOT_SAVE_STATIC))
834 {
835 ecma_collection_t *lit_pool_p = ecma_new_collection ();
836
837 ecma_save_literals_add_compiled_code (bytecode_data_p, lit_pool_p);
838
839 if (!ecma_save_literals_for_snapshot (lit_pool_p,
840 buffer_p,
841 buffer_size,
842 &globals.snapshot_buffer_write_offset,
843 &lit_map_p,
844 &literals_num))
845 {
846 JERRY_ASSERT (lit_map_p == NULL);
847 const char * const error_message_p = "Cannot allocate memory for literals.";
848 ecma_bytecode_deref (bytecode_data_p);
849 return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t *) error_message_p);
850 }
851
852 jerry_snapshot_set_offsets (buffer_p + (aligned_header_size / sizeof (uint32_t)),
853 (uint32_t) (header.lit_table_offset - aligned_header_size),
854 lit_map_p);
855 }
856
857 size_t header_offset = 0;
858
859 snapshot_write_to_buffer_by_offset ((uint8_t *) buffer_p,
860 buffer_size,
861 &header_offset,
862 &header,
863 sizeof (header));
864
865 if (lit_map_p != NULL)
866 {
867 jmem_heap_free_block (lit_map_p, literals_num * sizeof (lit_mem_to_snapshot_id_map_entry_t));
868 }
869
870 ecma_bytecode_deref (bytecode_data_p);
871
872 return ecma_make_number_value ((ecma_number_t) globals.snapshot_buffer_write_offset);
873} /* jerry_generate_snapshot_with_args */
874
875#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
876
877/**
878 * Generate snapshot from specified source and arguments
879 *
880 * @return size of snapshot (a number value), if it was generated succesfully
881 * (i.e. there are no syntax errors in source code, buffer size is sufficient,
882 * and snapshot support is enabled in current configuration through JERRY_SNAPSHOT_SAVE),
883 * error object otherwise
884 */
885jerry_value_t
886jerry_generate_snapshot (const jerry_char_t *resource_name_p, /**< script resource name */
887 size_t resource_name_length, /**< script resource name length */
888 const jerry_char_t *source_p, /**< script source */
889 size_t source_size, /**< script source size */
890 uint32_t generate_snapshot_opts, /**< jerry_generate_snapshot_opts_t option bits */
891 uint32_t *buffer_p, /**< buffer to save snapshot to */
892 size_t buffer_size) /**< the buffer's size */
893{
894#if ENABLED (JERRY_SNAPSHOT_SAVE)
895 uint32_t allowed_opts = (JERRY_SNAPSHOT_SAVE_STATIC | JERRY_SNAPSHOT_SAVE_STRICT);
896
897 if ((generate_snapshot_opts & ~(allowed_opts)) != 0)
898 {
899 const char * const error_message_p = "Unsupported generate snapshot flags specified.";
900 return jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
901 }
902
903 return jerry_generate_snapshot_with_args (resource_name_p,
904 resource_name_length,
905 source_p,
906 source_size,
907 NULL,
908 0,
909 generate_snapshot_opts,
910 buffer_p,
911 buffer_size);
912#else /* !ENABLED (JERRY_SNAPSHOT_SAVE) */
913 JERRY_UNUSED (resource_name_p);
914 JERRY_UNUSED (resource_name_length);
915 JERRY_UNUSED (source_p);
916 JERRY_UNUSED (source_size);
917 JERRY_UNUSED (generate_snapshot_opts);
918 JERRY_UNUSED (buffer_p);
919 JERRY_UNUSED (buffer_size);
920
921 return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t *) "Snapshot save is not supported.");
922#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
923} /* jerry_generate_snapshot */
924
925#if ENABLED (JERRY_SNAPSHOT_EXEC)
926/**
927 * Execute/load snapshot from specified buffer
928 *
929 * Note:
930 * returned value must be freed with jerry_release_value, when it is no longer needed.
931 *
932 * @return result of bytecode - if run was successful
933 * thrown error - otherwise
934 */
935static jerry_value_t
936jerry_snapshot_result (const uint32_t *snapshot_p, /**< snapshot */
937 size_t snapshot_size, /**< size of snapshot */
938 size_t func_index, /**< index of primary function */
939 uint32_t exec_snapshot_opts, /**< jerry_exec_snapshot_opts_t option bits */
940 bool as_function) /** < specify if the loaded snapshot should be returned as a function */
941{
942 JERRY_ASSERT (snapshot_p != NULL);
943
944 uint32_t allowed_opts = (JERRY_SNAPSHOT_EXEC_COPY_DATA | JERRY_SNAPSHOT_EXEC_ALLOW_STATIC);
945
946 if ((exec_snapshot_opts & ~(allowed_opts)) != 0)
947 {
948 ecma_raise_range_error (ECMA_ERR_MSG ("Unsupported exec snapshot flags specified."));
949 return ecma_create_error_reference_from_context ();
950 }
951
952 const char * const invalid_version_error_p = "Invalid snapshot version or unsupported features present";
953 const char * const invalid_format_error_p = "Invalid snapshot format";
954 const uint8_t *snapshot_data_p = (uint8_t *) snapshot_p;
955
956 if (snapshot_size <= sizeof (jerry_snapshot_header_t))
957 {
958 ecma_raise_type_error (invalid_format_error_p);
959 return ecma_create_error_reference_from_context ();
960 }
961
962 const jerry_snapshot_header_t *header_p = (const jerry_snapshot_header_t *) snapshot_data_p;
963
964 if (header_p->magic != JERRY_SNAPSHOT_MAGIC
965 || header_p->version != JERRY_SNAPSHOT_VERSION
966 || !snapshot_check_global_flags (header_p->global_flags))
967 {
968 ecma_raise_type_error (invalid_version_error_p);
969 return ecma_create_error_reference_from_context ();
970 }
971
972 if (header_p->lit_table_offset > snapshot_size)
973 {
974 ecma_raise_type_error (invalid_version_error_p);
975 return ecma_create_error_reference_from_context ();
976 }
977
978 if (func_index >= header_p->number_of_funcs)
979 {
980 ecma_raise_range_error (ECMA_ERR_MSG ("Function index is higher than maximum"));
981 return ecma_create_error_reference_from_context ();
982 }
983
984 JERRY_ASSERT ((header_p->lit_table_offset % sizeof (uint32_t)) == 0);
985
986 uint32_t func_offset = header_p->func_offsets[func_index];
987 ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) (snapshot_data_p + func_offset);
988
989 if (bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)
990 {
991 if (!(exec_snapshot_opts & JERRY_SNAPSHOT_EXEC_ALLOW_STATIC))
992 {
993 ecma_raise_common_error (ECMA_ERR_MSG ("Static snapshots not allowed"));
994 return ecma_create_error_reference_from_context ();
995 }
996
997 if (exec_snapshot_opts & JERRY_SNAPSHOT_EXEC_COPY_DATA)
998 {
999 ecma_raise_common_error (ECMA_ERR_MSG ("Static snapshots cannot be copied into memory"));
1000 return ecma_create_error_reference_from_context ();
1001 }
1002 }
1003 else
1004 {
1005 const uint8_t *literal_base_p = snapshot_data_p + header_p->lit_table_offset;
1006
1007 bytecode_p = snapshot_load_compiled_code ((const uint8_t *) bytecode_p,
1008 literal_base_p,
1009 (exec_snapshot_opts & JERRY_SNAPSHOT_EXEC_COPY_DATA) != 0);
1010
1011 if (bytecode_p == NULL)
1012 {
1013 return ecma_raise_type_error (invalid_format_error_p);
1014 }
1015 }
1016
1017#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
1018 if (JERRY_CONTEXT (jerry_init_flags) & ECMA_INIT_SHOW_OPCODES)
1019 {
1020 util_print_cbc (bytecode_p);
1021 }
1022#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
1023
1024 ecma_value_t ret_val;
1025
1026 if (as_function)
1027 {
1028 ecma_object_t *global_object_p = ecma_builtin_get_global ();
1029
1030#if ENABLED (JERRY_BUILTIN_REALMS)
1031 JERRY_ASSERT (global_object_p == (ecma_object_t *) ecma_op_function_get_realm (bytecode_p));
1032#endif /* ENABLED (JERRY_BUILTIN_REALMS) */
1033
1034#if ENABLED (JERRY_ESNEXT)
1035 if (bytecode_p->status_flags & CBC_CODE_FLAGS_LEXICAL_BLOCK_NEEDED)
1036 {
1037 ecma_create_global_lexical_block (global_object_p);
1038 }
1039#endif /* ENABLED (JERRY_ESNEXT) */
1040
1041 ecma_object_t *lex_env_p = ecma_get_global_scope (global_object_p);
1042 ecma_object_t *func_obj_p = ecma_op_create_simple_function_object (lex_env_p, bytecode_p);
1043
1044 if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION))
1045 {
1046 ecma_bytecode_deref (bytecode_p);
1047 }
1048 ret_val = ecma_make_object_value (func_obj_p);
1049 }
1050 else
1051 {
1052 ret_val = vm_run_global (bytecode_p);
1053 if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION))
1054 {
1055 ecma_bytecode_deref (bytecode_p);
1056 }
1057 }
1058
1059 if (ECMA_IS_VALUE_ERROR (ret_val))
1060 {
1061 return ecma_create_error_reference_from_context ();
1062 }
1063
1064 return ret_val;
1065} /* jerry_snapshot_result */
1066#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */
1067
1068/**
1069 * Execute snapshot from specified buffer
1070 *
1071 * Note:
1072 * returned value must be freed with jerry_release_value, when it is no longer needed.
1073 *
1074 * @return result of bytecode - if run was successful
1075 * thrown error - otherwise
1076 */
1077jerry_value_t
1078jerry_exec_snapshot (const uint32_t *snapshot_p, /**< snapshot */
1079 size_t snapshot_size, /**< size of snapshot */
1080 size_t func_index, /**< index of primary function */
1081 uint32_t exec_snapshot_opts) /**< jerry_exec_snapshot_opts_t option bits */
1082{
1083#if ENABLED (JERRY_SNAPSHOT_EXEC)
1084 return jerry_snapshot_result (snapshot_p, snapshot_size, func_index, exec_snapshot_opts, false);
1085#else /* !ENABLED (JERRY_SNAPSHOT_EXEC) */
1086 JERRY_UNUSED (snapshot_p);
1087 JERRY_UNUSED (snapshot_size);
1088 JERRY_UNUSED (func_index);
1089 JERRY_UNUSED (exec_snapshot_opts);
1090
1091 return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t *) "Snapshot execution is not supported.");
1092#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */
1093} /* jerry_exec_snapshot */
1094
1095/**
1096 * @}
1097 */
1098
1099#if ENABLED (JERRY_SNAPSHOT_SAVE)
1100
1101/**
1102 * Collect all literals from a snapshot file.
1103 */
1104static void
1105scan_snapshot_functions (const uint8_t *buffer_p, /**< snapshot buffer start */
1106 const uint8_t *buffer_end_p, /**< snapshot buffer end */
1107 ecma_collection_t *lit_pool_p, /**< list of known values */
1108 const uint8_t *literal_base_p) /**< start of literal data */
1109{
1110 JERRY_ASSERT (buffer_end_p > buffer_p);
1111
1112 do
1113 {
1114 const ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) buffer_p;
1115 uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG;
1116
1117 if (CBC_IS_FUNCTION (bytecode_p->status_flags)
1118 && !(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION))
1119 {
1120 const ecma_value_t *literal_start_p;
1121 uint32_t const_literal_end;
1122
1123 if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
1124 {
1125 literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint16_arguments_t));
1126
1127 cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p;
1128 const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
1129 }
1130 else
1131 {
1132 literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint8_arguments_t));
1133
1134 cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p;
1135 const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
1136 }
1137
1138 for (uint32_t i = 0; i < const_literal_end; i++)
1139 {
1140 if ((literal_start_p[i] & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET)
1141 {
1142 ecma_value_t lit_value = ecma_snapshot_get_literal (literal_base_p, literal_start_p[i]);
1143 ecma_save_literals_append_value (lit_value, lit_pool_p);
1144 }
1145 }
1146
1147 uint8_t *byte_p = (uint8_t *) bytecode_p + (((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG);
1148 literal_start_p = ecma_snapshot_resolve_serializable_values ((ecma_compiled_code_t *) bytecode_p, byte_p);
1149
1150 while (literal_start_p < (ecma_value_t *) byte_p)
1151 {
1152 if ((*literal_start_p & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET)
1153 {
1154 ecma_value_t lit_value = ecma_snapshot_get_literal (literal_base_p, *literal_start_p);
1155 ecma_save_literals_append_value (lit_value, lit_pool_p);
1156 }
1157
1158 literal_start_p++;
1159 }
1160 }
1161
1162 buffer_p += code_size;
1163 }
1164 while (buffer_p < buffer_end_p);
1165} /* scan_snapshot_functions */
1166
1167/**
1168 * Update all literal offsets in a snapshot data.
1169 */
1170static void
1171update_literal_offsets (uint8_t *buffer_p, /**< [in,out] snapshot buffer start */
1172 const uint8_t *buffer_end_p, /**< snapshot buffer end */
1173 const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< literal map */
1174 const uint8_t *literal_base_p) /**< start of literal data */
1175{
1176 JERRY_ASSERT (buffer_end_p > buffer_p);
1177
1178 do
1179 {
1180 const ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) buffer_p;
1181 uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG;
1182
1183 if (CBC_IS_FUNCTION (bytecode_p->status_flags)
1184 && !(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION))
1185 {
1186 ecma_value_t *literal_start_p;
1187 uint32_t const_literal_end;
1188
1189 if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
1190 {
1191 literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint16_arguments_t));
1192
1193 cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p;
1194 const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
1195 }
1196 else
1197 {
1198 literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint8_arguments_t));
1199
1200 cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p;
1201 const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end);
1202 }
1203
1204 for (uint32_t i = 0; i < const_literal_end; i++)
1205 {
1206 if ((literal_start_p[i] & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET)
1207 {
1208 ecma_value_t lit_value = ecma_snapshot_get_literal (literal_base_p, literal_start_p[i]);
1209 const lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
1210
1211 while (current_p->literal_id != lit_value)
1212 {
1213 current_p++;
1214 }
1215
1216 literal_start_p[i] = current_p->literal_offset;
1217 }
1218 }
1219
1220 uint8_t *byte_p = (uint8_t *) bytecode_p + (((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG);
1221 literal_start_p = ecma_snapshot_resolve_serializable_values ((ecma_compiled_code_t *) bytecode_p, byte_p);
1222
1223 while (literal_start_p < (ecma_value_t *) byte_p)
1224 {
1225 if ((*literal_start_p & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET)
1226 {
1227 ecma_value_t lit_value = ecma_snapshot_get_literal (literal_base_p, *literal_start_p);
1228 const lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
1229
1230 while (current_p->literal_id != lit_value)
1231 {
1232 current_p++;
1233 }
1234
1235 *literal_start_p = current_p->literal_offset;
1236 }
1237
1238 literal_start_p++;
1239 }
1240 }
1241
1242 buffer_p += code_size;
1243 }
1244 while (buffer_p < buffer_end_p);
1245} /* update_literal_offsets */
1246
1247#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
1248
1249/**
1250 * Merge multiple snapshots into a single buffer
1251 *
1252 * @return length of merged snapshot file
1253 * 0 on error
1254 */
1255size_t
1256jerry_merge_snapshots (const uint32_t **inp_buffers_p, /**< array of (pointers to start of) input buffers */
1257 size_t *inp_buffer_sizes_p, /**< array of input buffer sizes */
1258 size_t number_of_snapshots, /**< number of snapshots */
1259 uint32_t *out_buffer_p, /**< output buffer */
1260 size_t out_buffer_size, /**< output buffer size */
1261 const char **error_p) /**< error description */
1262{
1263#if ENABLED (JERRY_SNAPSHOT_SAVE)
1264 uint32_t number_of_funcs = 0;
1265 uint32_t merged_global_flags = 0;
1266 size_t functions_size = sizeof (jerry_snapshot_header_t);
1267
1268 if (number_of_snapshots < 2)
1269 {
1270 *error_p = "at least two snapshots must be passed";
1271 return 0;
1272 }
1273
1274 ecma_collection_t *lit_pool_p = ecma_new_collection ();
1275
1276 for (uint32_t i = 0; i < number_of_snapshots; i++)
1277 {
1278 if (inp_buffer_sizes_p[i] < sizeof (jerry_snapshot_header_t))
1279 {
1280 *error_p = "invalid snapshot file";
1281 ecma_collection_destroy (lit_pool_p);
1282 return 0;
1283 }
1284
1285 const jerry_snapshot_header_t *header_p = (const jerry_snapshot_header_t *) inp_buffers_p[i];
1286
1287 if (header_p->magic != JERRY_SNAPSHOT_MAGIC
1288 || header_p->version != JERRY_SNAPSHOT_VERSION
1289 || !snapshot_check_global_flags (header_p->global_flags))
1290 {
1291 *error_p = "invalid snapshot version or unsupported features present";
1292 ecma_collection_destroy (lit_pool_p);
1293 return 0;
1294 }
1295
1296 merged_global_flags |= header_p->global_flags;
1297
1298 uint32_t start_offset = header_p->func_offsets[0];
1299 const uint8_t *data_p = (const uint8_t *) inp_buffers_p[i];
1300 const uint8_t *literal_base_p = data_p + header_p->lit_table_offset;
1301
1302 JERRY_ASSERT (header_p->number_of_funcs > 0);
1303
1304 number_of_funcs += header_p->number_of_funcs;
1305 functions_size += header_p->lit_table_offset - start_offset;
1306
1307 scan_snapshot_functions (data_p + start_offset,
1308 literal_base_p,
1309 lit_pool_p,
1310 literal_base_p);
1311 }
1312
1313 JERRY_ASSERT (number_of_funcs > 0);
1314
1315 functions_size += JERRY_ALIGNUP ((number_of_funcs - 1) * sizeof (uint32_t), JMEM_ALIGNMENT);
1316
1317 if (functions_size >= out_buffer_size)
1318 {
1319 *error_p = "output buffer is too small";
1320 ecma_collection_destroy (lit_pool_p);
1321 return 0;
1322 }
1323
1324 jerry_snapshot_header_t *header_p = (jerry_snapshot_header_t *) out_buffer_p;
1325
1326 header_p->magic = JERRY_SNAPSHOT_MAGIC;
1327 header_p->version = JERRY_SNAPSHOT_VERSION;
1328 header_p->global_flags = merged_global_flags;
1329 header_p->lit_table_offset = (uint32_t) functions_size;
1330 header_p->number_of_funcs = number_of_funcs;
1331
1332 lit_mem_to_snapshot_id_map_entry_t *lit_map_p;
1333 uint32_t literals_num;
1334
1335 if (!ecma_save_literals_for_snapshot (lit_pool_p,
1336 out_buffer_p,
1337 out_buffer_size,
1338 &functions_size,
1339 &lit_map_p,
1340 &literals_num))
1341 {
1342 *error_p = "buffer is too small";
1343 return 0;
1344 }
1345
1346 uint32_t *func_offset_p = header_p->func_offsets;
1347 uint8_t *dst_p = ((uint8_t *) out_buffer_p) + sizeof (jerry_snapshot_header_t);
1348 dst_p += JERRY_ALIGNUP ((number_of_funcs - 1) * sizeof (uint32_t), JMEM_ALIGNMENT);
1349
1350 for (uint32_t i = 0; i < number_of_snapshots; i++)
1351 {
1352 const jerry_snapshot_header_t *current_header_p = (const jerry_snapshot_header_t *) inp_buffers_p[i];
1353
1354 uint32_t start_offset = current_header_p->func_offsets[0];
1355
1356 memcpy (dst_p,
1357 ((const uint8_t *) inp_buffers_p[i]) + start_offset,
1358 current_header_p->lit_table_offset - start_offset);
1359
1360 const uint8_t *literal_base_p = ((const uint8_t *) inp_buffers_p[i]) + current_header_p->lit_table_offset;
1361 update_literal_offsets (dst_p,
1362 dst_p + current_header_p->lit_table_offset - start_offset,
1363 lit_map_p,
1364 literal_base_p);
1365
1366 uint32_t current_offset = (uint32_t) (dst_p - (uint8_t *) out_buffer_p) - start_offset;
1367
1368 for (uint32_t j = 0; j < current_header_p->number_of_funcs; j++)
1369 {
1370 /* Updating offset without changing any flags. */
1371 *func_offset_p++ = current_header_p->func_offsets[j] + current_offset;
1372 }
1373
1374 dst_p += current_header_p->lit_table_offset - start_offset;
1375 }
1376
1377 JERRY_ASSERT ((uint32_t) (dst_p - (uint8_t *) out_buffer_p) == header_p->lit_table_offset);
1378
1379 if (lit_map_p != NULL)
1380 {
1381 jmem_heap_free_block (lit_map_p, literals_num * sizeof (lit_mem_to_snapshot_id_map_entry_t));
1382 }
1383
1384 *error_p = NULL;
1385 return functions_size;
1386#else /* !ENABLED (JERRY_SNAPSHOT_SAVE) */
1387 JERRY_UNUSED (inp_buffers_p);
1388 JERRY_UNUSED (inp_buffer_sizes_p);
1389 JERRY_UNUSED (number_of_snapshots);
1390 JERRY_UNUSED (out_buffer_p);
1391 JERRY_UNUSED (out_buffer_size);
1392 JERRY_UNUSED (error_p);
1393
1394 *error_p = "snapshot merge not supported";
1395 return 0;
1396#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
1397} /* jerry_merge_snapshots */
1398
1399#if ENABLED (JERRY_SNAPSHOT_SAVE)
1400
1401/**
1402 * ====================== Functions for literal saving ==========================
1403 */
1404
1405/**
1406 * Compare two ecma_strings by size, then lexicographically.
1407 *
1408 * @return true - if the first string is less than the second one,
1409 * false - otherwise
1410 */
1411static bool
1412jerry_save_literals_compare (ecma_string_t *literal1, /**< first literal */
1413 ecma_string_t *literal2) /**< second literal */
1414{
1415 const lit_utf8_size_t lit1_size = ecma_string_get_size (literal1);
1416 const lit_utf8_size_t lit2_size = ecma_string_get_size (literal2);
1417
1418 if (lit1_size == lit2_size)
1419 {
1420 return ecma_compare_ecma_strings_relational (literal1, literal2);
1421 }
1422
1423 return (lit1_size < lit2_size);
1424} /* jerry_save_literals_compare */
1425
1426/**
1427 * Helper function for the heapsort algorithm.
1428 *
1429 * @return index of the maximum value
1430 */
1431static lit_utf8_size_t
1432jerry_save_literals_heap_max (ecma_string_t *literals[], /**< array of literals */
1433 lit_utf8_size_t num_of_nodes, /**< number of nodes */
1434 lit_utf8_size_t node_idx, /**< index of parent node */
1435 lit_utf8_size_t child_idx1, /**< index of the first child */
1436 lit_utf8_size_t child_idx2) /**< index of the second child */
1437{
1438 lit_utf8_size_t max_idx = node_idx;
1439
1440 if (child_idx1 < num_of_nodes
1441 && jerry_save_literals_compare (literals[max_idx], literals[child_idx1]))
1442 {
1443 max_idx = child_idx1;
1444 }
1445
1446 if (child_idx2 < num_of_nodes
1447 && jerry_save_literals_compare (literals[max_idx], literals[child_idx2]))
1448 {
1449 max_idx = child_idx2;
1450 }
1451
1452 return max_idx;
1453} /* jerry_save_literals_heap_max */
1454
1455/**
1456 * Helper function for the heapsort algorithm.
1457 */
1458static void
1459jerry_save_literals_down_heap (ecma_string_t *literals[], /**< array of literals */
1460 lit_utf8_size_t num_of_nodes, /**< number of nodes */
1461 lit_utf8_size_t node_idx) /**< index of parent node */
1462{
1463 while (true)
1464 {
1465 lit_utf8_size_t max_idx = jerry_save_literals_heap_max (literals,
1466 num_of_nodes,
1467 node_idx,
1468 2 * node_idx + 1,
1469 2 * node_idx + 2);
1470 if (max_idx == node_idx)
1471 {
1472 break;
1473 }
1474
1475 ecma_string_t *tmp_str_p = literals[node_idx];
1476 literals[node_idx] = literals[max_idx];
1477 literals[max_idx] = tmp_str_p;
1478
1479 node_idx = max_idx;
1480 }
1481} /* jerry_save_literals_down_heap */
1482
1483/**
1484 * Helper function for a heapsort algorithm.
1485 */
1486static void
1487jerry_save_literals_sort (ecma_string_t *literals[], /**< array of literals */
1488 lit_utf8_size_t num_of_literals) /**< number of literals */
1489{
1490 if (num_of_literals < 2)
1491 {
1492 return;
1493 }
1494
1495 lit_utf8_size_t lit_idx = (num_of_literals - 2) / 2;
1496
1497 while (lit_idx <= (num_of_literals - 2) / 2)
1498 {
1499 jerry_save_literals_down_heap (literals, num_of_literals, lit_idx--);
1500 }
1501
1502 for (lit_idx = 0; lit_idx < num_of_literals; lit_idx++)
1503 {
1504 const lit_utf8_size_t last_idx = num_of_literals - lit_idx - 1;
1505
1506 ecma_string_t *tmp_str_p = literals[last_idx];
1507 literals[last_idx] = literals[0];
1508 literals[0] = tmp_str_p;
1509
1510 jerry_save_literals_down_heap (literals, last_idx, 0);
1511 }
1512} /* jerry_save_literals_sort */
1513
1514/**
1515 * Append characters to the specified buffer.
1516 *
1517 * @return the position of the buffer pointer after copy.
1518 */
1519static uint8_t *
1520jerry_append_chars_to_buffer (uint8_t *buffer_p, /**< buffer */
1521 uint8_t *buffer_end_p, /**< the end of the buffer */
1522 const char *chars, /**< string */
1523 lit_utf8_size_t string_size) /**< string size */
1524{
1525 if (buffer_p > buffer_end_p)
1526 {
1527 return buffer_p;
1528 }
1529
1530 if (string_size == 0)
1531 {
1532 string_size = (lit_utf8_size_t) strlen (chars);
1533 }
1534
1535 if (buffer_p + string_size <= buffer_end_p)
1536 {
1537 memcpy ((char *) buffer_p, chars, string_size);
1538
1539 return buffer_p + string_size;
1540 }
1541
1542 /* Move the pointer behind the buffer to prevent further writes. */
1543 return buffer_end_p + 1;
1544} /* jerry_append_chars_to_buffer */
1545
1546/**
1547 * Append an ecma-string to the specified buffer.
1548 *
1549 * @return the position of the buffer pointer after copy.
1550 */
1551static uint8_t *
1552jerry_append_ecma_string_to_buffer (uint8_t *buffer_p, /**< buffer */
1553 uint8_t *buffer_end_p, /**< the end of the buffer */
1554 ecma_string_t *string_p) /**< ecma-string */
1555{
1556 ECMA_STRING_TO_UTF8_STRING (string_p, str_buffer_p, str_buffer_size);
1557
1558 /* Append the string to the buffer. */
1559 uint8_t *new_buffer_p = jerry_append_chars_to_buffer (buffer_p,
1560 buffer_end_p,
1561 (const char *) str_buffer_p,
1562 str_buffer_size);
1563
1564 ECMA_FINALIZE_UTF8_STRING (str_buffer_p, str_buffer_size);
1565
1566 return new_buffer_p;
1567} /* jerry_append_ecma_string_to_buffer */
1568
1569/**
1570 * Append an unsigned number to the specified buffer.
1571 *
1572 * @return the position of the buffer pointer after copy.
1573 */
1574static uint8_t *
1575jerry_append_number_to_buffer (uint8_t *buffer_p, /**< buffer */
1576 uint8_t *buffer_end_p, /**< the end of the buffer */
1577 lit_utf8_size_t number) /**< number */
1578{
1579 lit_utf8_byte_t uint32_to_str_buffer[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32];
1580 lit_utf8_size_t utf8_str_size = ecma_uint32_to_utf8_string (number,
1581 uint32_to_str_buffer,
1582 ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32);
1583
1584 JERRY_ASSERT (utf8_str_size <= ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32);
1585
1586 return jerry_append_chars_to_buffer (buffer_p,
1587 buffer_end_p,
1588 (const char *) uint32_to_str_buffer,
1589 utf8_str_size);
1590} /* jerry_append_number_to_buffer */
1591
1592#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
1593
1594/**
1595 * Get the literals from a snapshot. Copies certain string literals into the given
1596 * buffer in a specified format.
1597 *
1598 * Note:
1599 * Only valid identifiers are saved in C format.
1600 *
1601 * @return size of the literal-list in bytes, at most equal to the buffer size,
1602 * if the list of the literals isn't empty,
1603 * 0 - otherwise.
1604 */
1605size_t
1606jerry_get_literals_from_snapshot (const uint32_t *snapshot_p, /**< input snapshot buffer */
1607 size_t snapshot_size, /**< size of the input snapshot buffer */
1608 jerry_char_t *lit_buf_p, /**< [out] buffer to save literals to */
1609 size_t lit_buf_size, /**< the buffer's size */
1610 bool is_c_format) /**< format-flag */
1611{
1612#if ENABLED (JERRY_SNAPSHOT_SAVE)
1613 const uint8_t *snapshot_data_p = (uint8_t *) snapshot_p;
1614 const jerry_snapshot_header_t *header_p = (const jerry_snapshot_header_t *) snapshot_data_p;
1615
1616 if (snapshot_size <= sizeof (jerry_snapshot_header_t)
1617 || header_p->magic != JERRY_SNAPSHOT_MAGIC
1618 || header_p->version != JERRY_SNAPSHOT_VERSION
1619 || !snapshot_check_global_flags (header_p->global_flags))
1620 {
1621 /* Invalid snapshot format */
1622 return 0;
1623 }
1624
1625 JERRY_ASSERT ((header_p->lit_table_offset % sizeof (uint32_t)) == 0);
1626 const uint8_t *literal_base_p = snapshot_data_p + header_p->lit_table_offset;
1627
1628 ecma_collection_t *lit_pool_p = ecma_new_collection ();
1629 scan_snapshot_functions (snapshot_data_p + header_p->func_offsets[0],
1630 literal_base_p,
1631 lit_pool_p,
1632 literal_base_p);
1633
1634 lit_utf8_size_t literal_count = 0;
1635 ecma_value_t *buffer_p = lit_pool_p->buffer_p;
1636
1637 /* Count the valid and non-magic identifiers in the list. */
1638 for (uint32_t i = 0; i < lit_pool_p->item_count; i++)
1639 {
1640 if (ecma_is_value_string (buffer_p[i]))
1641 {
1642 ecma_string_t *literal_p = ecma_get_string_from_value (buffer_p[i]);
1643
1644 if (ecma_get_string_magic (literal_p) == LIT_MAGIC_STRING__COUNT)
1645 {
1646 literal_count++;
1647 }
1648 }
1649 }
1650
1651 if (literal_count == 0)
1652 {
1653 ecma_collection_destroy (lit_pool_p);
1654 return 0;
1655 }
1656
1657 jerry_char_t *const buffer_start_p = lit_buf_p;
1658 jerry_char_t *const buffer_end_p = lit_buf_p + lit_buf_size;
1659
1660 JMEM_DEFINE_LOCAL_ARRAY (literal_array, literal_count, ecma_string_t *);
1661 lit_utf8_size_t literal_idx = 0;
1662
1663 buffer_p = lit_pool_p->buffer_p;
1664
1665 /* Count the valid and non-magic identifiers in the list. */
1666 for (uint32_t i = 0; i < lit_pool_p->item_count; i++)
1667 {
1668 if (ecma_is_value_string (buffer_p[i]))
1669 {
1670 ecma_string_t *literal_p = ecma_get_string_from_value (buffer_p[i]);
1671
1672 if (ecma_get_string_magic (literal_p) == LIT_MAGIC_STRING__COUNT)
1673 {
1674 literal_array[literal_idx++] = literal_p;
1675 }
1676 }
1677 }
1678
1679 ecma_collection_destroy (lit_pool_p);
1680
1681 /* Sort the strings by size at first, then lexicographically. */
1682 jerry_save_literals_sort (literal_array, literal_count);
1683
1684 if (is_c_format)
1685 {
1686 /* Save literal count. */
1687 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p,
1688 buffer_end_p,
1689 "jerry_length_t literal_count = ",
1690 0);
1691
1692 lit_buf_p = jerry_append_number_to_buffer (lit_buf_p, buffer_end_p, literal_count);
1693
1694 /* Save the array of literals. */
1695 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p,
1696 buffer_end_p,
1697 ";\n\njerry_char_t *literals[",
1698 0);
1699
1700 lit_buf_p = jerry_append_number_to_buffer (lit_buf_p, buffer_end_p, literal_count);
1701 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "] =\n{\n", 0);
1702
1703 for (lit_utf8_size_t i = 0; i < literal_count; i++)
1704 {
1705 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, " \"", 0);
1706 ECMA_STRING_TO_UTF8_STRING (literal_array[i], str_buffer_p, str_buffer_size);
1707 for (lit_utf8_size_t j = 0; j < str_buffer_size; j++)
1708 {
1709 uint8_t byte = str_buffer_p[j];
1710 if (byte < 32 || byte > 127)
1711 {
1712 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "\\x", 0);
1713 ecma_char_t hex_digit = (ecma_char_t) (byte >> 4);
1714 *lit_buf_p++ = (lit_utf8_byte_t) ((hex_digit > 9) ? (hex_digit + ('A' - 10)) : (hex_digit + '0'));
1715 hex_digit = (lit_utf8_byte_t) (byte & 0xf);
1716 *lit_buf_p++ = (lit_utf8_byte_t) ((hex_digit > 9) ? (hex_digit + ('A' - 10)) : (hex_digit + '0'));
1717 }
1718 else
1719 {
1720 if (byte == '\\' || byte == '"')
1721 {
1722 *lit_buf_p++ = '\\';
1723 }
1724 *lit_buf_p++ = byte;
1725 }
1726 }
1727
1728 ECMA_FINALIZE_UTF8_STRING (str_buffer_p, str_buffer_size);
1729 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "\"", 0);
1730
1731 if (i < literal_count - 1)
1732 {
1733 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, ",", 0);
1734 }
1735
1736 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "\n", 0);
1737 }
1738
1739 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p,
1740 buffer_end_p,
1741 "};\n\njerry_length_t literal_sizes[",
1742 0);
1743
1744 lit_buf_p = jerry_append_number_to_buffer (lit_buf_p, buffer_end_p, literal_count);
1745 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "] =\n{\n", 0);
1746 }
1747
1748 /* Save the literal sizes respectively. */
1749 for (lit_utf8_size_t i = 0; i < literal_count; i++)
1750 {
1751 lit_utf8_size_t str_size = ecma_string_get_size (literal_array[i]);
1752
1753 if (is_c_format)
1754 {
1755 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, " ", 0);
1756 }
1757
1758 lit_buf_p = jerry_append_number_to_buffer (lit_buf_p, buffer_end_p, str_size);
1759 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, " ", 0);
1760
1761 if (is_c_format)
1762 {
1763 /* Show the given string as a comment. */
1764 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "/* ", 0);
1765 lit_buf_p = jerry_append_ecma_string_to_buffer (lit_buf_p, buffer_end_p, literal_array[i]);
1766 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, " */", 0);
1767
1768 if (i < literal_count - 1)
1769 {
1770 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, ",", 0);
1771 }
1772 }
1773 else
1774 {
1775 lit_buf_p = jerry_append_ecma_string_to_buffer (lit_buf_p, buffer_end_p, literal_array[i]);
1776 }
1777
1778 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "\n", 0);
1779 }
1780
1781 if (is_c_format)
1782 {
1783 lit_buf_p = jerry_append_chars_to_buffer (lit_buf_p, buffer_end_p, "};\n", 0);
1784 }
1785
1786 JMEM_FINALIZE_LOCAL_ARRAY (literal_array);
1787
1788 return lit_buf_p <= buffer_end_p ? (size_t) (lit_buf_p - buffer_start_p) : 0;
1789#else /* !ENABLED (JERRY_SNAPSHOT_SAVE) */
1790 JERRY_UNUSED (snapshot_p);
1791 JERRY_UNUSED (snapshot_size);
1792 JERRY_UNUSED (lit_buf_p);
1793 JERRY_UNUSED (lit_buf_size);
1794 JERRY_UNUSED (is_c_format);
1795
1796 return 0;
1797#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
1798} /* jerry_get_literals_from_snapshot */
1799
1800/**
1801 * Generate snapshot function from specified source and arguments
1802 *
1803 * @return size of snapshot (a number value), if it was generated succesfully
1804 * (i.e. there are no syntax errors in source code, buffer size is sufficient,
1805 * and snapshot support is enabled in current configuration through JERRY_SNAPSHOT_SAVE),
1806 * error object otherwise
1807 */
1808jerry_value_t
1809jerry_generate_function_snapshot (const jerry_char_t *resource_name_p, /**< script resource name */
1810 size_t resource_name_length, /**< script resource name length */
1811 const jerry_char_t *source_p, /**< script source */
1812 size_t source_size, /**< script source size */
1813 const jerry_char_t *args_p, /**< arguments string */
1814 size_t args_size, /**< arguments string size */
1815 uint32_t generate_snapshot_opts, /**< jerry_generate_snapshot_opts_t option bits */
1816 uint32_t *buffer_p, /**< buffer to save snapshot to */
1817 size_t buffer_size) /**< the buffer's size */
1818{
1819#if ENABLED (JERRY_SNAPSHOT_SAVE)
1820 uint32_t allowed_opts = (JERRY_SNAPSHOT_SAVE_STATIC | JERRY_SNAPSHOT_SAVE_STRICT);
1821
1822 if ((generate_snapshot_opts & ~(allowed_opts)) != 0)
1823 {
1824 const char * const error_message_p = "Unsupported generate snapshot flags specified.";
1825 return jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p);
1826 }
1827
1828 return jerry_generate_snapshot_with_args (resource_name_p,
1829 resource_name_length,
1830 source_p,
1831 source_size,
1832 args_p,
1833 args_size,
1834 generate_snapshot_opts,
1835 buffer_p,
1836 buffer_size);
1837#else /* !ENABLED (JERRY_SNAPSHOT_SAVE) */
1838 JERRY_UNUSED (resource_name_p);
1839 JERRY_UNUSED (resource_name_length);
1840 JERRY_UNUSED (source_p);
1841 JERRY_UNUSED (source_size);
1842 JERRY_UNUSED (args_p);
1843 JERRY_UNUSED (args_size);
1844 JERRY_UNUSED (generate_snapshot_opts);
1845 JERRY_UNUSED (buffer_p);
1846 JERRY_UNUSED (buffer_size);
1847
1848 return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t *) "Snapshot save is not supported.");
1849#endif /* ENABLED (JERRY_SNAPSHOT_SAVE) */
1850} /* jerry_generate_function_snapshot */
1851
1852/**
1853 * Load function from specified snapshot buffer
1854 *
1855 * Note:
1856 * returned value must be freed with jerry_release_value, when it is no longer needed.
1857 *
1858 * @return result of bytecode - if run was successful
1859 * thrown error - otherwise
1860 */
1861jerry_value_t
1862jerry_load_function_snapshot (const uint32_t *function_snapshot_p, /**< snapshot of the function(s) */
1863 const size_t function_snapshot_size, /**< size of the snapshot */
1864 size_t func_index, /**< index of the function to load */
1865 uint32_t exec_snapshot_opts) /**< jerry_exec_snapshot_opts_t option bits */
1866{
1867#if ENABLED (JERRY_SNAPSHOT_EXEC)
1868 return jerry_snapshot_result (function_snapshot_p, function_snapshot_size, func_index, exec_snapshot_opts, true);
1869#else /* !ENABLED (JERRY_SNAPSHOT_EXEC) */
1870 JERRY_UNUSED (function_snapshot_p);
1871 JERRY_UNUSED (function_snapshot_size);
1872 JERRY_UNUSED (func_index);
1873 JERRY_UNUSED (exec_snapshot_opts);
1874
1875 return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t *) "Snapshot execution is not supported.");
1876#endif /* ENABLED (JERRY_SNAPSHOT_EXEC) */
1877} /* jerry_load_function_snapshot */
1878