Skip to content

Commit ead2b56

Browse files
committed
Support multiple primary functions in a single snapshot.
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 [email protected]
1 parent 29f57ec commit ead2b56

File tree

11 files changed

+662
-204
lines changed

11 files changed

+662
-204
lines changed

CMakeLists.txt

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@ string(TOUPPER "${PLATFORM}" PLATFORM)
2323
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS )
2424

2525
# Components
26-
set(JERRY_CMDLINE ON CACHE BOOL "Build jerry command line tool?")
27-
set(JERRY_CMDLINE_MINIMAL OFF CACHE BOOL "Build jerry minimal command line tool?")
28-
set(JERRY_PORT_DEFAULT ON CACHE BOOL "Build default jerry port implementation?")
29-
set(JERRY_EXT ON CACHE BOOL "Build jerry-ext?")
30-
set(JERRY_LIBC ON CACHE BOOL "Build and use jerry-libc?")
31-
set(JERRY_LIBM ON CACHE BOOL "Build and use jerry-libm?")
32-
set(UNITTESTS OFF CACHE BOOL "Build unit tests?")
26+
set(JERRY_CMDLINE ON CACHE BOOL "Build jerry command line tool?")
27+
set(JERRY_CMDLINE_MINIMAL OFF CACHE BOOL "Build jerry minimal command line tool?")
28+
set(JERRY_CMDLINE_SNAPSHOT OFF CACHE BOOL "Build jerry snapshot command line tool?")
29+
set(JERRY_PORT_DEFAULT ON CACHE BOOL "Build default jerry port implementation?")
30+
set(JERRY_EXT ON CACHE BOOL "Build jerry-ext?")
31+
set(JERRY_LIBC ON CACHE BOOL "Build and use jerry-libc?")
32+
set(JERRY_LIBM ON CACHE BOOL "Build and use jerry-libm?")
33+
set(UNITTESTS OFF CACHE BOOL "Build unit tests?")
3334

3435
# Optional build settings
3536
set(ENABLE_ALL_IN_ONE OFF CACHE BOOL "Enable all-in-one build?")
@@ -41,7 +42,7 @@ if(NOT CMAKE_BUILD_TYPE)
4142
set(CMAKE_BUILD_TYPE "MinSizeRel")
4243
endif()
4344

44-
if(JERRY_CMDLINE OR JERRY_CMDLINE_MINIMAL)
45+
if(JERRY_CMDLINE OR JERRY_CMDLINE_MINIMAL OR JERRY_CMDLINE_SNAPSHOT)
4546
set(JERRY_PORT_DEFAULT "ON")
4647

