Support external context, heap and lcache (#1778)

JerryScript should support external context, heap and lcache,
so that it can have multiple instances and runtime configurable heap
size.

Related issue: 1746

JerryScript-DCO-1.0-Signed-off-by: Zidong Jiang zidong.jiang@intel.com
This commit is contained in:
Zidong Jiang 2017-05-20 11:00:19 +08:00 committed by GitHub
parent c6d890ee13
commit 5e28bfc28a
16 changed files with 319 additions and 21 deletions

View File

@ -94,6 +94,24 @@ bool jerry_port_get_time_zone (jerry_time_zone_t *);
double jerry_port_get_current_time (void);
```
## External instance
Allow user to provide external buffer for jerry instance (which includes an isolated context and heap with other instances), so that user can config the heap size in runtime and run multiple JS apps simultaneously.
```c
/**
* Get the current instance, which contains the current context, heap and other infomation.
* Each port should provide its own implementation of this interface.
*
*Note:
* This port function will be called automatically by jerry-core
* wnen JERRY_ENABLE_EXTERNAL_CONTEXT is defined. If not, this function will never be called.
*
* @return the pointer to the jerry instance.
*/
struct jerry_instance_t *jerry_port_get_current_instance (void);
```
# How to port JerryScript
This section describes a basic port implementation which was created for Unix based systems.
@ -181,3 +199,35 @@ double jerry_port_get_current_time (void)
return ((double) tv.tv_sec) * 1000.0 + ((double) tv.tv_usec) / 1000.0;
} /* jerry_port_get_current_time */
```
## External instance
```c
#include "jerryscript-port.h"
#include "jerryscript-port-default.h"
/**
* Pointer to the current instance.
* Note that it is a global variable, and is not a thread safe implementation.
*/
static jerry_instance_t *current_instance_p = NULL;
/**
* Set the current_instance_p as the passed pointer.
*/
void
jerry_port_default_set_instance (jerry_instance_t *instance_p) /**< points to the created instance */
{
current_instance_p = instance_p;
} /* jerry_port_default_set_instance */
/**
* Get the current instance.
*
* @return the pointer to the current instance
*/
jerry_instance_t *
jerry_port_get_current_instance (void)
{
return current_instance_p;
} /* jerry_port_get_current_instance */
```

View File

@ -21,6 +21,7 @@ set(FEATURE_CPOINTER_32_BIT OFF CACHE BOOL "Enable 32 bit compressed poin
set(FEATURE_DEBUGGER OFF CACHE BOOL "Enable JerryScript debugger?")
set(FEATURE_DEBUGGER_PORT "5001" CACHE STRING "Set debugger port number (default: 5001)")
set(FEATURE_ERROR_MESSAGES OFF CACHE BOOL "Enable error messages?")
set(FEATURE_EXTERNAL_CONTEXT OFF CACHE BOOL "Enable external context?")
set(FEATURE_JS_PARSER ON CACHE BOOL "Enable js-parser?")
set(FEATURE_MEM_STATS OFF CACHE BOOL "Enable memory statistics?")
set(FEATURE_MEM_STRESS_TEST OFF CACHE BOOL "Enable mem-stress test?")
@ -44,6 +45,7 @@ message(STATUS "FEATURE_CPOINTER_32_BIT " ${FEATURE_CPOINTER_32_BIT})
message(STATUS "FEATURE_DEBUGGER " ${FEATURE_DEBUGGER})
message(STATUS "FEATURE_DEBUGGER_PORT " ${FEATURE_DEBUGGER_PORT})
message(STATUS "FEATURE_ERROR_MESSAGES " ${FEATURE_ERROR_MESSAGES})
message(STATUS "FEATURE_EXTERNAL_CONTEXT " ${FEATURE_EXTERNAL_CONTEXT})
message(STATUS "FEATURE_JS_PARSER " ${FEATURE_JS_PARSER})
message(STATUS "FEATURE_MEM_STATS " ${FEATURE_MEM_STATS})
message(STATUS "FEATURE_MEM_STRESS_TEST " ${FEATURE_MEM_STRESS_TEST})
@ -154,6 +156,11 @@ if(FEATURE_ERROR_MESSAGES)
set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_ENABLE_ERROR_MESSAGES)
endif()
# Use external context instead of static one
if(FEATURE_EXTERNAL_CONTEXT)
set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_ENABLE_EXTERNAL_CONTEXT)
endif()
# JS-Parser
if(FEATURE_JS_PARSER)
set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_JS_PARSER=1)
@ -210,6 +217,10 @@ if(JERRY_LIBC AND FEATURE_DEBUGGER)
MESSAGE(FATAL_ERROR "This configuration is not supported. Please build against your system libc to enable the JerryScript debugger.")
endif()
if(JERRY_LIBC AND FEATURE_SYSTEM_ALLOCATOR)
MESSAGE(FATAL_ERROR "This configuration is not supported. Please build against your system libc to enable the system allocator.")
endif()
# RegExp byte-code dumps
if(FEATURE_REGEXP_DUMP)
set(DEFINES_JERRY ${DEFINES_JERRY} REGEXP_DUMP_BYTE_CODE)

