diff options
Diffstat (limited to 'targets/os/nuttx')
-rw-r--r-- | targets/os/nuttx/.gitignore | 7 | ||||
-rw-r--r-- | targets/os/nuttx/Kconfig | 20 | ||||
-rw-r--r-- | targets/os/nuttx/Make.defs | 17 | ||||
-rw-r--r-- | targets/os/nuttx/Makefile | 71 | ||||
-rw-r--r-- | targets/os/nuttx/Makefile.travis | 65 | ||||
-rw-r--r-- | targets/os/nuttx/README.md | 297 | ||||
-rw-r--r-- | targets/os/nuttx/jerry_main.c | 450 | ||||
-rw-r--r-- | targets/os/nuttx/jerry_module.c | 294 | ||||
-rw-r--r-- | targets/os/nuttx/jerry_port.c | 193 | ||||
-rw-r--r-- | targets/os/nuttx/setjmp.S | 65 | ||||
-rw-r--r-- | targets/os/nuttx/setjmp.h | 25 |
11 files changed, 1504 insertions, 0 deletions
diff --git a/targets/os/nuttx/.gitignore b/targets/os/nuttx/.gitignore new file mode 100644 index 00000000..35849a25 --- /dev/null +++ b/targets/os/nuttx/.gitignore @@ -0,0 +1,7 @@ +# Files generated / copied by the NuttX build +.built +.depend +Make.dep +*.c.obj +*.o +*.a diff --git a/targets/os/nuttx/Kconfig b/targets/os/nuttx/Kconfig new file mode 100644 index 00000000..ddc5fad8 --- /dev/null +++ b/targets/os/nuttx/Kconfig @@ -0,0 +1,20 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config INTERPRETERS_JERRYSCRIPT + bool "Jerryscript JavaScript engine" + default n + +if INTERPRETERS_JERRYSCRIPT + +config INTERPRETERS_JERRYSCRIPT_PRIORITY + int "Jerryscript priority" + default 100 + +config INTERPRETERS_JERRYSCRIPT_STACKSIZE + int "Jerryscript stack size" + default 16384 + +endif # INTERPRETERS_JERRYSCRIPT diff --git a/targets/os/nuttx/Make.defs b/targets/os/nuttx/Make.defs new file mode 100644 index 00000000..8cdbe329 --- /dev/null +++ b/targets/os/nuttx/Make.defs @@ -0,0 +1,17 @@ +# 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. + +ifeq ($(CONFIG_INTERPRETERS_JERRYSCRIPT),y) +CONFIGURED_APPS += $(APPDIR)/interpreters/jerryscript +endif diff --git a/targets/os/nuttx/Makefile b/targets/os/nuttx/Makefile new file mode 100644 index 00000000..f0d46272 --- /dev/null +++ b/targets/os/nuttx/Makefile @@ -0,0 +1,71 @@ +# 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 $(APPDIR)/Make.defs + +# Jerryscript built-in application information. +PROGNAME = jerry +PRIORITY = $(CONFIG_INTERPRETERS_JERRYSCRIPT_PRIORITY) +STACKSIZE = $(CONFIG_INTERPRETERS_JERRYSCRIPT_STACKSIZE) + +# Path to the JerryScript and NuttX projects. If not specified, it is +# supposed that JerryScript is located next to the nuttx folder. +JERRYSCRIPT_ROOT_DIR ?= ../../../../jerryscript +NUTTX_ROOT_DIR ?= $(JERRYSCRIPT_ROOT_DIR)/../nuttx + +CFLAGS += -std=c99 +CFLAGS += -I$(JERRYSCRIPT_ROOT_DIR)/jerry-core/include +CFLAGS += -I$(JERRYSCRIPT_ROOT_DIR)/jerry-ext/include +CFLAGS += -I$(JERRYSCRIPT_ROOT_DIR)/jerry-math/include + +# These libs should be copied from the JerryScript project. +LIBS = libjerry-core.a libjerry-ext.a libjerry-math.a + +ASRCS = setjmp.S +CSRCS = jerry_port.c jerry_module.c +MAINSRC = jerry_main.c + +.PHONY: copylibs +copylibs: + cp $(JERRYSCRIPT_ROOT_DIR)/build/lib/lib*.a . + +$(LIBS): copylibs + $(firstword $(AR)) x $@ + +.PHONY: updateobjs +updateobjs: + $(eval OBJS += $(shell find . -name "*.obj")) + +.PHONY: cleanlibs +cleanlibs: updateobjs + rm -f $(OBJS) + +.PHONY: libjerry +libjerry: + $(JERRYSCRIPT_ROOT_DIR)/tools/build.py \ + --clean \ + --lto=OFF \ + --jerry-cmdline=OFF \ + --jerry-math=ON \ + --amalgam=ON \ + --mem-heap=70 \ + --profile=es.next \ + --compile-flag="--sysroot=${NUTTX_ROOT_DIR}" \ + --toolchain=$(abspath $(JERRYSCRIPT_ROOT_DIR)/cmake/toolchain_mcu_stm32f4.cmake) + +clean:: cleanlibs + +archive: libjerry $(LIBS) updateobjs + +include $(APPDIR)/Application.mk diff --git a/targets/os/nuttx/Makefile.travis b/targets/os/nuttx/Makefile.travis new file mode 100644 index 00000000..aaa9e61e --- /dev/null +++ b/targets/os/nuttx/Makefile.travis @@ -0,0 +1,65 @@ +# 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. + + +# Default target for running the build test outside the Travis CI environment. +all: + $(MAKE) install + $(MAKE) script + + +## Targets for installing build dependencies of the NuttX JerryScript target. + +# Install cross-compiler and tools via apt. +install-apt-get-deps: + sudo apt-get install -q -y gcc-arm-none-eabi gperf + +# Fetch and build kconfig-frontends (kconfig-conf) from nuttx/tools. +LOCAL_INSTALL:=$(CURDIR)/../local/ + +install-kconfig: + git clone https://bitbucket.org/nuttx/tools.git ../tools + mkdir -p $(LOCAL_INSTALL) + # FIXME: 'autoreconf --force --install' is a workaround after + # https://bitbucket.org/nuttx/tools/commits/164450f982b404fdc2b3233db51dc3eaa1f08b7f + cd ../tools/kconfig-frontends && autoreconf --force --install && ./configure --disable-mconf --disable-nconf --disable-gconf --disable-qconf --disable-shared --enable-static --prefix=$(LOCAL_INSTALL) + $(MAKE) -C ../tools/kconfig-frontends + $(MAKE) -C ../tools/kconfig-frontends install + +# Fetch nuttx/{apps,nuttx} repositories. +install-clone-nuttx: + git clone https://github.com/apache/incubator-nuttx-apps.git ../apps -b releases/10.2 + git clone https://github.com/apache/incubator-nuttx.git ../nuttx -b releases/10.2 + +# Perform all the necessary (JerryScript-independent) installation steps. +install-noapt: install-kconfig install-clone-nuttx +install: install-apt-get-deps install-noapt + + +## Targets for building NuttX with JerryScript. + +# Link in the NuttX JerryScript target directory under the NuttX apps tree. +script-add-jerryscript-app: + ln -s ../../jerryscript/targets/os/nuttx ../apps/interpreters/jerryscript + +# Configure USB shell. +script-configure-usbnsh: + cd ../nuttx/tools && PATH=$(LOCAL_INSTALL)/bin:$$PATH ./configure.sh stm32f4discovery:usbnsh + +# Configure and build the firmware (NuttX with JerryScript). +script: script-add-jerryscript-app script-configure-usbnsh + echo 'CONFIG_ARCH_FPU=y' >> ../nuttx/.config + echo 'CONFIG_INTERPRETERS_JERRYSCRIPT=y'>> ../nuttx/.config + PATH=$(LOCAL_INSTALL)/bin:$$PATH $(MAKE) -C ../nuttx olddefconfig + PATH=$(LOCAL_INSTALL)/bin:$$PATH $(MAKE) -C ../nuttx diff --git a/targets/os/nuttx/README.md b/targets/os/nuttx/README.md new file mode 100644 index 00000000..a33be14a --- /dev/null +++ b/targets/os/nuttx/README.md @@ -0,0 +1,297 @@ +### About + +This folder contains files to run JerryScript on +[STM32F4-Discovery board](https://www.st.com/en/evaluation-tools/stm32f4discovery.html) with +[NuttX](https://nuttx.apache.org/). +The document had been validated on Ubuntu 20.04 operating system. + +### How to build + +#### 1. Setup the build environment for STM32F4-Discovery board + +Clone the necessary projects into a `jerry-nuttx` directory. +The latest tested working version of NuttX is 10.2. + +```sh +# Create a base folder for all the projects. +mkdir jerry-nuttx && cd jerry-nuttx + +git clone https://github.com/jerryscript-project/jerryscript.git +git clone https://github.com/apache/incubator-nuttx.git nuttx -b releases/10.2 +git clone https://github.com/apache/incubator-nuttx-apps.git apps -b releases/10.2 +git clone https://bitbucket.org/nuttx/tools.git tools +git clone https://github.com/texane/stlink.git -b v1.5.1-patch +``` + +The following directory structure is created after these commands: + +``` +jerry-nuttx + + jerryscript + | + targets + | + os + | + nuttx + + nuttx + + apps + + tools + + stlink +``` + +#### 2. Install dependencies of the projects + +```sh +# Assuming you are in jerry-nuttx folder. +jerryscript/tools/apt-get-install-deps.sh + +# Toolchain dependencies of NuttX. +sudo apt install gcc-arm-none-eabi binutils-arm-none-eabi + +# Tool dependencies of NuttX. +sudo apt install \ + bison flex gettext texinfo libncurses5-dev libncursesw5-dev \ + gperf automake libtool pkg-config build-essential gperf genromfs \ + libgmp-dev libmpc-dev libmpfr-dev libisl-dev binutils-dev libelf-dev \ + libexpat-dev gcc-multilib g++-multilib picocom u-boot-tools util-linux + +# ST-Link and serial communication dependencies. +sudo apt install libusb-1.0-0-dev minicom +``` + +#### 3. Copy JerryScript's application files to NuttX + +Move JerryScript application files to `apps/interpreters/jerryscript` folder. + +```sh +# Assuming you are in jerry-nuttx folder. +mkdir -p apps/interpreters/jerryscript +cp jerryscript/targets/os/nuttx/* apps/interpreters/jerryscript/ + +# Or more simply: +# ln -s jerryscript/targets/os/nuttx apps/interpreters/jerryscript +``` + +#### 4. Build kconfig-frontend to configure NuttX + +Skip this section if `kconfig-frontends` had alrady been installed by package manager. + +```sh +# Assuming you are in jerry-nuttx folder. +cd tools/kconfig-frontends + +./configure \ + --disable-nconf \ + --disable-gconf \ + --disable-qconf \ + --disable-shared \ + --enable-static \ + --prefix=${PWD}/install + +make +make install +# Add install folder to PATH +PATH=${PWD}/install/bin:$PATH +``` + +#### 5. Configure NuttX + +Configure NuttX for serial communication. A `.config` file contains all the options for the build. + +```sh +# Assuming you are in jerry-nuttx folder. +cd nuttx/tools + +# Configure NuttX to use USB console shell. +./configure.sh stm32f4discovery:usbnsh +``` + +By default, JerryScript is disabled so it is needed to modify the configuration file. It can +be done by using menuconfig (section 5.1) or modifying the `.config` file directly (section 5.2). + +##### 5.1 Enable JerryScript using menuconfig + +```sh +# Assuming you are in jerry-nuttx folder. +# Might be required to run `make menuconfig` twice. +make -C nuttx menuconfig +``` + +* Enable `System Type -> FPU support` +* Enable `Application Configuration -> Interpreters -> JerryScript` + +[Optional] Enabling ROMFS helps to flash JavaScript input files to the device's flash memory. + +* Enable `File systems -> ROMFS file system` +* Enable `Application configuration -> NSH library -> Scripting Support -> Support ROMFS start-up script` + +[Optional] Enabling MMCSD helps to mount sd card on the device. +Note: These options are for the micro-sd card slot of STM32F4-Discovery base-board. + +* Enable `System Type -> STM32 Peripheral Support -> SDIO` +* Enable `RTOS Features -> Work queue support -> High priority (kernel) worker thread` +* Enable `RTOS Features -> RTOS hooks -> Custom board late initialization` +* Enable `Driver Support -> MMC/SD Driver Support` +* Disable `Driver Support -> MMC/SD Driver Support -> MMC/SD write protect pin` +* Disable `Driver Support -> MMC/SD Driver Support -> MMC/SD SPI transfer support` +* Enable `Driver Support -> MMC/SD Driver Support -> MMC/SD SDIO transfer support` +* Enable `File systems -> FAT file system` +* Enable `File systems -> FAT file system -> FAT upper/lower names` +* Enable `File systems -> FAT file system -> FAT long file names` + +##### 5.2 Enable JerryScript without user interaction + +A simpler solution is to append the necessary content to the `.config` configuration file: + +```sh +# Assuming you are in jerry-nuttx folder. +cat >> nuttx/.config << EOL +CONFIG_ARCH_FPU=y +CONFIG_INTERPRETERS_JERRYSCRIPT=y +CONFIG_INTERPRETERS_JERRYSCRIPT_PRIORITY=100 +CONFIG_INTERPRETERS_JERRYSCRIPT_STACKSIZE=16384 +EOL +``` + +[Optional] Enable ROM File System + +```sh +# Assuming you are in jerry-nuttx folder. +cat >> nuttx/.config << EOL +CONFIG_BOARDCTL_ROMDISK=y +CONFIG_FS_ROMFS=y +CONFIG_NSH_ROMFSETC=y +CONFIG_NSH_ROMFSMOUNTPT="/etc" +CONFIG_NSH_INITSCRIPT="init.d/rcS" +CONFIG_NSH_ROMFSDEVNO=0 +CONFIG_NSH_ROMFSSECTSIZE=64 +CONFIG_NSH_DEFAULTROMFS=y +EOL +``` + +[Optional] Enable MMCSD driver and FAT File System + +Note: These options are for the micro-sd card slot of STM32F4-Discovery base-board. + +```sh +# Assuming you are in jerry-nuttx folder. +cat >> nuttx/.config << EOL +CONFIG_STM32_SDIO=y +CONFIG_STM32_SDIO_DMAPRIO=0x00010000 +CONFIG_MMCSD_HAVE_CARDDETECT=y +CONFIG_BOARD_LATE_INITIALIZE=y +CONFIG_BOARD_INITTHREAD_STACKSIZE=2048 +CONFIG_BOARD_INITTHREAD_PRIORITY=240 +CONFIG_SIG_SIGWORK=17 +CONFIG_SCHED_WORKQUEUE=y +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_HPNTHREADS=1 +CONFIG_SCHED_HPWORKPRIORITY=224 +CONFIG_SCHED_HPWORKSTACKSIZE=2048 +CONFIG_BCH=y +CONFIG_ARCH_HAVE_SDIO=y +CONFIG_ARCH_HAVE_SDIOWAIT_WRCOMPLETE=y +CONFIG_ARCH_HAVE_SDIO_PREFLIGHT=y +CONFIG_MMCSD=y +CONFIG_MMCSD_NSLOTS=1 +CONFIG_MMCSD_MMCSUPPORT=y +CONFIG_MMCSD_SDIO=y +CONFIG_FS_FAT=y +CONFIG_FAT_LCNAMES=y +CONFIG_FAT_LFN=y +CONFIG_FAT_MAXFNAME=32 +CONFIG_FAT_LFN_ALIAS_TRAILCHARS=0 +CONFIG_FSUTILS_MKFATFS=y +CONFIG_NSH_MMCSDSLOTNO=0 +EOL +``` + +#### 6. Provide JavaScript files for STM32F4 device + +##### 6.1. Create ROMFS image from a custom folder + +Skip this section if MMCSD is used. Otherwise, generate a C header file from a custom folder. +Try to minimize the size of the folder due to the limited capacity of flash memory. + +```sh +# Assuming you are in jerry-nuttx folder. +mkdir jerry-example +# Let hello.js be a possible JavaScript input for JerryScript. +cp jerryscript/tests/hello.js jerry-example + +# Generate ROMFS image from a custom folder. +genromfs -f romfs_img -d jerry-example + +# Dump image as C header file and override NuttX's default ROMFS file. +xxd -i romfs_img apps/nshlib/nsh_romfsimg.h + +# Add const modifier to place the content to flash memory. +sed -i "s/unsigned/const\ unsigned/g" apps/nshlib/nsh_romfsimg.h +``` + +##### 6.2. Copy files to memory card + +Skip this section if ROMFS is used. Otherwise, copy your files to a FAT32 formatted memory card. + +#### 7. Build NuttX (with JerryScript) + +```sh +# Assuming you are in jerry-nuttx folder. +make -C nuttx +``` + +#### 8. Flash the device + +Connect Mini-USB for charging and flasing the device. + +```sh +# Assuming you are in jerry-nuttx folder. +make -C stlink release + +sudo stlink/build/Release/st-flash write nuttx/nuttx.bin 0x8000000 +``` + +#### 9. Connect to the device + +Connect Micro-USB for serial communication. The device should be visible as `/dev/ttyACM0` on the host. +You can use `minicom` communication program with `115200` baud rate. + +```sh +sudo minicom --device=/dev/ttyACM0 --baud=115200 +``` + +Set `Add Carriage Ret` option in `minicom` by `CTRL-A -> Z -> U` key combinations. +You may have to press `RESET` on the board and press `Enter` key on the console several times to make `nsh` prompt visible. +NuttShell (NSH) prompt looks like as follows: + +``` +NuttShell (NSH) NuttX-10.2.0 +nsh> +``` + +#### 10. Run JerryScript + +##### 10.1 Run `jerry` without input + +``` +NuttShell (NSH) NuttX-10.2.0 +nsh> jerry +No input files, running a hello world demo: +Hello world 5 times from JerryScript +``` + +##### 10.2 Run `jerry` with files from ROMFS + +``` +NuttShell (NSH) NuttX-10.2.0 +nsh> jerry /etc/hello.js +``` + +##### 10.3 Run `jerry` with files from memory card + +After NuttX has initialized, the card reader should be visible as `/dev/mmcsd0` on the device. +Mount it to be JavaScript files reachable. + +``` +NuttShell (NSH) NuttX-10.2.0 +nsh> mount -t vfat /dev/mmcsd0 /mnt +nsh> jerry /mnt/hello.js +``` diff --git a/targets/os/nuttx/jerry_main.c b/targets/os/nuttx/jerry_main.c new file mode 100644 index 00000000..e4cb8392 --- /dev/null +++ b/targets/os/nuttx/jerry_main.c @@ -0,0 +1,450 @@ +/* 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 <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "jerryscript-port.h" +#include "jerryscript.h" + +#include "jerryscript-ext/debugger.h" +#include "jerryscript-ext/handler.h" +#include "setjmp.h" + +/** + * Maximum command line arguments number. + */ +#define JERRY_MAX_COMMAND_LINE_ARGS (16) + +/** + * Standalone Jerry exit codes. + */ +#define JERRY_STANDALONE_EXIT_CODE_OK (0) +#define JERRY_STANDALONE_EXIT_CODE_FAIL (1) + +/** + * Context size of the SYNTAX_ERROR + */ +#define SYNTAX_ERROR_CONTEXT_SIZE 2 + +void set_log_level (jerry_log_level_t level); + +/** + * Print usage and available options + */ +static void +print_help (char *name) +{ + printf ("Usage: %s [OPTION]... [FILE]...\n" + "\n" + "Options:\n" + " --log-level [0-3]\n" + " --mem-stats\n" + " --mem-stats-separate\n" + " --show-opcodes\n" + " --start-debug-server\n" + " --debug-server-port [port]\n" + "\n", + name); +} /* print_help */ + +/** + * Read source code into buffer. + * + * Returned value must be freed with jmem_heap_free_block if it's not NULL. + * @return NULL, if read or allocation has failed + * pointer to the allocated memory block, otherwise + */ +static const uint8_t * +read_file (const char *file_name, /**< source code */ + size_t *out_size_p) /**< [out] number of bytes successfully read from source */ +{ + FILE *file = fopen (file_name, "r"); + if (file == NULL) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: cannot open file: %s\n", file_name); + return NULL; + } + + int fseek_status = fseek (file, 0, SEEK_END); + if (fseek_status != 0) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Failed to seek (error: %d)\n", fseek_status); + fclose (file); + return NULL; + } + + long script_len = ftell (file); + if (script_len < 0) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Failed to get the file size(error %ld)\n", script_len); + fclose (file); + return NULL; + } + + rewind (file); + + uint8_t *buffer = (uint8_t *) malloc (script_len); + + if (buffer == NULL) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Out of memory error\n"); + fclose (file); + return NULL; + } + + size_t bytes_read = fread (buffer, 1u, script_len, file); + + if (!bytes_read || bytes_read != script_len) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to read file: %s\n", file_name); + free ((void *) buffer); + + fclose (file); + return NULL; + } + + fclose (file); + + *out_size_p = bytes_read; + return (const uint8_t *) buffer; +} /* read_file */ + +/** + * Convert string into unsigned integer + * + * @return converted number + */ +static uint32_t +str_to_uint (const char *num_str_p, /**< string to convert */ + char **out_p) /**< [out] end of the number */ +{ + assert (jerry_feature_enabled (JERRY_FEATURE_ERROR_MESSAGES)); + + uint32_t result = 0; + + while (*num_str_p >= '0' && *num_str_p <= '9') + { + result *= 10; + result += (uint32_t) (*num_str_p - '0'); + num_str_p++; + } + + if (out_p != NULL) + { + *out_p = num_str_p; + } + + return result; +} /* str_to_uint */ + +/** + * Print error value + */ +static void +print_unhandled_exception (jerry_value_t error_value) /**< error value */ +{ + assert (jerry_value_is_exception (error_value)); + + error_value = jerry_exception_value (error_value, false); + jerry_value_t err_str_val = jerry_value_to_string (error_value); + jerry_char_t err_str_buf[256]; + + jerry_value_free (error_value); + + jerry_size_t sz = jerry_string_to_buffer (err_str_val, JERRY_ENCODING_UTF8, err_str_buf, sizeof (err_str_buf) - 1); + err_str_buf[sz] = '\0'; + + if (jerry_feature_enabled (JERRY_FEATURE_ERROR_MESSAGES) && jerry_error_type (error_value) == JERRY_ERROR_SYNTAX) + { + jerry_char_t *string_end_p = err_str_buf + sz; + uint32_t err_line = 0; + uint32_t err_col = 0; + char *path_str_p = NULL; + char *path_str_end_p = NULL; + + /* 1. parse column and line information */ + for (jerry_char_t *current_p = err_str_buf; current_p < string_end_p; current_p++) + { + if (*current_p == '[') + { + current_p++; + + if (*current_p == '<') + { + break; + } + + path_str_p = (char *) current_p; + while (current_p < string_end_p && *current_p != ':') + { + current_p++; + } + + path_str_end_p = (char *) current_p++; + + err_line = str_to_uint ((char *) current_p, (char **) ¤t_p); + + current_p++; + + err_col = str_to_uint ((char *) current_p, NULL); + break; + } + } /* for */ + + if (err_line != 0 && err_col != 0) + { + uint32_t curr_line = 1; + + bool is_printing_context = false; + uint32_t pos = 0; + + /* Temporarily modify the error message, so we can use the path. */ + *path_str_end_p = '\0'; + + size_t source_size; + const jerry_char_t *source_p = read_file (path_str_p, &source_size); + + /* Revert the error message. */ + *path_str_end_p = ':'; + + /* 2. seek and print */ + while (source_p[pos] != '\0') + { + if (source_p[pos] == '\n') + { + curr_line++; + } + + if (err_line < SYNTAX_ERROR_CONTEXT_SIZE + || (err_line >= curr_line && (err_line - curr_line) <= SYNTAX_ERROR_CONTEXT_SIZE)) + { + /* context must be printed */ + is_printing_context = true; + } + + if (curr_line > err_line) + { + break; + } + + if (is_printing_context) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "%c", source_p[pos]); + } + + pos++; + } + + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "\n"); + + while (--err_col) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "~"); + } + + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "^\n"); + } + } + + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Script Error: %s\n", err_str_buf); + jerry_value_free (err_str_val); +} /* print_unhandled_exception */ + +/** + * Register a JavaScript function in the global object. + */ +static void +register_js_function (const char *name_p, /**< name of the function */ + jerry_external_handler_t handler_p) /**< function callback */ +{ + jerry_value_t result_val = jerryx_handler_register_global (name_p, handler_p); + + if (jerry_value_is_exception (result_val)) + { + jerry_port_log (JERRY_LOG_LEVEL_WARNING, "Warning: failed to register '%s' method.", name_p); + } + + jerry_value_free (result_val); +} /* register_js_function */ + +/** + * Main program. + * + * @return 0 if success, error code otherwise + */ +#ifdef CONFIG_BUILD_KERNEL +int +main (int argc, FAR char *argv[]) +#else /* !defined(CONFIG_BUILD_KERNEL) */ +int +jerry_main (int argc, char *argv[]) +#endif /* defined(CONFIG_BUILD_KERNEL) */ +{ + if (argc > JERRY_MAX_COMMAND_LINE_ARGS) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, + "Too many command line arguments. Current maximum is %d\n", + JERRY_MAX_COMMAND_LINE_ARGS); + + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + + const char *file_names[JERRY_MAX_COMMAND_LINE_ARGS]; + int i; + int files_counter = 0; + bool start_debug_server = false; + uint16_t debug_port = 5001; + + jerry_init_flag_t flags = JERRY_INIT_EMPTY; + + for (i = 1; i < argc; i++) + { + if (!strcmp ("-h", argv[i]) || !strcmp ("--help", argv[i])) + { + print_help (argv[0]); + return JERRY_STANDALONE_EXIT_CODE_OK; + } + else if (!strcmp ("--mem-stats", argv[i])) + { + flags |= JERRY_INIT_MEM_STATS; + set_log_level (JERRY_LOG_LEVEL_DEBUG); + } + else if (!strcmp ("--show-opcodes", argv[i])) + { + flags |= JERRY_INIT_SHOW_OPCODES | JERRY_INIT_SHOW_REGEXP_OPCODES; + set_log_level (JERRY_LOG_LEVEL_DEBUG); + } + else if (!strcmp ("--log-level", argv[i])) + { + if (++i < argc && strlen (argv[i]) == 1 && argv[i][0] >= '0' && argv[i][0] <= '3') + { + set_log_level (argv[i][0] - '0'); + } + else + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: wrong format or invalid argument\n"); + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + } + else if (!strcmp ("--start-debug-server", argv[i])) + { + start_debug_server = true; + } + else if (!strcmp ("--debug-server-port", argv[i])) + { + if (++i < argc) + { + debug_port = str_to_uint (argv[i], NULL); + } + else + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: wrong format or invalid argument\n"); + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + } + else + { + file_names[files_counter++] = argv[i]; + } + } + + jerry_init (flags); + + if (start_debug_server) + { + jerryx_debugger_after_connect (jerryx_debugger_tcp_create (debug_port) && jerryx_debugger_ws_create ()); + } + + register_js_function ("assert", jerryx_handler_assert); + register_js_function ("gc", jerryx_handler_gc); + register_js_function ("print", jerryx_handler_print); + + jerry_value_t ret_value = jerry_undefined (); + + if (files_counter == 0) + { + printf ("No input files, running a hello world demo:\n"); + const jerry_char_t script[] = "var str = 'Hello World'; print(str + ' from JerryScript')"; + + ret_value = jerry_parse (script, sizeof (script) - 1, NULL); + + if (!jerry_value_is_exception (ret_value)) + { + ret_value = jerry_run (ret_value); + } + } + else + { + for (i = 0; i < files_counter; i++) + { + size_t source_size; + const jerry_char_t *source_p = read_file (file_names[i], &source_size); + + if (source_p == NULL) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Source file load error\n"); + return JERRY_STANDALONE_EXIT_CODE_FAIL; + } + + jerry_parse_options_t parse_options; + parse_options.options = JERRY_PARSE_HAS_SOURCE_NAME; + parse_options.source_name = jerry_string_sz (file_names[i]); + + ret_value = jerry_parse (source_p, source_size, &parse_options); + jerry_value_free (parse_options.source_name); + free ((void *) source_p); + + if (!jerry_value_is_exception (ret_value)) + { + jerry_value_t func_val = ret_value; + ret_value = jerry_run (func_val); + jerry_value_free (func_val); + } + + if (jerry_value_is_exception (ret_value)) + { + print_unhandled_exception (ret_value); + break; + } + + jerry_value_free (ret_value); + ret_value = jerry_undefined (); + } + } + + int ret_code = JERRY_STANDALONE_EXIT_CODE_OK; + + if (jerry_value_is_exception (ret_value)) + { + ret_code = JERRY_STANDALONE_EXIT_CODE_FAIL; + } + + jerry_value_free (ret_value); + + ret_value = jerry_run_jobs (); + + if (jerry_value_is_exception (ret_value)) + { + ret_code = JERRY_STANDALONE_EXIT_CODE_FAIL; + } + + jerry_value_free (ret_value); + jerry_cleanup (); + + return ret_code; +} /* main */ diff --git a/targets/os/nuttx/jerry_module.c b/targets/os/nuttx/jerry_module.c new file mode 100644 index 00000000..39494d16 --- /dev/null +++ b/targets/os/nuttx/jerry_module.c @@ -0,0 +1,294 @@ +/* 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "jerryscript-port.h" +#include "jerryscript.h" + +/** + * Computes the end of the directory part of a path. + * + * @return end of the directory part of a path. + */ +static size_t +jerry_port_get_directory_end (const jerry_char_t *path_p) /**< path */ +{ + const jerry_char_t *end_p = path_p + strlen ((const char *) path_p); + + while (end_p > path_p) + { + if (end_p[-1] == '/') + { + return (size_t) (end_p - path_p); + } + + end_p--; + } + + return 0; +} /* jerry_port_get_directory_end */ + +/** + * Normalize a file path. + * + * @return a newly allocated buffer with the normalized path if the operation is successful, + * NULL otherwise + */ +static jerry_char_t * +jerry_port_normalize_path (const jerry_char_t *in_path_p, /**< path to the referenced module */ + size_t in_path_length, /**< length of the path */ + const jerry_char_t *base_path_p, /**< base path */ + size_t base_path_length) /**< length of the base path */ +{ + char *path_p; + + if (base_path_length > 0) + { + path_p = (char *) malloc (base_path_length + in_path_length + 1); + + if (path_p == NULL) + { + return NULL; + } + + memcpy (path_p, base_path_p, base_path_length); + memcpy (path_p + base_path_length, in_path_p, in_path_length); + path_p[base_path_length + in_path_length] = '\0'; + } + else + { + path_p = (char *) malloc (in_path_length + 1); + + if (path_p == NULL) + { + return NULL; + } + + memcpy (path_p, in_path_p, in_path_length); + path_p[in_path_length] = '\0'; + } + + return (jerry_char_t *) path_p; +} /* jerry_port_normalize_path */ + +/** + * A module descriptor. + */ +typedef struct jerry_port_module_t +{ + struct jerry_port_module_t *next_p; /**< next_module */ + jerry_char_t *path_p; /**< path to the module */ + size_t base_path_length; /**< base path length for relative difference */ + jerry_value_t realm; /**< the realm of the module */ + jerry_value_t module; /**< the module itself */ +} jerry_port_module_t; + +/** + * Native info descriptor for modules. + */ +static const jerry_object_native_info_t jerry_port_module_native_info = { + .free_cb = NULL, +}; + +/** + * Default module manager. + */ +typedef struct +{ + jerry_port_module_t *module_head_p; /**< first module */ +} jerry_port_module_manager_t; + +/** + * Release known modules. + */ +static void +jerry_port_module_free (jerry_port_module_manager_t *manager_p, /**< module manager */ + const jerry_value_t realm) /**< if this argument is object, release only those modules, + * which realm value is equal to this argument. */ +{ + jerry_port_module_t *module_p = manager_p->module_head_p; + + bool release_all = !jerry_value_is_object (realm); + + jerry_port_module_t *prev_p = NULL; + + while (module_p != NULL) + { + jerry_port_module_t *next_p = module_p->next_p; + + if (release_all || module_p->realm == realm) + { + free (module_p->path_p); + jerry_value_free (module_p->realm); + jerry_value_free (module_p->module); + + free (module_p); + + if (prev_p == NULL) + { + manager_p->module_head_p = next_p; + } + else + { + prev_p->next_p = next_p; + } + } + else + { + prev_p = module_p; + } + + module_p = next_p; + } +} /* jerry_port_module_free */ + +/** + * Initialize the default module manager. + */ +static void +jerry_port_module_manager_init (void *user_data_p) +{ + ((jerry_port_module_manager_t *) user_data_p)->module_head_p = NULL; +} /* jerry_port_module_manager_init */ + +/** + * Deinitialize the default module manager. + */ +static void +jerry_port_module_manager_deinit (void *user_data_p) /**< context pointer to deinitialize */ +{ + jerry_value_t undef = jerry_undefined (); + jerry_port_module_free ((jerry_port_module_manager_t *) user_data_p, undef); + jerry_value_free (undef); +} /* jerry_port_module_manager_deinit */ + +/** + * Declare the context data manager for modules. + */ +static const jerry_context_data_manager_t jerry_port_module_manager = { .init_cb = jerry_port_module_manager_init, + .deinit_cb = jerry_port_module_manager_deinit, + .bytes_needed = + sizeof (jerry_port_module_manager_t) }; + +/** + * Default module resolver. + * + * @return a module object if resolving is successful, an error otherwise + */ +jerry_value_t +jerry_port_module_resolve (const jerry_value_t specifier, /**< module specifier string */ + const jerry_value_t referrer, /**< parent module */ + void *user_p) /**< user data */ +{ + (void) user_p; + + const jerry_char_t *base_path_p = NULL; + size_t base_path_length = 0; + jerry_port_module_t *module_p = jerry_object_get_native_ptr (referrer, &jerry_port_module_native_info); + + if (module_p != NULL) + { + base_path_p = module_p->path_p; + base_path_length = module_p->base_path_length; + } + + jerry_size_t in_path_length = jerry_string_size (specifier, JERRY_ENCODING_UTF8); + jerry_char_t *in_path_p = (jerry_char_t *) malloc (in_path_length + 1); + jerry_string_to_buffer (specifier, JERRY_ENCODING_UTF8, in_path_p, in_path_length); + in_path_p[in_path_length] = '\0'; + + jerry_char_t *path_p = jerry_port_normalize_path (in_path_p, in_path_length, base_path_p, base_path_length); + + if (path_p == NULL) + { + return jerry_throw_sz (JERRY_ERROR_COMMON, "Out of memory"); + } + + jerry_value_t realm = jerry_current_realm (); + + jerry_port_module_manager_t *manager_p; + manager_p = (jerry_port_module_manager_t *) jerry_context_data (&jerry_port_module_manager); + + module_p = manager_p->module_head_p; + + while (module_p != NULL) + { + if (module_p->realm == realm && strcmp ((const char *) module_p->path_p, (const char *) path_p) == 0) + { + free (path_p); + free (in_path_p); + jerry_value_free (realm); + return jerry_value_copy (module_p->module); + } + + module_p = module_p->next_p; + } + + size_t source_size; + uint8_t *source_p = jerry_port_read_source ((const char *) path_p, &source_size); + + if (source_p == NULL) + { + free (path_p); + free (in_path_p); + jerry_value_free (realm); + + return jerry_throw_sz (JERRY_ERROR_SYNTAX, "Module file not found"); + } + + jerry_parse_options_t parse_options; + parse_options.options = JERRY_PARSE_MODULE | JERRY_PARSE_HAS_SOURCE_NAME; + parse_options.source_name = jerry_string (in_path_p, in_path_length, JERRY_ENCODING_UTF8); + + jerry_value_t ret_value = jerry_parse (source_p, source_size, &parse_options); + + jerry_value_free (parse_options.source_name); + jerry_port_release_source (source_p); + free (in_path_p); + + if (jerry_value_is_exception (ret_value)) + { + free (path_p); + jerry_value_free (realm); + return ret_value; + } + + module_p = (jerry_port_module_t *) malloc (sizeof (jerry_port_module_t)); + + module_p->next_p = manager_p->module_head_p; + module_p->path_p = path_p; + module_p->base_path_length = jerry_port_get_directory_end (module_p->path_p); + module_p->realm = realm; + module_p->module = jerry_value_copy (ret_value); + + jerry_object_set_native_ptr (ret_value, &jerry_port_module_native_info, module_p); + manager_p->module_head_p = module_p; + + return ret_value; +} /* jerry_port_module_resolve */ + +/** + * Release known modules. + */ +void +jerry_port_module_release (const jerry_value_t realm) /**< if this argument is object, release only those modules, + * which realm value is equal to this argument. */ +{ + jerry_port_module_free ((jerry_port_module_manager_t *) jerry_context_data (&jerry_port_module_manager), realm); +} /* jerry_port_module_release */ diff --git a/targets/os/nuttx/jerry_port.c b/targets/os/nuttx/jerry_port.c new file mode 100644 index 00000000..6814fbad --- /dev/null +++ b/targets/os/nuttx/jerry_port.c @@ -0,0 +1,193 @@ +/* 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 <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "jerryscript.h" +#include "jerryscript-port.h" + +/** + * JerryScript log level + */ +static jerry_log_level_t jerry_log_level = JERRY_LOG_LEVEL_ERROR; + +/** + * Sets log level. + */ +void set_log_level (jerry_log_level_t level) +{ + jerry_log_level = level; +} /* set_log_level */ + +/** + * Aborts the program. + */ +void jerry_port_fatal (jerry_fatal_code_t code) +{ + exit (1); +} /* jerry_port_fatal */ + +/** + * Provide log message implementation for the engine. + */ +void +jerry_port_log (jerry_log_level_t level, /**< log level */ + const char *format, /**< format string */ + ...) /**< parameters */ +{ + if (level <= jerry_log_level) + { + va_list args; + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); + } +} /* jerry_port_log */ + +/** + * Determines the size of the given file. + * @return size of the file + */ +static size_t +jerry_port_get_file_size (FILE *file_p) /**< opened file */ +{ + fseek (file_p, 0, SEEK_END); + long size = ftell (file_p); + fseek (file_p, 0, SEEK_SET); + + return (size_t) size; +} /* jerry_port_get_file_size */ + +/** + * Opens file with the given path and reads its source. + * @return the source of the file + */ +uint8_t * +jerry_port_read_source (const char *file_name_p, /**< file name */ + size_t *out_size_p) /**< [out] read bytes */ +{ + FILE *file_p = fopen (file_name_p, "rb"); + + if (file_p == NULL) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to open file: %s\n", file_name_p); + return NULL; + } + + size_t file_size = jerry_port_get_file_size (file_p); + uint8_t *buffer_p = (uint8_t *) malloc (file_size); + + if (buffer_p == NULL) + { + fclose (file_p); + + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to allocate memory for module"); + return NULL; + } + + size_t bytes_read = fread (buffer_p, 1u, file_size, file_p); + + if (!bytes_read) + { + fclose (file_p); + free (buffer_p); + + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Error: failed to read file: %s\n", file_name_p); + return NULL; + } + + fclose (file_p); + *out_size_p = bytes_read; + + return buffer_p; +} /* jerry_port_read_source */ + +/** + * Release the previously opened file's content. + */ +void +jerry_port_release_source (uint8_t *buffer_p) /**< buffer to free */ +{ + free (buffer_p); +} /* jerry_port_release_source */ + +/** + * Dummy function to get the time zone adjustment. + * + * @return 0 + */ +double +jerry_port_get_local_time_zone_adjustment (double unix_ms, bool is_utc) +{ + /* We live in UTC. */ + return 0; +} /* jerry_port_get_local_time_zone_adjustment */ + +/** + * Dummy function to get the current time. + * + * @return 0 + */ +double +jerry_port_get_current_time (void) +{ + return 0; +} /* jerry_port_get_current_time */ + +/** + * Provide the implementation of jerry_port_print_char. + * Uses 'printf' to print a single character to standard output. + */ +void +jerry_port_print_char (char c) /**< the character to print */ +{ + printf ("%c", c); +} /* jerry_port_print_char */ + +/** + * Provide implementation of jerry_port_sleep. + */ +void jerry_port_sleep (uint32_t sleep_time) /**< milliseconds to sleep */ +{ + usleep ((useconds_t) sleep_time * 1000); +} /* jerry_port_sleep */ + +/** + * Pointer to the current context. + */ +static jerry_context_t *current_context_p = NULL; + +/** + * Set the current_context_p as the passed pointer. + */ +void +jerry_port_default_set_current_context (jerry_context_t *context_p) /**< points to the created context */ +{ + current_context_p = context_p; +} /* jerry_port_default_set_current_context */ + +/** + * Get the current context. + * + * @return the pointer to the current context + */ +jerry_context_t * +jerry_port_get_current_context (void) +{ + return current_context_p; +} /* jerry_port_get_current_context */ diff --git a/targets/os/nuttx/setjmp.S b/targets/os/nuttx/setjmp.S new file mode 100644 index 00000000..783d87c9 --- /dev/null +++ b/targets/os/nuttx/setjmp.S @@ -0,0 +1,65 @@ +/* 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. + */ + +.syntax unified + +.macro func _name +.global \_name +.type \_name, %function +\_name: +.endm +.macro endfunc _name +.size \_name, .-\_name +.endm + +/** + * setjmp (jmp_buf env) + * + * See also: + * longjmp + * + * @return 0 - if returns from direct call, + * nonzero - if returns after longjmp. + */ +func setjmp + stmia r0!, {r4 - r11, lr} + str sp, [r0], #4 + vstm r0, {s16 - s31} + mov r0, #0 + bx lr +endfunc setjmp + +/** + * longjmp (jmp_buf env, int val) + * + * Note: + * if val is not 0, then it would be returned from setjmp, + * otherwise - 0 would be returned. + * + * See also: + * setjmp + */ +func longjmp + ldmia r0!, {r4 - r11, lr} + ldr sp, [r0] + add r0, r0, #4 + vldm r0, {s16 - s31} + mov r0, r1 + cmp r0, #0 + bne 1f + mov r0, #1 + 1: + bx lr +endfunc longjmp diff --git a/targets/os/nuttx/setjmp.h b/targets/os/nuttx/setjmp.h new file mode 100644 index 00000000..aad7f934 --- /dev/null +++ b/targets/os/nuttx/setjmp.h @@ -0,0 +1,25 @@ +/* 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. + */ +#ifndef SETJMP_H +#define SETJMP_H + +#include <stdint.h> + +typedef uint64_t jmp_buf[14]; + +int setjmp (jmp_buf env); +void longjmp (jmp_buf env, int val); + +#endif /* !SETJMP_H */ |