4748
set(JERRY_PORT_DEFAULT_MESSAGE " (FORCED BY CMDLINE)")
@@ -100,6 +101,7 @@ message(STATUS "ENABLE_STATIC_LINK " ${ENABLE_STATIC_LINK} ${ENABLE_STATI
100101
message(STATUS "ENABLE_STRIP " ${ENABLE_STRIP} ${ENABLE_STRIP_MESSAGE})
101102
message(STATUS "JERRY_CMDLINE " ${JERRY_CMDLINE})
102103
message(STATUS "JERRY_CMDLINE_MINIMAL " ${JERRY_CMDLINE_MINIMAL})
104+
message(STATUS "JERRY_CMDLINE_SNAPSHOT " ${JERRY_CMDLINE_SNAPSHOT})
103105
message(STATUS "JERRY_PORT_DEFAULT " ${JERRY_PORT_DEFAULT} ${JERRY_PORT_DEFAULT_MESSAGE})
104106
message(STATUS "JERRY_EXT " ${JERRY_EXT} ${JERRY_EXT_MESSAGE})
105107
message(STATUS "JERRY_LIBC " ${JERRY_LIBC} ${JERRY_LIBC_MESSAGE})
@@ -252,7 +254,7 @@ if(JERRY_EXT)
252254
endif()
253255

254256
# Jerry command line tool
255-
if(JERRY_CMDLINE OR JERRY_CMDLINE_MINIMAL)
257+
if(JERRY_CMDLINE OR JERRY_CMDLINE_MINIMAL OR JERRY_CMDLINE_SNAPSHOT)
256258
add_subdirectory(jerry-main)
257259
endif()
258260

docs/02.API-REFERENCE.md

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4012,9 +4012,9 @@ jerry_exec_snapshot (const uint32_t *snapshot_p,
40124012

40134013
jerry_init (JERRY_INIT_EMPTY);
40144014

4015-
res = (jerry_exec_snapshot (global_mode_snapshot_buffer,
4016-
global_mode_snapshot_size,
4017-
false);
4015+
res = jerry_exec_snapshot (global_mode_snapshot_buffer,
4016+
global_mode_snapshot_size,
4017+
false);
40184018

40194019
jerry_cleanup ();
40204020
}
@@ -4024,6 +4024,76 @@ jerry_exec_snapshot (const uint32_t *snapshot_p,
40244024

40254025
- [jerry_init](#jerry_init)
40264026
- [jerry_cleanup](#jerry_cleanup)
4027+
- [jerry_exec_snapshot_at](#jerry_exec_snapshot_at)
4028+
- [jerry_parse_and_save_snapshot](#jerry_parse_and_save_snapshot)
4029+
4030+
4031+
## jerry_exec_snapshot_at
4032+
4033+
**Summary**
4034+
4035+
Execute the selected snapshot function from the specified buffer.
4036+
4037+
Same function as [jerry_exec_snapshot](#jerry_exec_snapshot) except
4038+
the executed function index can be specified.
4039+
4040+
*Note*: Returned value must be freed with [jerry_release_value](#jerry_release_value) when it
4041+
is no longer needed.
4042+
4043+
**Prototype**
4044+
4045+
```c
4046+
jerry_value_t
4047+
jerry_exec_snapshot_at (const uint32_t *snapshot_p,
4048+
size_t snapshot_size,
4049+
size_t func_index,
4050+
bool copy_bytecode);
4051+
```
4052+
4053+
- `snapshot_p` - pointer to snapshot
4054+
- `snapshot_size` - size of snapshot
4055+
- `func_index` - index of executed function
4056+
- `copy_bytecode` - flag, indicating whether the passed snapshot buffer should be copied to the
4057+
engine's memory. If set the engine should not reference the buffer after the function returns
4058+
(in this case, the passed buffer could be freed after the call). Otherwise (if the flag is not
4059+
set) - the buffer could only be freed after the engine stops (i.e. after call to jerry_cleanup).
4060+
- return value
4061+
- result of bytecode, if run was successful
4062+
- thrown error, otherwise
4063+
4064+
**Example**
4065+
4066+
```c
4067+
{
4068+
jerry_value_t res;
4069+
static uint32_t global_mode_snapshot_buffer[256];
4070+
const jerry_char_t *code_to_snapshot_p = "(function () { return 'string from snapshot'; }) ();";
4071+
4072+
jerry_init (JERRY_INIT_EMPTY);
4073+
size_t global_mode_snapshot_size = jerry_parse_and_save_snapshot (code_to_snapshot_p,
4074+
strlen ((const char *) code_to_snapshot_p),
4075+
true,
4076+
false,
4077+
global_mode_snapshot_buffer,
4078+
sizeof (global_mode_snapshot_buffer) / sizeof (uint32_t));
4079+
jerry_cleanup ();
4080+
4081+
jerry_init (JERRY_INIT_EMPTY);
4082+
4083+
res = jerry_exec_snapshot_at (global_mode_snapshot_buffer,
4084+
global_mode_snapshot_size,
4085+
0,
4086+
false);
4087+
4088+
jerry_cleanup ();
4089+
}
4090+
```
4091+
4092+
**See also**
4093+
4094+
- [jerry_init](#jerry_init)
4095+
- [jerry_cleanup](#jerry_cleanup)
4096+
- [jerry_exec_snapshot](#jerry_exec_snapshot)
40274097
- [jerry_parse_and_save_snapshot](#jerry_parse_and_save_snapshot)
40284098

40294099

jerry-core/api/jerry-snapshot.c

Lines changed: 89 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,10 @@ snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled
9191
return 0;
9292
}
9393

94-
uint16_t start_offset = (uint16_t) (globals_p->snapshot_buffer_write_offset >> JMEM_ALIGNMENT_LOG);
94+
/* The snapshot generator always parses a single file,
95+
* so the base always starts right after the snapshot header. */
96+
size_t buffer_offset = globals_p->snapshot_buffer_write_offset - sizeof (jerry_snapshot_header_t);
97+
uint16_t start_offset = (uint16_t) (buffer_offset >> JMEM_ALIGNMENT_LOG);
9598

9699
uint8_t *copied_code_start_p = snapshot_buffer_p + globals_p->snapshot_buffer_write_offset;
97100
ecma_compiled_code_t *copied_code_p = (ecma_compiled_code_t *) copied_code_start_p;
@@ -252,10 +255,10 @@ jerry_snapshot_set_offsets (uint32_t *buffer_p, /**< buffer */
252255
{
253256
for (uint32_t i = 0; i < argument_end; i++)
254257
{
255-
lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
256-
257258
if (literal_start_p[i] != JMEM_CP_NULL)
258259
{
260+
lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
261+
259262
while (current_p->literal_id != literal_start_p[i])
260263
{
261264
current_p++;
@@ -316,12 +319,14 @@ jerry_snapshot_set_offsets (uint32_t *buffer_p, /**< buffer */
316319
* @return byte code
317320
*/
318321
static ecma_compiled_code_t *
319-
snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data */
322+
snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of the
323+
* current primary function */
320324
size_t offset, /**< byte code offset */
321-
lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< literal map */
325+
const uint8_t *literal_base_p, /**< literal start */
326+
const uint8_t *number_base_p, /**< literal number start */
322327
bool copy_bytecode) /**< byte code should be copied to memory */
323328
{
324-
ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) (snapshot_data_p + offset);
329+
ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) (base_addr_p + offset);
325330
uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG;
326331

327332
if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION))
@@ -377,7 +382,7 @@ snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data
377382
jmem_stats_allocate_byte_code_bytes (code_size);
378383
#endif /* JMEM_STATS */
379384

380-
memcpy (bytecode_p, snapshot_data_p + offset, code_size);
385+
memcpy (bytecode_p, base_addr_p + offset, code_size);
381386
}
382387
else
383388
{
@@ -392,7 +397,7 @@ snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data
392397
jmem_stats_allocate_byte_code_bytes (total_size);
393398
#endif /* JMEM_STATS */
394399

395-
memcpy (bytecode_p, snapshot_data_p + offset, code_size);
400+
memcpy (bytecode_p, base_addr_p + offset, code_size);
396401

397402
bytecode_p->size = (uint16_t) (total_size >> JMEM_ALIGNMENT_LOG);
398403

@@ -412,17 +417,9 @@ snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data
412417

413418
for (uint32_t i = 0; i < const_literal_end; i++)
414419
{
415-
lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
416-
417-
if (literal_start_p[i] != 0)
418-
{
419-
while (current_p->literal_offset != literal_start_p[i])
420-
{
421-
current_p++;
422-
}
423-
424-
literal_start_p[i] = current_p->literal_id;
425-
}
420+
literal_start_p[i] = ecma_snapshot_get_literal (literal_base_p,
421+
number_base_p,
422+
literal_start_p[i]);
426423
}
427424

428425
for (uint32_t i = const_literal_end; i < literal_end; i++)
@@ -438,9 +435,10 @@ snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data
438435
else
439436
{
440437
ecma_compiled_code_t *literal_bytecode_p;
441-
literal_bytecode_p = snapshot_load_compiled_code (snapshot_data_p,
438+
literal_bytecode_p = snapshot_load_compiled_code (base_addr_p,
442439
literal_offset,
443-
lit_map_p,
440+
literal_base_p,
441+
number_base_p,
444442
copy_bytecode);
445443

446444
ECMA_SET_NON_NULL_POINTER (literal_start_p[i],
@@ -500,7 +498,13 @@ jerry_parse_and_save_snapshot (const jerry_char_t *source_p, /**< script source
500498
jerry_snapshot_header_t header;
501499
header.version = JERRY_SNAPSHOT_VERSION;
502500
header.lit_table_offset = (uint32_t) globals.snapshot_buffer_write_offset;
503-
header.is_run_global = is_for_global;
501+
header.number_of_funcs = 1;
502+
header.func_offsets[0] = sizeof (jerry_snapshot_header_t);
503+
504+
if (!is_for_global)
505+
{
506+
header.func_offsets[0] |= JERRY_SNAPSHOT_EVAL_CONTEXT;
507+
}
504508

505509
lit_mem_to_snapshot_id_map_entry_t *lit_map_p = NULL;
506510
uint32_t literals_num;
@@ -509,8 +513,7 @@ jerry_parse_and_save_snapshot (const jerry_char_t *source_p, /**< script source
509513
buffer_size,
510514
&globals.snapshot_buffer_write_offset,
511515
&lit_map_p,
512-
&literals_num,
513-
&header.lit_table_size))
516+
&literals_num))
514517
{
515518
JERRY_ASSERT (lit_map_p == NULL);
516519
return 0;
@@ -559,15 +562,16 @@ jerry_parse_and_save_snapshot (const jerry_char_t *source_p, /**< script source
559562
* thrown error - otherwise
560563
*/
561564
jerry_value_t
562-
jerry_exec_snapshot (const uint32_t *snapshot_p, /**< snapshot */
563-
size_t snapshot_size, /**< size of snapshot */
564-
bool copy_bytecode) /**< flag, indicating whether the passed snapshot
565-
* buffer should be copied to the engine's memory.
566-
* If set the engine should not reference the buffer
567-
* after the function returns (in this case, the passed
568-
* buffer could be freed after the call).
569-
* Otherwise (if the flag is not set) - the buffer could only be
570-
* freed after the engine stops (i.e. after call to jerry_cleanup). */
565+
jerry_exec_snapshot_at (const uint32_t *snapshot_p, /**< snapshot */
566+
size_t snapshot_size, /**< size of snapshot */
567+
size_t func_index, /**< index of primary function */
568+
bool copy_bytecode) /**< flag, indicating whether the passed snapshot
569+
* buffer should be copied to the engine's memory.
570+
* If set the engine should not reference the buffer
571+
* after the function returns (in this case, the passed
572+
* buffer could be freed after the call).
573+
* Otherwise (if the flag is not set) - the buffer could only be
574+
* freed after the engine stops (i.e. after call to jerry_cleanup). */
571575
{
572576
#ifdef JERRY_ENABLE_SNAPSHOT_EXEC
573577
JERRY_ASSERT (snapshot_p != NULL);
@@ -588,34 +592,32 @@ jerry_exec_snapshot (const uint32_t *snapshot_p, /**< snapshot */
588592
return ecma_raise_type_error (invalid_version_error_p);
589593
}
590594

591-
lit_mem_to_snapshot_id_map_entry_t *lit_map_p = NULL;
592-
uint32_t literals_num;
593-
594595
if (header_p->lit_table_offset >= snapshot_size)
595596
{
596597
return ecma_raise_type_error (invalid_version_error_p);
597598
}
598599

599-
JERRY_ASSERT ((header_p->lit_table_offset % sizeof (uint32_t)) == 0);
600-
if (!ecma_load_literals_from_snapshot ((uint32_t *) (snapshot_data_p + header_p->lit_table_offset),
601-
header_p->lit_table_size,
602-
&lit_map_p,
603-
&literals_num))
600+
if (func_index >= header_p->number_of_funcs)
604601
{
605-
JERRY_ASSERT (lit_map_p == NULL);
606-
return ecma_raise_type_error (invalid_format_error_p);
602+
return ecma_raise_range_error (ECMA_ERR_MSG ("Function index is higher than maximum"));
607603
}
608604

605+
JERRY_ASSERT ((header_p->lit_table_offset % sizeof (uint32_t)) == 0);
606+
607+
const uint8_t *literal_base_p;
608+
const uint8_t *number_base_p;
609+
610+
literal_base_p = ecma_snapshot_get_literals_base ((uint32_t *) (snapshot_data_p + header_p->lit_table_offset),
611+
&number_base_p);
612+
609613
ecma_compiled_code_t *bytecode_p;
610-
bytecode_p = snapshot_load_compiled_code (snapshot_data_p,
611-
sizeof (jerry_snapshot_header_t),
612-
lit_map_p,
613-
copy_bytecode);
614614

615-
if (lit_map_p != NULL)
616-
{
617-
jmem_heap_free_block (lit_map_p, literals_num * sizeof (lit_mem_to_snapshot_id_map_entry_t));
618-
}
615+
uint32_t func_offset = header_p->func_offsets[func_index] & ~JERRY_SNAPSHOT_EVAL_CONTEXT;
616+
bytecode_p = snapshot_load_compiled_code (snapshot_data_p + func_offset,
617+
0,
618+
literal_base_p,
619+
number_base_p,
620+
copy_bytecode);
619621

620622
if (bytecode_p == NULL)
621623
{
@@ -624,17 +626,49 @@ jerry_exec_snapshot (const uint32_t *snapshot_p, /**< snapshot */
624626

625627
ecma_value_t ret_val;
626628

627-
if (header_p->is_run_global)
629+
if (header_p->func_offsets[func_index] & JERRY_SNAPSHOT_EVAL_CONTEXT)
628630
{
629-
ret_val = vm_run_global (bytecode_p);
630-
ecma_bytecode_deref (bytecode_p);
631+
ret_val = vm_run_eval (bytecode_p, false);
631632
}
632633
else
633634
{
634-
ret_val = vm_run_eval (bytecode_p, false);
635+
ret_val = vm_run_global (bytecode_p);
636+
ecma_bytecode_deref (bytecode_p);
635637
}
636638

637639
return ret_val;
640+
#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */
641+
JERRY_UNUSED (snapshot_p);
642+
JERRY_UNUSED (snapshot_size);
643+
JERRY_UNUSED (func_index);
644+
JERRY_UNUSED (copy_bytecode);
645+
646+
return ecma_make_simple_value (ECMA_SIMPLE_VALUE_FALSE);
647+
#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */
648+
} /* jerry_exec_snapshot_at */
649+
650+
/**
651+
* Execute snapshot from specified buffer
652+
*
653+
* Note:
654+
* returned value must be freed with jerry_release_value, when it is no longer needed.
655+
*
656+
* @return result of bytecode - if run was successful
657+
* thrown error - otherwise
658+
*/
659+
jerry_value_t
660+
jerry_exec_snapshot (const uint32_t *snapshot_p, /**< snapshot */
661+
size_t snapshot_size, /**< size of snapshot */
662+
bool copy_bytecode) /**< flag, indicating whether the passed snapshot
663+
* buffer should be copied to the engine's memory.
664+
* If set the engine should not reference the buffer
665+
* after the function returns (in this case, the passed
666+
* buffer could be freed after the call).
667+
* Otherwise (if the flag is not set) - the buffer could only be
668+
* freed after the engine stops (i.e. after call to jerry_cleanup). */
669+
{
670+
#ifdef JERRY_ENABLE_SNAPSHOT_EXEC
671+
return jerry_exec_snapshot_at (snapshot_p, snapshot_size, 0, copy_bytecode);
638672
#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */
639673
JERRY_UNUSED (snapshot_p);
640674
JERRY_UNUSED (snapshot_size);

0 commit comments

Comments
 (0)