Skip to content

Commit e603d29

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 7d133e5 commit e603d29

File tree

11 files changed

+661
-202
lines changed

11 files changed

+661
-202
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
@@ -3976,9 +3976,9 @@ jerry_exec_snapshot (const uint32_t *snapshot_p,
39763976

39773977
jerry_init (JERRY_INIT_EMPTY);
39783978

3979-
res = (jerry_exec_snapshot (global_mode_snapshot_buffer,
3980-
global_mode_snapshot_size,
3981-
false);
3979+
res = jerry_exec_snapshot (global_mode_snapshot_buffer,
3980+
global_mode_snapshot_size,
3981+
false);
39823982

39833983
jerry_cleanup ();
39843984
}
@@ -3988,6 +3988,76 @@ jerry_exec_snapshot (const uint32_t *snapshot_p,
39883988

39893989
- [jerry_init](#jerry_init)
39903990
- [jerry_cleanup](#jerry_cleanup)
3991+
- [jerry_exec_snapshot_at](#jerry_exec_snapshot_at)
3992+
- [jerry_parse_and_save_snapshot](#jerry_parse_and_save_snapshot)
3993+
3994+
3995+
## jerry_exec_snapshot_at
3996+
3997+
**Summary**
3998+
3999+
Execute the selected snapshot function from the specified buffer.
4000+
4001+
Same function as [jerry_exec_snapshot](#jerry_exec_snapshot) except
4002+
the executed function index can be specified.
4003+
4004+
*Note*: Returned value must be freed with [jerry_release_value](#jerry_release_value) when it
4005+
is no longer needed.
4006+
4007+
**Prototype**
4008+
4009+
```c
4010+
jerry_value_t
4011+
jerry_exec_snapshot_at (const uint32_t *snapshot_p,
4012+
size_t snapshot_size,
4013+
size_t func_index,
4014+
bool copy_bytecode);
4015+
```
4016+
4017+
- `snapshot_p` - pointer to snapshot
4018+
- `snapshot_size` - size of snapshot
4019+
- `func_index` - index of executed function
4020+
- `copy_bytecode` - flag, indicating whether the passed snapshot buffer should be copied to the
4021+
engine's memory. If set the engine should not reference the buffer after the function returns
4022+
(in this case, the passed buffer could be freed after the call). Otherwise (if the flag is not
4023+
set) - the buffer could only be freed after the engine stops (i.e. after call to jerry_cleanup).
4024+
- return value
4025+
- result of bytecode, if run was successful
4026+
- thrown error, otherwise
4027+
4028+
**Example**
4029+
4030+
```c
4031+
{
4032+
jerry_value_t res;
4033+
static uint32_t global_mode_snapshot_buffer[256];
4034+
const jerry_char_t *code_to_snapshot_p = "(function () { return 'string from snapshot'; }) ();";
4035+
4036+
jerry_init (JERRY_INIT_EMPTY);
4037+
size_t global_mode_snapshot_size = jerry_parse_and_save_snapshot (code_to_snapshot_p,
4038+
strlen ((const char *) code_to_snapshot_p),
4039+
true,
4040+
false,
4041+
global_mode_snapshot_buffer,
4042+
sizeof (global_mode_snapshot_buffer) / sizeof (uint32_t));
4043+
jerry_cleanup ();
4044+
4045+
jerry_init (JERRY_INIT_EMPTY);
4046+
4047+
res = jerry_exec_snapshot_at (global_mode_snapshot_buffer,
4048+
global_mode_snapshot_size,
4049+
0,
4050+
false);
4051+
4052+
jerry_cleanup ();
4053+
}
4054+
```
4055+
4056+
**See also**
4057+
4058+
- [jerry_init](#jerry_init)
4059+
- [jerry_cleanup](#jerry_cleanup)
4060+
- [jerry_exec_snapshot](#jerry_exec_snapshot)
39914061
- [jerry_parse_and_save_snapshot](#jerry_parse_and_save_snapshot)
39924062

39934063

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))
@@ -373,7 +378,7 @@ snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data
373378
{
374379
bytecode_p = (ecma_compiled_code_t *) jmem_heap_alloc_block (code_size);
375380

376-
memcpy (bytecode_p, snapshot_data_p + offset, code_size);
381+
memcpy (bytecode_p, base_addr_p + offset, code_size);
377382
}
378383
else
379384
{
@@ -384,7 +389,7 @@ snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data
384389

385390
bytecode_p = (ecma_compiled_code_t *) jmem_heap_alloc_block (total_size);
386391

387-
memcpy (bytecode_p, snapshot_data_p + offset, code_size);
392+
memcpy (bytecode_p, base_addr_p + offset, code_size);
388393

389394
bytecode_p->size = (uint16_t) (total_size >> JMEM_ALIGNMENT_LOG);
390395

@@ -404,17 +409,9 @@ snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data
404409

405410
for (uint32_t i = 0; i < const_literal_end; i++)
406411
{
407-
lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p;
408-
409-
if (literal_start_p[i] != 0)
410-
{
411-
while (current_p->literal_offset != literal_start_p[i])
412-
{
413-
current_p++;
414-
}
415-
416-
literal_start_p[i] = current_p->literal_id;
417-
}
412+
literal_start_p[i] = ecma_snapshot_get_literal (literal_base_p,
413+
number_base_p,
414+
literal_start_p[i]);
418415
}
419416

420417
for (uint32_t i = const_literal_end; i < literal_end; i++)
@@ -430,9 +427,10 @@ snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data
430427
else
431428
{
432429
ecma_compiled_code_t *literal_bytecode_p;
433-
literal_bytecode_p = snapshot_load_compiled_code (snapshot_data_p,
430+
literal_bytecode_p = snapshot_load_compiled_code (base_addr_p,
434431
literal_offset,
435-
lit_map_p,
432+
literal_base_p,
433+
number_base_p,
436434
copy_bytecode);
437435

438436
ECMA_SET_NON_NULL_POINTER (literal_start_p[i],
@@ -492,7 +490,13 @@ jerry_parse_and_save_snapshot (const jerry_char_t *source_p, /**< script source
492490
jerry_snapshot_header_t header;
493491
header.version = JERRY_SNAPSHOT_VERSION;
494492
header.lit_table_offset = (uint32_t) globals.snapshot_buffer_write_offset;
495-
header.is_run_global = is_for_global;
493+
header.number_of_funcs = 1;
494+
header.func_offsets[0] = sizeof (jerry_snapshot_header_t);
495+
496+
if (!is_for_global)
497+
{
498+
header.func_offsets[0] |= JERRY_SNAPSHOT_EVAL_CONTEXT;
499+
}
496500

497501
lit_mem_to_snapshot_id_map_entry_t *lit_map_p = NULL;
498502
uint32_t literals_num;
@@ -501,8 +505,7 @@ jerry_parse_and_save_snapshot (const jerry_char_t *source_p, /**< script source
501505
buffer_size,
502506
&globals.snapshot_buffer_write_offset,
503507
&lit_map_p,
504-
&literals_num,
505-
&header.lit_table_size))
508+
&literals_num))
506509
{
507510
JERRY_ASSERT (lit_map_p == NULL);
508511
return 0;
@@ -551,15 +554,16 @@ jerry_parse_and_save_snapshot (const jerry_char_t *source_p, /**< script source
551554
* thrown error - otherwise
552555
*/
553556
jerry_value_t
554-
jerry_exec_snapshot (const uint32_t *snapshot_p, /**< snapshot */
555-
size_t snapshot_size, /**< size of snapshot */
556-
bool copy_bytecode) /**< flag, indicating whether the passed snapshot
557-
* buffer should be copied to the engine's memory.
558-
* If set the engine should not reference the buffer
559-
* after the function returns (in this case, the passed
560-
* buffer could be freed after the call).
561-
* Otherwise (if the flag is not set) - the buffer could only be
562-
* freed after the engine stops (i.e. after call to jerry_cleanup). */
557+
jerry_exec_snapshot_at (const uint32_t *snapshot_p, /**< snapshot */
558+
size_t snapshot_size, /**< size of snapshot */
559+
size_t func_index, /**< index of primary function */
560+
bool copy_bytecode) /**< flag, indicating whether the passed snapshot
561+
* buffer should be copied to the engine's memory.
562+
* If set the engine should not reference the buffer
563+
* after the function returns (in this case, the passed
564+
* buffer could be freed after the call).
565+
* Otherwise (if the flag is not set) - the buffer could only be
566+
* freed after the engine stops (i.e. after call to jerry_cleanup). */
563567
{
564568
#ifdef JERRY_ENABLE_SNAPSHOT_EXEC
565569
JERRY_ASSERT (snapshot_p != NULL);
@@ -580,34 +584,32 @@ jerry_exec_snapshot (const uint32_t *snapshot_p, /**< snapshot */
580584
return ecma_raise_type_error (invalid_version_error_p);
581585
}
582586

583-
lit_mem_to_snapshot_id_map_entry_t *lit_map_p = NULL;
584-
uint32_t literals_num;
585-
586587
if (header_p->lit_table_offset >= snapshot_size)
587588
{
588589
return ecma_raise_type_error (invalid_version_error_p);
589590
}
590591

591-
JERRY_ASSERT ((header_p->lit_table_offset % sizeof (uint32_t)) == 0);
592-
if (!ecma_load_literals_from_snapshot ((uint32_t *) (snapshot_data_p + header_p->lit_table_offset),
593-
header_p->lit_table_size,
594-
&lit_map_p,
595-
&literals_num))
592+
if (func_index >= header_p->number_of_funcs)
596593
{
597-
JERRY_ASSERT (lit_map_p == NULL);
598-
return ecma_raise_type_error (invalid_format_error_p);
594+
return ecma_raise_range_error (ECMA_ERR_MSG ("Function index is higher than maximum"));
599595
}
600596

597+
JERRY_ASSERT ((header_p->lit_table_offset % sizeof (uint32_t)) == 0);
598+
599+
const uint8_t *literal_base_p;
600+
const uint8_t *number_base_p;
601+
602+
literal_base_p = ecma_snapshot_get_literals_base ((uint32_t *) (snapshot_data_p + header_p->lit_table_offset),
603+
&number_base_p);
604+
601605
ecma_compiled_code_t *bytecode_p;
602-
bytecode_p = snapshot_load_compiled_code (snapshot_data_p,
603-
sizeof (jerry_snapshot_header_t),
604-
lit_map_p,
605-
copy_bytecode);
606606

607-
if (lit_map_p != NULL)
608-
{
609-
jmem_heap_free_block (lit_map_p, literals_num * sizeof (lit_mem_to_snapshot_id_map_entry_t));
610-
}
607+
uint32_t func_offset = header_p->func_offsets[func_index] & ~JERRY_SNAPSHOT_EVAL_CONTEXT;
608+
bytecode_p = snapshot_load_compiled_code (snapshot_data_p + func_offset,
609+
0,
610+
literal_base_p,
611+
number_base_p,
612+
copy_bytecode);
611613

612614
if (bytecode_p == NULL)
613615
{
@@ -616,17 +618,49 @@ jerry_exec_snapshot (const uint32_t *snapshot_p, /**< snapshot */
616618

617619
ecma_value_t ret_val;
618620

619-
if (header_p->is_run_global)
621+
if (header_p->func_offsets[func_index] & JERRY_SNAPSHOT_EVAL_CONTEXT)
620622
{
621-
ret_val = vm_run_global (bytecode_p);
622-
ecma_bytecode_deref (bytecode_p);
623+
ret_val = vm_run_eval (bytecode_p, false);
623624
}
624625
else
625626
{
626-
ret_val = vm_run_eval (bytecode_p, false);
627+
ret_val = vm_run_global (bytecode_p);
628+
ecma_bytecode_deref (bytecode_p);
627629
}
628630

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

0 commit comments

Comments
 (0)