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 */ 36static inline uint32_t JERRY_ATTR_ALWAYS_INLINE 37snapshot_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 */ 60static inline bool JERRY_ATTR_ALWAYS_INLINE 61snapshot_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 */ 80typedef 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 */ 101static inline bool JERRY_ATTR_ALWAYS_INLINE 102snapshot_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 */ 134static uint32_t 135snapshot_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 */ 294static void 295static_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 */ 321static uint32_t 322static_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 */ 448static void 449jerry_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 */ 550static ecma_compiled_code_t * 551snapshot_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 */ 731static jerry_value_t 732jerry_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 */ 853jerry_value_t 854jerry_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 */ 903static jerry_value_t 904jerry_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 */ 1032jerry_value_t 1033jerry_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 */ 1059static void 1060scan_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 */ 1130static void 1131update_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 */ 1220size_t 1221jerry_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 */ 1376static bool 1377jerry_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 */ 1396static lit_utf8_size_t 1397jerry_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 */ 1423static void 1424jerry_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 */ 1451static void 1452jerry_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 */ 1484static uint8_t * 1485jerry_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 */ 1516static uint8_t * 1517jerry_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 */ 1539static uint8_t * 1540jerry_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 */ 1570size_t 1571jerry_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 */ 1773jerry_value_t 1774jerry_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 */ 1826jerry_value_t 1827jerry_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