View File

@ -2248,6 +2248,64 @@ jerry_is_valid_cesu8_string (const jerry_char_t *cesu8_buf_p, /**< CESU-8 string
(lit_utf8_size_t) buf_size);
} /* jerry_is_valid_cesu8_string */
/*
* Create a jerry instance for external context.
*
* @return the pointer to the instance.
*/
jerry_instance_t *
jerry_create_instance (uint32_t heap_size, /**< the size of heap */
jerry_instance_alloc_t alloc, /**< the alloc function */
void *cb_data_p) /**< the cb_data for alloc function */
{
#ifdef JERRY_ENABLE_EXTERNAL_CONTEXT
uint32_t lcache_size = 0;
#ifndef CONFIG_ECMA_LCACHE_DISABLE
lcache_size = sizeof (jerry_hash_table_t);
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
uint32_t alloc_size = (uint32_t) (sizeof (jerry_instance_t) + lcache_size);
#ifndef JERRY_SYSTEM_ALLOCATOR
alloc_size = alloc_size + heap_size + JMEM_ALIGNMENT - 1;
#endif /* !JERRY_SYSTEM_ALLOCATOR */
jerry_instance_t *instance_p = (jerry_instance_t *) alloc (alloc_size, cb_data_p);
memset (instance_p, 0, alloc_size);
if (instance_p == NULL)
{
return NULL;
}
instance_p->heap_size = heap_size;
instance_p->lcache_p = instance_p->buffer;
#ifndef JERRY_SYSTEM_ALLOCATOR
uint8_t *unaligned_heap_p = instance_p->lcache_p + lcache_size;
uintptr_t alignment_mask = ~(uintptr_t) (JMEM_ALIGNMENT - 1);
instance_p->heap_p = (uint8_t *) (((uintptr_t) unaligned_heap_p + JMEM_ALIGNMENT - 1) & alignment_mask);
JERRY_ASSERT (((uintptr_t) instance_p->heap_p & (uintptr_t) (JMEM_ALIGNMENT - 1)) == 0);
#endif /* !JERRY_SYSTEM_ALLOCATOR */
return instance_p;
#else /* !JERRY_ENABLE_EXTERNAL_CONTEXT */
JERRY_UNUSED (heap_size);
JERRY_UNUSED (alloc);
JERRY_UNUSED (cb_data_p);
return NULL;
#endif /* JERRY_ENABLE_EXTERNAL_CONTEXT */
} /* jerry_create_instance */
/**
* If JERRY_VM_EXEC_STOP is defined the callback passed to this function is
* periodically called with the user_p argument. If frequency is greater

View File

@ -98,7 +98,7 @@ ecma_lcache_insert (ecma_object_t *object_p, /**< object */
size_t row_index = ecma_lcache_row_index (object_cp, name_hash);
ecma_lcache_hash_entry_t *entries_p = JERRY_HASH_TABLE_CONTEXT (table)[row_index];
int32_t entry_index;
uint32_t entry_index;
for (entry_index = 0; entry_index < ECMA_LCACHE_HASH_ROW_LENGTH; entry_index++)
{
if (entries_p[entry_index].object_cp == ECMA_NULL_POINTER)

View File

@ -205,6 +205,11 @@ typedef void *(*jerry_user_context_init_t) (void);
*/
typedef void (*jerry_user_context_deinit_t) (void *user_context_p);
/**
* Function type for allocating buffer for JerryScript instance.
*/
typedef void *(*jerry_instance_alloc_t) (size_t size, void *cb_data_p);
/**
* Type information of a native pointer.
*/
@ -213,6 +218,11 @@ typedef struct
jerry_object_native_free_callback_t free_cb; /**< the free callback of the native pointer */
} jerry_object_native_info_t;
/**
* A forward declaration of the JerryScript instance structure.
*/
typedef struct jerry_instance_t jerry_instance_t;
/**
* General engine functions.
*/
@ -403,6 +413,11 @@ jerry_value_t jerry_resolve_or_reject_promise (jerry_value_t promise, jerry_valu
bool jerry_is_valid_utf8_string (const jerry_char_t *utf8_buf_p, jerry_size_t buf_size);
bool jerry_is_valid_cesu8_string (const jerry_char_t *cesu8_buf_p, jerry_size_t buf_size);
/*
* External context functions.
*/
jerry_instance_t *jerry_create_instance (uint32_t heap_size, jerry_instance_alloc_t alloc, void *cb_data_p);
/**
* Miscellaneous functions.
*/

View File

@ -126,6 +126,18 @@ bool jerry_port_get_time_zone (jerry_time_zone_t *tz_p);
*/
double jerry_port_get_current_time (void);
/**
* Get the current instance, which contains the current context, heap and other infomation.
* Each port should provide its own implementation of this interface.
*
*Note:
* This port function will be called automatically by jerry-core
* wnen JERRY_ENABLE_EXTERNAL_CONTEXT is defined. If not, this function will never be called.
*
* @return the pointer to the jerry instance.
*/
struct jerry_instance_t *jerry_port_get_current_instance (void);
/**
* @}
*/

View File

@ -19,6 +19,7 @@
* @{
*/
#ifndef JERRY_ENABLE_EXTERNAL_CONTEXT
/**
* Global context.
*/
@ -48,6 +49,7 @@ jmem_heap_t jerry_global_heap __attribute__ ((aligned (JMEM_ALIGNMENT))) JERRY_G
jerry_hash_table_t jerry_global_hash_table;
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
#endif /* !JERRY_ENABLE_EXTERNAL_CONTEXT */
/**
* @}

View File

@ -21,6 +21,7 @@
#include "ecma-builtins.h"
#include "ecma-jobqueue.h"
#include "jerryscript-port.h"
#include "jerry-debugger.h"
#include "jmem.h"
#include "re-bytecode.h"
@ -120,6 +121,84 @@ typedef struct
#endif /* JERRY_VALGRIND_FREYA */
} jerry_context_t;
/**
* Description of jerry instance, which contains the meta data and buffer.
*/
struct jerry_instance_t
{
uint32_t heap_size; /**< size of the heap */
#ifndef JERRY_SYSTEM_ALLOCATOR
uint8_t *heap_p; /**< point to the entrance of the heap in buffer */
#endif /* !JERRY_SYSTEM_ALLOCATOR */
#ifndef CONFIG_ECMA_LCACHE_DISABLE
uint8_t *lcache_p; /**< point to the entrance of the lcache in buffer */
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
jerry_context_t context; /**< the context of the instance */
uint8_t buffer[]; /**< the flexible array for storing context, heap and lcache */
};
#ifndef CONFIG_ECMA_LCACHE_DISABLE
/**
* Hash table for caching the last access of properties.
*/
typedef struct
{
ecma_lcache_hash_entry_t table[ECMA_LCACHE_HASH_ROWS_COUNT][ECMA_LCACHE_HASH_ROW_LENGTH];
} jerry_hash_table_t;
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
#ifdef JERRY_ENABLE_EXTERNAL_CONTEXT
/**
* This part is for Jerry which enable external context.
*/
typedef struct
{
jmem_heap_free_t first; /**< first node in free region list */
uint8_t area[]; /**< heap area */
} jmem_heap_t;
#define JERRY_CONTEXT(field) (jerry_port_get_current_instance ()->context.field)
#ifndef JERRY_SYSTEM_ALLOCATOR
static inline jmem_heap_t * __attr_always_inline___
jerry_context_get_current_heap (void)
{
return (jmem_heap_t *) (jerry_port_get_current_instance ()->heap_p);
} /* jerry_context_get_current_heap */
#define JERRY_HEAP_CONTEXT(field) (jerry_context_get_current_heap ()->field)
#ifdef JMEM_HEAP_SIZE
#error "JMEM_HEAP_SIZE must not be defined if JERRY_ENABLE_EXTERNAL_CONTEXT is defined"
#endif /* JMEM_HEAP_SIZE */
#define JMEM_HEAP_SIZE (jerry_port_get_current_instance ()->heap_size)
#define JMEM_HEAP_AREA_SIZE (jerry_port_get_current_instance ()->heap_size - JMEM_ALIGNMENT)
#endif /* !JERRY_SYSTEM_ALLOCATOR */
#ifndef CONFIG_ECMA_LCACHE_DISABLE
static inline jerry_hash_table_t * __attr_always_inline___
jerry_context_get_current_lcache (void)
{
return (jerry_hash_table_t *) (jerry_port_get_current_instance ()->lcache_p);
} /* jerry_context_get_current_lcache */
#define JERRY_HASH_TABLE_CONTEXT(field) (jerry_context_get_current_lcache ()->field)
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
#else /* !JERRY_ENABLE_EXTERNAL_CONTEXT */
/**
* This part is for Jerry which use default context.
*/
/**
* Calculate heap area size, leaving space for a pointer to the free list
*/
@ -143,21 +222,6 @@ typedef struct
uint8_t area[JMEM_HEAP_AREA_SIZE]; /**< heap area */
} jmem_heap_t;
#ifndef CONFIG_ECMA_LCACHE_DISABLE
/**
* JerryScript global hash table for caching the last access of properties.
*/
typedef struct
{
/**
* Hash table
*/
ecma_lcache_hash_entry_t table[ECMA_LCACHE_HASH_ROWS_COUNT][ECMA_LCACHE_HASH_ROW_LENGTH];
} jerry_hash_table_t;
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
/**
* Global context.
*/
@ -189,6 +253,7 @@ extern jerry_hash_table_t jerry_global_hash_table;
* Provides a reference to the area field of the heap.
*/
#define JERRY_HEAP_CONTEXT(field) (jerry_global_heap.field)
#endif /* !JERRY_SYSTEM_ALLOCATOR */
#ifndef CONFIG_ECMA_LCACHE_DISABLE
@ -200,6 +265,8 @@ extern jerry_hash_table_t jerry_global_hash_table;
#endif /* !CONFIG_ECMA_LCACHE_DISABLE */
#endif /* JERRY_ENABLE_EXTERNAL_CONTEXT */
/**
* @}
*/

View File

@ -103,11 +103,13 @@ jmem_heap_get_region_end (jmem_heap_free_t *curr_p) /**< current region */
} /* jmem_heap_get_region_end */
#endif /* !JERRY_SYSTEM_ALLOCATOR */
#ifndef JERRY_ENABLE_EXTERNAL_CONTEXT
/**
* Check size of heap is corresponding to configuration
*/
JERRY_STATIC_ASSERT (sizeof (jmem_heap_t) <= JMEM_HEAP_SIZE,
size_of_mem_heap_must_be_less_than_or_equal_to_MEM_HEAP_SIZE);
#endif /* !JERRY_ENABLE_EXTERNAL_CONTEXT */
#ifdef JMEM_STATS
@ -148,8 +150,8 @@ void
jmem_heap_init (void)
{
#ifndef JERRY_CPOINTER_32_BIT
JERRY_STATIC_ASSERT (((UINT16_MAX + 1) << JMEM_ALIGNMENT_LOG) >= JMEM_HEAP_SIZE,
maximum_heap_size_for_16_bit_compressed_pointers_is_512K);
/* the maximum heap size for 16bit compressed pointers should be 512K */
JERRY_ASSERT (((UINT16_MAX + 1) << JMEM_ALIGNMENT_LOG) >= JMEM_HEAP_SIZE);
#endif /* !JERRY_CPOINTER_32_BIT */
#ifndef JERRY_SYSTEM_ALLOCATOR
@ -181,7 +183,7 @@ jmem_heap_finalize (void)
{
JERRY_ASSERT (JERRY_CONTEXT (jmem_heap_allocated_size) == 0);
#ifndef JERRY_SYSTEM_ALLOCATOR
VALGRIND_NOACCESS_SPACE (&JERRY_HEAP_CONTEXT (first), sizeof (jmem_heap_t));
VALGRIND_NOACCESS_SPACE (&JERRY_HEAP_CONTEXT (first), JMEM_HEAP_SIZE);
#endif /* !JERRY_SYSTEM_ALLOCATOR */
} /* jmem_heap_finalize */

View File

@ -25,10 +25,12 @@
* @{
*/
#ifndef JERRY_ENABLE_EXTERNAL_CONTEXT
/**
* Size of heap
*/
#define JMEM_HEAP_SIZE ((size_t) (CONFIG_MEM_HEAP_AREA_SIZE))
#endif /* !JERRY_ENABLE_EXTERNAL_CONTEXT */
/**
* Logarithm of required alignment for allocated units/blocks

View File

@ -55,6 +55,10 @@ macro(jerry_create_executable JERRY_NAME)
install(TARGETS ${JERRY_NAME} DESTINATION bin)
endmacro()
if(JERRY_LIBC AND FEATURE_EXTERNAL_CONTEXT)
MESSAGE(FATAL_ERROR "This configuration is not supported for jerry-main. Please build against your system libc to enable the external context.")
endif()
# Jerry standalones
if(JERRY_CMDLINE)
jerry_create_executable("jerry" "main-unix.c" "cli.c")

View File

@ -390,6 +390,20 @@ check_usage (bool condition, /**< the condition that must hold */
}
} /* check_usage */
#ifdef JERRY_ENABLE_EXTERNAL_CONTEXT
/**
* The alloc function passed to jerry_create_instance
*/
static void *
instance_alloc (size_t size,
void *cb_data_p __attribute__((unused)))
{
return malloc (size);
} /* instance_alloc */
#endif /* JERRY_ENABLE_EXTERNAL_CONTEXT */
int
main (int argc,
char **argv)
@ -560,6 +574,13 @@ main (int argc,
is_repl_mode = true;
}
#ifdef JERRY_ENABLE_EXTERNAL_CONTEXT
jerry_instance_t *instance_p = jerry_create_instance (512*1024, instance_alloc, NULL);
jerry_port_default_set_instance (instance_p);
#endif /* JERRY_ENABLE_EXTERNAL_CONTEXT */
jerry_init (flags);
register_js_function ("assert", jerryx_handler_assert);
@ -764,6 +785,8 @@ main (int argc,
}
jerry_release_value (ret_value);
jerry_cleanup ();
#ifdef JERRY_ENABLE_EXTERNAL_CONTEXT
free (instance_p);
#endif /* JERRY_ENABLE_EXTERNAL_CONTEXT */
return ret_code;
} /* main */

