From bb84466fcf7928abd8cefcc09b2ef95235df1f59 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Mon, 19 Mar 2018 23:46:52 +0100 Subject: [PATCH] Support static snapshots. (#2239) Unlike normal snapshots, no part of a static snapshot is loaded into the RAM when executed from ROM. Static snapshots rely heavily on external magic strings. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- docs/02.API-REFERENCE.md | 147 +++++++ jerry-core/api/jerry-snapshot.c | 405 +++++++++++++++--- jerry-core/api/jerry-snapshot.h | 2 +- jerry-core/api/jerry.c | 6 +- jerry-core/ecma/base/ecma-gc.c | 32 +- jerry-core/ecma/base/ecma-globals.h | 54 ++- jerry-core/ecma/base/ecma-helpers-value.c | 12 + jerry-core/ecma/base/ecma-helpers.c | 1 + jerry-core/ecma/base/ecma-helpers.h | 1 + .../ecma/operations/ecma-function-object.c | 120 +++++- .../ecma/operations/ecma-function-object.h | 14 +- jerry-core/ecma/operations/ecma-objects.c | 18 +- jerry-core/include/jerryscript-snapshot.h | 5 + jerry-core/parser/js/byte-code.h | 3 +- jerry-core/vm/vm.c | 37 +- jerry-main/main-unix-snapshot.c | 92 ++-- tests/unit-core/test-snapshot.c | 67 ++- 17 files changed, 850 insertions(+), 166 deletions(-) diff --git a/docs/02.API-REFERENCE.md b/docs/02.API-REFERENCE.md index dec8efa08..30840ae40 100644 --- a/docs/02.API-REFERENCE.md +++ b/docs/02.API-REFERENCE.md @@ -4736,6 +4736,77 @@ main (void) - [jerry_init](#jerry_init) - [jerry_cleanup](#jerry_cleanup) - [jerry_exec_snapshot](#jerry_exec_snapshot) +- [jerry_parse_and_save_static_snapshot](#jerry_parse_and_save_static_snapshot) + + +## jerry_parse_and_save_static_snapshot + +**Summary** + +Generate static snapshot from the specified source code. + +Unlike normal snaphots static snaphots are fully executed from ROM. Not +even their header is loaded into the RAM. However they can only depend +on magic strings and 28 bit integer numbers. Regular expression literals +are not supported as well. + +**Prototype** + +```c +size_t +jerry_parse_and_save_static_snapshot (const jerry_char_t *source_p, + size_t source_size, + bool is_for_global, + bool is_strict, + uint32_t *buffer_p, + size_t buffer_size); +``` + +- `source_p` - script source, it must be a valid utf8 string. +- `source_size` - script source size, in bytes. +- `is_for_global` - snapshot would be executed as global (true) or eval (false). +- `is_strict` - strict mode +- `buffer_p` - buffer to save snapshot to. +- `buffer_size` - the buffer's size. +- return value + - the size of snapshot, if it was generated succesfully (i.e. there are no syntax errors in source + code, buffer size is sufficient, only magic strings are used by the snapshot, and snapshot support + is enabled in current configuration through JERRY_ENABLE_SNAPSHOT_SAVE) + - 0 otherwise. + +**Example** + +[doctest]: # () + +```c +#include +#include "jerryscript.h" + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + static uint32_t global_mode_snapshot_buffer[256]; + const jerry_char_t *code_to_snapshot_p = (const jerry_char_t *) "(function () { return 'string'; }) ();"; + + size_t global_mode_snapshot_size = jerry_parse_and_save_static_snapshot (code_to_snapshot_p, + strlen ((const char *) code_to_snapshot_p), + true, + false, + global_mode_snapshot_buffer, + sizeof (global_mode_snapshot_buffer) / sizeof (uint32_t)); + + jerry_cleanup (); +} +``` + +**See also** + +- [jerry_init](#jerry_init) +- [jerry_cleanup](#jerry_cleanup) +- [jerry_exec_snapshot](#jerry_exec_snapshot) +- [jerry_parse_and_save_snapshot](#jerry_parse_and_save_snapshot) ## jerry_parse_and_save_function_snapshot @@ -4808,6 +4879,82 @@ main (void) - [jerry_init](#jerry_init) - [jerry_cleanup](#jerry_cleanup) - [jerry_load_function_snapshot_at](#jerry_load_function_snapshot_at) +- [jerry_parse_and_save_static_function_snapshot](#jerry_parse_and_save_static_function_snapshot) + + +## jerry_parse_and_save_static_function_snapshot + +**Summary** + +Generate static function snapshot from the specified source code +with the given function body and arguments. + +Unlike normal snaphots static snaphots are fully executed from ROM. Not +even their header is loaded into the RAM. However they can only depend +on magic strings and 28 bit integer numbers. Regular expression literals +are not supported as well. + +**Prototype** + +```c +size_t +jerry_parse_and_save_static_function_snapshot (const jerry_char_t *source_p, + size_t source_size, + const jerry_char_t *args_p, + size_t args_size, + bool is_strict, + uint32_t *buffer_p, + size_t buffer_size) +``` + +- `source_p` - script source, it must be a valid utf8 string. +- `source_size` - script source size, in bytes. +- `args_p` - function arguments, it must be a valid utf8 string. +- `args_size` - function argument size, in bytes. +- `is_strict` - strict mode +- `buffer_p` - buffer to save snapshot to. +- `buffer_size` - the buffer's size. +- return value + - the size of snapshot, if it was generated succesfully (i.e. there are no syntax errors in source + code, buffer size is sufficient, only magic strings are used by the snapshot, and snapshot support + is enabled in current configuration through JERRY_ENABLE_SNAPSHOT_SAVE) + - 0 otherwise. + +**Example** + +[doctest]: # () + +```c +#include +#include "jerryscript.h" + +int +main (void) +{ + jerry_init (JERRY_INIT_EMPTY); + + static uint32_t func_snapshot_buffer[256]; + const jerry_char_t *args_p = (const jerry_char_t *) "string, bind"; + const jerry_char_t *src_p = (const jerry_char_t *) "return bind(string)"; + + size_t func_snapshot_size = jerry_parse_and_save_static_function_snapshot (src_p, + strlen ((const char *) src_p), + args_p, + strlen ((const char *) args_p), + false, + func_snapshot_buffer, + sizeof (func_snapshot_buffer) / sizeof (uint32_t)); + + jerry_cleanup (); +} +``` + +**See also** + +- [jerry_init](#jerry_init) +- [jerry_cleanup](#jerry_cleanup) +- [jerry_load_function_snapshot_at](#jerry_load_function_snapshot_at) +- [jerry_parse_and_save_function_snapshot](#jerry_parse_and_save_function_snapshot) ## jerry_exec_snapshot diff --git a/jerry-core/api/jerry-snapshot.c b/jerry-core/api/jerry-snapshot.c index 90852f45a..6c64a0cb5 100644 --- a/jerry-core/api/jerry-snapshot.c +++ b/jerry-core/api/jerry-snapshot.c @@ -111,11 +111,11 @@ snapshot_write_to_buffer_by_offset (uint8_t *buffer_p, /**< buffer */ } /* snapshot_write_to_buffer_by_offset */ /** - * Snapshot callback for byte codes. + * Save snapshot helper. * * @return start offset */ -static uint16_t +static uint32_t snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled code */ uint8_t *snapshot_buffer_p, /**< snapshot buffer */ size_t snapshot_buffer_size, /**< snapshot buffer size */ @@ -128,7 +128,7 @@ snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled JERRY_ASSERT ((globals_p->snapshot_buffer_write_offset & (JMEM_ALIGNMENT - 1)) == 0); - if ((globals_p->snapshot_buffer_write_offset >> JMEM_ALIGNMENT_LOG) > 0xffffu) + if (globals_p->snapshot_buffer_write_offset > (UINT32_MAX >> 1)) { globals_p->snapshot_error_occured = true; return 0; @@ -136,8 +136,7 @@ snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled /* The snapshot generator always parses a single file, * so the base always starts right after the snapshot header. */ - size_t buffer_offset = globals_p->snapshot_buffer_write_offset - sizeof (jerry_snapshot_header_t); - uint16_t start_offset = (uint16_t) (buffer_offset >> JMEM_ALIGNMENT_LOG); + uint32_t start_offset = (uint32_t) (globals_p->snapshot_buffer_write_offset - sizeof (jerry_snapshot_header_t)); uint8_t *copied_code_start_p = snapshot_buffer_p + globals_p->snapshot_buffer_write_offset; ecma_compiled_code_t *copied_code_p = (ecma_compiled_code_t *) copied_code_start_p; @@ -203,28 +202,24 @@ snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled } /* Sub-functions and regular expressions are stored recursively. */ - uint8_t *src_buffer_p = (uint8_t *) compiled_code_p; - uint8_t *dst_buffer_p = (uint8_t *) copied_code_p; - ecma_value_t *src_literal_start_p; - ecma_value_t *dst_literal_start_p; + uint8_t *buffer_p = (uint8_t *) copied_code_p; + ecma_value_t *literal_start_p; uint32_t const_literal_end; uint32_t literal_end; if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { - src_literal_start_p = (ecma_value_t *) (src_buffer_p + sizeof (cbc_uint16_arguments_t)); - dst_literal_start_p = (ecma_value_t *) (dst_buffer_p + sizeof (cbc_uint16_arguments_t)); + literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint16_arguments_t)); - cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) src_buffer_p; + cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p; literal_end = (uint32_t) (args_p->literal_end - args_p->register_end); const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end); } else { - src_literal_start_p = (ecma_value_t *) (src_buffer_p + sizeof (cbc_uint8_arguments_t)); - dst_literal_start_p = (ecma_value_t *) (dst_buffer_p + sizeof (cbc_uint8_arguments_t)); + literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint8_arguments_t)); - cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) src_buffer_p; + cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p; literal_end = (uint32_t) (args_p->literal_end - args_p->register_end); const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end); } @@ -232,24 +227,154 @@ snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled for (uint32_t i = const_literal_end; i < literal_end; i++) { ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, - src_literal_start_p[i]); + literal_start_p[i]); if (bytecode_p == compiled_code_p) { - dst_literal_start_p[i] = start_offset; + literal_start_p[i] = 0; } else { - dst_literal_start_p[i] = snapshot_add_compiled_code (bytecode_p, - snapshot_buffer_p, - snapshot_buffer_size, - globals_p); + uint32_t offset = snapshot_add_compiled_code (bytecode_p, + snapshot_buffer_p, + snapshot_buffer_size, + globals_p); + + JERRY_ASSERT (globals_p->snapshot_error_occured || offset > start_offset); + + literal_start_p[i] = offset - start_offset; } } return start_offset; } /* snapshot_add_compiled_code */ +/** + * Save static snapshot helper. + * + * @return start offset + */ +static uint32_t +static_snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled code */ + uint8_t *snapshot_buffer_p, /**< snapshot buffer */ + size_t snapshot_buffer_size, /**< snapshot buffer size */ + snapshot_globals_t *globals_p) /**< snapshot globals */ +{ + if (globals_p->snapshot_error_occured) + { + return 0; + } + + JERRY_ASSERT ((globals_p->snapshot_buffer_write_offset & (JMEM_ALIGNMENT - 1)) == 0); + + if (globals_p->snapshot_buffer_write_offset >= UINT32_MAX) + { + globals_p->snapshot_error_occured = true; + return 0; + } + + /* The snapshot generator always parses a single file, + * so the base always starts right after the snapshot header. */ + uint32_t start_offset = (uint32_t) (globals_p->snapshot_buffer_write_offset - sizeof (jerry_snapshot_header_t)); + + uint8_t *copied_code_start_p = snapshot_buffer_p + globals_p->snapshot_buffer_write_offset; + ecma_compiled_code_t *copied_code_p = (ecma_compiled_code_t *) copied_code_start_p; + + if (!(compiled_code_p->status_flags & CBC_CODE_FLAGS_FUNCTION)) + { + /* Regular expression literals are not supported. */ + globals_p->snapshot_error_occured = true; + return 0; + } + + if (!snapshot_write_to_buffer_by_offset (snapshot_buffer_p, + snapshot_buffer_size, + &globals_p->snapshot_buffer_write_offset, + compiled_code_p, + ((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG)) + { + globals_p->snapshot_error_occured = true; + return 0; + } + + /* Sub-functions and regular expressions are stored recursively. */ + uint8_t *buffer_p = (uint8_t *) copied_code_p; + ecma_value_t *literal_start_p; + uint32_t argument_end; + uint32_t const_literal_end; + uint32_t literal_end; + + ((ecma_compiled_code_t *) copied_code_p)->status_flags |= CBC_CODE_FLAGS_STATIC_FUNCTION; + + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) + { + literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint16_arguments_t)); + + cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p; + argument_end = args_p->argument_end; + literal_end = (uint32_t) (args_p->literal_end - args_p->register_end); + const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end); + } + else + { + literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint8_arguments_t)); + + cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p; + argument_end = args_p->argument_end; + literal_end = (uint32_t) (args_p->literal_end - args_p->register_end); + const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end); + } + + for (uint32_t i = 0; i < const_literal_end; i++) + { + if (!ecma_is_value_direct (literal_start_p[i]) + && !ecma_is_value_direct_string (literal_start_p[i])) + { + globals_p->snapshot_error_occured = true; + return 0; + } + } + + for (uint32_t i = const_literal_end; i < literal_end; i++) + { + ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, + literal_start_p[i]); + + if (bytecode_p == compiled_code_p) + { + literal_start_p[i] = 0; + } + else + { + uint32_t offset = static_snapshot_add_compiled_code (bytecode_p, + snapshot_buffer_p, + snapshot_buffer_size, + globals_p); + + JERRY_ASSERT (globals_p->snapshot_error_occured || offset > start_offset); + + literal_start_p[i] = offset - start_offset; + } + } + + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED) + { + buffer_p += ((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG; + literal_start_p = ((ecma_value_t *) buffer_p) - argument_end; + + for (uint32_t i = 0; i < argument_end; i++) + { + if (!ecma_is_value_direct_string (literal_start_p[i])) + { + globals_p->snapshot_error_occured = true; + return 0; + } + } + } + + return start_offset; +} /* static_snapshot_add_compiled_code */ + /** * Set the uint16_t offsets in the code area. */ @@ -358,11 +483,10 @@ jerry_snapshot_set_offsets (uint32_t *buffer_p, /**< buffer */ static ecma_compiled_code_t * snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of the * current primary function */ - size_t offset, /**< byte code offset */ const uint8_t *literal_base_p, /**< literal start */ bool copy_bytecode) /**< byte code should be copied to memory */ { - ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) (base_addr_p + offset); + ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) base_addr_p; uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION)) @@ -431,7 +555,7 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th jmem_stats_allocate_byte_code_bytes (code_size); #endif /* JMEM_STATS */ - memcpy (bytecode_p, base_addr_p + offset, code_size); + memcpy (bytecode_p, base_addr_p, code_size); } else { @@ -453,7 +577,7 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th jmem_stats_allocate_byte_code_bytes (new_code_size); #endif /* JMEM_STATS */ - memcpy (bytecode_p, base_addr_p + offset, start_offset); + memcpy (bytecode_p, base_addr_p, start_offset); bytecode_p->size = (uint16_t) (new_code_size >> JMEM_ALIGNMENT_LOG); @@ -463,7 +587,7 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th { uint32_t argument_size = (uint32_t) (argument_end * sizeof (ecma_value_t)); memcpy (byte_p + new_code_size - argument_size, - base_addr_p + offset + code_size - argument_size, + base_addr_p + code_size - argument_size, argument_size); } @@ -491,9 +615,9 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th for (uint32_t i = const_literal_end; i < literal_end; i++) { - size_t literal_offset = ((size_t) literal_start_p[i]) << JMEM_ALIGNMENT_LOG; + size_t literal_offset = (size_t) literal_start_p[i]; - if (literal_offset == offset) + if (literal_offset == 0) { /* Self reference */ ECMA_SET_INTERNAL_VALUE_POINTER (literal_start_p[i], @@ -502,8 +626,7 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th else { ecma_compiled_code_t *literal_bytecode_p; - literal_bytecode_p = snapshot_load_compiled_code (base_addr_p, - literal_offset, + literal_bytecode_p = snapshot_load_compiled_code (base_addr_p + literal_offset, literal_base_p, copy_bytecode); @@ -532,6 +655,17 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th #endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ #ifdef JERRY_ENABLE_SNAPSHOT_SAVE + +/** + * jerry_parse_and_save_snapshot_with_args flags. + */ +typedef enum +{ + JERRY_SNAPSHOT_SAVE_STATIC = (1u << 0), /**< static snapshot */ + JERRY_SNAPSHOT_SAVE_STRICT = (1u << 1), /**< strict mode code */ + JERRY_SNAPSHOT_SAVE_EVAL = (1u << 2), /**< eval context code */ +} jerry_parse_and_save_snapshot_flags_t; + /** * Generate snapshot from specified source and arguments * @@ -545,9 +679,7 @@ jerry_parse_and_save_snapshot_with_args (const jerry_char_t *source_p, /**< scri size_t source_size, /**< script source size */ const jerry_char_t *args_p, /**< arguments string */ size_t args_size, /**< arguments string size */ - bool is_for_global, /**< snapshot would be executed as global (true) - * or eval (false) */ - bool is_strict, /**< strict mode */ + uint32_t flags, /**< jerry_parse_and_save_snapshot_flags_t flags */ uint32_t *buffer_p, /**< buffer to save snapshot to */ size_t buffer_size) /**< the buffer's size */ { @@ -565,7 +697,7 @@ jerry_parse_and_save_snapshot_with_args (const jerry_char_t *source_p, /**< scri args_size, source_p, source_size, - is_strict, + (flags & JERRY_SNAPSHOT_SAVE_STRICT) != 0, &bytecode_data_p); if (ECMA_IS_VALUE_ERROR (parse_status)) @@ -574,7 +706,14 @@ jerry_parse_and_save_snapshot_with_args (const jerry_char_t *source_p, /**< scri return 0; } - snapshot_add_compiled_code (bytecode_data_p, (uint8_t *) buffer_p, buffer_size, &globals); + if (flags & JERRY_SNAPSHOT_SAVE_STATIC) + { + static_snapshot_add_compiled_code (bytecode_data_p, (uint8_t *) buffer_p, buffer_size, &globals); + } + else + { + snapshot_add_compiled_code (bytecode_data_p, (uint8_t *) buffer_p, buffer_size, &globals); + } if (globals.snapshot_error_occured) { @@ -589,32 +728,35 @@ jerry_parse_and_save_snapshot_with_args (const jerry_char_t *source_p, /**< scri header.number_of_funcs = 1; header.func_offsets[0] = aligned_header_size; - if (!is_for_global) + if (flags & JERRY_SNAPSHOT_SAVE_EVAL) { header.func_offsets[0] |= JERRY_SNAPSHOT_EVAL_CONTEXT; } lit_mem_to_snapshot_id_map_entry_t *lit_map_p = NULL; - uint32_t literals_num; + uint32_t literals_num = 0; - ecma_collection_header_t *lit_pool_p = ecma_new_values_collection (); - - ecma_save_literals_add_compiled_code (bytecode_data_p, lit_pool_p); - - if (!ecma_save_literals_for_snapshot (lit_pool_p, - buffer_p, - buffer_size, - &globals.snapshot_buffer_write_offset, - &lit_map_p, - &literals_num)) + if (!(flags & JERRY_SNAPSHOT_SAVE_STATIC)) { - JERRY_ASSERT (lit_map_p == NULL); - return 0; - } + ecma_collection_header_t *lit_pool_p = ecma_new_values_collection (); - jerry_snapshot_set_offsets (buffer_p + (aligned_header_size / sizeof (uint32_t)), - (uint32_t) (header.lit_table_offset - aligned_header_size), - lit_map_p); + ecma_save_literals_add_compiled_code (bytecode_data_p, lit_pool_p); + + if (!ecma_save_literals_for_snapshot (lit_pool_p, + buffer_p, + buffer_size, + &globals.snapshot_buffer_write_offset, + &lit_map_p, + &literals_num)) + { + JERRY_ASSERT (lit_map_p == NULL); + return 0; + } + + jerry_snapshot_set_offsets (buffer_p + (aligned_header_size / sizeof (uint32_t)), + (uint32_t) (header.lit_table_offset - aligned_header_size), + lit_map_p); + } size_t header_offset = 0; @@ -633,6 +775,7 @@ jerry_parse_and_save_snapshot_with_args (const jerry_char_t *source_p, /**< scri return globals.snapshot_buffer_write_offset; } /* jerry_parse_and_save_snapshot_with_args */ + #endif /* JERRY_ENABLE_SNAPSHOT_SAVE */ /** @@ -653,12 +796,14 @@ jerry_parse_and_save_snapshot (const jerry_char_t *source_p, /**< script source size_t buffer_size) /**< the buffer's size */ { #ifdef JERRY_ENABLE_SNAPSHOT_SAVE + uint32_t flags = (!is_for_global ? JERRY_SNAPSHOT_SAVE_EVAL : 0); + flags |= (is_strict ? JERRY_SNAPSHOT_SAVE_STRICT : 0); + return jerry_parse_and_save_snapshot_with_args (source_p, source_size, NULL, 0, - is_for_global, - is_strict, + flags, buffer_p, buffer_size); #else /* !JERRY_ENABLE_SNAPSHOT_SAVE */ @@ -673,6 +818,48 @@ jerry_parse_and_save_snapshot (const jerry_char_t *source_p, /**< script source #endif /* JERRY_ENABLE_SNAPSHOT_SAVE */ } /* jerry_parse_and_save_snapshot */ +/** + * Generate static snapshot from specified source + * + * @return size of snapshot, if it was generated succesfully + * (i.e. there are no syntax errors in source code, all static snapshot requirements + * are satisfied, buffer size is sufficient, and snapshot support is enabled in + * current configuration through JERRY_ENABLE_SNAPSHOT_SAVE), + * 0 - otherwise. + */ +size_t +jerry_parse_and_save_static_snapshot (const jerry_char_t *source_p, /**< script source */ + size_t source_size, /**< script source size */ + bool is_for_global, /**< snapshot would be executed as global (true) + * or eval (false) */ + bool is_strict, /**< strict mode */ + uint32_t *buffer_p, /**< buffer to save snapshot to */ + size_t buffer_size) /**< the buffer's size */ +{ +#ifdef JERRY_ENABLE_SNAPSHOT_SAVE + uint32_t flags = JERRY_SNAPSHOT_SAVE_STATIC; + flags |= (!is_for_global ? JERRY_SNAPSHOT_SAVE_EVAL : 0); + flags |= (is_strict ? JERRY_SNAPSHOT_SAVE_STRICT : 0); + + return jerry_parse_and_save_snapshot_with_args (source_p, + source_size, + NULL, + 0, + flags, + buffer_p, + buffer_size); +#else /* !JERRY_ENABLE_SNAPSHOT_SAVE */ + JERRY_UNUSED (source_p); + JERRY_UNUSED (source_size); + JERRY_UNUSED (is_for_global); + JERRY_UNUSED (is_strict); + JERRY_UNUSED (buffer_p); + JERRY_UNUSED (buffer_size); + + return 0; +#endif /* JERRY_ENABLE_SNAPSHOT_SAVE */ +} /* jerry_parse_and_save_static_snapshot */ + #ifdef JERRY_ENABLE_SNAPSHOT_EXEC /** * Execute/load snapshot from specified buffer @@ -731,18 +918,29 @@ jerry_snapshot_result_at (const uint32_t *snapshot_p, /**< snapshot */ JERRY_ASSERT ((header_p->lit_table_offset % sizeof (uint32_t)) == 0); - const uint8_t *literal_base_p = (uint8_t *) (snapshot_data_p + header_p->lit_table_offset); - ecma_compiled_code_t *bytecode_p; - uint32_t func_offset = header_p->func_offsets[func_index] & ~JERRY_SNAPSHOT_EVAL_CONTEXT; - bytecode_p = snapshot_load_compiled_code (snapshot_data_p + func_offset, - 0, - literal_base_p, - copy_bytecode); + ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) (snapshot_data_p + func_offset); - if (bytecode_p == NULL) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION) { - return ecma_raise_type_error (invalid_format_error_p); + if (copy_bytecode) + { + ecma_raise_common_error (ECMA_ERR_MSG ("Static snapshots cannot be copied into memory")); + return ecma_create_error_reference_from_context (); + } + } + else + { + const uint8_t *literal_base_p = (uint8_t *) (snapshot_data_p + header_p->lit_table_offset); + + bytecode_p = snapshot_load_compiled_code ((const uint8_t *) bytecode_p, + literal_base_p, + copy_bytecode); + + if (bytecode_p == NULL) + { + return ecma_raise_type_error (invalid_format_error_p); + } } ecma_value_t ret_val; @@ -752,8 +950,11 @@ jerry_snapshot_result_at (const uint32_t *snapshot_p, /**< snapshot */ ecma_object_t *lex_env_p = ecma_get_global_environment (); ecma_object_t *func_obj_p = ecma_op_create_function_object (lex_env_p, bytecode_p); - ecma_bytecode_deref (bytecode_p); + if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) + { + ecma_bytecode_deref (bytecode_p); + } ret_val = ecma_make_object_value (func_obj_p); } else if (header_p->func_offsets[func_index] & JERRY_SNAPSHOT_EVAL_CONTEXT) @@ -763,7 +964,10 @@ jerry_snapshot_result_at (const uint32_t *snapshot_p, /**< snapshot */ else { ret_val = vm_run_global (bytecode_p); - ecma_bytecode_deref (bytecode_p); + if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) + { + ecma_bytecode_deref (bytecode_p); + } } if (ECMA_IS_VALUE_ERROR (ret_val)) @@ -861,7 +1065,8 @@ scan_snapshot_functions (const uint8_t *buffer_p, /**< snapshot buffer start */ ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) buffer_p; uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; - if (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) + if ((bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) + && !(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) { ecma_value_t *literal_start_p; uint32_t argument_end; @@ -932,7 +1137,8 @@ update_literal_offsets (uint8_t *buffer_p, /**< snapshot buffer start */ ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) buffer_p; uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; - if (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) + if ((bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) + && !(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) { ecma_value_t *literal_start_p; uint32_t argument_end; @@ -1574,6 +1780,14 @@ jerry_parse_and_save_literals (const jerry_char_t *source_p, /**< script source #endif /* JERRY_ENABLE_SNAPSHOT_SAVE */ } /* jerry_parse_and_save_literals */ +/** + * Generate snapshot from specified function source + * + * @return size of snapshot, if it was generated succesfully + * (i.e. there are no syntax errors in source code, buffer size is sufficient, + * and snapshot support is enabled in current configuration through JERRY_ENABLE_SNAPSHOT_SAVE), + * 0 - otherwise. + */ size_t jerry_parse_and_save_function_snapshot (const jerry_char_t *source_p, /**< function body source */ size_t source_size, /**< function body size */ const jerry_char_t *args_p, /**< arguments string */ @@ -1583,12 +1797,13 @@ size_t jerry_parse_and_save_function_snapshot (const jerry_char_t *source_p, /** size_t buffer_size) /**< the buffer's size */ { #ifdef JERRY_ENABLE_SNAPSHOT_SAVE + uint32_t flags = (is_strict ? JERRY_SNAPSHOT_SAVE_STRICT : 0); + return jerry_parse_and_save_snapshot_with_args (source_p, source_size, args_p, args_size, - true, - is_strict, + flags, buffer_p, buffer_size); #else /* !JERRY_ENABLE_SNAPSHOT_SAVE */ @@ -1604,6 +1819,56 @@ size_t jerry_parse_and_save_function_snapshot (const jerry_char_t *source_p, /** #endif /* JERRY_ENABLE_SNAPSHOT_SAVE */ } /* jerry_parse_and_save_function_snapshot */ +/** + * Generate static snapshot from specified function source + * + * @return size of snapshot, if it was generated succesfully + * (i.e. there are no syntax errors in source code, all static snapshot requirements + * are satisfied, buffer size is sufficient, and snapshot support is enabled in + * current configuration through JERRY_ENABLE_SNAPSHOT_SAVE), + * 0 - otherwise. + */ +size_t jerry_parse_and_save_static_function_snapshot (const jerry_char_t *source_p, /**< function body source */ + size_t source_size, /**< function body size */ + const jerry_char_t *args_p, /**< arguments string */ + size_t args_size, /**< arguments string size */ + bool is_strict, /**< strict mode */ + uint32_t *buffer_p, /**< buffer to save snapshot to */ + size_t buffer_size) /**< the buffer's size */ +{ +#ifdef JERRY_ENABLE_SNAPSHOT_SAVE + uint32_t flags = JERRY_SNAPSHOT_SAVE_STATIC; + flags |= (is_strict ? JERRY_SNAPSHOT_SAVE_STRICT : 0); + + return jerry_parse_and_save_snapshot_with_args (source_p, + source_size, + args_p, + args_size, + flags, + buffer_p, + buffer_size); +#else /* !JERRY_ENABLE_SNAPSHOT_SAVE */ + JERRY_UNUSED (source_p); + JERRY_UNUSED (source_size); + JERRY_UNUSED (args_p); + JERRY_UNUSED (args_size); + JERRY_UNUSED (is_strict); + JERRY_UNUSED (buffer_p); + JERRY_UNUSED (buffer_size); + + return 0; +#endif /* JERRY_ENABLE_SNAPSHOT_SAVE */ +} /* jerry_parse_and_save_static_function_snapshot */ + +/** + * Load function from specified snapshot buffer + * + * Note: + * returned value must be freed with jerry_release_value, when it is no longer needed. + * + * @return result of bytecode - if run was successful + * thrown error - otherwise + */ jerry_value_t jerry_load_function_snapshot_at (const uint32_t *function_snapshot_p, /**< snapshot of the function(s) */ const size_t function_snapshot_size, /**< size of the snapshot */ size_t func_index, /**< index of the function to load */ diff --git a/jerry-core/api/jerry-snapshot.h b/jerry-core/api/jerry-snapshot.h index 76038dda9..080d729d0 100644 --- a/jerry-core/api/jerry-snapshot.h +++ b/jerry-core/api/jerry-snapshot.h @@ -46,7 +46,7 @@ typedef struct /** * Jerry snapshot format version. */ -#define JERRY_SNAPSHOT_VERSION (9u) +#define JERRY_SNAPSHOT_VERSION (10u) /** * Snapshot configuration flags. diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 5b3d164c4..4b9e002b0 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -558,11 +558,7 @@ jerry_run (const jerry_value_t func_val) /**< function to run */ return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p))); } - const ecma_compiled_code_t *bytecode_data_p; - bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp); - - return jerry_return (vm_run_global (bytecode_data_p)); + return jerry_return (vm_run_global (ecma_op_function_get_compiled_code (ext_func_p))); } /* jerry_run */ /** diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 995cf665f..6bd2c53a1 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -631,10 +631,22 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ /* Function with byte-code (not a built-in function). */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (ext_func_p->u.function.bytecode_cp != ECMA_NULL_POINTER) + { + ecma_bytecode_deref (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, + ext_func_p->u.function.bytecode_cp)); + ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); + } + else + { + ecma_dealloc_extended_object (object_p, sizeof (ecma_static_function_t)); + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ ecma_bytecode_deref (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, ext_func_p->u.function.bytecode_cp)); - ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); +#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ return; } @@ -643,12 +655,24 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ { ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; - ecma_bytecode_deref (ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, - arrow_func_p->bytecode_cp)); - ecma_free_value_if_not_object (arrow_func_p->this_binding); +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (arrow_func_p->bytecode_cp != ECMA_NULL_POINTER) + { + ecma_bytecode_deref (ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, + arrow_func_p->bytecode_cp)); + ecma_dealloc_extended_object (object_p, sizeof (ecma_arrow_function_t)); + } + else + { + ecma_dealloc_extended_object (object_p, sizeof (ecma_static_arrow_function_t)); + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ + ecma_bytecode_deref (ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, + arrow_func_p->bytecode_cp)); ecma_dealloc_extended_object (object_p, sizeof (ecma_arrow_function_t)); +#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ return; } #endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index 8ca734d15..794bb67eb 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -797,6 +797,33 @@ typedef struct ecma_built_in_props_t built_in; /**< built-in object part */ } ecma_extended_built_in_object_t; +/** + * Compiled byte code data. + */ +typedef struct +{ + uint16_t size; /**< real size >> JMEM_ALIGNMENT_LOG */ + uint16_t refs; /**< reference counter for the byte code */ + uint16_t status_flags; /**< various status flags: + * CBC_CODE_FLAGS_FUNCTION flag tells whether + * the byte code is function or regular expression. + * If function, the other flags must be CBC_CODE_FLAGS... + * If regexp, the other flags must be RE_FLAG... */ +} ecma_compiled_code_t; + +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + +/** + * Description of static function objects. + */ +typedef struct +{ + ecma_extended_object_t header; + const ecma_compiled_code_t *bytecode_p; +} ecma_static_function_t; + +#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ + #ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION /** @@ -810,6 +837,19 @@ typedef struct jmem_cpointer_t bytecode_cp; /**< function byte code */ } ecma_arrow_function_t; +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + +/** + * Description of static arrow function objects. + */ +typedef struct +{ + ecma_arrow_function_t header; + const ecma_compiled_code_t *bytecode_p; +} ecma_static_arrow_function_t; + +#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ + #endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ /** @@ -1276,20 +1316,6 @@ typedef struct ecma_value_t value; /**< referenced value */ } ecma_error_reference_t; -/** - * Compiled byte code data. - */ -typedef struct -{ - uint16_t size; /**< real size >> JMEM_ALIGNMENT_LOG */ - uint16_t refs; /**< reference counter for the byte code */ - uint16_t status_flags; /**< various status flags: - * CBC_CODE_FLAGS_FUNCTION flag tells whether - * the byte code is function or regular expression. - * If function, the other flags must be CBC_CODE_FLAGS... - * If regexp, the other flags must be RE_FLAG... */ -} ecma_compiled_code_t; - #ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE /** diff --git a/jerry-core/ecma/base/ecma-helpers-value.c b/jerry-core/ecma/base/ecma-helpers-value.c index 38283827f..ae596e03b 100644 --- a/jerry-core/ecma/base/ecma-helpers-value.c +++ b/jerry-core/ecma/base/ecma-helpers-value.c @@ -311,6 +311,18 @@ ecma_is_value_string (ecma_value_t value) /**< ecma value */ return ((value & (ECMA_VALUE_TYPE_MASK - 0x4)) == ECMA_TYPE_STRING); } /* ecma_is_value_string */ +/** + * Check if the value is direct_ecma-string. + * + * @return true - if the value contains ecma-string value, + * false - otherwise + */ +inline bool __attr_const___ __attr_always_inline___ +ecma_is_value_direct_string (ecma_value_t value) /**< ecma value */ +{ + return (ecma_get_value_type_field (value) == ECMA_TYPE_DIRECT_STRING); +} /* ecma_is_value_direct_string */ + /** * Check if the value is object. * diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c index 7541b983b..3272f944c 100644 --- a/jerry-core/ecma/base/ecma-helpers.c +++ b/jerry-core/ecma/base/ecma-helpers.c @@ -1487,6 +1487,7 @@ void ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */ { JERRY_ASSERT (bytecode_p->refs > 0); + JERRY_ASSERT (!(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)); bytecode_p->refs--; diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h index 457f89bd6..765b72c82 100644 --- a/jerry-core/ecma/base/ecma-helpers.h +++ b/jerry-core/ecma/base/ecma-helpers.h @@ -154,6 +154,7 @@ bool ecma_are_values_integer_numbers (ecma_value_t first_value, ecma_value_t sec bool ecma_is_value_float_number (ecma_value_t value) __attr_const___; bool ecma_is_value_number (ecma_value_t value) __attr_const___; bool ecma_is_value_string (ecma_value_t value) __attr_const___; +bool ecma_is_value_direct_string (ecma_value_t value) __attr_const___; bool ecma_is_value_object (ecma_value_t value) __attr_const___; bool ecma_is_value_error_reference (ecma_value_t value) __attr_const___; bool ecma_is_value_collection_chunk (ecma_value_t value) __attr_const___; diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index 7991b35fb..90e76103b 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -124,8 +124,17 @@ ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */ /* 1., 4., 13. */ ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); + size_t function_object_size = sizeof (ecma_extended_object_t); + +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION) + { + function_object_size = sizeof (ecma_static_function_t); + } +#endif + ecma_object_t *func_p = ecma_create_object (prototype_obj_p, - sizeof (ecma_extended_object_t), + function_object_size, ECMA_OBJECT_TYPE_FUNCTION); ecma_deref_object (prototype_obj_p); @@ -150,8 +159,22 @@ ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */ ECMA_SET_INTERNAL_VALUE_POINTER (ext_func_p->u.function.scope_cp, scope_p); /* 10., 11., 12. */ + +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) + { + ECMA_SET_INTERNAL_VALUE_POINTER (ext_func_p->u.function.bytecode_cp, bytecode_data_p); + ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p); + } + else + { + ext_func_p->u.function.bytecode_cp = ECMA_NULL_POINTER; + ((ecma_static_function_t *) func_p)->bytecode_p = bytecode_data_p; + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ ECMA_SET_INTERNAL_VALUE_POINTER (ext_func_p->u.function.bytecode_cp, bytecode_data_p); ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p); +#endif /* 14., 15., 16., 17., 18. */ /* @@ -179,8 +202,17 @@ ecma_op_create_arrow_function_object (ecma_object_t *scope_p, /**< function's sc { ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); + size_t arrow_function_object_size = sizeof (ecma_arrow_function_t); + +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION) + { + arrow_function_object_size = sizeof (ecma_static_arrow_function_t); + } +#endif + ecma_object_t *func_p = ecma_create_object (prototype_obj_p, - sizeof (ecma_arrow_function_t), + arrow_function_object_size, ECMA_OBJECT_TYPE_ARROW_FUNCTION); ecma_deref_object (prototype_obj_p); @@ -190,8 +222,21 @@ ecma_op_create_arrow_function_object (ecma_object_t *scope_p, /**< function's sc ECMA_SET_NON_NULL_POINTER (arrow_func_p->scope_cp, scope_p); +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) + { + ECMA_SET_NON_NULL_POINTER (arrow_func_p->bytecode_cp, bytecode_data_p); + ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p); + } + else + { + arrow_func_p->bytecode_cp = ECMA_NULL_POINTER; + ((ecma_static_arrow_function_t *) func_p)->bytecode_p = bytecode_data_p; + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ ECMA_SET_NON_NULL_POINTER (arrow_func_p->bytecode_cp, bytecode_data_p); ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p); +#endif arrow_func_p->this_binding = ecma_copy_value_if_not_object (this_binding); return func_p; @@ -232,6 +277,58 @@ ecma_op_create_external_function_object (ecma_external_handler_t handler_cb) /** return function_obj_p; } /* ecma_op_create_external_function_object */ +/** + * Get compiled code of a function object. + * + * @return compiled code + */ +inline const ecma_compiled_code_t * __attr_always_inline___ +ecma_op_function_get_compiled_code (ecma_extended_object_t *function_p) /**< function pointer */ +{ +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (function_p->u.function.bytecode_cp != ECMA_NULL_POINTER) + { + return ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, + function_p->u.function.bytecode_cp); + } + else + { + return ((ecma_static_function_t *) function_p)->bytecode_p; + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ + return ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, + function_p->u.function.bytecode_cp); +#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ +} /* ecma_op_function_get_compiled_code */ + +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + +/** + * Get compiled code of an arrow function object. + * + * @return compiled code + */ +inline const ecma_compiled_code_t * __attr_always_inline___ +ecma_op_arrow_function_get_compiled_code (ecma_arrow_function_t *arrow_function_p) /**< arrow function pointer */ +{ +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (arrow_function_p->bytecode_cp != ECMA_NULL_POINTER) + { + return ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, + arrow_function_p->bytecode_cp); + } + else + { + return ((ecma_static_arrow_function_t *) arrow_function_p)->bytecode_p; + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ + return ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, + arrow_function_p->bytecode_cp); +#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ +} /* ecma_op_arrow_function_get_compiled_code */ + +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ + /** * [[Call]] implementation for Function objects, * created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION) @@ -357,9 +454,7 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ bool is_strict; bool is_no_lex_env; - const ecma_compiled_code_t *bytecode_data_p; - bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp); + const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) ? true : false; is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) ? true : false; @@ -428,9 +523,7 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ bool is_no_lex_env; - const ecma_compiled_code_t *bytecode_data_p; - bytecode_data_p = ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, - arrow_func_p->bytecode_cp); + const ecma_compiled_code_t *bytecode_data_p = ecma_op_arrow_function_get_compiled_code (arrow_func_p); is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) ? true : false; @@ -782,15 +875,13 @@ ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARROW_FUNCTION) { ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; - bytecode_data_p = ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, - arrow_func_p->bytecode_cp); + bytecode_data_p = ecma_op_arrow_function_get_compiled_code (arrow_func_p); } else { #endif /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp); + bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); #ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION } #endif /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ @@ -961,11 +1052,8 @@ ecma_op_function_list_lazy_property_names (ecma_object_t *object_p, /**< functio ecma_make_magic_string_value (LIT_MAGIC_STRING_PROTOTYPE), 0); - ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - const ecma_compiled_code_t *bytecode_data_p; - bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp); + bytecode_data_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p); if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) { diff --git a/jerry-core/ecma/operations/ecma-function-object.h b/jerry-core/ecma/operations/ecma-function-object.h index 3a92c092e..a047b6ad0 100644 --- a/jerry-core/ecma/operations/ecma-function-object.h +++ b/jerry-core/ecma/operations/ecma-function-object.h @@ -43,6 +43,17 @@ ecma_op_create_arrow_function_object (ecma_object_t *scope_p, const ecma_compile ecma_object_t * ecma_op_create_external_function_object (ecma_external_handler_t handler_cb); +const ecma_compiled_code_t * +ecma_op_function_get_compiled_code (ecma_extended_object_t *function_p); + +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION +const ecma_compiled_code_t * +ecma_op_arrow_function_get_compiled_code (ecma_arrow_function_t *arrow_function_p); +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ + +ecma_value_t +ecma_op_function_has_instance (ecma_object_t *func_obj_p, ecma_value_t value); + ecma_value_t ecma_op_function_call (ecma_object_t *func_obj_p, ecma_value_t this_arg_value, const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len); @@ -51,9 +62,6 @@ ecma_value_t ecma_op_function_construct (ecma_object_t *func_obj_p, const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len); -ecma_value_t -ecma_op_function_has_instance (ecma_object_t *func_obj_p, ecma_value_t value); - ecma_property_t * ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, ecma_string_t *property_name_p); diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 5c80a0f86..d535d4b6a 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -208,19 +208,16 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ if (type != ECMA_OBJECT_TYPE_ARROW_FUNCTION) { ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp); + bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); } else { ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; - bytecode_data_p = ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, - arrow_func_p->bytecode_cp); + bytecode_data_p = ecma_op_arrow_function_get_compiled_code (arrow_func_p); } #else /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp); + bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); #endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ uint32_t len; @@ -532,19 +529,16 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */ if (type != ECMA_OBJECT_TYPE_ARROW_FUNCTION) { ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp); + bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); } else { ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; - bytecode_data_p = ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, - arrow_func_p->bytecode_cp); + bytecode_data_p = ecma_op_arrow_function_get_compiled_code (arrow_func_p); } #else /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp); + bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); #endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ uint32_t len; diff --git a/jerry-core/include/jerryscript-snapshot.h b/jerry-core/include/jerryscript-snapshot.h index e8c66916e..df6e1ef37 100644 --- a/jerry-core/include/jerryscript-snapshot.h +++ b/jerry-core/include/jerryscript-snapshot.h @@ -32,6 +32,8 @@ extern "C" */ size_t jerry_parse_and_save_snapshot (const jerry_char_t *source_p, size_t source_size, bool is_for_global, bool is_strict, uint32_t *buffer_p, size_t buffer_size); +size_t jerry_parse_and_save_static_snapshot (const jerry_char_t *source_p, size_t source_size, bool is_for_global, + bool is_strict, uint32_t *buffer_p, size_t buffer_size); jerry_value_t jerry_exec_snapshot (const uint32_t *snapshot_p, size_t snapshot_size, bool copy_bytecode); jerry_value_t jerry_exec_snapshot_at (const uint32_t *snapshot_p, size_t snapshot_size, size_t func_index, bool copy_bytecode); @@ -43,6 +45,9 @@ size_t jerry_parse_and_save_literals (const jerry_char_t *source_p, size_t sourc size_t jerry_parse_and_save_function_snapshot (const jerry_char_t *source_p, size_t source_size, const jerry_char_t *args_p, size_t args_size, bool is_strict, uint32_t *buffer_p, size_t buffer_size); +size_t jerry_parse_and_save_static_function_snapshot (const jerry_char_t *source_p, size_t source_size, + const jerry_char_t *args_p, size_t args_size, + bool is_strict, uint32_t *buffer_p, size_t buffer_size); jerry_value_t jerry_load_function_snapshot_at (const uint32_t *function_snapshot_p, const size_t function_snapshot_size, size_t func_index, diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index 58531f057..e8f234f37 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -653,7 +653,8 @@ typedef enum CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED = (1u << 5), /**< non-strict arguments object must be constructed */ CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED = (1u << 6), /**< no need to create a lexical environment */ CBC_CODE_FLAGS_ARROW_FUNCTION = (1u << 7), /**< this function is an arrow function */ - CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 8), /**< this function should be ignored by debugger */ + CBC_CODE_FLAGS_STATIC_FUNCTION = (1u << 8), /**< this function is a static snapshot function */ + CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 9), /**< this function should be ignored by debugger */ } cbc_code_flags; #define CBC_OPCODE(arg1, arg2, arg3, arg4) arg1, diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index d10b6ffae..d1dce341d 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -275,7 +275,15 @@ vm_run_eval (ecma_compiled_code_t *bytecode_data_p, /**< byte-code data */ ecma_deref_object (lex_env_p); ecma_free_value (this_binding); + +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) + { + ecma_bytecode_deref (bytecode_data_p); + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ ecma_bytecode_deref (bytecode_data_p); +#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ return completion_value; } /* vm_run_eval */ @@ -289,8 +297,24 @@ static ecma_value_t vm_construct_literal_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ ecma_value_t lit_value) /**< literal */ { +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + ecma_compiled_code_t *bytecode_p; + + if (likely (!(frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION))) + { + bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, + lit_value); + } + else + { + uint8_t *byte_p = ((uint8_t *) frame_ctx_p->bytecode_header_p) + lit_value; + bytecode_p = (ecma_compiled_code_t *) byte_p; + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, lit_value); +#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ + bool is_function = ((bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) != 0); if (is_function) @@ -556,7 +580,16 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_value_t *literal_start_p = frame_ctx_p->literal_start_p; bool is_strict = ((frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0); ecma_value_t self_reference; + +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + self_reference = 0; + if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) + { + ECMA_SET_INTERNAL_VALUE_POINTER (self_reference, bytecode_header_p); + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ ECMA_SET_INTERNAL_VALUE_POINTER (self_reference, bytecode_header_p); +#endif /* Prepare. */ if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_FULL_LITERAL_ENCODING)) @@ -625,6 +658,7 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { uint32_t value_index; ecma_value_t lit_value; + bool is_immutable_binding = false; READ_LITERAL_INDEX (value_index); @@ -634,6 +668,7 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } else { + is_immutable_binding = (self_reference == literal_start_p[value_index]); lit_value = vm_construct_literal_object (frame_ctx_p, literal_start_p[value_index]); } @@ -646,7 +681,7 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); - if (likely (value_index < register_end || self_reference != literal_start_p[value_index])) + if (likely (!is_immutable_binding)) { vm_var_decl (frame_ctx_p, name_p); diff --git a/jerry-main/main-unix-snapshot.c b/jerry-main/main-unix-snapshot.c index e5faaf5b6..94ee4c53c 100644 --- a/jerry-main/main-unix-snapshot.c +++ b/jerry-main/main-unix-snapshot.c @@ -126,10 +126,11 @@ read_file (uint8_t *input_pos_p, /**< next position in the input buffer */ typedef enum { OPT_GENERATE_HELP, + OPT_GENERATE_STATIC, OPT_GENERATE_CONTEXT, - OPT_GENERATE_SHOW_OP, OPT_GENERATE_LITERAL_LIST, OPT_GENERATE_LITERAL_C, + OPT_GENERATE_SHOW_OP, OPT_GENERATE_OUT, } generate_opt_id_t; @@ -140,8 +141,8 @@ static const cli_opt_t generate_opts[] = { CLI_OPT_DEF (.id = OPT_GENERATE_HELP, .opt = "h", .longopt = "help", .help = "print this help and exit"), - CLI_OPT_DEF (.id = OPT_GENERATE_SHOW_OP, .longopt = "show-opcodes", - .help = "print generated opcodes"), + CLI_OPT_DEF (.id = OPT_GENERATE_STATIC, .opt = "s", .longopt = "static", + .help = "generate static snapshot"), CLI_OPT_DEF (.id = OPT_GENERATE_CONTEXT, .opt = "c", .longopt = "context", .meta = "MODE", .help = "specify the execution context of the snapshot: " @@ -152,6 +153,8 @@ static const cli_opt_t generate_opts[] = CLI_OPT_DEF (.id = OPT_GENERATE_LITERAL_C, .longopt = "save-literals-c-format", .meta = "FILE", .help = "export literals found in parsed JS input (in C source format)"), + CLI_OPT_DEF (.id = OPT_GENERATE_SHOW_OP, .longopt = "show-opcodes", + .help = "print generated opcodes"), CLI_OPT_DEF (.id = OPT_GENERATE_OUT, .opt = "o", .meta="FILE", .help = "specify output file name (default: js.snapshot)"), CLI_OPT_DEF (.id = CLI_OPT_DEFAULT, .meta = "FILE", @@ -178,6 +181,7 @@ process_generate (cli_state_t *cli_state_p, /**< cli state */ uint8_t *source_p = input_buffer; size_t source_length = 0; const char *save_literals_file_name_p = NULL; + bool static_snapshot = false; cli_change_opts (cli_state_p, generate_opts); @@ -190,31 +194,9 @@ process_generate (cli_state_t *cli_state_p, /**< cli state */ cli_help (prog_name_p, "generate", generate_opts); return JERRY_STANDALONE_EXIT_CODE_OK; } - case OPT_GENERATE_OUT: + case OPT_GENERATE_STATIC: { - output_file_name_p = cli_consume_string (cli_state_p); - break; - } - case OPT_GENERATE_LITERAL_LIST: - case OPT_GENERATE_LITERAL_C: - { - if (save_literals_file_name_p != NULL) - { - jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: literal file name already specified"); - return JERRY_STANDALONE_EXIT_CODE_FAIL; - } - - is_save_literals_mode_in_c_format = (id == OPT_GENERATE_LITERAL_C); - save_literals_file_name_p = cli_consume_string (cli_state_p); - break; - } - case OPT_GENERATE_SHOW_OP: - { - if (check_feature (JERRY_FEATURE_PARSER_DUMP, cli_state_p->arg)) - { - jerry_port_default_set_log_level (JERRY_LOG_LEVEL_DEBUG); - flags |= JERRY_INIT_SHOW_OPCODES; - } + static_snapshot = true; break; } case OPT_GENERATE_CONTEXT: @@ -241,6 +223,33 @@ process_generate (cli_state_t *cli_state_p, /**< cli state */ } break; } + case OPT_GENERATE_LITERAL_LIST: + case OPT_GENERATE_LITERAL_C: + { + if (save_literals_file_name_p != NULL) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: literal file name already specified"); + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + + is_save_literals_mode_in_c_format = (id == OPT_GENERATE_LITERAL_C); + save_literals_file_name_p = cli_consume_string (cli_state_p); + break; + } + case OPT_GENERATE_SHOW_OP: + { + if (check_feature (JERRY_FEATURE_PARSER_DUMP, cli_state_p->arg)) + { + jerry_port_default_set_log_level (JERRY_LOG_LEVEL_DEBUG); + flags |= JERRY_INIT_SHOW_OPCODES; + } + break; + } + case OPT_GENERATE_OUT: + { + output_file_name_p = cli_consume_string (cli_state_p); + break; + } case CLI_OPT_DEFAULT: { const char *file_name_p = cli_consume_string (cli_state_p); @@ -274,7 +283,7 @@ process_generate (cli_state_t *cli_state_p, /**< cli state */ if (number_of_files != 1) { - jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: No input file specified!\n"); + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Exactly one input file must be specified\n"); return JERRY_STANDALONE_EXIT_CODE_FAIL; } @@ -286,12 +295,27 @@ process_generate (cli_state_t *cli_state_p, /**< cli state */ return JERRY_STANDALONE_EXIT_CODE_FAIL; } - size_t snapshot_size = jerry_parse_and_save_snapshot ((jerry_char_t *) source_p, - source_length, - is_snapshot_mode_for_global, - false, - output_buffer, - sizeof (output_buffer) / sizeof (uint32_t)); + size_t snapshot_size; + + if (static_snapshot) + { + snapshot_size = jerry_parse_and_save_static_snapshot ((jerry_char_t *) source_p, + source_length, + is_snapshot_mode_for_global, + false, + output_buffer, + sizeof (output_buffer) / sizeof (uint32_t)); + } + else + { + snapshot_size = jerry_parse_and_save_snapshot ((jerry_char_t *) source_p, + source_length, + is_snapshot_mode_for_global, + false, + output_buffer, + sizeof (output_buffer) / sizeof (uint32_t)); + } + if (snapshot_size == 0) { jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: Generating snapshot failed!\n"); diff --git a/tests/unit-core/test-snapshot.c b/tests/unit-core/test-snapshot.c index 6bc10eb16..30e9d2627 100644 --- a/tests/unit-core/test-snapshot.c +++ b/tests/unit-core/test-snapshot.c @@ -23,6 +23,29 @@ */ #define SNAPSHOT_BUFFER_SIZE (256) +/** + * Magic strings + */ +static const jerry_char_ptr_t magic_strings[] = +{ + (const jerry_char_ptr_t) " ", + (const jerry_char_ptr_t) "a", + (const jerry_char_ptr_t) "b", + (const jerry_char_ptr_t) "c", + (const jerry_char_ptr_t) "from", + (const jerry_char_ptr_t) "func", + (const jerry_char_ptr_t) "string", + (const jerry_char_ptr_t) "snapshot" +}; + +/** + * Magic string lengths + */ +static const jerry_length_t magic_string_lengths[] = +{ + 1, 1, 1, 1, 4, 4, 6, 8 +}; + static void test_function_snapshot (void) { /* function to snapshot */ @@ -142,6 +165,10 @@ static void test_exec_snapshot (uint32_t *snapshot_p, size_t snapshot_size, bool jerry_init (JERRY_INIT_EMPTY); + jerry_register_magic_strings (magic_strings, + sizeof (magic_string_lengths) / sizeof (jerry_length_t), + magic_string_lengths); + jerry_value_t res = jerry_exec_snapshot (snapshot_p, snapshot_size, copy_bytecode); @@ -161,15 +188,15 @@ static void test_exec_snapshot (uint32_t *snapshot_p, size_t snapshot_size, bool int main (void) { + static uint32_t global_mode_snapshot_buffer[SNAPSHOT_BUFFER_SIZE]; + static uint32_t eval_mode_snapshot_buffer[SNAPSHOT_BUFFER_SIZE]; + TEST_INIT (); /* Dump / execute snapshot */ if (jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_SAVE) && jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_EXEC)) { - static uint32_t global_mode_snapshot_buffer[SNAPSHOT_BUFFER_SIZE]; - static uint32_t eval_mode_snapshot_buffer[SNAPSHOT_BUFFER_SIZE]; - const char *code_to_snapshot_p = "(function () { return 'string from snapshot'; }) ();"; jerry_init (JERRY_INIT_EMPTY); @@ -184,11 +211,11 @@ main (void) /* Check the snapshot data. Unused bytes should be filled with zeroes */ const uint8_t expected_data[] = { - 0x4A, 0x52, 0x52, 0x59, 0x09, 0x00, 0x00, 0x00, + 0x4A, 0x52, 0x52, 0x59, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x00, 0x28, 0x00, 0xB7, 0x46, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x00, @@ -229,6 +256,36 @@ main (void) true); } + /* Static snapshot */ + if (jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_SAVE) + && jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_EXEC)) + { + const char *code_to_snapshot_p = ("function func(a, b, c) {" + " c = 'snapshot';" + " return arguments[0] + ' ' + b + ' ' + arguments[2];" + "};" + "func('string', 'from');"); + + jerry_init (JERRY_INIT_EMPTY); + jerry_register_magic_strings (magic_strings, + sizeof (magic_string_lengths) / sizeof (jerry_length_t), + magic_string_lengths); + + size_t global_mode_snapshot_size = jerry_parse_and_save_static_snapshot ((jerry_char_t *) code_to_snapshot_p, + strlen (code_to_snapshot_p), + true, + false, + global_mode_snapshot_buffer, + SNAPSHOT_BUFFER_SIZE); + TEST_ASSERT (global_mode_snapshot_size != 0); + + jerry_cleanup (); + + test_exec_snapshot (global_mode_snapshot_buffer, + global_mode_snapshot_size, + false); + } + /* Merge snapshot */ if (jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_SAVE) && jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_EXEC))