Implement snapshot functionality.

JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com
JerryScript-DCO-1.0-Signed-off-by: Andrey Shitov a.shitov@samsung.com
This commit is contained in:
Andrey Shitov
2015-09-07 18:38:24 +03:00
committed by Ruben Ayrapetyan
parent 7481fb606f
commit 311cc65b33
16 changed files with 1489 additions and 95 deletions
+279 -22
View File
@@ -269,6 +269,48 @@ jerry_api_convert_api_value_to_ecma_value (ecma_value_t *out_value_p, /**< out:
}
} /* jerry_api_convert_api_value_to_ecma_value */
/**
* Convert completion of 'eval' to API value and completion code
*
* Note:
* if the output value contains string / object, it should be freed
* with jerry_api_release_string / jerry_api_release_object,
* just when it becomes unnecessary.
*
* @return completion code
*/
static jerry_completion_code_t
jerry_api_convert_eval_completion_to_retval (jerry_api_value_t *retval_p, /**< out: api value */
ecma_completion_value_t completion) /**< completion of 'eval'-mode
* code execution */
{
jerry_completion_code_t ret_code;
if (ecma_is_completion_value_normal (completion))
{
ret_code = JERRY_COMPLETION_CODE_OK;
jerry_api_convert_ecma_value_to_api_value (retval_p,
ecma_get_completion_value_value (completion));
}
else
{
jerry_api_convert_ecma_value_to_api_value (retval_p, ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED));
if (ecma_is_completion_value_throw (completion))
{
ret_code = JERRY_COMPLETION_CODE_UNHANDLED_EXCEPTION;
}
else
{
JERRY_ASSERT (ecma_is_completion_value_empty (completion));
ret_code = JERRY_COMPLETION_CODE_OK;
}
}
return ret_code;
} /* jerry_api_convert_eval_completion_to_retval */
/**
* @}
@@ -1268,28 +1310,7 @@ jerry_api_eval (const jerry_api_char_t *source_p, /**< source code */
is_direct,
is_strict);
if (ecma_is_completion_value_normal (completion))
{
status = JERRY_COMPLETION_CODE_OK;
jerry_api_convert_ecma_value_to_api_value (retval_p,
ecma_get_completion_value_value (completion));
}
else
{
jerry_api_convert_ecma_value_to_api_value (retval_p, ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED));
if (ecma_is_completion_value_throw (completion))
{
status = JERRY_COMPLETION_CODE_UNHANDLED_EXCEPTION;
}
else
{
JERRY_ASSERT (ecma_is_completion_value_empty (completion));
status = JERRY_COMPLETION_CODE_OK;
}
}
status = jerry_api_convert_eval_completion_to_retval (retval_p, completion);
ecma_free_completion_value (completion);
@@ -1539,3 +1560,239 @@ jerry_register_external_magic_strings (const jerry_api_char_ptr_t* ex_str_items,
{
lit_magic_strings_ex_set ((const lit_utf8_byte_t **) ex_str_items, count, (const lit_utf8_size_t *) str_lengths);
} /* jerry_register_external_magic_strings */
/**
* Generate snapshot from specified source
*
* @return size of snapshot, if it was generated succesfully
* (i.e. there are no syntax errors in source code, buffer size is sufficient,
* and snapshot support is enabled in current configuration through JERRY_ENABLE_SNAPSHOT),
* 0 - otherwise.
*/
size_t
jerry_parse_and_save_snapshot (const jerry_api_char_t* source_p, /**< script source */
size_t source_size, /**< script source size */
bool is_for_global, /**< snapshot would be executed as global (true)
* or eval (false) */
uint8_t *buffer_p, /**< buffer to dump snapshot to */
size_t buffer_size) /**< the buffer's size */
{
#ifdef JERRY_ENABLE_SNAPSHOT
jsp_status_t parse_status;
const bytecode_data_header_t *bytecode_data_p;
if (is_for_global)
{
parse_status = parser_parse_script (source_p, source_size, &bytecode_data_p);
}
else
{
bool code_contains_functions;
parse_status = parser_parse_eval (source_p,
source_size,
false,
&bytecode_data_p,
&code_contains_functions);
}
if (parse_status != JSP_STATUS_OK)
{
return 0;
}
size_t buffer_write_offset = 0;
jerry_snapshot_header_t header;
header.is_run_global = is_for_global;
uint64_t version = JERRY_SNAPSHOT_VERSION;
if (!jrt_write_to_buffer_by_offset (buffer_p,
buffer_size,
&buffer_write_offset,
version))
{
return 0;
}
size_t header_offset = buffer_write_offset;
if (buffer_write_offset + sizeof (jerry_snapshot_header_t) > buffer_size)
{
return 0;
}
buffer_write_offset += sizeof (jerry_snapshot_header_t);
lit_mem_to_snapshot_id_map_entry_t* lit_map_p = NULL;
uint32_t literals_num;
if (!lit_dump_literals_for_snapshot (buffer_p,
buffer_size,
&buffer_write_offset,
&lit_map_p,
&literals_num,
&header.lit_table_size))
{
JERRY_ASSERT (lit_map_p == NULL);
return 0;
}
size_t bytecode_offset = sizeof (version) + sizeof (jerry_snapshot_header_t) + header.lit_table_size;
JERRY_ASSERT (JERRY_ALIGNUP (bytecode_offset, MEM_ALIGNMENT) == bytecode_offset);
bool is_ok = serializer_dump_bytecode_with_idx_map (buffer_p,
buffer_size,
&buffer_write_offset,
bytecode_data_p,
lit_map_p,
literals_num,
&header.bytecode_size,
&header.idx_to_lit_map_size);
if (lit_map_p != NULL)
{
mem_heap_free_block (lit_map_p);
}
if (!is_ok)
{
return 0;
}
is_ok = jrt_write_to_buffer_by_offset (buffer_p, buffer_size, &header_offset, header);
JERRY_ASSERT (is_ok && header_offset < buffer_write_offset);
return buffer_write_offset;
#else /* JERRY_ENABLE_SNAPSHOT */
(void) source_p;
(void) source_size;
(void) is_for_global;
(void) buffer_p;
(void) buffer_size;
return 0;
#endif /* !JERRY_ENABLE_SNAPSHOT */
} /* jerry_parse_and_save_snapshot */
/**
* Execute snapshot from specified buffer
*
* @return completion code
*/
jerry_completion_code_t
jerry_exec_snapshot (const void *snapshot_p, /**< snapshot */
size_t snapshot_size, /**< size of snapshot */
bool is_copy, /**< flag, indicating whether the passed snapshot
* buffer should be copied to engine's memory,
* so engine should not reference the buffer
* after the function returns (in the case, the passed
* buffer could be freed after the call);
* otherwise (if flag not set) - the buffer could be freed
* only after engine stops (i.e. after call to jerry_cleanup). */
jerry_api_value_t *retval_p) /**< out: returned value (ECMA-262 'undefined' if code is executed
* as global scope code) */
{
jerry_api_convert_ecma_value_to_api_value (retval_p, ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED));
#ifdef JERRY_ENABLE_SNAPSHOT
JERRY_ASSERT (snapshot_p != NULL);
const uint8_t *snapshot_data_p = (uint8_t *) snapshot_p;
size_t snapshot_read = 0;
uint64_t version;
if (!jrt_read_from_buffer_by_offset (snapshot_data_p,
snapshot_size,
&snapshot_read,
&version))
{
return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_FORMAT;
}
if (version != JERRY_SNAPSHOT_VERSION)
{
return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_VERSION;
}
const jerry_snapshot_header_t *header_p = (const jerry_snapshot_header_t *) (snapshot_data_p + snapshot_read);
if (snapshot_read + sizeof (jerry_snapshot_header_t) > snapshot_size)
{
return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_FORMAT;
}
snapshot_read += sizeof (jerry_snapshot_header_t);
if (snapshot_read + header_p->lit_table_size > snapshot_size)
{
return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_FORMAT;
}
lit_mem_to_snapshot_id_map_entry_t *lit_map_p = NULL;
uint32_t literals_num;
if (!lit_load_literals_from_snapshot (snapshot_data_p + snapshot_read,
header_p->lit_table_size,
&lit_map_p,
&literals_num,
is_copy))
{
JERRY_ASSERT (lit_map_p == NULL);
return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_FORMAT;
}
snapshot_read += header_p->lit_table_size;
if (snapshot_read + header_p->bytecode_size + header_p->idx_to_lit_map_size > snapshot_size)
{
mem_heap_free_block (lit_map_p);
return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_FORMAT;
}
const bytecode_data_header_t *bytecode_data_p;
bytecode_data_p = serializer_load_bytecode_with_idx_map (snapshot_data_p + snapshot_read,
header_p->bytecode_size,
header_p->idx_to_lit_map_size,
lit_map_p,
literals_num,
is_copy);
if (lit_map_p != NULL)
{
mem_heap_free_block (lit_map_p);
}
if (bytecode_data_p == NULL)
{
return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_FORMAT;
}
jerry_completion_code_t ret_code;
if (header_p->is_run_global)
{
vm_init (bytecode_data_p, false);
ret_code = vm_run_global ();
vm_finalize ();
}
else
{
/* vm should be already initialized */
ecma_completion_value_t completion = vm_run_eval (bytecode_data_p, false);
ret_code = jerry_api_convert_eval_completion_to_retval (retval_p, completion);
ecma_free_completion_value (completion);
}
return ret_code;
#else /* JERRY_ENABLE_SNAPSHOT */
(void) snapshot_p;
(void) snapshot_size;
(void) is_copy;
(void) retval_p;
return JERRY_COMPLETION_CODE_INVALID_SNAPSHOT_VERSION;
#endif /* !JERRY_ENABLE_SNAPSHOT */
} /* jerry_exec_snapshot */