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
This commit is contained in:
Zoltan Herczeg 2018-03-19 23:46:52 +01:00 committed by yichoi
parent dde09cc4b6
commit bb84466fcf
17 changed files with 850 additions and 166 deletions

View File

@ -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 <string.h>
#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 <string.h>
#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

View File

@ -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 */

View File

@ -46,7 +46,7 @@ typedef struct
/**
* Jerry snapshot format version.
*/
#define JERRY_SNAPSHOT_VERSION (9u)
#define JERRY_SNAPSHOT_VERSION (10u)
/**
* Snapshot configuration flags.

View File

@ -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 */
/**

View File

@ -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 */

View File

@ -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
/**

View File

@ -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.
*

View File

@ -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--;

View File

@ -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___;

View File

@ -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)
{

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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");

View File

@ -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))