From 67b36030dc028592bb49d52cbddaf2f90ac5beab Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Thu, 28 Dec 2023 17:00:35 +0100 Subject: [PATCH] Berry sync upstream #369 (#20330) --- lib/libesp32/berry/CMakeLists.txt | 38 ++++++++++++++ lib/libesp32/berry/default/berry.c | 81 ++++++++++++++++++++++-------- lib/libesp32/berry/src/be_mem.c | 69 +++++++++++++------------ 3 files changed, 135 insertions(+), 53 deletions(-) create mode 100644 lib/libesp32/berry/CMakeLists.txt diff --git a/lib/libesp32/berry/CMakeLists.txt b/lib/libesp32/berry/CMakeLists.txt new file mode 100644 index 000000000..aba79bf1b --- /dev/null +++ b/lib/libesp32/berry/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.10) + +project(Berry C) +set(CMAKE_C_STANDARD 99) + +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +set(BERRY_COC ${CMAKE_CURRENT_SOURCE_DIR}/tools/coc/coc) +set(BERRY_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) +set(BERRY_CONFIG_DIR default CACHE FILEPATH "The directory of berry_conf.h.") +set(BERRY_CONFIG ${CMAKE_CURRENT_SOURCE_DIR}/${BERRY_CONFIG_DIR}/berry_conf.h) +set(BERRY_GENERATE ${CMAKE_CURRENT_SOURCE_DIR}/generate) + +if (${CMAKE_HOST_WIN32}) + set(BERRY_COC python ${BERRY_COC}) +endif () + +file(MAKE_DIRECTORY generate) + +# berry library +file(GLOB SOURCES src/*.c) +add_library(libberry ${SOURCES}) +target_include_directories(libberry PUBLIC src ${BERRY_CONFIG_DIR}) + +add_custom_target(berry-coc + COMMAND ${BERRY_COC} -o ${BERRY_GENERATE} ${BERRY_SOURCE_DIR} -c ${BERRY_CONFIG} + DEPENDS ${SOURCES} COMMAND_EXPAND_LISTS + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Generate coc objects" +) +add_dependencies(libberry berry-coc) + +# berry default exe +file(GLOB SOURCES_EXE default/*.c) +add_executable(berry ${SOURCES_EXE}) +target_link_libraries(berry PUBLIC libberry) diff --git a/lib/libesp32/berry/default/berry.c b/lib/libesp32/berry/default/berry.c index 8a63d8ea8..4ddf7b6f0 100644 --- a/lib/libesp32/berry/default/berry.c +++ b/lib/libesp32/berry/default/berry.c @@ -59,6 +59,13 @@ FULL_VERSION " (build in " __DATE__ ", " __TIME__ ")\n" \ "[" COMPILER "] on " OS_NAME " (default)\n" \ +#if defined(_WIN32) +#define PATH_SEPARATOR ";" +#else +#define PATH_SEPARATOR ":" +#endif + + /* command help information */ #define help_information \ "Usage: berry [options] [script [args]]\n" \ @@ -66,6 +73,7 @@ " -i enter interactive mode after executing 'file'\n" \ " -l all variables in 'file' are parsed as local\n" \ " -e load 'script' source string and execute\n" \ + " -m custom module search path(s) separated by '" PATH_SEPARATOR "'\n"\ " -c compile script 'file' to bytecode file\n" \ " -o save bytecode to 'file'\n" \ " -g force named globals in VM\n" \ @@ -87,6 +95,7 @@ #define arg_g (1 << 7) #define arg_s (1 << 8) #define arg_err (1 << 9) +#define arg_m (1 << 10) struct arg_opts { int idx; @@ -95,6 +104,7 @@ struct arg_opts { const char *errarg; const char *src; const char *dst; + const char *modulepath; }; /* check if the character is a letter */ @@ -257,6 +267,10 @@ static int parse_arg(struct arg_opts *opt, int argc, char *argv[]) case 'e': args |= arg_e; break; case 'g': args |= arg_g; break; case 's': args |= arg_s; break; + case 'm': + args |= arg_m; + opt->modulepath = opt->optarg; + break; case '?': return args | arg_err; case 'c': args |= arg_c; @@ -286,12 +300,47 @@ static void push_args(bvm *vm, int argc, char *argv[]) be_pop(vm, 1); } +#if defined(_WIN32) +#define BERRY_ROOT "\\Windows\\system32" +static const char *module_paths[] = { + BERRY_ROOT "\\berry\\packages", +}; +#else +#define BERRY_ROOT "/usr/local" +static const char *module_paths[] = { + BERRY_ROOT "/lib/berry/packages", +}; +#endif + +static void berry_paths(bvm * vm) +{ + size_t i; + for (i = 0; i < array_count(module_paths); ++i) { + be_module_path_set(vm, module_paths[i]); + } +} + +static void berry_custom_paths(bvm *vm, const char *modulepath) +{ + const char delim[] = PATH_SEPARATOR; + char *copy = malloc(strlen(modulepath) + 1); + strcpy(copy, modulepath); + char *ptr = strtok(copy, delim); + + while (ptr != NULL) { + be_module_path_set(vm, ptr); + ptr = strtok(NULL, delim); + } + free(copy); +} + /* * command format: berry [options] [script [args]] * command options: * -i: enter interactive mode after executing 'script' * -b: load code from bytecode file * -e: load 'script' source and execute + * -m: specify custom module search path(s) * command format: berry options * command options: * -v: show version information @@ -305,7 +354,7 @@ static int analysis_args(bvm *vm, int argc, char *argv[]) { int args = 0; struct arg_opts opt = { 0 }; - opt.pattern = "vhilegsc?o?"; + opt.pattern = "m?vhilegsc?o?"; args = parse_arg(&opt, argc, argv); argc -= opt.idx; argv += opt.idx; @@ -315,6 +364,16 @@ static int analysis_args(bvm *vm, int argc, char *argv[]) be_pop(vm, 1); return -1; } + + if (args & arg_m) { + berry_custom_paths(vm, opt.modulepath); + args &= ~arg_m; + } + else { + // use default module paths + berry_paths(vm); + } + if (args & arg_g) { comp_set_named_gbl(vm); /* forced named global in VM code */ args &= ~arg_g; /* clear the flag for this option not to interfere with other options */ @@ -339,31 +398,11 @@ static int analysis_args(bvm *vm, int argc, char *argv[]) return load_script(vm, argc, argv, args); } -#if defined(_WIN32) -#define BERRY_ROOT "\\Windows\\system32" -static const char *module_paths[] = { - BERRY_ROOT "\\berry\\packages", -}; -#else -#define BERRY_ROOT "/usr/local" -static const char *module_paths[] = { - BERRY_ROOT "/lib/berry/packages", -}; -#endif - -static void berry_paths(bvm * vm) -{ - size_t i; - for (i = 0; i < array_count(module_paths); ++i) { - be_module_path_set(vm, module_paths[i]); - } -} int main(int argc, char *argv[]) { int res; bvm *vm = be_vm_new(); /* create a virtual machine instance */ - berry_paths(vm); res = analysis_args(vm, argc, argv); be_vm_delete(vm); /* free all objects and vm */ return res; diff --git a/lib/libesp32/berry/src/be_mem.c b/lib/libesp32/berry/src/be_mem.c index 24b75ec18..9d20ca055 100644 --- a/lib/libesp32/berry/src/be_mem.c +++ b/lib/libesp32/berry/src/be_mem.c @@ -26,12 +26,43 @@ #define realloc BE_EXPLICIT_REALLOC #endif -static void* malloc_from_pool(bvm *vm, size_t size); -static void free_from_pool(bvm *vm, void* ptr, size_t old_size); - #define POOL16_SIZE 16 #define POOL32_SIZE 32 +#ifdef _MSC_VER +#include +#pragma intrinsic(_BitScanForward) +#endif + +#if defined(__GNUC__) +#define popcount(v) __builtin_popcount(v) +#define ffs(v) __builtin_ffs(v) +#elif defined(_MSC_VER) +#define popcount(v) __popcnt(v) + +static int ffs(unsigned x) +{ + unsigned long i; + return _BitScanForward(&i, x) ? i : 0; +} +#else +/* https://github.com/hcs0/Hackers-Delight/blob/master/pop.c.txt - count number of 1-bits */ +static int popcount(uint32_t n) +{ + n = (n & 0x55555555u) + ((n >> 1) & 0x55555555u); + n = (n & 0x33333333u) + ((n >> 2) & 0x33333333u); + n = (n & 0x0f0f0f0fu) + ((n >> 4) & 0x0f0f0f0fu); + n = (n & 0x00ff00ffu) + ((n >> 8) & 0x00ff00ffu); + n = (n & 0x0000ffffu) + ((n >>16) & 0x0000ffffu); + return n; +} + +#error "unsupport compiler for ffs()" +#endif + +static void* malloc_from_pool(bvm *vm, size_t size); +static void free_from_pool(bvm *vm, void* ptr, size_t old_size); + BERRY_API void* be_os_malloc(size_t size) { return malloc(size); @@ -66,7 +97,7 @@ BERRY_API void* be_realloc(bvm *vm, void *ptr, size_t old_size, size_t new_size) if (!ptr || (old_size == 0)) { block = malloc_from_pool(vm, new_size); } - + /* Case 2: deallocate */ else if (new_size == 0) { #if BE_USE_PERF_COUNTERS @@ -176,11 +207,7 @@ static void* malloc_from_pool(bvm *vm, size_t size) { /* look for an empty slot */ if (pool16->bitmap != 0x0000) { /* there is a free slot */ -#ifdef __GNUC__ - int bit = __builtin_ffs(pool16->bitmap) - 1; -#else int bit = ffs(pool16->bitmap) - 1; -#endif if (bit >= 0) { /* we found a free slot */ // bitClear(pool16->bitmap, bit); @@ -208,11 +235,7 @@ static void* malloc_from_pool(bvm *vm, size_t size) { /* look for an empty slot */ if (pool32->bitmap != 0x0000) { /* there is a free slot */ -#ifdef __GNUC__ - int bit = __builtin_ffs(pool32->bitmap) - 1; -#else int bit = ffs(pool32->bitmap) - 1; -#endif if (bit >= 0) { /* we found a free slot */ // bitClear(pool32->bitmap, bit); @@ -327,24 +350,6 @@ BERRY_API void be_gc_free_memory_pools(bvm *vm) { vm->gc.pool32 = NULL; } -/* https://github.com/hcs0/Hackers-Delight/blob/master/pop.c.txt - count number of 1-bits */ -static int pop0(uint32_t n) __attribute__((unused)); -static int pop0(uint32_t n) { - n = (n & 0x55555555u) + ((n >> 1) & 0x55555555u); - n = (n & 0x33333333u) + ((n >> 2) & 0x33333333u); - n = (n & 0x0f0f0f0fu) + ((n >> 4) & 0x0f0f0f0fu); - n = (n & 0x00ff00ffu) + ((n >> 8) & 0x00ff00ffu); - n = (n & 0x0000ffffu) + ((n >>16) & 0x0000ffffu); - return n; -} - -#ifdef __GNUC__ - #define count_bits_1(v) __builtin_popcount(v) -#else - #define count_bits_1(v) pop0(v) -#endif - - BERRY_API void be_gc_memory_pools_info(bvm *vm, size_t* slots_used, size_t* slots_allocated) { size_t used = 0; size_t allocated = 0; @@ -352,14 +357,14 @@ BERRY_API void be_gc_memory_pools_info(bvm *vm, size_t* slots_used, size_t* slot gc16_t* pool16 = vm->gc.pool16; while (pool16) { allocated += POOL16_SLOTS; - used += POOL16_SLOTS - count_bits_1(pool16->bitmap); + used += POOL16_SLOTS - popcount(pool16->bitmap); pool16 = pool16->next; } gc32_t* pool32 = vm->gc.pool32; while (pool32) { allocated += POOL32_SLOTS; - used += POOL32_SLOTS - count_bits_1(pool32->bitmap); + used += POOL32_SLOTS - popcount(pool32->bitmap); pool32 = pool32->next; } if (slots_used) { *slots_used = used; }