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:
+12
-10
@@ -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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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 ==========================
|
||||
*/
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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))
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
@@ -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)
|
||||
|
||||
@@ -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():
|
||||
|
||||
Reference in New Issue
Block a user