Support multiple primary functions in a single snapshot. (#1797)

This patch adds an extension to snapshots which allows storing
multiple position independent primary functions in a single
snapshot data. A new application called jerry-snapshot is
added to the project to manage snapshots. Currently the only
option is merging snapshots.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2017-10-12 14:43:32 +02:00
committed by GitHub
parent 9f0cf9ef1c
commit fe26674752
17 changed files with 1280 additions and 462 deletions
+12 -10
View File
@@ -38,14 +38,15 @@ if(NOT CMAKE_BUILD_TYPE)
endif()
# Optional components
set(JERRY_CMDLINE ON CACHE BOOL "Build jerry command line tool?")
set(JERRY_CMDLINE_MINIMAL OFF CACHE BOOL "Build jerry minimal command line tool?")
set(JERRY_PORT_DEFAULT ON CACHE BOOL "Build default jerry port implementation?")
set(JERRY_EXT ON CACHE BOOL "Build jerry-ext?")
set(JERRY_LIBC ON CACHE BOOL "Build and use jerry-libc?")
set(JERRY_LIBM ON CACHE BOOL "Build and use jerry-libm?")
set(UNITTESTS OFF CACHE BOOL "Build unit tests?")
set(DOCTESTS OFF CACHE BOOL "Build doc tests?")
set(JERRY_CMDLINE ON CACHE BOOL "Build jerry command line tool?")
set(JERRY_CMDLINE_MINIMAL OFF CACHE BOOL "Build jerry minimal command line tool?")
set(JERRY_CMDLINE_SNAPSHOT OFF CACHE BOOL "Build jerry snapshot command line tool?")
set(JERRY_PORT_DEFAULT ON CACHE BOOL "Build default jerry port implementation?")
set(JERRY_EXT ON CACHE BOOL "Build jerry-ext?")
set(JERRY_LIBC ON CACHE BOOL "Build and use jerry-libc?")
set(JERRY_LIBM ON CACHE BOOL "Build and use jerry-libm?")
set(UNITTESTS OFF CACHE BOOL "Build unit tests?")
set(DOCTESTS OFF CACHE BOOL "Build doc tests?")
# Optional build settings
set(ENABLE_ALL_IN_ONE OFF CACHE BOOL "Enable all-in-one build?")
@@ -57,7 +58,7 @@ set(ENABLE_STRIP ON CACHE BOOL "Enable stripping all symbols from release
set(FEATURE_INIT_FINI OFF CACHE BOOL "Enable init/fini arrays?")
# Option overrides
if(JERRY_CMDLINE OR JERRY_CMDLINE_MINIMAL OR UNITTESTS OR DOCTESTS)
if(JERRY_CMDLINE OR JERRY_CMDLINE_MINIMAL OR JERRY_CMDLINE_SNAPSHOT OR UNITTESTS OR DOCTESTS)
set(JERRY_PORT_DEFAULT ON)
set(JERRY_PORT_DEFAULT_MESSAGE " (FORCED BY CMDLINE OR TESTS)")
@@ -103,6 +104,7 @@ message(STATUS "ENABLE_STATIC_LINK " ${ENABLE_STATIC_LINK} ${ENABLE_STATI
message(STATUS "ENABLE_STRIP " ${ENABLE_STRIP} ${ENABLE_STRIP_MESSAGE})
message(STATUS "JERRY_CMDLINE " ${JERRY_CMDLINE})
message(STATUS "JERRY_CMDLINE_MINIMAL " ${JERRY_CMDLINE_MINIMAL})
message(STATUS "JERRY_CMDLINE_SNAPSHOT " ${JERRY_CMDLINE_SNAPSHOT})
message(STATUS "JERRY_PORT_DEFAULT " ${JERRY_PORT_DEFAULT} ${JERRY_PORT_DEFAULT_MESSAGE})
message(STATUS "JERRY_EXT " ${JERRY_EXT} ${JERRY_EXT_MESSAGE})
message(STATUS "JERRY_LIBC " ${JERRY_LIBC} ${JERRY_LIBC_MESSAGE})
@@ -268,7 +270,7 @@ if(JERRY_EXT)
endif()
# Jerry command line tool
if(JERRY_CMDLINE OR JERRY_CMDLINE_MINIMAL)
if(JERRY_CMDLINE OR JERRY_CMDLINE_MINIMAL OR JERRY_CMDLINE_SNAPSHOT)
add_subdirectory(jerry-main)
endif()
+79
View File
@@ -4236,6 +4236,85 @@ main (void)
- [jerry_init](#jerry_init)
- [jerry_cleanup](#jerry_cleanup)
- [jerry_exec_snapshot_at](#jerry_exec_snapshot_at)
- [jerry_parse_and_save_snapshot](#jerry_parse_and_save_snapshot)
## jerry_exec_snapshot_at
**Summary**
Execute the selected snapshot function from the specified buffer.
Same function as [jerry_exec_snapshot](#jerry_exec_snapshot) except
the executed function index can be specified.
*Note*: Returned value must be freed with [jerry_release_value](#jerry_release_value) when it
is no longer needed.
**Prototype**
```c
jerry_value_t
jerry_exec_snapshot_at (const uint32_t *snapshot_p,
size_t snapshot_size,
size_t func_index,
bool copy_bytecode);
```
- `snapshot_p` - pointer to snapshot
- `snapshot_size` - size of snapshot
- `func_index` - index of executed function
- `copy_bytecode` - flag, indicating whether the passed snapshot buffer should be copied to the
engine's memory. If set the engine should not reference the buffer after the function returns
(in this case, the passed buffer could be freed after the call). Otherwise (if the flag is not
set) - the buffer could only be freed after the engine stops (i.e. after call to jerry_cleanup).
- return value
- result of bytecode, if run was successful
- thrown error, otherwise
**Example**
[doctest]: # ()
```c
#include <string.h>
#include "jerryscript.h"
int
main (void)
{
static uint32_t global_mode_snapshot_buffer[256];
const jerry_char_t *code_to_snapshot_p = (const jerry_char_t *) "(function () { return 'string from snapshot'; }) ();";
jerry_init (JERRY_INIT_EMPTY);
size_t global_mode_snapshot_size = jerry_parse_and_save_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 ();
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t res = jerry_exec_snapshot_at (global_mode_snapshot_buffer,
global_mode_snapshot_size,
0,
false);
jerry_release_value (res);
jerry_cleanup ();
return 0;
}
```
**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)
+7 -1
View File
@@ -50,6 +50,12 @@ if(NOT FEATURE_JS_PARSER)
set(FEATURE_PARSER_DUMP_MESSAGE " (FORCED BY DISABLED JS PARSER)")
endif()
if(JERRY_CMDLINE_SNAPSHOT)
set(FEATURE_SNAPSHOT_SAVE ON)
set(FEATURE_SNAPSHOT_SAVE_MESSAGE " (FORCED BY SNAPSHOT TOOL)")
endif()
# Status messages
message(STATUS "FEATURE_CPOINTER_32_BIT " ${FEATURE_CPOINTER_32_BIT} ${FEATURE_CPOINTER_32_BIT_MESSAGE})
message(STATUS "FEATURE_DEBUGGER " ${FEATURE_DEBUGGER})
@@ -62,7 +68,7 @@ message(STATUS "FEATURE_PARSER_DUMP " ${FEATURE_PARSER_DUMP} ${FEATURE_PAR
message(STATUS "FEATURE_PROFILE " ${FEATURE_PROFILE})
message(STATUS "FEATURE_REGEXP_DUMP " ${FEATURE_REGEXP_DUMP})
message(STATUS "FEATURE_SNAPSHOT_EXEC " ${FEATURE_SNAPSHOT_EXEC} ${FEATURE_SNAPSHOT_EXEC_MESSAGE})
message(STATUS "FEATURE_SNAPSHOT_SAVE " ${FEATURE_SNAPSHOT_SAVE})
message(STATUS "FEATURE_SNAPSHOT_SAVE " ${FEATURE_SNAPSHOT_SAVE} ${FEATURE_SNAPSHOT_SAVE_MESSAGE})
message(STATUS "FEATURE_SYSTEM_ALLOCATOR " ${FEATURE_SYSTEM_ALLOCATOR})
message(STATUS "FEATURE_VALGRIND " ${FEATURE_VALGRIND})
message(STATUS "FEATURE_VALGRIND_FREYA " ${FEATURE_VALGRIND_FREYA})
+430 -95
View File
@@ -24,6 +24,47 @@
#include "lit-char-helpers.h"
#include "re-compiler.h"
#if defined JERRY_ENABLE_SNAPSHOT_SAVE || defined JERRY_ENABLE_SNAPSHOT_EXEC
/**
* Get snapshot configuration flags.
*
* @return configuration flags
*/
static inline uint32_t __attr_always_inline___
snapshot_get_global_flags (bool has_regex) /**< regex literal is present */
{
JERRY_UNUSED (has_regex);
uint32_t flags = 0;
#ifdef JERRY_CPOINTER_32_BIT
flags |= JERRY_SNAPSHOT_FOUR_BYTE_CPOINTER;
#endif /* JERRY_CPOINTER_32_BIT */
#ifndef CONFIG_DISABLE_REGEXP_BUILTIN
flags |= (has_regex ? JERRY_SNAPSHOT_HAS_REGEX_LITERAL : 0);
#endif /* CONFIG_DISABLE_REGEXP_BUILTIN */
return flags;
} /* snapshot_get_global_flags */
/**
* Checks whether the global_flags argument matches to the current feature set.
*
* @return true if global_flags accepted, false otherwise
*/
static inline bool __attr_always_inline___
snapshot_check_global_flags (uint32_t global_flags) /**< global flags */
{
#ifndef CONFIG_DISABLE_REGEXP_BUILTIN
global_flags &= (uint32_t) ~JERRY_SNAPSHOT_HAS_REGEX_LITERAL;
#endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */
return global_flags == snapshot_get_global_flags (false);
} /* snapshot_check_global_flags */
#endif /* JERRY_ENABLE_SNAPSHOT_SAVE || JERRY_ENABLE_SNAPSHOT_EXEC */
#ifdef JERRY_ENABLE_SNAPSHOT_SAVE
/**
@@ -31,8 +72,9 @@
*/
typedef struct
{
bool snapshot_error_occured;
size_t snapshot_buffer_write_offset;
bool snapshot_error_occured;
bool regex_found;
} snapshot_globals_t;
/** \addtogroup jerrysnapshot Jerry snapshot operations
@@ -91,7 +133,10 @@ snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled
return 0;
}
uint16_t start_offset = (uint16_t) (globals_p->snapshot_buffer_write_offset >> JMEM_ALIGNMENT_LOG);
/* 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);
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;
@@ -129,6 +174,7 @@ snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled
ECMA_FINALIZE_UTF8_STRING (buffer_p, buffer_size);
globals_p->regex_found = true;
globals_p->snapshot_buffer_write_offset = JERRY_ALIGNUP (globals_p->snapshot_buffer_write_offset,
JMEM_ALIGNMENT);
@@ -252,10 +298,10 @@ jerry_snapshot_set_offsets (uint32_t *buffer_p, /**< buffer */
{
for (uint32_t i = 0; i < argument_end; i++)
{
lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
if (literal_start_p[i] != JMEM_CP_NULL)
{
lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
while (current_p->literal_id != literal_start_p[i])
{
current_p++;
@@ -316,12 +362,14 @@ jerry_snapshot_set_offsets (uint32_t *buffer_p, /**< buffer */
* @return byte code
*/
static ecma_compiled_code_t *
snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data */
snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of the
* current primary function */
size_t offset, /**< byte code offset */
lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< literal map */
const uint8_t *literal_base_p, /**< literal start */
const uint8_t *number_base_p, /**< literal number start */
bool copy_bytecode) /**< byte code should be copied to memory */
{
ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) (snapshot_data_p + offset);
ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) (base_addr_p + offset);
uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG;
if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION))
@@ -377,7 +425,7 @@ snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data
jmem_stats_allocate_byte_code_bytes (code_size);
#endif /* JMEM_STATS */
memcpy (bytecode_p, snapshot_data_p + offset, code_size);
memcpy (bytecode_p, base_addr_p + offset, code_size);
}
else
{
@@ -392,7 +440,7 @@ snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data
jmem_stats_allocate_byte_code_bytes (total_size);
#endif /* JMEM_STATS */
memcpy (bytecode_p, snapshot_data_p + offset, code_size);
memcpy (bytecode_p, base_addr_p + offset, code_size);
bytecode_p->size = (uint16_t) (total_size >> JMEM_ALIGNMENT_LOG);
@@ -412,17 +460,9 @@ snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data
for (uint32_t i = 0; i < const_literal_end; i++)
{
lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
if (literal_start_p[i] != 0)
{
while (current_p->literal_offset != literal_start_p[i])
{
current_p++;
}
literal_start_p[i] = current_p->literal_id;
}
literal_start_p[i] = ecma_snapshot_get_literal (literal_base_p,
number_base_p,
literal_start_p[i]);
}
for (uint32_t i = const_literal_end; i < literal_end; i++)
@@ -438,9 +478,10 @@ snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data
else
{
ecma_compiled_code_t *literal_bytecode_p;
literal_bytecode_p = snapshot_load_compiled_code (snapshot_data_p,
literal_bytecode_p = snapshot_load_compiled_code (base_addr_p,
literal_offset,
lit_map_p,
literal_base_p,
number_base_p,
copy_bytecode);
ECMA_SET_NON_NULL_POINTER (literal_start_p[i],
@@ -474,10 +515,12 @@ jerry_parse_and_save_snapshot (const jerry_char_t *source_p, /**< script source
snapshot_globals_t globals;
ecma_value_t parse_status;
ecma_compiled_code_t *bytecode_data_p;
const uint32_t aligned_header_size = JERRY_ALIGNUP (sizeof (jerry_snapshot_header_t),
JMEM_ALIGNMENT);
globals.snapshot_buffer_write_offset = JERRY_ALIGNUP (sizeof (jerry_snapshot_header_t),
JMEM_ALIGNMENT);
globals.snapshot_buffer_write_offset = aligned_header_size;
globals.snapshot_error_occured = false;
globals.regex_found = false;
parse_status = parser_parse_script (NULL,
0,
@@ -500,9 +543,17 @@ jerry_parse_and_save_snapshot (const jerry_char_t *source_p, /**< script source
}
jerry_snapshot_header_t header;
header.magic = JERRY_SNAPSHOT_MAGIC;
header.version = JERRY_SNAPSHOT_VERSION;
header.global_flags = snapshot_get_global_flags (globals.regex_found);
header.lit_table_offset = (uint32_t) globals.snapshot_buffer_write_offset;
header.is_run_global = is_for_global;
header.number_of_funcs = 1;
header.func_offsets[0] = aligned_header_size;
if (!is_for_global)
{
header.func_offsets[0] |= JERRY_SNAPSHOT_EVAL_CONTEXT;
}
lit_mem_to_snapshot_id_map_entry_t *lit_map_p = NULL;
uint32_t literals_num;
@@ -511,16 +562,14 @@ jerry_parse_and_save_snapshot (const jerry_char_t *source_p, /**< script source
buffer_size,
&globals.snapshot_buffer_write_offset,
&lit_map_p,
&literals_num,
&header.lit_table_size))
&literals_num))
{
JERRY_ASSERT (lit_map_p == NULL);
return 0;
}
jerry_snapshot_set_offsets (buffer_p + (JERRY_ALIGNUP (sizeof (jerry_snapshot_header_t),
JMEM_ALIGNMENT) / sizeof (uint32_t)),
(uint32_t) (header.lit_table_offset - sizeof (jerry_snapshot_header_t)),
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;
@@ -551,6 +600,103 @@ jerry_parse_and_save_snapshot (const jerry_char_t *source_p, /**< script source
#endif /* JERRY_ENABLE_SNAPSHOT_SAVE */
} /* jerry_parse_and_save_snapshot */
/**
* Execute snapshot from specified 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_exec_snapshot_at (const uint32_t *snapshot_p, /**< snapshot */
size_t snapshot_size, /**< size of snapshot */
size_t func_index, /**< index of primary function */
bool copy_bytecode) /**< flag, indicating whether the passed snapshot
* buffer should be copied to the engine's memory.
* If set the engine should not reference the buffer
* after the function returns (in this case, the passed
* buffer could be freed after the call).
* Otherwise (if the flag is not set) - the buffer could only be
* freed after the engine stops (i.e. after call to jerry_cleanup). */
{
#ifdef JERRY_ENABLE_SNAPSHOT_EXEC
JERRY_ASSERT (snapshot_p != NULL);
static const char * const invalid_version_error_p = "Invalid snapshot version or unsupported features present";
static const char * const invalid_format_error_p = "Invalid snapshot format";
const uint8_t *snapshot_data_p = (uint8_t *) snapshot_p;
if (snapshot_size <= sizeof (jerry_snapshot_header_t))
{
return ecma_raise_type_error (invalid_format_error_p);
}
const jerry_snapshot_header_t *header_p = (const jerry_snapshot_header_t *) snapshot_data_p;
if (header_p->magic != JERRY_SNAPSHOT_MAGIC
|| header_p->version != JERRY_SNAPSHOT_VERSION
|| !snapshot_check_global_flags (header_p->global_flags))
{
return ecma_raise_type_error (invalid_version_error_p);
}
if (header_p->lit_table_offset >= snapshot_size)
{
return ecma_raise_type_error (invalid_version_error_p);
}
if (func_index >= header_p->number_of_funcs)
{
return ecma_raise_range_error (ECMA_ERR_MSG ("Function index is higher than maximum"));
}
JERRY_ASSERT ((header_p->lit_table_offset % sizeof (uint32_t)) == 0);
const uint8_t *literal_base_p;
const uint8_t *number_base_p;
literal_base_p = ecma_snapshot_get_literals_base ((uint32_t *) (snapshot_data_p + header_p->lit_table_offset),
&number_base_p);
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,
number_base_p,
copy_bytecode);
if (bytecode_p == NULL)
{
return ecma_raise_type_error (invalid_format_error_p);
}
ecma_value_t ret_val;
if (header_p->func_offsets[func_index] & JERRY_SNAPSHOT_EVAL_CONTEXT)
{
ret_val = vm_run_eval (bytecode_p, false);
}
else
{
ret_val = vm_run_global (bytecode_p);
ecma_bytecode_deref (bytecode_p);
}
return ret_val;
#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */
JERRY_UNUSED (snapshot_p);
JERRY_UNUSED (snapshot_size);
JERRY_UNUSED (func_index);
JERRY_UNUSED (copy_bytecode);
return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE);
#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */
} /* jerry_exec_snapshot_at */
/**
* Execute snapshot from specified buffer
*
@@ -572,71 +718,7 @@ jerry_exec_snapshot (const uint32_t *snapshot_p, /**< snapshot */
* freed after the engine stops (i.e. after call to jerry_cleanup). */
{
#ifdef JERRY_ENABLE_SNAPSHOT_EXEC
JERRY_ASSERT (snapshot_p != NULL);
static const char * const invalid_version_error_p = "Invalid snapshot version";
static const char * const invalid_format_error_p = "Invalid snapshot format";
const uint8_t *snapshot_data_p = (uint8_t *) snapshot_p;
if (snapshot_size <= sizeof (jerry_snapshot_header_t))
{
return ecma_raise_type_error (invalid_format_error_p);
}
const jerry_snapshot_header_t *header_p = (const jerry_snapshot_header_t *) snapshot_data_p;
if (header_p->version != JERRY_SNAPSHOT_VERSION)
{
return ecma_raise_type_error (invalid_version_error_p);
}
lit_mem_to_snapshot_id_map_entry_t *lit_map_p = NULL;
uint32_t literals_num;
if (header_p->lit_table_offset >= snapshot_size)
{
return ecma_raise_type_error (invalid_version_error_p);
}
JERRY_ASSERT ((header_p->lit_table_offset % sizeof (uint32_t)) == 0);
if (!ecma_load_literals_from_snapshot ((uint32_t *) (snapshot_data_p + header_p->lit_table_offset),
header_p->lit_table_size,
&lit_map_p,
&literals_num))
{
JERRY_ASSERT (lit_map_p == NULL);
return ecma_raise_type_error (invalid_format_error_p);
}
ecma_compiled_code_t *bytecode_p;
bytecode_p = snapshot_load_compiled_code (snapshot_data_p,
sizeof (jerry_snapshot_header_t),
lit_map_p,
copy_bytecode);
if (lit_map_p != NULL)
{
jmem_heap_free_block (lit_map_p, literals_num * sizeof (lit_mem_to_snapshot_id_map_entry_t));
}
if (bytecode_p == NULL)
{
return ecma_raise_type_error (invalid_format_error_p);
}
ecma_value_t ret_val;
if (header_p->is_run_global)
{
ret_val = vm_run_global (bytecode_p);
ecma_bytecode_deref (bytecode_p);
}
else
{
ret_val = vm_run_eval (bytecode_p, false);
}
return ret_val;
return jerry_exec_snapshot_at (snapshot_p, snapshot_size, 0, copy_bytecode);
#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */
JERRY_UNUSED (snapshot_p);
JERRY_UNUSED (snapshot_size);
@@ -652,6 +734,259 @@ jerry_exec_snapshot (const uint32_t *snapshot_p, /**< snapshot */
#ifdef JERRY_ENABLE_SNAPSHOT_SAVE
/**
* Collect all literals from a snapshot file.
*/
static void
scan_snapshot_functions (const uint8_t *buffer_p, /**< snapshot buffer start */
const uint8_t *buffer_end_p, /**< snapshot buffer end */
const uint8_t *literal_base_p, /**< start of literal data */
const uint8_t *number_base_p) /**< start of number data */
{
JERRY_ASSERT (buffer_end_p > buffer_p);
do
{
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)
{
jmem_cpointer_t *literal_start_p;
uint32_t const_literal_end;
if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
literal_start_p = (jmem_cpointer_t *) (buffer_p + sizeof (cbc_uint16_arguments_t));
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p;
const_literal_end = args_p->const_literal_end;
}
else
{
literal_start_p = (jmem_cpointer_t *) (buffer_p + sizeof (cbc_uint8_arguments_t));
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p;
const_literal_end = args_p->const_literal_end;
}
for (uint32_t i = 0; i < const_literal_end; i++)
{
if (literal_start_p[i] != JMEM_CP_NULL)
{
literal_start_p[i] = ecma_snapshot_get_literal (literal_base_p, number_base_p, literal_start_p[i]);
}
}
}
buffer_p += code_size;
}
while (buffer_p < buffer_end_p);
} /* scan_snapshot_functions */
/**
* Update all literal offsets in a snapshot data.
*/
static void
update_literal_offsets (uint8_t *buffer_p, /**< snapshot buffer start */
const uint8_t *buffer_end_p, /**< snapshot buffer start */
lit_mem_to_snapshot_id_map_entry_t *lit_map_p) /**< literal map */
{
JERRY_ASSERT (buffer_end_p > buffer_p);
do
{
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)
{
jmem_cpointer_t *literal_start_p;
uint32_t const_literal_end;
if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS)
{
literal_start_p = (jmem_cpointer_t *) (buffer_p + sizeof (cbc_uint16_arguments_t));
cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p;
const_literal_end = args_p->const_literal_end;
}
else
{
literal_start_p = (jmem_cpointer_t *) (buffer_p + sizeof (cbc_uint8_arguments_t));
cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p;
const_literal_end = args_p->const_literal_end;
}
for (uint32_t i = 0; i < const_literal_end; i++)
{
if (literal_start_p[i] != JMEM_CP_NULL)
{
lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
while (current_p->literal_id != literal_start_p[i])
{
current_p++;
}
literal_start_p[i] = current_p->literal_offset;
}
}
}
buffer_p += code_size;
}
while (buffer_p < buffer_end_p);
} /* update_literal_offsets */
#endif /* JERRY_ENABLE_SNAPSHOT_SAVE */
/**
* Merge multiple snapshots into a single buffer
*
* @return length of merged snapshot file
* 0 on error
*/
size_t
jerry_merge_snapshots (const uint32_t **inp_buffers_p, /**< array of (pointers to start of) input buffers */
size_t *inp_buffer_sizes_p, /**< array of input buffer sizes */
size_t number_of_snapshots, /**< number of snapshots */
uint32_t *out_buffer_p, /**< output buffer */
size_t out_buffer_size, /**< output buffer size */
const char **error_p) /**< error description */
{
#ifdef JERRY_ENABLE_SNAPSHOT_SAVE
uint32_t number_of_funcs = 0;
uint32_t merged_global_flags = 0;
size_t functions_size = sizeof (jerry_snapshot_header_t);
if (number_of_snapshots < 2)
{
*error_p = "at least two snapshots must be passed";
return 0;
}
for (uint32_t i = 0; i < number_of_snapshots; i++)
{
if (inp_buffer_sizes_p[i] < sizeof (jerry_snapshot_header_t))
{
*error_p = "invalid snapshot file";
return 0;
}
const jerry_snapshot_header_t *header_p = (const jerry_snapshot_header_t *) inp_buffers_p[i];
if (header_p->magic != JERRY_SNAPSHOT_MAGIC
|| header_p->version != JERRY_SNAPSHOT_VERSION
|| !snapshot_check_global_flags (header_p->global_flags))
{
*error_p = "invalid snapshot version or unsupported features present";
return 0;
}
merged_global_flags |= header_p->global_flags;
uint32_t start_offset = header_p->func_offsets[0] & ~JERRY_SNAPSHOT_EVAL_CONTEXT;
const uint8_t *data_p = (const uint8_t *) inp_buffers_p[i];
const uint8_t *literal_base_p;
const uint8_t *number_base_p;
literal_base_p = ecma_snapshot_get_literals_base ((uint32_t *) (data_p + header_p->lit_table_offset),
&number_base_p);
JERRY_ASSERT (header_p->number_of_funcs > 0);
number_of_funcs += header_p->number_of_funcs;
functions_size += header_p->lit_table_offset - start_offset;
scan_snapshot_functions (data_p + start_offset,
data_p + header_p->lit_table_offset,
literal_base_p,
number_base_p);
}
JERRY_ASSERT (number_of_funcs > 0);
functions_size += JERRY_ALIGNUP ((number_of_funcs - 1) * sizeof (uint32_t), JMEM_ALIGNMENT);
if (functions_size >= out_buffer_size)
{
*error_p = "output buffer is too small";
return 0;
}
jerry_snapshot_header_t *header_p = (jerry_snapshot_header_t *) out_buffer_p;
header_p->magic = JERRY_SNAPSHOT_MAGIC;
header_p->version = JERRY_SNAPSHOT_VERSION;
header_p->global_flags = merged_global_flags;
header_p->lit_table_offset = (uint32_t) functions_size;
header_p->number_of_funcs = number_of_funcs;
lit_mem_to_snapshot_id_map_entry_t *lit_map_p;
uint32_t literals_num;
if (!ecma_save_literals_for_snapshot (out_buffer_p,
out_buffer_size,
&functions_size,
&lit_map_p,
&literals_num))
{
*error_p = "buffer is too small";
return 0;
}
uint32_t *func_offset_p = header_p->func_offsets;
uint8_t *dst_p = ((uint8_t *) out_buffer_p) + sizeof (jerry_snapshot_header_t);
dst_p += JERRY_ALIGNUP ((number_of_funcs - 1) * sizeof (uint32_t), JMEM_ALIGNMENT);
for (uint32_t i = 0; i < number_of_snapshots; i++)
{
const jerry_snapshot_header_t *current_header_p = (const jerry_snapshot_header_t *) inp_buffers_p[i];
uint32_t start_offset = current_header_p->func_offsets[0] & ~JERRY_SNAPSHOT_EVAL_CONTEXT;
memcpy (dst_p,
((const uint8_t *) inp_buffers_p[i]) + start_offset,
current_header_p->lit_table_offset - start_offset);
update_literal_offsets (dst_p,
dst_p + current_header_p->lit_table_offset - start_offset,
lit_map_p);
uint32_t current_offset = (uint32_t) (dst_p - (uint8_t *) out_buffer_p) - start_offset;
for (uint32_t j = 0; j < current_header_p->number_of_funcs; j++)
{
/* Updating offset without changing any flags. */
*func_offset_p++ = current_header_p->func_offsets[j] + current_offset;
}
dst_p += current_header_p->lit_table_offset - start_offset;
}
JERRY_ASSERT ((uint32_t) (dst_p - (uint8_t *) out_buffer_p) == header_p->lit_table_offset);
jmem_heap_free_block (lit_map_p, literals_num * sizeof (lit_mem_to_snapshot_id_map_entry_t));
*error_p = NULL;
return functions_size;
#else /* !JERRY_ENABLE_SNAPSHOT_SAVE */
JERRY_UNUSED (inp_buffers_p);
JERRY_UNUSED (inp_buffer_sizes_p);
JERRY_UNUSED (number_of_snapshots);
JERRY_UNUSED (out_buffer_p);
JERRY_UNUSED (out_buffer_size);
JERRY_UNUSED (error_p);
*error_p = "snapshot merge not supported";
return 0;
#endif /* JERRY_ENABLE_SNAPSHOT_SAVE */
} /* jerry_merge_snapshots */
#ifdef JERRY_ENABLE_SNAPSHOT_SAVE
/**
* ====================== Functions for literal saving ==========================
*/
+29 -8
View File
@@ -24,18 +24,39 @@
typedef struct
{
/* The size of this structure is recommended to be divisible by
* JMEM_ALIGNMENT. Otherwise some bytes after the header are wasted. */
* uint32_t alignment. Otherwise some bytes after the header are wasted. */
uint32_t magic; /**< four byte magic number */
uint32_t version; /**< version number */
uint32_t lit_table_offset; /**< offset of the literal table */
uint32_t lit_table_size; /**< size of literal table */
uint32_t is_run_global; /**< flag, indicating whether the snapshot
* was saved as 'Global scope'-mode code (true)
* or as eval-mode code (false) */
uint32_t global_flags; /**< global configuration and feature flags */
uint32_t lit_table_offset; /**< byte offset of the literal table */
uint32_t number_of_funcs; /**< number of primary ECMAScript functions */
uint32_t func_offsets[1]; /**< function offsets (lowest bit: global(0) or eval(1) context) */
} jerry_snapshot_header_t;
/**
* Jerry snapshot format version
* Evaluate this function on the top of the scope chain.
*/
#define JERRY_SNAPSHOT_VERSION (7u)
#define JERRY_SNAPSHOT_EVAL_CONTEXT 0x1u
/**
* Jerry snapshot magic marker.
*/
#define JERRY_SNAPSHOT_MAGIC (0x5952524Au)
/**
* Jerry snapshot format version.
*/
#define JERRY_SNAPSHOT_VERSION (8u)
/**
* Snapshot configuration flags.
*/
typedef enum
{
/* 8 bits are reserved for dynamic features */
JERRY_SNAPSHOT_HAS_REGEX_LITERAL = (1u << 0), /**< byte code has regex literal */
/* 24 bits are reserved for compile time features */
JERRY_SNAPSHOT_FOUR_BYTE_CPOINTER = (1u << 8) /**< compressed pointers are four byte long */
} jerry_snapshot_global_flags_t;
#endif /* !JERRY_SNAPSHOT_H */
+39 -128
View File
@@ -233,13 +233,11 @@ ecma_save_literals_for_snapshot (uint32_t *buffer_p, /**< [out] output snapshot
lit_mem_to_snapshot_id_map_entry_t **out_map_p, /**< [out] map from literal identifiers
* to the literal offsets
* in snapshot */
uint32_t *out_map_len_p, /**< [out] number of literals */
uint32_t *out_lit_table_size_p) /**< [out] number of bytes, saved to snapshot buffer */
uint32_t *out_map_len_p) /**< [out] number of literals */
{
/* Count literals and literal space. */
uint32_t string_count = 0;
uint32_t number_count = 0;
uint32_t lit_table_size = 2 * sizeof (uint32_t);
uint32_t lit_table_size = sizeof (uint32_t);
uint32_t total_count = 0;
ecma_lit_storage_item_t *string_list_p = JERRY_CONTEXT (string_list_first_p);
@@ -254,13 +252,15 @@ ecma_save_literals_for_snapshot (uint32_t *buffer_p, /**< [out] output snapshot
lit_table_size += (uint32_t) JERRY_ALIGNUP (sizeof (uint16_t) + ecma_string_get_size (string_p),
JERRY_SNAPSHOT_LITERAL_ALIGNMENT);
string_count++;
total_count++;
}
}
string_list_p = JMEM_CP_GET_POINTER (ecma_lit_storage_item_t, string_list_p->next_cp);
}
uint32_t number_offset = lit_table_size;
ecma_lit_storage_item_t *number_list_p = JERRY_CONTEXT (number_list_first_p);
while (number_list_p != NULL)
@@ -270,7 +270,7 @@ ecma_save_literals_for_snapshot (uint32_t *buffer_p, /**< [out] output snapshot
if (number_list_p->values[i] != JMEM_CP_NULL)
{
lit_table_size += (uint32_t) sizeof (ecma_number_t);
number_count++;
total_count++;
}
}
@@ -289,7 +289,6 @@ ecma_save_literals_for_snapshot (uint32_t *buffer_p, /**< [out] output snapshot
return false;
}
uint32_t total_count = string_count + number_count;
lit_mem_to_snapshot_id_map_entry_t *map_p;
map_p = jmem_heap_alloc_block (total_count * sizeof (lit_mem_to_snapshot_id_map_entry_t));
@@ -300,7 +299,6 @@ ecma_save_literals_for_snapshot (uint32_t *buffer_p, /**< [out] output snapshot
*in_out_buffer_offset_p += lit_table_size;
*out_map_p = map_p;
*out_map_len_p = total_count;
*out_lit_table_size_p = lit_table_size;
/* Write data into the buffer. */
@@ -308,9 +306,7 @@ ecma_save_literals_for_snapshot (uint32_t *buffer_p, /**< [out] output snapshot
* constant so the first literal must have offset one. */
uint32_t literal_offset = JERRY_SNAPSHOT_LITERAL_ALIGNMENT;
buffer_p[0] = string_count;
buffer_p[1] = number_count;
buffer_p += 2;
*buffer_p++ = number_offset;
string_list_p = JERRY_CONTEXT (string_list_first_p);
@@ -383,137 +379,52 @@ ecma_save_literals_for_snapshot (uint32_t *buffer_p, /**< [out] output snapshot
#endif /* JERRY_ENABLE_SNAPSHOT_SAVE */
#ifdef JERRY_ENABLE_SNAPSHOT_EXEC
#if defined JERRY_ENABLE_SNAPSHOT_EXEC || defined JERRY_ENABLE_SNAPSHOT_SAVE
/**
* Helper function for ecma_load_literals_from_snapshot.
* Computes the base pointer of the literals and starting offset of numbers.
*
* Note: always inline because it is used only once.
*
* @return true - if load was performed successfully
* false - otherwise (i.e. buffer length is incorrect)
* @return the base pointer of the literals
*/
static inline bool __attr_always_inline___
ecma_load_literals_from_buffer (const uint16_t *buffer_p, /**< buffer with literal table in snapshot */
uint32_t lit_table_size, /**< size of literal table in snapshot */
lit_mem_to_snapshot_id_map_entry_t *map_p, /**< literal map */
uint32_t string_count, /**< number of strings */
uint32_t number_count) /**< number of numbers */
const uint8_t *
ecma_snapshot_get_literals_base (uint32_t *buffer_p, /**< literal buffer start */
const uint8_t **number_base_p) /**< [out] literal number start */
{
/* The zero value is reserved for NULL (no literal)
* constant so the first literal must have offset one. */
uint32_t literal_offset = JERRY_SNAPSHOT_LITERAL_ALIGNMENT;
*number_base_p = ((uint8_t *) buffer_p) + buffer_p[0];
/* Load strings first. */
while (string_count > 0)
return ((uint8_t *) (buffer_p + 1)) - JERRY_SNAPSHOT_LITERAL_ALIGNMENT;
} /* ecma_snapshot_get_literals_base */
/**
* Get the compressed pointer of a given literal.
*
* @return literal compressed pointer
*/
jmem_cpointer_t
ecma_snapshot_get_literal (const uint8_t *literal_base_p, /**< literal start */
const uint8_t *number_base_p, /**< literal number start */
jmem_cpointer_t offset)
{
if (offset == 0)
{
if (lit_table_size < literal_offset + sizeof (uint32_t))
{
/* Buffer is not sufficent. */
return false;
}
lit_utf8_size_t length = *buffer_p;
lit_utf8_size_t aligned_length = JERRY_ALIGNUP (sizeof (uint16_t) + length,
JERRY_SNAPSHOT_LITERAL_ALIGNMENT);
if (lit_table_size < literal_offset + aligned_length)
{
/* Buffer is not sufficent. */
return false;
}
map_p->literal_id = ecma_find_or_create_literal_string (((lit_utf8_byte_t *) buffer_p) + sizeof (uint16_t), length);
map_p->literal_offset = (jmem_cpointer_t) (literal_offset >> JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG);
map_p++;
JERRY_ASSERT ((aligned_length % sizeof (uint16_t)) == 0);
buffer_p += aligned_length / sizeof (uint16_t);
literal_offset += aligned_length;
string_count--;
return ECMA_NULL_POINTER;
}
/* Load numbers. */
while (number_count > 0)
{
if (lit_table_size < literal_offset + sizeof (ecma_number_t))
{
/* Buffer is not sufficent. */
return false;
}
const uint8_t *literal_p = literal_base_p + (((size_t) offset) << JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG);
if (literal_p >= number_base_p)
{
ecma_number_t num;
memcpy (&num, buffer_p, sizeof (ecma_number_t));
map_p->literal_id = ecma_find_or_create_literal_number (num);
map_p->literal_offset = (jmem_cpointer_t) (literal_offset >> JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG);
map_p++;
ecma_length_t length = JERRY_ALIGNUP (sizeof (ecma_number_t),
JERRY_SNAPSHOT_LITERAL_ALIGNMENT);
JERRY_ASSERT ((length % sizeof (uint16_t)) == 0);
buffer_p += length / sizeof (uint16_t);
literal_offset += length;
number_count--;
memcpy (&num, literal_p, sizeof (ecma_number_t));
return ecma_find_or_create_literal_number (num);
}
return (lit_table_size == (literal_offset + 2 * sizeof (uint32_t) - JERRY_SNAPSHOT_LITERAL_ALIGNMENT));
} /* ecma_load_literals_from_buffer */
uint16_t length = *(const uint16_t *) literal_p;
/**
* Load literals from snapshot.
*
* @return true - if load was performed successfully (i.e. literals saved in the snapshot are consistent),
* false - otherwise (i.e. snapshot is incorrect)
*/
bool
ecma_load_literals_from_snapshot (const uint32_t *buffer_p, /**< buffer with literal table in snapshot */
uint32_t lit_table_size, /**< size of literal table in snapshot */
lit_mem_to_snapshot_id_map_entry_t **out_map_p, /**< [out] map from literal offsets
* in snapshot to identifiers
* of loaded literals in literal
* storage */
uint32_t *out_map_len_p) /**< [out] literals number */
{
*out_map_p = NULL;
return ecma_find_or_create_literal_string (literal_p + sizeof (uint16_t), length);
} /* ecma_snapshot_get_literal */
if (lit_table_size < 2 * sizeof (uint32_t))
{
/* Buffer is not sufficent. */
return false;
}
uint32_t string_count = buffer_p[0];
uint32_t number_count = buffer_p[1];
buffer_p += 2;
uint32_t total_count = string_count + number_count;
lit_mem_to_snapshot_id_map_entry_t *map_p;
*out_map_len_p = total_count;
if (total_count == 0)
{
return true;
}
map_p = jmem_heap_alloc_block (total_count * sizeof (lit_mem_to_snapshot_id_map_entry_t));
*out_map_p = map_p;
if (ecma_load_literals_from_buffer ((uint16_t *) buffer_p, lit_table_size, map_p, string_count, number_count))
{
return true;
}
jmem_heap_free_block (map_p, total_count * sizeof (lit_mem_to_snapshot_id_map_entry_t));
*out_map_p = NULL;
return false;
} /* ecma_load_literals_from_snapshot */
#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */
#endif /* JERRY_ENABLE_SNAPSHOT_EXEC || JERRY_ENABLE_SNAPSHOT_SAVE */
/**
* @}
+9 -7
View File
@@ -43,15 +43,17 @@ jmem_cpointer_t ecma_find_or_create_literal_number (ecma_number_t number_arg);
#ifdef JERRY_ENABLE_SNAPSHOT_SAVE
bool
ecma_save_literals_for_snapshot (uint32_t *, size_t, size_t *,
lit_mem_to_snapshot_id_map_entry_t **, uint32_t *, uint32_t *);
ecma_save_literals_for_snapshot (uint32_t *buffer_p, size_t buffer_size, size_t *in_out_buffer_offset_p,
lit_mem_to_snapshot_id_map_entry_t **out_map_p, uint32_t *out_map_len_p);
#endif /* JERRY_ENABLE_SNAPSHOT_SAVE */
#ifdef JERRY_ENABLE_SNAPSHOT_EXEC
bool
ecma_load_literals_from_snapshot (const uint32_t *, uint32_t,
lit_mem_to_snapshot_id_map_entry_t **, uint32_t *);
#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */
#if defined JERRY_ENABLE_SNAPSHOT_EXEC || defined JERRY_ENABLE_SNAPSHOT_SAVE
const uint8_t *
ecma_snapshot_get_literals_base (uint32_t *buffer_p, const uint8_t **number_base_p);
jmem_cpointer_t
ecma_snapshot_get_literal (const uint8_t *literal_base_p, const uint8_t *number_base_p,
jmem_cpointer_t offset);
#endif /* JERRY_ENABLE_SNAPSHOT_EXEC || JERRY_ENABLE_SNAPSHOT_SAVE */
/**
* @}
@@ -33,6 +33,10 @@ 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);
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);
size_t jerry_merge_snapshots (const uint32_t **inp_buffers_p, size_t *inp_buffer_sizes_p, size_t number_of_snapshots,
uint32_t *out_buffer_p, size_t out_buffer_size, const char **error_p);
size_t jerry_parse_and_save_literals (const jerry_char_t *source_p, size_t source_size, bool is_strict,
uint32_t *buffer_p, size_t buffer_size, bool is_c_format);
+5
View File
@@ -68,3 +68,8 @@ if(JERRY_CMDLINE_MINIMAL)
jerry_create_executable("jerry-minimal" "main-unix-minimal.c")
target_link_libraries("jerry-minimal" jerry-port-default-minimal)
endif()
if(JERRY_CMDLINE_SNAPSHOT)
jerry_create_executable("jerry-snapshot" "main-unix-snapshot.c" "cli.c")
target_link_libraries("jerry-snapshot" jerry-port-default)
endif()
+107 -81
View File
@@ -62,7 +62,7 @@
* @return the state that should be passed to other cli_ functions.
*/
cli_state_t
cli_init (const cli_opt_t *options, /**< array of option definitions, terminated by CLI_OPT_DEFAULT */
cli_init (const cli_opt_t *options_p, /**< array of option definitions, terminated by CLI_OPT_DEFAULT */
int argc, /**< number of command line arguments */
char **argv) /**< array of command line arguments */
{
@@ -72,35 +72,45 @@ cli_init (const cli_opt_t *options, /**< array of option definitions, terminated
.arg = NULL,
.argc = argc,
.argv = argv,
.opts = options
.opts = options_p
};
} /* cli_init */
/**
* Use another option list.
*/
void
cli_change_opts (cli_state_t *state_p, /**< state of the command line option processor */
const cli_opt_t *options_p) /**< array of option definitions, terminated by CLI_OPT_DEFAULT */
{
state_p->opts = options_p;
} /* cli_change_opts */
/**
* Checks whether the current argument is an option.
*
* Note:
* The state->error is not NULL on error and it contains the error message.
* The state_p->error is not NULL on error and it contains the error message.
*
* @return the ID of the option that was found or a CLI_OPT_ constant otherwise.
*/
int
cli_consume_option (cli_state_t *state) /**< state of the command line option processor */
cli_consume_option (cli_state_t *state_p) /**< state of the command line option processor */
{
if (state->error != NULL)
if (state_p->error != NULL)
{
return CLI_OPT_END;
}
if (state->argc <= 0)
if (state_p->argc <= 0)
{
state->arg = NULL;
state_p->arg = NULL;
return CLI_OPT_END;
}
const char *arg = state->argv[0];
const char *arg = state_p->argv[0];
state->arg = arg;
state_p->arg = arg;
if (arg[0] != '-')
{
@@ -111,33 +121,33 @@ cli_consume_option (cli_state_t *state) /**< state of the command line option pr
{
arg += 2;
for (const cli_opt_t *opt = state->opts; opt->id != CLI_OPT_DEFAULT; opt++)
for (const cli_opt_t *opt = state_p->opts; opt->id != CLI_OPT_DEFAULT; opt++)
{
if (opt->longopt != NULL && strcmp (arg, opt->longopt) == 0)
{
state->argc--;
state->argv++;
state_p->argc--;
state_p->argv++;
return opt->id;
}
}
state->error = "Unknown long option";
state_p->error = "Unknown long option";
return CLI_OPT_END;
}
arg++;
for (const cli_opt_t *opt = state->opts; opt->id != CLI_OPT_DEFAULT; opt++)
for (const cli_opt_t *opt = state_p->opts; opt->id != CLI_OPT_DEFAULT; opt++)
{
if (opt->opt != NULL && strcmp (arg, opt->opt) == 0)
{
state->argc--;
state->argv++;
state_p->argc--;
state_p->argv++;
return opt->id;
}
}
state->error = "Unknown option";
state_p->error = "Unknown option";
return CLI_OPT_END;
} /* cli_consume_option */
@@ -145,69 +155,69 @@ cli_consume_option (cli_state_t *state) /**< state of the command line option pr
* Returns the next argument as string.
*
* Note:
* The state->error is not NULL on error and it contains the error message.
* The state_p->error is not NULL on error and it contains the error message.
*
* @return argument string
*/
const char *
cli_consume_string (cli_state_t *state) /**< state of the command line option processor */
cli_consume_string (cli_state_t *state_p) /**< state of the command line option processor */
{
if (state->error != NULL)
if (state_p->error != NULL)
{
return NULL;
}
if (state->argc <= 0)
if (state_p->argc <= 0)
{
state->error = "Expected string argument";
state->arg = NULL;
state_p->error = "Expected string argument";
state_p->arg = NULL;
return NULL;
}
state->arg = state->argv[0];
state_p->arg = state_p->argv[0];
state->argc--;
state->argv++;
return state->arg;
state_p->argc--;
state_p->argv++;
return state_p->arg;
} /* cli_consume_string */
/**
* Returns the next argument as integer.
*
* Note:
* The state->error is not NULL on error and it contains the error message.
* The state_p->error is not NULL on error and it contains the error message.
*
* @return argument integer
*/
int
cli_consume_int (cli_state_t *state) /**< state of the command line option processor */
cli_consume_int (cli_state_t *state_p) /**< state of the command line option processor */
{
if (state->error != NULL)
if (state_p->error != NULL)
{
return 0;
}
state->error = "Expected integer argument";
state_p->error = "Expected integer argument";
if (state->argc <= 0)
if (state_p->argc <= 0)
{
state->arg = NULL;
state_p->arg = NULL;
return 0;
}
state->arg = state->argv[0];
state_p->arg = state_p->argv[0];
char *endptr;
long int value = strtol (state->arg, &endptr, 10);
long int value = strtol (state_p->arg, &endptr, 10);
if (*endptr != '\0')
{
return 0;
}
state->error = NULL;
state->argc--;
state->argv++;
state_p->error = NULL;
state_p->argc--;
state_p->argv++;
return (int) value;
} /* cli_consume_int */
@@ -244,26 +254,41 @@ cli_print_prefix (const char *str, /**< string to print */
* Print usage summary of options.
*/
static void
cli_opt_usage (const char *progname, /**< program name, typically argv[0] */
const cli_opt_t *opts) /**< array of command line option definitions, terminated by CLI_OPT_DEFAULT */
cli_opt_usage (const char *prog_name_p, /**< program name, typically argv[0] */
const char *command_name_p, /**< command name if available */
const cli_opt_t *opts_p) /**< array of command line option definitions, terminated by CLI_OPT_DEFAULT */
{
int length = (int) strlen (progname);
const cli_opt_t *o = opts;
int length = (int) strlen (prog_name_p);
const cli_opt_t *current_opt_p = opts_p;
printf ("%s", progname);
printf ("%s", prog_name_p);
while (o->id != CLI_OPT_DEFAULT)
if (command_name_p != NULL)
{
const char *opt = o->opt;
int command_length = (int) strlen (command_name_p);
if (length + 1 + command_length > CLI_LINE_LENGTH)
{
length = CLI_LINE_INDENT - 1;
printf ("\n");
cli_print_pad (length);
}
printf (" %s", command_name_p);
}
while (current_opt_p->id != CLI_OPT_DEFAULT)
{
const char *opt_p = current_opt_p->opt;
int opt_length = 2 + 1;
if (opt == NULL)
if (opt_p == NULL)
{
opt = o->longopt;
opt_p = current_opt_p->longopt;
opt_length++;
}
opt_length += (int) strlen (opt);
opt_length += (int) strlen (opt_p);
if (length + 1 + opt_length >= CLI_LINE_LENGTH)
{
@@ -275,29 +300,29 @@ cli_opt_usage (const char *progname, /**< program name, typically argv[0] */
printf (" [");
if (o->opt != NULL)
if (current_opt_p->opt != NULL)
{
printf ("-%s", opt);
printf ("-%s", opt_p);
}
else
{
printf ("--%s", opt);
printf ("--%s", opt_p);
}
if (o->meta != NULL)
if (current_opt_p->meta != NULL)
{
printf (" %s", o->meta);
printf (" %s", current_opt_p->meta);
}
printf ("]");
o++;
current_opt_p++;
}
if (o->meta != NULL)
if (current_opt_p->meta != NULL)
{
const char *opt = o->meta;
int opt_length = (int) (2 + strlen (opt));
const char *opt_p = current_opt_p->meta;
int opt_length = (int) (2 + strlen (opt_p));
if (length + 1 + opt_length >= CLI_LINE_LENGTH)
{
@@ -306,7 +331,7 @@ cli_opt_usage (const char *progname, /**< program name, typically argv[0] */
cli_print_pad (length);
}
printf (" [%s]", opt);
printf (" [%s]", opt_p);
}
printf ("\n\n");
@@ -354,43 +379,44 @@ cli_print_help (const char *help) /**< the help message to print */
* Print detailed help for options.
*/
void
cli_help (const char *progname, /**< program name, typically argv[0] */
const cli_opt_t *options) /**< array of command line option definitions, terminated by CLI_OPT_DEFAULT */
cli_help (const char *prog_name_p, /**< program name, typically argv[0] */
const char *command_name_p, /**< command name if available */
const cli_opt_t *options_p) /**< array of command line option definitions, terminated by CLI_OPT_DEFAULT */
{
cli_opt_usage (progname, options);
cli_opt_usage (prog_name_p, command_name_p, options_p);
const cli_opt_t *opt = options;
const cli_opt_t *opt_p = options_p;
while (opt->id != CLI_OPT_DEFAULT)
while (opt_p->id != CLI_OPT_DEFAULT)
{
int length = CLI_LINE_INDENT;
cli_print_pad (CLI_LINE_INDENT);
if (opt->opt != NULL)
if (opt_p->opt != NULL)
{
printf ("-%s", opt->opt);
length += (int) (strlen (opt->opt) + 1);
printf ("-%s", opt_p->opt);
length += (int) (strlen (opt_p->opt) + 1);
}
if (opt->opt != NULL && opt->longopt != NULL)
if (opt_p->opt != NULL && opt_p->longopt != NULL)
{
printf (", ");
length += 2;
}
if (opt->longopt != NULL)
if (opt_p->longopt != NULL)
{
printf ("--%s", opt->longopt);
length += (int) (strlen (opt->longopt) + 2);
printf ("--%s", opt_p->longopt);
length += (int) (strlen (opt_p->longopt) + 2);
}
if (opt->meta != NULL)
if (opt_p->meta != NULL)
{
printf (" %s", opt->meta);
length += 1 + (int) strlen (opt->meta);
printf (" %s", opt_p->meta);
length += 1 + (int) strlen (opt_p->meta);
}
if (opt->help != NULL)
if (opt_p->help != NULL)
{
if (length >= CLI_LINE_TAB)
{
@@ -400,23 +426,23 @@ cli_help (const char *progname, /**< program name, typically argv[0] */
cli_print_pad (CLI_LINE_TAB - length);
length = CLI_LINE_TAB;
cli_print_help (opt->help);
cli_print_help (opt_p->help);
}
printf ("\n");
opt++;
opt_p++;
}
if (opt->help != NULL)
if (opt_p->help != NULL)
{
int length = 0;
if (opt->meta != NULL)
if (opt_p->meta != NULL)
{
length = (int) (CLI_LINE_INDENT + strlen (opt->meta));
length = (int) (CLI_LINE_INDENT + strlen (opt_p->meta));
cli_print_pad (CLI_LINE_INDENT);
printf ("%s", opt->meta);
printf ("%s", opt_p->meta);
}
if (length >= CLI_LINE_TAB)
@@ -427,7 +453,7 @@ cli_help (const char *progname, /**< program name, typically argv[0] */
cli_print_pad (CLI_LINE_TAB - length);
cli_print_help (opt->help);
cli_print_help (opt_p->help);
printf ("\n");
}
} /* cli_help */
+6 -5
View File
@@ -66,10 +66,11 @@ typedef struct
* Functions for CLI.
*/
cli_state_t cli_init (const cli_opt_t *options, int argc, char **argv);
int cli_consume_option (cli_state_t *state);
const char * cli_consume_string (cli_state_t *state);
int cli_consume_int (cli_state_t *state);
void cli_help (const char *progname, const cli_opt_t *options);
cli_state_t cli_init (const cli_opt_t *options_p, int argc, char **argv);
void cli_change_opts (cli_state_t *state_p, const cli_opt_t *options_p);
int cli_consume_option (cli_state_t *state_p);
const char * cli_consume_string (cli_state_t *state_p);
int cli_consume_int (cli_state_t *state_p);
void cli_help (const char *prog_name_p, const char *command_name_p, const cli_opt_t *options_p);
#endif /* CLI_H */
+308
View File
@@ -0,0 +1,308 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "jerryscript.h"
#include "jerryscript-port.h"
#include "cli.h"
/**
* Maximum size for loaded snapshots
*/
#define JERRY_BUFFER_SIZE (1048576)
/**
* Standalone Jerry exit codes
*/
#define JERRY_STANDALONE_EXIT_CODE_OK (0)
#define JERRY_STANDALONE_EXIT_CODE_FAIL (1)
static uint8_t input_buffer[ JERRY_BUFFER_SIZE ];
static uint32_t output_buffer[ JERRY_BUFFER_SIZE / 4 ];
/**
* Loading a single file into the memory.
*
* @return size of file - if loading is successful
* 0 - otherwise
*/
static size_t
read_file (uint8_t *input_pos_p, /**< next position in the input buffer */
const char *file_name) /**< file name */
{
FILE *file = fopen (file_name, "r");
if (file == NULL)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to open file: %s\n", file_name);
return 0;
}
size_t max_size = (size_t) (input_buffer + JERRY_BUFFER_SIZE - input_pos_p);
size_t bytes_read = fread (input_pos_p, 1u, max_size, file);
fclose (file);
if (bytes_read == 0)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to read file: %s\n", file_name);
return 0;
}
if (bytes_read == max_size)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: file too large: %s\n", file_name);
return 0;
}
printf ("Input file '%s' (%d bytes) loaded.\n", file_name, (int) bytes_read);
return bytes_read;
} /* read_file */
/**
* Merge command line option IDs
*/
typedef enum
{
OPT_MERGE_HELP,
OPT_MERGE_OUT,
} merge_opt_id_t;
/**
* Merge command line options
*/
static const cli_opt_t merge_opts[] =
{
CLI_OPT_DEF (.id = OPT_MERGE_HELP, .opt = "h", .longopt = "help",
.help = "print this help and exit"),
CLI_OPT_DEF (.id = OPT_MERGE_OUT, .opt = "o",
.help = "specify output file name (default: merged.snapshot)"),
CLI_OPT_DEF (.id = CLI_OPT_DEFAULT, .meta = "FILE",
.help = "input snapshot files, minimum two")
};
/**
* Process 'merge' command.
*
* @return error code (0 - no error)
*/
static int
process_merge (cli_state_t *cli_state_p, /**< cli state */
int argc, /**< number of arguments */
char *prog_name_p) /**< program name */
{
jerry_init (JERRY_INIT_EMPTY);
uint8_t *input_pos_p = input_buffer;
cli_change_opts (cli_state_p, merge_opts);
const char *output_file_name_p = "merged.snapshot";
const uint32_t *merge_buffers[argc];
size_t merge_buffer_sizes[argc];
uint32_t number_of_files = 0;
for (int id = cli_consume_option (cli_state_p); id != CLI_OPT_END; id = cli_consume_option (cli_state_p))
{
switch (id)
{
case OPT_MERGE_HELP:
{
cli_help (prog_name_p, "merge", merge_opts);
return JERRY_STANDALONE_EXIT_CODE_OK;
}
case OPT_MERGE_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);
if (cli_state_p->error == NULL)
{
size_t size = read_file (input_pos_p, file_name_p);
if (size == 0)
{
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
merge_buffers[number_of_files] = (const uint32_t *) input_pos_p;
merge_buffer_sizes[number_of_files] = size;
number_of_files++;
const uintptr_t mask = sizeof (uint32_t) - 1;
input_pos_p = (uint8_t *) ((((uintptr_t) input_pos_p) + size + mask) & ~mask);
}
break;
}
default:
{
cli_state_p->error = "Internal error";
break;
}
}
}
if (cli_state_p->error != NULL)
{
if (cli_state_p->arg != NULL)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s %s\n", cli_state_p->error, cli_state_p->arg);
}
else
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", cli_state_p->error);
}
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
if (number_of_files < 2)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: at least two input files must be passed.\n");
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
const char *error_p;
size_t size = jerry_merge_snapshots (merge_buffers,
merge_buffer_sizes,
number_of_files,
output_buffer,
JERRY_BUFFER_SIZE,
&error_p);
if (size == 0)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", error_p);
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
FILE *file_p = fopen (output_file_name_p, "w");
if (file_p != NULL)
{
fwrite (output_buffer, 1u, size, file_p);
fclose (file_p);
}
else
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: cannot open file: '%s'\n", output_file_name_p);
}
return JERRY_STANDALONE_EXIT_CODE_OK;
} /* process_merge */
/**
* Command line option IDs
*/
typedef enum
{
OPT_HELP,
} main_opt_id_t;
/**
* Command line options
*/
static const cli_opt_t main_opts[] =
{
CLI_OPT_DEF (.id = OPT_HELP, .opt = "h", .longopt = "help",
.help = "print this help and exit"),
CLI_OPT_DEF (.id = CLI_OPT_DEFAULT, .meta = "COMMAND",
.help = "specify the command")
};
/**
* Print available commands.
*/
static void
print_commands (char *prog_name_p) /**< program name */
{
cli_help (prog_name_p, NULL, main_opts);
printf ("\nAvailable commands:\n"
" merge\n"
"\nPassing -h or --help after a command displays its help.\n");
} /* print_commands */
/**
* Main function.
*
* @return error code (0 - no error)
*/
int
main (int argc, /**< number of arguments */
char **argv) /**< argument list */
{
cli_state_t cli_state = cli_init (main_opts, argc - 1, argv + 1);
for (int id = cli_consume_option (&cli_state); id != CLI_OPT_END; id = cli_consume_option (&cli_state))
{
switch (id)
{
case OPT_MERGE_HELP:
{
/* Help is always printed if no command is provided. */
break;
}
case CLI_OPT_DEFAULT:
{
const char *command_p = cli_consume_string (&cli_state);
if (cli_state.error != NULL)
{
break;
}
if (!strcmp ("merge", command_p))
{
return process_merge (&cli_state, argc, argv[0]);
}
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: unknown command: %s\n\n", command_p);
print_commands (argv[0]);
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
default:
{
cli_state.error = "Internal error";
break;
}
}
}
if (cli_state.error != NULL)
{
if (cli_state.arg != NULL)
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s %s\n", cli_state.error, cli_state.arg);
}
else
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: %s\n", cli_state.error);
}
return JERRY_STANDALONE_EXIT_CODE_FAIL;
}
print_commands (argv[0]);
return JERRY_STANDALONE_EXIT_CODE_OK;
} /* main */
+24 -5
View File
@@ -319,6 +319,7 @@ typedef enum
OPT_SAVE_LIT_LIST,
OPT_SAVE_LIT_C,
OPT_EXEC_SNAP,
OPT_EXEC_SNAP_FUNC,
OPT_LOG_LEVEL,
OPT_ABORT_ON_FAIL,
OPT_NO_PROMPT
@@ -357,6 +358,8 @@ static const cli_opt_t main_opts[] =
.help = "export literals found in parsed JS input (in C source format)"),
CLI_OPT_DEF (.id = OPT_EXEC_SNAP, .longopt = "exec-snapshot", .meta = "FILE",
.help = "execute input snapshot file(s)"),
CLI_OPT_DEF (.id = OPT_EXEC_SNAP_FUNC, .longopt = "exec-snapshot-func", .meta = "FILE NUM",
.help = "execute specific function from input snapshot file(s)"),
CLI_OPT_DEF (.id = OPT_LOG_LEVEL, .longopt = "log-level", .meta = "NUM",
.help = "set log level (0-3)"),
CLI_OPT_DEF (.id = OPT_ABORT_ON_FAIL, .longopt = "abort-on-fail",
@@ -427,6 +430,7 @@ main (int argc,
jerry_init_flag_t flags = JERRY_INIT_EMPTY;
const char *exec_snapshot_file_names[argc];
uint32_t exec_snapshot_file_indices[argc];
int exec_snapshots_count = 0;
bool is_parse_only = false;
@@ -452,7 +456,7 @@ main (int argc,
{
case OPT_HELP:
{
cli_help (argv[0], main_opts);
cli_help (argv[0], NULL, main_opts);
return JERRY_STANDALONE_EXIT_CODE_OK;
}
case OPT_VERSION:
@@ -544,7 +548,21 @@ main (int argc,
{
if (check_feature (JERRY_FEATURE_SNAPSHOT_EXEC, cli_state.arg))
{
exec_snapshot_file_names[exec_snapshots_count++] = cli_consume_string (&cli_state);
exec_snapshot_file_names[exec_snapshots_count] = cli_consume_string (&cli_state);
exec_snapshot_file_indices[exec_snapshots_count++] = 0;
}
else
{
cli_consume_string (&cli_state);
}
break;
}
case OPT_EXEC_SNAP_FUNC:
{
if (check_feature (JERRY_FEATURE_SNAPSHOT_EXEC, cli_state.arg))
{
exec_snapshot_file_names[exec_snapshots_count] = cli_consume_string (&cli_state);
exec_snapshot_file_indices[exec_snapshots_count++] = (uint32_t) cli_consume_int (&cli_state);
}
else
{
@@ -650,9 +668,10 @@ main (int argc,
}
else
{
ret_value = jerry_exec_snapshot (snapshot_p,
snapshot_size,
true);
ret_value = jerry_exec_snapshot_at (snapshot_p,
snapshot_size,
exec_snapshot_file_indices[i],
true);
}
if (jerry_value_has_error_flag (ret_value))
-122
View File
@@ -18,11 +18,6 @@
#include "test-common.h"
/**
* Maximum size of snapshots buffer
*/
#define SNAPSHOT_BUFFER_SIZE (256)
const char *test_source = (
"function assert (arg) { "
" if (!arg) { "
@@ -1181,122 +1176,5 @@ main (void)
jerry_cleanup ();
/* 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_SHOW_OPCODES);
size_t global_mode_snapshot_size = jerry_parse_and_save_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 ();
jerry_init (JERRY_INIT_SHOW_OPCODES);
size_t eval_mode_snapshot_size = jerry_parse_and_save_snapshot ((jerry_char_t *) code_to_snapshot_p,
strlen (code_to_snapshot_p),
false,
false,
eval_mode_snapshot_buffer,
SNAPSHOT_BUFFER_SIZE);
TEST_ASSERT (eval_mode_snapshot_size != 0);
jerry_cleanup ();
jerry_init (JERRY_INIT_SHOW_OPCODES);
res = jerry_exec_snapshot (global_mode_snapshot_buffer,
global_mode_snapshot_size,
false);
TEST_ASSERT (!jerry_value_has_error_flag (res));
TEST_ASSERT (jerry_value_is_string (res));
sz = jerry_get_string_size (res);
TEST_ASSERT (sz == 20);
sz = jerry_string_to_char_buffer (res, (jerry_char_t *) buffer, sz);
TEST_ASSERT (sz == 20);
jerry_release_value (res);
TEST_ASSERT (!strncmp (buffer, "string from snapshot", (size_t) sz));
res = jerry_exec_snapshot (eval_mode_snapshot_buffer,
eval_mode_snapshot_size,
false);
TEST_ASSERT (!jerry_value_has_error_flag (res));
TEST_ASSERT (jerry_value_is_string (res));
sz = jerry_get_string_size (res);
TEST_ASSERT (sz == 20);
sz = jerry_string_to_char_buffer (res, (jerry_char_t *) buffer, sz);
TEST_ASSERT (sz == 20);
jerry_release_value (res);
TEST_ASSERT (!strncmp (buffer, "string from snapshot", (size_t) sz));
jerry_cleanup ();
}
/* Save literals */
if (jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_SAVE))
{
/* C format generation */
jerry_init (JERRY_INIT_EMPTY);
static uint32_t literal_buffer_c[SNAPSHOT_BUFFER_SIZE];
static const char *code_for_c_format_p = "var object = { aa:'fo o', Bb:'max', aaa:'xzy0' };";
size_t literal_sizes_c_format = jerry_parse_and_save_literals ((jerry_char_t *) code_for_c_format_p,
strlen (code_for_c_format_p),
false,
literal_buffer_c,
SNAPSHOT_BUFFER_SIZE,
true);
TEST_ASSERT (literal_sizes_c_format == 203);
static const char *expected_c_format = (
"jerry_length_t literal_count = 4;\n\n"
"jerry_char_ptr_t literals[4] =\n"
"{\n"
" \"Bb\",\n"
" \"aa\",\n"
" \"aaa\",\n"
" \"xzy0\"\n"
"};\n\n"
"jerry_length_t literal_sizes[4] =\n"
"{\n"
" 2 /* Bb */,\n"
" 2 /* aa */,\n"
" 3 /* aaa */,\n"
" 4 /* xzy0 */\n"
"};\n"
);
TEST_ASSERT (!strncmp ((char *) literal_buffer_c, expected_c_format, literal_sizes_c_format));
jerry_cleanup ();
/* List format generation */
jerry_init (JERRY_INIT_EMPTY);
static uint32_t literal_buffer_list[SNAPSHOT_BUFFER_SIZE];
static const char *code_for_list_format_p = "var obj = { a:'aa', bb:'Bb' };";
size_t literal_sizes_list_format = jerry_parse_and_save_literals ((jerry_char_t *) code_for_list_format_p,
strlen (code_for_list_format_p),
false,
literal_buffer_list,
SNAPSHOT_BUFFER_SIZE,
false);
TEST_ASSERT (literal_sizes_list_format == 25);
TEST_ASSERT (!strncmp ((char *) literal_buffer_list, "1 a\n2 Bb\n2 aa\n2 bb\n3 obj\n", literal_sizes_list_format));
jerry_cleanup ();
}
return 0;
} /* main */
+216
View File
@@ -0,0 +1,216 @@
/* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "config.h"
#include "jerryscript.h"
#include "test-common.h"
/**
* Maximum size of snapshots buffer
*/
#define SNAPSHOT_BUFFER_SIZE (256)
int
main (void)
{
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];
char string_data[32];
const char *code_to_snapshot_p = "(function () { return 'string from snapshot'; }) ();";
jerry_init (JERRY_INIT_EMPTY);
size_t global_mode_snapshot_size = jerry_parse_and_save_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 ();
jerry_init (JERRY_INIT_EMPTY);
size_t eval_mode_snapshot_size = jerry_parse_and_save_snapshot ((jerry_char_t *) code_to_snapshot_p,
strlen (code_to_snapshot_p),
false,
false,
eval_mode_snapshot_buffer,
SNAPSHOT_BUFFER_SIZE);
TEST_ASSERT (eval_mode_snapshot_size != 0);
jerry_cleanup ();
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t res = jerry_exec_snapshot (global_mode_snapshot_buffer,
global_mode_snapshot_size,
false);
TEST_ASSERT (!jerry_value_has_error_flag (res));
TEST_ASSERT (jerry_value_is_string (res));
jerry_size_t sz = jerry_get_string_size (res);
TEST_ASSERT (sz == 20);
sz = jerry_string_to_char_buffer (res, (jerry_char_t *) string_data, sz);
TEST_ASSERT (sz == 20);
jerry_release_value (res);
TEST_ASSERT (!strncmp (string_data, "string from snapshot", (size_t) sz));
res = jerry_exec_snapshot (eval_mode_snapshot_buffer,
eval_mode_snapshot_size,
false);
TEST_ASSERT (!jerry_value_has_error_flag (res));
TEST_ASSERT (jerry_value_is_string (res));
sz = jerry_get_string_size (res);
TEST_ASSERT (sz == 20);
sz = jerry_string_to_char_buffer (res, (jerry_char_t *) string_data, sz);
TEST_ASSERT (sz == 20);
jerry_release_value (res);
TEST_ASSERT (!strncmp (string_data, "string from snapshot", (size_t) sz));
jerry_cleanup ();
}
/* Merge snapshot */
if (jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_SAVE)
&& jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_EXEC))
{
static uint32_t snapshot_buffer_0[SNAPSHOT_BUFFER_SIZE];
static uint32_t snapshot_buffer_1[SNAPSHOT_BUFFER_SIZE];
size_t snapshot_sizes[2];
static uint32_t merged_snapshot_buffer[SNAPSHOT_BUFFER_SIZE];
const char *code_to_snapshot_p = "123";
jerry_init (JERRY_INIT_EMPTY);
snapshot_sizes[0] = jerry_parse_and_save_snapshot ((jerry_char_t *) code_to_snapshot_p,
strlen (code_to_snapshot_p),
true,
false,
snapshot_buffer_0,
SNAPSHOT_BUFFER_SIZE);
TEST_ASSERT (snapshot_sizes[0] != 0);
jerry_cleanup ();
code_to_snapshot_p = "456";
jerry_init (JERRY_INIT_EMPTY);
snapshot_sizes[1] = jerry_parse_and_save_snapshot ((jerry_char_t *) code_to_snapshot_p,
strlen (code_to_snapshot_p),
true,
false,
snapshot_buffer_1,
SNAPSHOT_BUFFER_SIZE);
TEST_ASSERT (snapshot_sizes[1] != 0);
jerry_cleanup ();
jerry_init (JERRY_INIT_EMPTY);
const char *error_p;
const uint32_t *snapshot_buffers[2];
snapshot_buffers[0] = snapshot_buffer_0;
snapshot_buffers[1] = snapshot_buffer_1;
size_t merged_size = jerry_merge_snapshots (snapshot_buffers,
snapshot_sizes,
2,
merged_snapshot_buffer,
SNAPSHOT_BUFFER_SIZE,
&error_p);
jerry_cleanup ();
jerry_init (JERRY_INIT_EMPTY);
jerry_value_t res = jerry_exec_snapshot_at (merged_snapshot_buffer, merged_size, 0, false);
TEST_ASSERT (!jerry_value_has_error_flag (res));
TEST_ASSERT (jerry_get_number_value (res) == 123);
jerry_release_value (res);
res = jerry_exec_snapshot_at (merged_snapshot_buffer, merged_size, 1, false);
TEST_ASSERT (!jerry_value_has_error_flag (res));
TEST_ASSERT (jerry_get_number_value (res) == 456);
jerry_release_value (res);
jerry_cleanup ();
}
/* Save literals */
if (jerry_is_feature_enabled (JERRY_FEATURE_SNAPSHOT_SAVE))
{
/* C format generation */
jerry_init (JERRY_INIT_EMPTY);
static uint32_t literal_buffer_c[SNAPSHOT_BUFFER_SIZE];
static const char *code_for_c_format_p = "var object = { aa:'fo o', Bb:'max', aaa:'xzy0' };";
size_t literal_sizes_c_format = jerry_parse_and_save_literals ((jerry_char_t *) code_for_c_format_p,
strlen (code_for_c_format_p),
false,
literal_buffer_c,
SNAPSHOT_BUFFER_SIZE,
true);
TEST_ASSERT (literal_sizes_c_format == 203);
static const char *expected_c_format = (
"jerry_length_t literal_count = 4;\n\n"
"jerry_char_ptr_t literals[4] =\n"
"{\n"
" \"Bb\",\n"
" \"aa\",\n"
" \"aaa\",\n"
" \"xzy0\"\n"
"};\n\n"
"jerry_length_t literal_sizes[4] =\n"
"{\n"
" 2 /* Bb */,\n"
" 2 /* aa */,\n"
" 3 /* aaa */,\n"
" 4 /* xzy0 */\n"
"};\n"
);
TEST_ASSERT (!strncmp ((char *) literal_buffer_c, expected_c_format, literal_sizes_c_format));
jerry_cleanup ();
/* List format generation */
jerry_init (JERRY_INIT_EMPTY);
static uint32_t literal_buffer_list[SNAPSHOT_BUFFER_SIZE];
static const char *code_for_list_format_p = "var obj = { a:'aa', bb:'Bb' };";
size_t literal_sizes_list_format = jerry_parse_and_save_literals ((jerry_char_t *) code_for_list_format_p,
strlen (code_for_list_format_p),
false,
literal_buffer_list,
SNAPSHOT_BUFFER_SIZE,
false);
TEST_ASSERT (literal_sizes_list_format == 25);
TEST_ASSERT (!strncmp ((char *) literal_buffer_list, "1 a\n2 Bb\n2 aa\n2 bb\n3 obj\n", literal_sizes_list_format));
jerry_cleanup ();
}
return 0;
} /* main */
+3
View File
@@ -74,6 +74,8 @@ def get_arguments():
help='build jerry command line tool (%(choices)s; default: %(default)s)')
parser.add_argument('--jerry-cmdline-minimal', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
help='build minimal version of the jerry command line tool (%(choices)s; default: %(default)s)')
parser.add_argument('--jerry-cmdline-snapshot', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
help='build snapshot command line tool (%(choices)s; default: %(default)s)')
parser.add_argument('--jerry-debugger', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
help='enable the jerry debugger (%(choices)s; default: %(default)s)')
parser.add_argument('--jerry-ext', metavar='X', choices=['ON', 'OFF'], default='ON', type=str.upper,
@@ -150,6 +152,7 @@ def generate_build_options(arguments):
build_options.append('-DFEATURE_ERROR_MESSAGES=%s' % arguments.error_messages)
build_options.append('-DJERRY_CMDLINE=%s' % arguments.jerry_cmdline)
build_options.append('-DJERRY_CMDLINE_MINIMAL=%s' % arguments.jerry_cmdline_minimal)
build_options.append('-DJERRY_CMDLINE_SNAPSHOT=%s' % arguments.jerry_cmdline_snapshot)
build_options.append('-DJERRY_PORT_DEFAULT=%s' % arguments.jerry_port_default)
build_options.append('-DJERRY_EXT=%s' % arguments.jerry_ext)
build_options.append('-DJERRY_LIBC=%s' % arguments.jerry_libc)
+2
View File
@@ -128,6 +128,8 @@ JERRY_BUILDOPTIONS = [
['--jerry-libc=off', '--compile-flag=-m32', '--cpointer-32bit=on', '--system-allocator=on']),
Options('buildoption_test-external_context',
['--jerry-libc=off', '--external-context=on']),
Options('buildoption_test-snapshot_tool',
['--jerry-cmdline-snapshot=on']),
]
def get_arguments():