View File

@ -0,0 +1,43 @@
/* 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 "jerryscript-port.h"
#include "jerryscript-port-default.h"
/**
* Pointer to the current instance.
* Note that it is a global variable, and is not a thread safe implementation.
*/
static jerry_instance_t *current_instance_p = NULL;
/**
* Set the current_instance_p as the passed pointer.
*/
void
jerry_port_default_set_instance (jerry_instance_t *instance_p) /**< points to the created instance */
{
current_instance_p = instance_p;
} /* jerry_port_default_set_instance */
/**
* Get the current instance.
*
* @return the pointer to the current instance
*/
jerry_instance_t *
jerry_port_get_current_instance (void)
{
return current_instance_p;
} /* jerry_port_get_current_instance */

View File

@ -37,6 +37,8 @@ bool jerry_port_default_is_abort_on_fail (void);
jerry_log_level_t jerry_port_default_get_log_level (void);
void jerry_port_default_set_log_level (jerry_log_level_t level);
void jerry_port_default_set_instance (jerry_instance_t *instance_p);
/**
* @}
*/

View File

@ -64,6 +64,8 @@ def get_arguments():
help='debug build')
parser.add_argument('--error-messages', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
help='enable error messages (%(choices)s; default: %(default)s)')
parser.add_argument('--external-context', metavar='X', choices=['ON', 'OFF'], default='OFF', type=str.upper,
help='enable external context (%(choices)s; default: %(default)s)')
parser.add_argument('-j', '--jobs', metavar='N', action='store', type=int, default=multiprocessing.cpu_count() + 1,
help='Allowed N build jobs at once (default: %(default)s)')
parser.add_argument('--jerry-cmdline', metavar='X', choices=['ON', 'OFF'], default='ON', type=str.upper,
@ -161,6 +163,7 @@ def generate_build_options(arguments):
build_options.append('-DFEATURE_PROFILE=%s' % arguments.profile)
build_options.append('-DFEATURE_DEBUGGER=%s' % arguments.jerry_debugger)
build_options.append('-DFEATURE_DEBUGGER_PORT=%d' % arguments.jerry_debugger_port)
build_options.append('-DFEATURE_EXTERNAL_CONTEXT=%s' % arguments.external_context)
build_options.append('-DFEATURE_SNAPSHOT_EXEC=%s' % arguments.snapshot_exec)
build_options.append('-DFEATURE_SNAPSHOT_SAVE=%s' % arguments.snapshot_save)
build_options.append('-DFEATURE_SYSTEM_ALLOCATOR=%s' % arguments.system_allocator)

View File

@ -61,7 +61,9 @@ JERRY_TESTS_OPTIONS = [
['--debug', '--snapshot-save=on', '--snapshot-exec=on'],
['--snapshot']),
Options('jerry_tests-es2015-subset-debug',
['--debug', '--profile=es2015-subset'])
['--debug', '--profile=es2015-subset']),
Options('jerry_tests-debug-external-context',
['--debug', '--jerry-libc=off', '--external-context=on'])
]
# Test options for jerry-test-suite
@ -120,6 +122,8 @@ JERRY_BUILDOPTIONS = [
['--jerry-libc=off']),
Options('buildoption_test-cpointer_32bit',
['--jerry-libc=off', '--compile-flag=-m32', '--cpointer-32bit=on', '--system-allocator=on']),
Options('buildoption_test-external_context',
['--jerry-libc=off', '--external-context=on']),
]
def get_arguments():