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