From: Haesik Jun Date: Wed, 25 Apr 2018 09:14:00 +0000 (+0900) Subject: iotjs update 2018.04.24 X-Git-Tag: submit/tizen/20180425.094327^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=59f006b4d9f253b97176f405c9e746daac2844cc;p=platform%2Fupstream%2Fiotjs.git iotjs update 2018.04.24 github commitid: 58bc52f7f004ebf43357ae18d93f24c01e537f13 Change-Id: I45594dd36aa62d807a4e5720cfb5b3a5b62e7a60 Signed-off-by: Haesik, Jun --- diff --git a/.eslintrc.js b/.eslintrc.js index d7316c3..a4a114e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -25,6 +25,7 @@ var es6 = { var eslintRecommended = { 'no-console': 0, 'no-empty': 0, // TODO: remove this feature + 'no-constant-condition': [2, { 'checkLoops': false }] } var style = { @@ -62,7 +63,7 @@ var syntax = { 'no-caller': 2, 'no-extend-native': 2, 'no-new-wrappers': 2, - 'new-cap': 2, + 'new-cap': [2, { 'capIsNew': false, 'newIsCapExceptions': ['native'] }], 'no-array-constructor': 2, 'no-new-object': 2, 'semi': 2, @@ -74,6 +75,9 @@ module.exports = { 'node': true, 'es6': false, }, + 'globals': { + 'native': true, + }, 'rules': Object.assign( eslintRecommended, style, diff --git a/.gitignore b/.gitignore index 8e9b258..97cf8e6 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ cscope.* # Dependency directories node_modules/ +iotjs_modules/ # Coverage directory used by tools like istanbul coverage diff --git a/.travis.yml b/.travis.yml index 2929e6a..8353bff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,11 +8,12 @@ services: - docker before_install: - - if [[ "$RUN_DOCKER" == "yes" ]]; then docker pull iotjs/ubuntu:0.3; fi + - if [[ "$RUN_DOCKER" == "yes" ]]; then docker pull iotjs/ubuntu:0.6; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then tools/brew-install-deps.sh; fi - if [[ "$OPTS" == "misc" ]]; then tools/apt-get-install-deps.sh; fi install: + pip install --user jsonmerge script: tools/travis_script.py @@ -25,14 +26,17 @@ env: - OPTS="rpi2" RUN_DOCKER=yes - OPTS="stm32f4dis" RUN_DOCKER=yes - OPTS="artik053" RUN_DOCKER=yes + - OPTS="tizen" RUN_DOCKER=yes + - OPTS="es2015" RUN_DOCKER=yes - OPTS="external-modules" RUN_DOCKER=yes - OPTS="no-snapshot" RUN_DOCKER=yes - - OPTS="misc" + - OPTS="misc" RUN_DOCKER=yes matrix: include: - os: osx env: OPTS="host-darwin" + install: pip2 install --user jsonmerge - compiler: gcc-4.9 before_install: tools/apt-get-install-travis-i686.sh addons: diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f21a1f..acf9c19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,10 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") iotjs_add_compile_flags(-DDEBUG -DENABLE_DEBUG_LOG) endif() +if(EXPERIMENTAL) + iotjs_add_compile_flags(-DEXPERIMENTAL) +endif() + # Add arch-dependant flags if("${TARGET_ARCH}" STREQUAL "arm") iotjs_add_compile_flags(-D__arm__ -mthumb -fno-short-enums -mlittle-endian) @@ -79,6 +83,16 @@ elseif("${TARGET_ARCH}" STREQUAL "i686") iotjs_add_compile_flags(-D__i686__ -D__x86__ -march=i686 -m32) elseif("${TARGET_ARCH}" STREQUAL "x86_64") iotjs_add_compile_flags(-D__x86_64__) +elseif("${TARGET_ARCH}" STREQUAL "mips") + message("MIPS support is experimental!") + if(NOT EXPERIMENTAL) + message(FATAL_ERROR "Missing --experimental build option for MIPS!") + endif() + + if(ENABLE_SNAPSHOT) + message(FATAL_ERROR "Cross endian snapshots are not supported. " + "Please disable snapshot mode for mips!") + endif() elseif("${TARGET_ARCH}" STREQUAL "noarch") else() message(WARNING "Unknown target arch: ${TARGET_ARCH}.") @@ -106,19 +120,27 @@ endif() if("${TARGET_OS}" STREQUAL "darwin") iotjs_add_compile_flags(-D__DARWIN__ -fno-builtin) elseif("${TARGET_OS}" STREQUAL "linux") - iotjs_add_compile_flags(-D__LINUX__ -fno-builtin) + iotjs_add_compile_flags(-D__LINUX__ -fno-builtin -rdynamic) iotjs_add_link_flags(-pthread) iotjs_add_flags(EXTERNAL_LIBS m rt) elseif("${TARGET_OS}" STREQUAL "nuttx") iotjs_add_compile_flags(-D__NUTTX__ -Os -fno-strict-aliasing) iotjs_add_compile_flags(-fno-strength-reduce -fomit-frame-pointer) elseif("${TARGET_OS}" STREQUAL "tizen") - iotjs_add_compile_flags(-D__LINUX__ -fno-builtin) + iotjs_add_compile_flags(-D__TIZEN__ -fno-builtin -rdynamic) iotjs_add_link_flags(-pthread) iotjs_add_flags(EXTERNAL_LIBS m rt) elseif("${TARGET_OS}" STREQUAL "tizenrt") iotjs_add_compile_flags(-D__TIZENRT__ -Os -fno-strict-aliasing) iotjs_add_compile_flags(-fno-strength-reduce -fomit-frame-pointer) +elseif("${TARGET_OS}" STREQUAL "openwrt") + message("OpenWrt support is experimental!") + if(NOT EXPERIMENTAL) + message(FATAL_ERROR "Missing --experimental build option for OpenWrt!") + endif() + + iotjs_add_compile_flags(-D__OPENWRT__ -D_GNU_SOURCE) + iotjs_add_link_flags(-pthread) else() message(WARNING "Unknown target os: ${TARGET_OS}.") endif() @@ -143,6 +165,5 @@ include(ExternalProject) include(cmake/jerry.cmake) include(cmake/http-parser.cmake) include(cmake/libtuv.cmake) -include(cmake/mbedtls.cmake) include(cmake/iotjs.cmake) diff --git a/README.md b/README.md index 9d7e299..7b4f7bd 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,14 @@ You can find project details on our [project page](http://samsung.github.io/iotjs/) and [wiki](https://github.com/Samsung/iotjs/wiki). -Memory usage and Binary footprint are measured at [here](https://samsung.github.io/js-remote-test) with real target daily. +Memory usage and Binary footprint are measured at [here](https://samsung.github.io/iotjs-test-results) with real target daily. The following table shows the latest results on the devices: -| Artik053 | [![Remote Testrunner](https://samsung.github.io/js-remote-test/status/artik053.svg)](https://samsung.github.io/js-remote-test/?view=artik053) | +| Artik053 | [![Remote Testrunner](https://firebasestorage.googleapis.com/v0/b/remote-testrunner.appspot.com/o/status%2Fiotjs%2Fartik053.svg?alt=media&token=1)](https://samsung.github.io/iotjs-test-results/?view=artik053) | | :---: | :---: | -| **Raspberry Pi 2** | [![Remote Testrunner](https://samsung.github.io/js-remote-test/status/rpi2.svg)](https://samsung.github.io/js-remote-test/?view=rpi2) | -| **STM32F4-Discovery** | [![Remote Testrunner](https://samsung.github.io/js-remote-test/status/stm32f4dis.svg)](https://samsung.github.io/js-remote-test/?view=stm32) | +| **Raspberry Pi 2** | [![Remote Testrunner](https://firebasestorage.googleapis.com/v0/b/remote-testrunner.appspot.com/o/status%2Fiotjs%2Frpi2.svg?alt=media&token=1)](https://samsung.github.io/iotjs-test-results/?view=rpi2) | +| **STM32F4-Discovery** | [![Remote Testrunner](https://firebasestorage.googleapis.com/v0/b/remote-testrunner.appspot.com/o/status%2Fiotjs%2Fstm32f4dis.svg?alt=media&token=1)](https://samsung.github.io/iotjs-test-results/?view=stm32f4dis) | IRC channel: #iotjs on [freenode](https://freenode.net) @@ -37,7 +37,7 @@ tools/build.py ### How to Test ```bash -build/x86_64-linux/debug/bin/iotjs tools/check_test.js +tools/testrunner.py build/x86_64-linux/debug/bin/iotjs ``` diff --git a/cmake/config/mips-openwrt.cmake b/cmake/config/mips-openwrt.cmake new file mode 100644 index 0000000..c61a347 --- /dev/null +++ b/cmake/config/mips-openwrt.cmake @@ -0,0 +1,20 @@ +# Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors +# +# 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. + +set(CMAKE_SYSTEM_NAME Openwrt) +set(CMAKE_SYSTEM_PROCESSOR mips) + +set(CMAKE_C_COMPILER mips-openwrt-linux-gcc) +set(CMAKE_C_COMPILER_WORKS TRUE) + diff --git a/cmake/iotjs.cmake b/cmake/iotjs.cmake index 5286573..0dcaf0b 100644 --- a/cmake/iotjs.cmake +++ b/cmake/iotjs.cmake @@ -46,12 +46,14 @@ function(addModuleDependencies module varResult) string(TOUPPER ${module} MODULE) set(moduleDefines) - if(NOT "${${IOTJS_MODULE_${MODULE}_JSON}.modules.${module}.require}" + set(MODULE_PREFIX ${IOTJS_MODULE_${MODULE}_JSON}.modules.${module}) + + if(NOT "${${MODULE_PREFIX}.require}" STREQUAL "") foreach(idx - ${${IOTJS_MODULE_${MODULE}_JSON}.modules.${module}.require}) + ${${MODULE_PREFIX}.require}) set(dependency - ${${IOTJS_MODULE_${MODULE}_JSON}.modules.${module}.require_${idx}}) + ${${MODULE_PREFIX}.require_${idx}}) string(TOUPPER ${dependency} DEPENDENCY) if(NOT ${ENABLE_MODULE_${DEPENDENCY}}) list(APPEND moduleDefines ENABLE_MODULE_${DEPENDENCY}) @@ -62,6 +64,18 @@ function(addModuleDependencies module varResult) endforeach() endif() + set(PLATFORM_REQUIRE_PREFIX ${MODULE_PREFIX}.platforms.${IOTJS_SYSTEM_OS}) + foreach(idx ${${PLATFORM_REQUIRE_PREFIX}.require}) + set(dependency ${${PLATFORM_REQUIRE_PREFIX}.require_${idx}}) + string(TOUPPER ${dependency} DEPENDENCY) + if (NOT ${ENABLE_MODULE_${DEPENDENCY}}) + list(APPEND moduleDefines ENABLE_MODULE_${DEPENDENCY}) + addModuleDependencies(${dependency} deps) + list(APPEND varResult ${deps}) + list(REMOVE_DUPLICATES varResult) + endif() + endforeach() + set(${varResult} ${moduleDefines} PARENT_SCOPE) endfunction() @@ -158,6 +172,8 @@ foreach(MODULE ${IOTJS_ENABLED_MODULES}) endif() endforeach() +set(EXTRA_CMAKE_FILES) + # Collect the files of enabled modules foreach(MODULE ${IOTJS_ENABLED_MODULES}) if(${ENABLE_MODULE_${MODULE}}) @@ -178,6 +194,18 @@ foreach(MODULE ${IOTJS_ENABLED_MODULES}) endif() endif() + # Check extra cmake file + set(EXTRA_CMAKE_FILE ${${MODULE_PREFIX}cmakefile}) + if(NOT "${EXTRA_CMAKE_FILE}" STREQUAL "") + set(EXTRA_CMAKE_FILE_PATH "${MODULE_BASE_DIR}/${EXTRA_CMAKE_FILE}") + if(EXISTS "${EXTRA_CMAKE_FILE_PATH}") + list(APPEND EXTRA_CMAKE_FILES "${EXTRA_CMAKE_FILE_PATH}") + else() + message(FATAL_ERROR + "CMake file doesn't exists: ${EXTRA_CMAKE_FILE_PATH}") + endif() + endif() + # Add platform-related native source if(NOT "${${MODULE_PREFIX}native_files}" STREQUAL "" AND NOT "${${MODULE_PREFIX}init}" STREQUAL "") @@ -348,6 +376,33 @@ add_custom_command( ${IOTJS_JS_MODULE_SRC} ) +# Load all external module cmake files +foreach(MODULE_EXTRA_CMAKE_FILE ${EXTRA_CMAKE_FILES}) + message("Using CMake file: ${MODULE_EXTRA_CMAKE_FILE}") + + set(MODULE_BINARY_DIR ${CMAKE_BINARY_DIR}/external/) + set(MODULE_LIBS) + get_filename_component(MODULE_DIR ${MODULE_EXTRA_CMAKE_FILE} DIRECTORY) + + # Variables which should be used by the external module(s): + # - MODULE_DIR - the modules root directory + # - MODULE_BINARY_DIR - the build directory for the current module + # - MODULE_LIBS - list of libraries to use during linking (set this) + include(${MODULE_EXTRA_CMAKE_FILE}) + + if (NOT MODULE_NAME) + message(FATAL_ERROR + "MODULE_NAME was not specified in ${MODULE_EXTRA_CMAKE_FILE}") + endif() + + list(APPEND EXTERNAL_LIBS ${MODULE_LIBS}) + + # Just to make sure it will always be unset + unset(MODULE_NAME) # This is usually set by the included cmake file + unset(MODULE_BINARY_DIR) + unset(MODULE_LIBS) +endforeach() + # Collect all sources into LIB_IOTJS_SRC file(GLOB LIB_IOTJS_SRC ${IOTJS_SOURCE_DIR}/*.c) list(APPEND LIB_IOTJS_SRC @@ -444,4 +499,6 @@ if(NOT BUILD_LIB_ONLY) target_include_directories(${TARGET_IOTJS} PRIVATE ${IOTJS_INCLUDE_DIRS}) target_link_libraries(${TARGET_IOTJS} ${TARGET_LIB_IOTJS}) install(TARGETS ${TARGET_IOTJS} DESTINATION ${BIN_INSTALL_DIR}) + + add_subdirectory(test) endif() diff --git a/cmake/jerry.cmake b/cmake/jerry.cmake index 4ade9ea..598036a 100644 --- a/cmake/jerry.cmake +++ b/cmake/jerry.cmake @@ -70,7 +70,7 @@ if("${TARGET_OS}" MATCHES "TIZENRT|NUTTX") -DEXTERNAL_LIBC_INTERFACE=${EXTERNAL_LIBC_INTERFACE} -DEXTERNAL_CMAKE_SYSTEM_PROCESSOR=${EXTERNAL_CMAKE_SYSTEM_PROCESSOR} ) -elseif("${TARGET_OS}" MATCHES "LINUX|TIZEN|DARWIN") +elseif("${TARGET_OS}" MATCHES "LINUX|TIZEN|DARWIN|OPENWRT") list(APPEND JERRY_LIBS m) list(APPEND DEPS_LIB_JERRY_ARGS -DJERRY_LIBC=OFF @@ -123,6 +123,7 @@ ExternalProject_Add(libjerry -DFEATURE_SNAPSHOT_EXEC=${ENABLE_SNAPSHOT} -DFEATURE_SNAPSHOT_SAVE=OFF -DFEATURE_PROFILE=${FEATURE_PROFILE} + -DFEATURE_LINE_INFO=${FEATURE_JS_BACKTRACE} -DFEATURE_VM_EXEC_STOP=ON -DENABLE_LTO=${ENABLE_LTO} ${DEPS_LIB_JERRY_ARGS} @@ -169,4 +170,4 @@ if(NOT "${TARGET_OS}" MATCHES "NUTTX") set(JERRY_PORT_DIR ${DEPS_LIB_JERRY_SRC}/jerry-port/default) endif() -set(JERRY_INCLUDE_DIR ${DEPS_LIB_JERRY}/jerry-core/include) +set(JERRY_INCLUDE_DIR ${DEPS_LIB_JERRY_SRC}/jerry-core/include) diff --git a/cmake/mbedtls.cmake b/cmake/mbedtls.cmake index 3834ce2..212f6e0 100644 --- a/cmake/mbedtls.cmake +++ b/cmake/mbedtls.cmake @@ -14,17 +14,25 @@ cmake_minimum_required(VERSION 2.8) -if(NOT EXPERIMENTAL_BUILD_MBEDTLS) - return() -endif() - -if(NOT "${TARGET_BOARD}" STREQUAL "None") - return() -endif() - set(DEPS_MBEDTLS deps/mbedtls) set(DEPS_MBEDTLS_SRC ${ROOT_DIR}/${DEPS_MBEDTLS}) set(DEPS_MBEDTLS_BUILD_DIR ${CMAKE_BINARY_DIR}/${DEPS_MBEDTLS}/library) +set(MODULE_NAME "tls") +set(MODULE_BINARY_DIR ${DEPS_MBEDTLS_BUILD_DIR}) + +if("${TARGET_OS}" STREQUAL "TIZEN") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-cpp") +endif() +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-sign-conversion") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${ROOT_DIR}/config/mbedtls") +set(CMAKE_C_FLAGS + "${CMAKE_C_FLAGS} -DMBEDTLS_CONFIG_FILE=''") + +# FIXME: +# Remove this workaround when the related bug is fixed in +# mbedtls. https://github.com/ARMmbed/mbedtls/issues/1550 +set(CMAKE_C_FLAGS_BCK "${CMAKE_C_FLAGS}") +string(REPLACE "-fsanitize=address" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) ExternalProject_Add(mbedtls PREFIX ${DEPS_MBEDTLS} @@ -73,3 +81,8 @@ set_property(DIRECTORY APPEND PROPERTY set(MBEDTLS_LIBS libmbedtls libmbedx509 libmbedcrypto) set(MBEDTLS_INCLUDE_DIR ${DEPS_MBEDTLS}/include) + +# FIXME: +# Remove this workaround when the related bug is fixed in +# mbedtls. https://github.com/ARMmbed/mbedtls/issues/1550 +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_BCK}") diff --git a/config/mbedtls/config-for-iotjs.h b/config/mbedtls/config-for-iotjs.h new file mode 100644 index 0000000..6581586 --- /dev/null +++ b/config/mbedtls/config-for-iotjs.h @@ -0,0 +1,776 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ +/* + * Minimal configuration for TLS 1.1 (RFC 4346) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CONFIG_H +#define MBEDTLS_CONFIG_H + +/** + * \name SECTION: System support + * + * This section sets system specific settings. + * \{ + */ + +/** + * \def MBEDTLS_HAVE_ASM + * + * The compiler has support for asm(). + * + * Requires support for asm() in compiler. + * + * Used in: + * library/timing.c + * library/padlock.c + * include/mbedtls/bn_mul.h + * + * Comment to disable the use of assembly code. + */ +#define MBEDTLS_HAVE_ASM + +/** + * \def MBEDTLS_HAVE_TIME + * + * System has time.h and time(). + * The time does not need to be correct, only time differences are used, + * by contrast with MBEDTLS_HAVE_TIME_DATE + * + * Defining MBEDTLS_HAVE_TIME allows you to specify MBEDTLS_PLATFORM_TIME_ALT, + * MBEDTLS_PLATFORM_TIME_MACRO, MBEDTLS_PLATFORM_TIME_TYPE_MACRO and + * MBEDTLS_PLATFORM_STD_TIME. + * + * Comment if your system does not support time functions + */ +#define MBEDTLS_HAVE_TIME + +/** + * \def MBEDTLS_AES_ROM_TABLES + * + * Store the AES tables in ROM. + * + * Uncomment this macro to store the AES tables in ROM. + */ +#define MBEDTLS_AES_ROM_TABLES + +/** + * \def MBEDTLS_CIPHER_MODE_CBC + * + * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CBC + +/** + * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES + * + * Remove RC4 ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on RC4 from the default list as + * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible to + * enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including them + * explicitly. + * + * Uncomment this macro to remove RC4 ciphersuites by default. + */ +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES + +/** + * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED + * + * MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve + * module. By default all supported curves are enabled. + * + * Comment macros to disable the curve and functions for it + */ +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +#define MBEDTLS_ECP_DP_BP256R1_ENABLED +#define MBEDTLS_ECP_DP_BP384R1_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + * + * Enable the RSA-only based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + * + * Enable the DHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + * + * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + * + * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_ECDSA_C, MBEDTLS_X509_CRT_PARSE_C, + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + * + * Enable the ECDH-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + */ +#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + * + * Enable the ECDH-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + */ +#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + +/** + * \def MBEDTLS_PKCS1_V15 + * + * Enable support for PKCS#1 v1.5 encoding. + * + * Requires: MBEDTLS_RSA_C + * + * This enables support for PKCS#1 v1.5 operations. + */ +#define MBEDTLS_PKCS1_V15 + +/** + * \def MBEDTLS_PKCS1_V21 + * + * Enable support for PKCS#1 v2.1 encoding. + * + * Requires: MBEDTLS_MD_C, MBEDTLS_RSA_C + * + * This enables support for RSAES-OAEP and RSASSA-PSS operations. + */ +#define MBEDTLS_PKCS1_V21 + +/** + * \def MBEDTLS_SHA256_SMALLER + * + * Enable an implementation of SHA-256 that has lower ROM footprint but also + * lower performance. + * + * The default implementation is meant to be a reasonnable compromise between + * performance and size. This version optimizes more aggressively for size at + * the expense of performance. Eg on Cortex-M4 it reduces the size of + * mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about + * 30%. + * + * Uncomment to enable the smaller implementation of SHA256. + */ +#define MBEDTLS_SHA256_SMALLER + +/** + * \def MBEDTLS_SSL_PROTO_TLS1 + * + * Enable support for TLS 1.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.0 + */ +#define MBEDTLS_SSL_PROTO_TLS1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_1 + * + * Enable support for TLS 1.1 (and DTLS 1.0 if DTLS is enabled). + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.1 / DTLS 1.0 + */ +#define MBEDTLS_SSL_PROTO_TLS1_1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_2 + * + * Enable support for TLS 1.2 (and DTLS 1.2 if DTLS is enabled). + * + * Requires: MBEDTLS_SHA1_C or MBEDTLS_SHA256_C or MBEDTLS_SHA512_C + * (Depends on ciphersuites) + * + * Comment this macro to disable support for TLS 1.2 / DTLS 1.2 + */ +#define MBEDTLS_SSL_PROTO_TLS1_2 + +/** + * \def MBEDTLS_SSL_SERVER_NAME_INDICATION + * + * Enable support for RFC 6066 server name indication (SNI) in SSL. + * + * Requires: MBEDTLS_X509_CRT_PARSE_C + * + * Comment this macro to disable support for server name indication in SSL + */ +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +/* \} name SECTION: mbed TLS feature support */ + +/** + * \name SECTION: mbed TLS modules + * + * This section enables or disables entire modules in mbed TLS + * \{ + */ + +/** + * \def MBEDTLS_AES_C + * + * Enable the AES block cipher. + * + * Module: library/aes.c + * Caller: library/ssl_tls.c + * library/pem.c + * library/ctr_drbg.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * + * PEM_PARSE uses AES for decrypting encrypted keys. + */ +#define MBEDTLS_AES_C + +/** + * \def MBEDTLS_ASN1_PARSE_C + * + * Enable the generic ASN1 parser. + * + * Module: library/asn1.c + * Caller: library/x509.c + * library/dhm.c + * library/pkcs12.c + * library/pkcs5.c + * library/pkparse.c + */ +#define MBEDTLS_ASN1_PARSE_C + +/** + * \def MBEDTLS_ASN1_WRITE_C + * + * Enable the generic ASN1 writer. + * + * Module: library/asn1write.c + * Caller: library/ecdsa.c + * library/pkwrite.c + * library/x509_create.c + * library/x509write_crt.c + * library/mbedtls_x509write_csr.c + */ +#define MBEDTLS_ASN1_WRITE_C + +/** + * \def MBEDTLS_BASE64_C + * + * Enable the Base64 module. + * + * Module: library/base64.c + * Caller: library/pem.c + * + * This module is required for PEM support (required by X.509). + */ +#define MBEDTLS_BASE64_C + +/** + * \def MBEDTLS_BIGNUM_C + * + * Enable the multi-precision integer library. + * + * Module: library/bignum.c + * Caller: library/dhm.c + * library/ecp.c + * library/ecdsa.c + * library/rsa.c + * library/ssl_tls.c + * + * This module is required for RSA, DHM and ECC (ECDH, ECDSA) support. + */ +#define MBEDTLS_BIGNUM_C + +/** + * \def MBEDTLS_CIPHER_C + * + * Enable the generic cipher layer. + * + * Module: library/cipher.c + * Caller: library/ssl_tls.c + * + * Uncomment to enable generic cipher wrappers. + */ +#define MBEDTLS_CIPHER_C + +/** + * \def MBEDTLS_CTR_DRBG_C + * + * Enable the CTR_DRBG AES-256-based random generator. + * + * Module: library/ctr_drbg.c + * Caller: + * + * Requires: MBEDTLS_AES_C + * + * This module provides the CTR_DRBG AES-256 random number generator. + */ +#define MBEDTLS_CTR_DRBG_C + +/** + * \def MBEDTLS_DHM_C + * + * Enable the Diffie-Hellman-Merkle module. + * + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * DHE-RSA, DHE-PSK + */ +#define MBEDTLS_DHM_C + +/** + * \def MBEDTLS_ECDH_C + * + * Enable the elliptic curve Diffie-Hellman library. + * + * Module: library/ecdh.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA, ECDHE-RSA, DHE-PSK + * + * Requires: MBEDTLS_ECP_C + */ +#define MBEDTLS_ECDH_C + +/** + * \def MBEDTLS_ECDSA_C + * + * Enable the elliptic curve DSA library. + * + * Module: library/ecdsa.c + * Caller: + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_ASN1_WRITE_C, MBEDTLS_ASN1_PARSE_C + */ +#define MBEDTLS_ECDSA_C + +/** + * \def MBEDTLS_ECP_C + * + * Enable the elliptic curve over GF(p) library. + * + * Module: library/ecp.c + * Caller: library/ecdh.c + * library/ecdsa.c + * library/ecjpake.c + * + * Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED + */ +#define MBEDTLS_ECP_C + +/** + * \def MBEDTLS_ENTROPY_C + * + * Enable the platform-specific entropy code. + * + * Module: library/entropy.c + * Caller: + * + * Requires: MBEDTLS_SHA512_C or MBEDTLS_SHA256_C + * + * This module provides a generic entropy pool + */ +#define MBEDTLS_ENTROPY_C + +/** + * \def MBEDTLS_GCM_C + * + * Enable the Galois/Counter Mode (GCM) for AES. + * + * Module: library/gcm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other + * requisites are enabled as well. + */ +#define MBEDTLS_GCM_C + +/** + * \def MBEDTLS_MD_C + * + * Enable the generic message digest layer. + * + * Module: library/mbedtls_md.c + * Caller: + * + * Uncomment to enable generic message digest wrappers. + */ +#define MBEDTLS_MD_C + +/** + * \def MBEDTLS_MD5_C + * + * Enable the MD5 hash algorithm. + * + * Module: library/mbedtls_md5.c + * Caller: library/mbedtls_md.c + * library/pem.c + * library/ssl_tls.c + * + * This module is required for SSL/TLS and X.509. + * PEM_PARSE uses MD5 for decrypting encrypted keys. + */ +#define MBEDTLS_MD5_C + +/** + * \def MBEDTLS_OID_C + * + * Enable the OID database. + * + * Module: library/oid.c + * Caller: library/asn1write.c + * library/pkcs5.c + * library/pkparse.c + * library/pkwrite.c + * library/rsa.c + * library/x509.c + * library/x509_create.c + * library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * library/x509write_crt.c + * library/mbedtls_x509write_csr.c + * + * This modules translates between OIDs and internal values. + */ +#define MBEDTLS_OID_C + +/** + * \def MBEDTLS_PEM_PARSE_C + * + * Enable PEM decoding / parsing. + * + * Module: library/pem.c + * Caller: library/dhm.c + * library/pkparse.c + * library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for decoding / parsing PEM files. + */ +#define MBEDTLS_PEM_PARSE_C + +/** + * \def MBEDTLS_PK_C + * + * Enable the generic public (asymetric) key layer. + * + * Module: library/pk.c + * Caller: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_RSA_C or MBEDTLS_ECP_C + * + * Uncomment to enable generic public key wrappers. + */ +#define MBEDTLS_PK_C + +/** + * \def MBEDTLS_PK_PARSE_C + * + * Enable the generic public (asymetric) key parser. + * + * Module: library/pkparse.c + * Caller: library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key parse functions. + */ +#define MBEDTLS_PK_PARSE_C + +/** + * \def MBEDTLS_RSA_C + * + * Enable the RSA public-key cryptosystem. + * + * Module: library/rsa.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509.c + * + * This module is used by the following key exchanges: + * RSA, DHE-RSA, ECDHE-RSA, RSA-PSK + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C + */ +#define MBEDTLS_RSA_C + +/** + * \def MBEDTLS_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/mbedtls_sha1.c + * Caller: library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509write_crt.c + * + * This module is required for SSL/TLS and SHA1-signed certificates. + */ +#define MBEDTLS_SHA1_C + +/** + * \def MBEDTLS_SHA256_C + * + * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. + * + * Module: library/mbedtls_sha256.c + * Caller: library/entropy.c + * library/mbedtls_md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module adds support for SHA-224 and SHA-256. + * This module is required for the SSL/TLS 1.2 PRF function. + */ +#define MBEDTLS_SHA256_C + +/** + * \def MBEDTLS_SSL_CLI_C + * + * Enable the SSL/TLS client code. + * + * Module: library/ssl_cli.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS client support. + */ +#define MBEDTLS_SSL_CLI_C + +/** + * \def MBEDTLS_SSL_SRV_C + * + * Enable the SSL/TLS server code. + * + * Module: library/ssl_srv.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS server support. + */ +#define MBEDTLS_SSL_SRV_C + +/** + * \def MBEDTLS_SSL_TLS_C + * + * Enable the generic SSL/TLS code. + * + * Module: library/ssl_tls.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * and at least one of the MBEDTLS_SSL_PROTO_XXX defines + * + * This module is required for SSL/TLS. + */ +#define MBEDTLS_SSL_TLS_C + +/** + * \def MBEDTLS_X509_USE_C + * + * Enable X.509 core for using certificates. + * + * Module: library/x509.c + * Caller: library/mbedtls_x509_crl.c + * library/mbedtls_x509_crt.c + * library/mbedtls_x509_csr.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, + * MBEDTLS_PK_PARSE_C + * + * This module is required for the X.509 parsing modules. + */ +#define MBEDTLS_X509_USE_C + +/** + * \def MBEDTLS_X509_CRT_PARSE_C + * + * Enable X.509 certificate parsing. + * + * Module: library/mbedtls_x509_crt.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 certificate parsing. + */ +#define MBEDTLS_X509_CRT_PARSE_C + +/* \} name SECTION: mbed TLS modules */ + +#endif /* MBEDTLS_CONFIG_H */ diff --git a/config/tizen/.gbs.conf b/config/tizen/.gbs.conf new file mode 100644 index 0000000..27429e2 --- /dev/null +++ b/config/tizen/.gbs.conf @@ -0,0 +1,4 @@ +[general] +upstream_branch = ${upstreamversion} +upstream_tag = ${upstreamversion} +packaging_dir = config/tizen/packaging diff --git a/config/tizen/gbsbuild.sh b/config/tizen/gbsbuild.sh index 2c6a3d6..965f110 100755 --- a/config/tizen/gbsbuild.sh +++ b/config/tizen/gbsbuild.sh @@ -14,50 +14,79 @@ # See the License for the specific language governing permissions and # limitations under the License. -cd .. +function print_usage { + echo "USAGE: $0 [--debug|--clean]" + echo "" + echo "Optional arguments:" + echo "--debug: Build IoT.js in debug mode. The default is release mode." + echo "--clean: Make a clean gbs build by deleting the old build root." + echo "" +} + +buildtype="release" +unset cleanbuild + +while [ -n "$1" ]; do + case $1 in + --debug ) + buildtype="debug" + ;; + --clean ) + cleanbuild=true + ;; + * ) + print_usage + exit 1; + ;; + esac + shift +done echo "******************************************************************" echo "* Tizen GBS build *" echo "* ~/.gbs.conf sample is at 'config/tizen/sample.gbs.conf'. *" echo "******************************************************************" -read -p "[Warning] This working folder will be copied to ../iotjs_tizen_gbs \ -Are you sure to continue? (y/n) " -n 1 -r - echo "" -if [[ $REPLY =~ ^[Yy]$ ]] +echo "This working folder will be copied to ../iotjs_tizen_gbs" + +cd .. +echo copy from $OLDPWD to ../iotjs_tizen_gbs +cp -ra $OLDPWD iotjs_tizen_gbs +cd iotjs_tizen_gbs +echo -e "\n(1) Now, cloning submodules. " +git submodule init +echo -e "\n(2) Update submodules... " +git submodule update + +find ./ -name '.git' | xargs rm -rf +# Initialize Git repositoryㅣ +if [ ! -d .git ] then - echo copy from $OLDPWD to ../iotjs_tizen_gbs - cp -ra $OLDPWD iotjs_tizen_gbs - cd iotjs_tizen_gbs - echo -e "\n(1) Now, cloning submodules. " - git submodule init - echo -e "\n(2) Update submodules... " - git submodule update - - find ./ -name '.git' | xargs rm -rf - # Initialize Git repositoryㅣ - if [ ! -d .git ] - then - git init ./ - git checkout -b tizen_gbs - git add ./ - git commit -m "Initial commit" - fi - - echo -e "\n(3) Calling core gbs build command" - gbsconf="config/tizen/sample.gbs.conf" - gbscommand="gbs -c $gbsconf build -A armv7l --include-all --clean" - echo $gbscommand - if eval $gbscommand - then - echo "========================================================" - echo "1. GBS Build is successful." - echo "2. You can find rpm packages in below folder" - echo " GBS-ROOT/local/repos/tizen_unified_preview1/armv7l/RPMS" - else - echo "GBS Build failed!" - fi + git init ./ + git checkout -b tizen_gbs + git add ./ + git commit -m "Initial commit" +fi + +echo -e "\n(3) Calling core gbs build command" +gbsconf="config/tizen/sample.gbs.conf" +gbscommand="gbs -c $gbsconf build -A armv7l --include-all" +gbscommand+=" ${cleanbuild:+--clean} --define='build_mode $buildtype'" +gbscommand+=" --define='external_build_options $IOTJS_BUILD_OPTION'" + +ret=0 +echo $gbscommand +if eval $gbscommand +then + echo "========================================================" + echo "1. GBS Build is successful." + echo "2. You can find rpm packages in below folder" + echo " GBS-ROOT/local/repos/tizen_unified_rreview2/armv7l/RPMS" +else + echo "GBS Build failed!" + ret=1 +fi cd .. rm -rf iotjs_tizen_gbs cd iotjs -fi +exit $ret diff --git a/config/tizen/packaging/iotjs.pc.in b/config/tizen/packaging/iotjs.pc.in index 4d4ff64..4860237 100644 --- a/config/tizen/packaging/iotjs.pc.in +++ b/config/tizen/packaging/iotjs.pc.in @@ -6,5 +6,5 @@ includedir=@includedir@ Name: iotjs Description: Platform for Internet of Things with JavaScript Version: 1.0.0 -Libs: -Cflags: -I${includedir} +Libs: -L${libdir} -liotjs -lcapi-system-peripheral-io -lpthread -lcurl -ldlog -lappcore-agent +Cflags: -I${includedir}/iotjs diff --git a/config/tizen/packaging/iotjs.spec b/config/tizen/packaging/iotjs.spec index 1f8be93..9b7bede 100644 --- a/config/tizen/packaging/iotjs.spec +++ b/config/tizen/packaging/iotjs.spec @@ -14,13 +14,16 @@ BuildRequires: python BuildRequires: cmake BuildRequires: glibc-static #BuildRequires: aul -#BuildRequires: pkgconfig(appcore-agent) -#BuildRequires: pkgconfig(capi-appfw-service-application) -#BuildRequires: pkgconfig(capi-appfw-app-common) +BuildRequires: pkgconfig(appcore-agent) +BuildRequires: pkgconfig(capi-appfw-service-application) +BuildRequires: pkgconfig(capi-appfw-app-common) #BuildRequires: pkgconfig(capi-appfw-package-manager) -#BuildRequires: pkgconfig(capi-appfw-application) +BuildRequires: pkgconfig(capi-appfw-application) BuildRequires: pkgconfig(capi-system-peripheral-io) BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(capi-appfw-app-control) +BuildRequires: pkgconfig(bundle) #BuildRequires: pkgconfig(st_things_sdkapi) #for https @@ -33,18 +36,9 @@ Requires(post): /sbin/ldconfig %description Platform for Internet of Things with JavaScript -# default is RELEASE mode. -# If DEBUG mode is needed, please use tizen_build_devel_mode -%define RELEASE False -# For Example -%if %{RELEASE} == "True" -%define build_mode release -%else -%define build_mode debug -%endif - -# Default values to be eventually overiden BEFORE or as gbs params: -%{!?RELEASE: %define RELEASE 0} +# Initialize the variables +%{!?build_mode: %define build_mode release} +%{!?external_build_options: %define external_build_options %{nil}} %package service Summary: Development files for %{name} @@ -70,16 +64,37 @@ cat LICENSE cp %{SOURCE1001} . %build -./tools/build.py --clean --buildtype=%{build_mode} --target-arch=noarch \ - --target-os=tizen --target-board=rpi3 \ - --external-lib=capi-system-peripheral-io \ - --compile-flag=-D__TIZEN__ \ - --cmake-param=-DENABLE_MODULE_DGRAM=ON \ - --cmake-param=-DENABLE_MODULE_GPIO=ON \ - --jerry-cmake-param=-DENABLE_STATIC_LINK=OFF \ - --no-init-submodule --no-parallel-build +./tools/build.py \ + --clean \ + --buildtype=%{build_mode} \ + --profile=test/profiles/tizen.profile \ + --target-arch=noarch \ + --target-os=tizen \ + --target-board=rpi3 \ + --external-lib=capi-system-peripheral-io \ + --external-lib=capi-appfw-app-common \ + --external-lib=dlog \ + --external-lib=bundle \ + --external-lib=capi-appfw-app-control \ + --external-include-dir=/usr/include/dlog/ \ + --external-include-dir=/usr/include/appcore-agent/ \ + --external-include-dir=/usr/include/appfw/ \ + --external-include-dir=/usr/include/glib-2.0/ \ + --external-include-dir=/usr/lib/glib-2.0/include/ \ + --compile-flag=-D__TIZEN__ \ + --compile-flag=-fPIC \ + --jerry-cmake-param=-DENABLE_STATIC_LINK=OFF \ + --no-init-submodule \ + --no-parallel-build \ + %{external_build_options} # --external-lib=sdkapi \ +# Create shared library +%define iotjs_target_lib libjerry-core.a libjerry-port-default.a libhttpparser.a libtuv.a \\\ + libmbedx509.a libmbedtls.a libmbedcrypto.a libiotjs.a +%define iotjs_lib_flag -lcapi-system-peripheral-io -lpthread -lcurl -ldlog -lappcore-agent -lcapi-appfw-app-common -lbundle -lcapi-appfw-app-control +cd ./build/noarch-tizen/%{build_mode}/lib/ +gcc -shared -o libiotjs.so -Wl,--whole-archive %{iotjs_target_lib} -Wl,--no-whole-archive %{iotjs_lib_flag} %install mkdir -p %{buildroot}%{_bindir} @@ -89,10 +104,9 @@ mkdir -p %{buildroot}%{_libdir}/pkgconfig cp ./build/noarch-tizen/%{build_mode}/bin/iotjs %{buildroot}%{_bindir}/ -cp ./build/noarch-tizen/%{build_mode}/lib/* %{buildroot}%{_libdir}/iotjs/ +cp ./build/noarch-tizen/%{build_mode}/lib/*.so %{buildroot}%{_libdir}/ -cp ./include/*.h %{buildroot}%{_includedir} -cp ./src/*.h %{buildroot}%{_includedir} +cp ./src/platform/tizen/iotjs_tizen_service_app.h %{buildroot}%{_includedir}/iotjs cp ./config/tizen/packaging/%{name}.pc.in %{buildroot}/%{_libdir}/pkgconfig/%{name}.pc %post -p /sbin/ldconfig @@ -106,7 +120,8 @@ cp ./config/tizen/packaging/%{name}.pc.in %{buildroot}/%{_libdir}/pkgconfig/%{na %{_bindir}/* %files devel +%manifest config/tizen/packaging/%{name}.manifest %defattr(-,root,root,-) -%{_libdir}/iotjs/*.a +%{_libdir}/libiotjs.so %{_libdir}/pkgconfig/%{name}.pc %{_includedir}/* diff --git a/config/tizen/sample.gbs.conf b/config/tizen/sample.gbs.conf index 2e2b9d8..961c381 100644 --- a/config/tizen/sample.gbs.conf +++ b/config/tizen/sample.gbs.conf @@ -1,16 +1,22 @@ [general] -profile = profile.tizen_unified_preview1 +profile = profile.tizen_unified_preview2 +#profile = profile.tizen_4.0_unified +#profile = profile.tizen_unified upstream_branch = ${upstreamversion} upstream_tag = ${upstreamversion} packaging_dir = config/tizen/packaging -[profile.tizen_unified_preview1] +[profile.tizen_unified_preview2] obs = obs.spin -repos = repo.tizen_local, repo.public_4.0_base_arm_20170929.1, repo.tizen_unified_20171016.1 +repos = repo.tizen_local, repo.tizen_4.0_base_arm_20171222.1, repo.tizen_4.0_unified_20180118.1 + +[profile.tizen_4.0_unified] +obs = obs.spin +repos = repo.public_4.0_base_arm, repo.tizen_4.0_unified [profile.tizen_unified] obs = obs.spin -repos = repo.public_4.0_base_arm, repo.tizen_unified +repos = repo.tizen_base_arm, repo.tizen_unified [profile.tizen_artik10] obs = obs.spin @@ -24,41 +30,49 @@ url = https://api.tizen.org user = obs_viewer passwdx = QlpoOTFBWSZTWRP5nYMAAB6fgCAAeUA9mr+QBvzF4CAAVGAZDTRoDI0YBlCKeptQBoA0aGZIAottAkltEPOK7BAFXE9mTUzocPMzQRkPoPpNwEZx3rRQhxkXmGHS6wCjHskyVCP4u5IpwoSAn8zsGA== + [repo.public_3_arm] url = http://download.tizen.org/releases/milestone/tizen/3.0.m2/common_artik/tizen-common-artik_20170111.3/repos/arm-wayland/packages/ user = passwdx = -[repo.tizen_unified] -url=http://download.tizen.org/snapshots/tizen/unified/latest/repos/standard/packages/ -user= -passwdx= - -[repo.base_arm] -url=http://download.tizen.org/snapshots/tizen/base/latest/repos/arm/ -user= -passwdx= - - [repo.public_3.0_base_arm] url = http://download.tizen.org/snapshots/tizen/base/latest/repos/arm/packages/armv7l/ user = passwdx = -[repo.public_4.0_base_arm] + +[repo.tizen_unified] +url = http://download.tizen.org/snapshots/tizen/unified/latest/repos/standard/packages/ +user = +passwdx = + +[repo.tizen_base_arm] url = http://download.tizen.org/snapshots/tizen/base/latest/repos/standard/packages/ +user = +passwdx = + + +[repo.tizen_4.0_unified] +url = http://download.tizen.org/snapshots/tizen/4.0-unified/latest/repos/standard/packages/ +user = +passwdx = + +[repo.public_4.0_base_arm] +url = http://download.tizen.org/snapshots/tizen/4.0-base/latest/repos/arm/packages/ user = passwdx = -[repo.public_4.0_base_arm_20170929.1] -url = http://download.tizen.org/releases/previews/iot/preview1/tizen-4.0-base_20170929.1/repos/arm/packages/ + +[repo.tizen_4.0_base_arm_20171222.1] +url = http://download.tizen.org/releases/previews/iot/preview2/tizen-4.0-base_20171222.1/repos/arm/packages/ user = passwdx = -[repo.tizen_unified_20171016.1] -url=http://download.tizen.org/releases/previews/iot/preview1/tizen-4.0-unified_20171016.1/repos/standard/packages/ +[repo.tizen_4.0_unified_20180118.1] +url = http://download.tizen.org/releases/previews/iot/preview2/tizen-4.0-unified_20180118.1/repos/standard/packages/ user = passwdx = [repo.tizen_local] -url = ~/GBS-ROOT/local/repos/tizen_unified_preview1/ +url = ~/GBS-ROOT/local/repos/tizen_unified_preview2/ diff --git a/config/tizen/template/IoTjsApp/description.xml b/config/tizen/template/IoTjsApp/description.xml new file mode 100644 index 0000000..e24c004 --- /dev/null +++ b/config/tizen/template/IoTjsApp/description.xml @@ -0,0 +1,25 @@ + + + IoTjs App + 1.0 + + + iot-headless + 4.0 + + + org.tizen.nativecore.buildArtefactType.app + False + + Template + + + ic_s_service.png + ic_m_service_n.png + ic_m_service_s.png + ic_l_service.png + + + This is the empty template for developing IoT.js application. + + diff --git a/config/tizen/template/IoTjsApp/ic_l_service.png b/config/tizen/template/IoTjsApp/ic_l_service.png new file mode 100644 index 0000000..50e796f Binary files /dev/null and b/config/tizen/template/IoTjsApp/ic_l_service.png differ diff --git a/config/tizen/template/IoTjsApp/ic_m_service_n.png b/config/tizen/template/IoTjsApp/ic_m_service_n.png new file mode 100644 index 0000000..3c3c4ae Binary files /dev/null and b/config/tizen/template/IoTjsApp/ic_m_service_n.png differ diff --git a/config/tizen/template/IoTjsApp/ic_m_service_s.png b/config/tizen/template/IoTjsApp/ic_m_service_s.png new file mode 100644 index 0000000..02c8c08 Binary files /dev/null and b/config/tizen/template/IoTjsApp/ic_m_service_s.png differ diff --git a/config/tizen/template/IoTjsApp/ic_s_service.png b/config/tizen/template/IoTjsApp/ic_s_service.png new file mode 100644 index 0000000..b982002 Binary files /dev/null and b/config/tizen/template/IoTjsApp/ic_s_service.png differ diff --git a/config/tizen/template/IoTjsApp/project/inc/main.h b/config/tizen/template/IoTjsApp/project/inc/main.h new file mode 100644 index 0000000..9d90e54 --- /dev/null +++ b/config/tizen/template/IoTjsApp/project/inc/main.h @@ -0,0 +1,12 @@ +#ifndef __$(appName)_H__ +#define __$(appName)_H__ + +#include + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "$(appName)" + + +#endif /* __$(appName)_H__ */ diff --git a/config/tizen/template/IoTjsApp/project/project_def.prop b/config/tizen/template/IoTjsApp/project/project_def.prop new file mode 100644 index 0000000..32b9507 --- /dev/null +++ b/config/tizen/template/IoTjsApp/project/project_def.prop @@ -0,0 +1,11 @@ +APPNAME = $(appName) + +type = app +profile = $(platform) + +USER_SRCS = src/$(appName).c +USER_DEFS = +USER_INC_DIRS = inc +USER_OBJS = +USER_LIBS = +USER_EDCS = diff --git a/config/tizen/template/IoTjsApp/project/res/index.js b/config/tizen/template/IoTjsApp/project/res/index.js new file mode 100644 index 0000000..8e0c1bb --- /dev/null +++ b/config/tizen/template/IoTjsApp/project/res/index.js @@ -0,0 +1,2 @@ +console.log('Hello IoT.js'); + diff --git a/config/tizen/template/IoTjsApp/project/src/main.c b/config/tizen/template/IoTjsApp/project/src/main.c new file mode 100644 index 0000000..8e38c72 --- /dev/null +++ b/config/tizen/template/IoTjsApp/project/src/main.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include "$(appName).h" + + +bool service_app_create(void *data) +{ + // Todo: add your code here. + return true; +} + +void service_app_terminate(void *data) +{ + // Todo: add your code here. + return; +} + +void service_app_control(app_control_h app_control, void *data) +{ + // Todo: add your code here. + return; +} + +static void +service_app_lang_changed(app_event_info_h event_info, void *user_data) +{ + /*APP_EVENT_LANGUAGE_CHANGED*/ + return; +} + +static void +service_app_region_changed(app_event_info_h event_info, void *user_data) +{ + /*APP_EVENT_REGION_FORMAT_CHANGED*/ +} + +static void +service_app_low_battery(app_event_info_h event_info, void *user_data) +{ + /*APP_EVENT_LOW_BATTERY*/ +} + +static void +service_app_low_memory(app_event_info_h event_info, void *user_data) +{ + /*APP_EVENT_LOW_MEMORY*/ +} + +int main(int argc, char* argv[]) +{ + char ad[50] = {0,}; + service_app_lifecycle_callback_s event_callback; + app_event_handler_h handlers[5] = {NULL, }; + + event_callback.create = service_app_create; + event_callback.terminate = service_app_terminate; + event_callback.app_control = service_app_control; + + service_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY], APP_EVENT_LOW_BATTERY, service_app_low_battery, &ad); + service_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY], APP_EVENT_LOW_MEMORY, service_app_low_memory, &ad); + service_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, service_app_lang_changed, &ad); + service_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED, service_app_region_changed, &ad); + + return iotjs_service_app_start(argc, argv, "index.js", &event_callback, ad); +} diff --git a/config/tizen/template/IoTjsApp/project/tizen-manifest.xml b/config/tizen/template/IoTjsApp/project/tizen-manifest.xml new file mode 100644 index 0000000..956edd5 --- /dev/null +++ b/config/tizen/template/IoTjsApp/project/tizen-manifest.xml @@ -0,0 +1,17 @@ + + + + + $(appName).png + + + + + http://tizen.org/privilege/network.get + http://tizen.org/privilege/network.set + http://tizen.org/privilege/internet + http://tizen.org/privilege/alarm.set + http://tizen.org/privilege/network.profile + http://tizen.org/privilege/peripheralio + + diff --git a/config/tizen/template/IoTjsApp/sample.xml b/config/tizen/template/IoTjsApp/sample.xml new file mode 100644 index 0000000..f201e13 --- /dev/null +++ b/config/tizen/template/IoTjsApp/sample.xml @@ -0,0 +1,51 @@ + + diff --git a/config/tizenrt/Kconfig.runtime b/config/tizenrt/Kconfig.runtime new file mode 100644 index 0000000..9b4cee0 --- /dev/null +++ b/config/tizenrt/Kconfig.runtime @@ -0,0 +1,34 @@ +# +# For a description of the syntax of this configuration file, +# see kconfig-language at https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt +# + +config ENABLE_IOTJS + bool "IoT.js" + default n + select SPI_EXCHANGE + select IOTBUS + select IOTBUS_GPIO + select IOTBUS_I2C + select IOTBUS_PWM + select IOTBUS_SPI + select IOTBUS_UART + ---help--- + Enable IoT.js framework + +if ENABLE_IOTJS + +config IOTJS_PRIORITY + int "IoT.js task priority" + default 100 + +config IOTJS_STACKSIZE + int "IoT.js stack size" + default 32768 + +config IOTJS_JERRY_HEAP + int "Jerryscript Heaplimit" + default 128 + +endif #ENABLE_IOTJS + diff --git a/deps/jerry/.travis.yml b/deps/jerry/.travis.yml index 7e0c75b..3379411 100644 --- a/deps/jerry/.travis.yml +++ b/deps/jerry/.travis.yml @@ -22,22 +22,21 @@ script: tools/run-tests.py $OPTS # All the job definitions in the matrix. matrix: include: - - env: OPTS="--check-signed-off=travis --check-cppcheck --check-doxygen --check-vera --check-license --check-magic-strings" + - env: OPTS="--check-signed-off=travis --check-cppcheck --check-doxygen --check-vera --check-license --check-magic-strings --check-pylint" + install: pip install --user pylint==1.6.5 - env: OPTS="--jerry-debugger" - - env: OPTS="--jerry-tests --jerry-test-suite" - - env: OPTS="--jerry-tests --jerry-test-suite --toolchain=cmake/toolchain_linux_armv7l.cmake" TIMEOUT=300 + - env: OPTS="--quiet --jerry-tests --jerry-test-suite" + - env: OPTS="--quiet --jerry-tests --jerry-test-suite --toolchain=cmake/toolchain_linux_armv7l.cmake" TIMEOUT=300 install: tools/apt-get-install-qemu-arm.sh - env: OPTS="--buildoption-test" - - env: OPTS="--jerry-tests --jerry-test-suite --buildoptions=--jerry-libc=off,--compile-flag=-m32,--cpointer-32bit=on" + - env: OPTS="--quiet --jerry-tests --jerry-test-suite --buildoptions=--jerry-libc=off,--compile-flag=-m32,--cpointer-32bit=on" - env: OPTS="--unittests" - env: OPTS="--unittests --buildoptions=--cmake-param=-DFEATURE_INIT_FINI=ON" - env: OPTS="--test262" install: sudo timedatectl set-timezone America/Los_Angeles - - env: OPTS="--check-pylint" - install: pip install --user pylint==1.6.5 - os: osx before_install: tools/brew-install-deps.sh - env: OPTS="--jerry-tests --jerry-test-suite --unittests" + env: OPTS="--quiet --jerry-tests --jerry-test-suite --unittests" - install: echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- env: # Declaration of the encrypted COVERITY_SCAN_TOKEN, created via the @@ -60,7 +59,7 @@ matrix: packages: - gcc-5 - gcc-5-multilib - env: OPTS="--jerry-tests --jerry-test-suite --skip-list=parser-oom.js --buildoptions=--compile-flag=-fsanitize=address,--compile-flag=-m32,--compile-flag=-fno-omit-frame-pointer,--compile-flag=-fno-common,--compile-flag=-O2,--debug,--jerry-libc=off,--static-link=off,--system-allocator=on,--linker-flag=-fuse-ld=gold" ASAN_OPTIONS=detect_stack_use_after_return=1:check_initialization_order=true:strict_init_order=true TIMEOUT=600 + env: OPTS="--quiet --jerry-tests --jerry-test-suite --skip-list=parser-oom.js --buildoptions=--compile-flag=-fsanitize=address,--compile-flag=-m32,--compile-flag=-fno-omit-frame-pointer,--compile-flag=-fno-common,--compile-flag=-O2,--debug,--jerry-libc=off,--static-link=off,--system-allocator=on,--linker-flag=-fuse-ld=gold" ASAN_OPTIONS=detect_stack_use_after_return=1:check_initialization_order=true:strict_init_order=true TIMEOUT=600 - compiler: gcc-5 addons: apt: @@ -69,7 +68,7 @@ matrix: packages: - gcc-5 - gcc-5-multilib - env: OPTS="--jerry-tests --jerry-test-suite --skip-list=parser-oom.js --buildoptions=--compile-flag=-fsanitize=undefined,--compile-flag=-m32,--compile-flag=-fno-omit-frame-pointer,--compile-flag=-fno-common,--debug,--jerry-libc=off,--static-link=off,--system-allocator=on,--linker-flag=-fuse-ld=gold" UBSAN_OPTIONS=print_stacktrace=1 TIMEOUT=600 + env: OPTS="--quiet --jerry-tests --jerry-test-suite --skip-list=parser-oom.js --buildoptions=--compile-flag=-fsanitize=undefined,--compile-flag=-m32,--compile-flag=-fno-omit-frame-pointer,--compile-flag=-fno-common,--debug,--jerry-libc=off,--static-link=off,--system-allocator=on,--linker-flag=-fuse-ld=gold" UBSAN_OPTIONS=print_stacktrace=1 TIMEOUT=600 - env: JOBNAME="ESP8266 Build Test" cache: ccache @@ -112,8 +111,8 @@ matrix: install: make -f ./targets/zephyr/Makefile.travis install script: make -f ./targets/zephyr/Makefile.travis script allow_failures: - - env: OPTS="--check-pylint" - env: JOBNAME="Mbed/K64F Build Test" + - env: JOBNAME="Zephyr/Arduino 101 Build Test" fast_finish: true # The channel name "chat.freenode.net#jerryscript" diff --git a/deps/jerry/CMakeLists.txt b/deps/jerry/CMakeLists.txt index 2a4b22b..262009f 100644 --- a/deps/jerry/CMakeLists.txt +++ b/deps/jerry/CMakeLists.txt @@ -242,6 +242,7 @@ endif() # External compiler & linker flags if(DEFINED EXTERNAL_COMPILE_FLAGS) jerry_add_compile_flags(${EXTERNAL_COMPILE_FLAGS}) + jerry_add_flags(CMAKE_ASM_FLAGS "${EXTERNAL_COMPILE_FLAGS}") endif() if(DEFINED EXTERNAL_LINKER_FLAGS) diff --git a/deps/jerry/cmake/toolchain_mcu_artik053.cmake b/deps/jerry/cmake/toolchain_mcu_artik053.cmake new file mode 100644 index 0000000..17d846c --- /dev/null +++ b/deps/jerry/cmake/toolchain_mcu_artik053.cmake @@ -0,0 +1,22 @@ +# 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. + +set(CMAKE_SYSTEM_NAME TizenRT) +set(CMAKE_SYSTEM_PROCESSOR armv7l) +set(CMAKE_SYSTEM_VERSION ARTIK053) + +set(FLAGS_COMMON_ARCH -mcpu=cortex-r4 -mfpu=vfpv3 -fno-builtin -fno-strict-aliasing -fomit-frame-pointer -fno-strength-reduce -Wall -Werror -Wshadow -Wno-error=conversion) + +set(CMAKE_C_COMPILER arm-none-eabi-gcc) +set(CMAKE_C_COMPILER_WORKS TRUE) diff --git a/deps/jerry/cmake/toolchain_openwrt_mips.cmake b/deps/jerry/cmake/toolchain_openwrt_mips.cmake index b0b99f7..53336a0 100644 --- a/deps/jerry/cmake/toolchain_openwrt_mips.cmake +++ b/deps/jerry/cmake/toolchain_openwrt_mips.cmake @@ -15,4 +15,4 @@ set(CMAKE_SYSTEM_NAME Openwrt) set(CMAKE_SYSTEM_PROCESSOR mips) -set(CMAKE_C_COMPILER mipsel-openwrt-linux-gcc) +set(CMAKE_C_COMPILER mips-openwrt-linux-gcc) diff --git a/deps/jerry/cmake/toolchain_openwrt_mipsel.cmake b/deps/jerry/cmake/toolchain_openwrt_mipsel.cmake new file mode 100644 index 0000000..b0b99f7 --- /dev/null +++ b/deps/jerry/cmake/toolchain_openwrt_mipsel.cmake @@ -0,0 +1,18 @@ +# 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. + +set(CMAKE_SYSTEM_NAME Openwrt) +set(CMAKE_SYSTEM_PROCESSOR mips) + +set(CMAKE_C_COMPILER mipsel-openwrt-linux-gcc) diff --git a/deps/jerry/docs/02.API-REFERENCE.md b/deps/jerry/docs/02.API-REFERENCE.md index ce9c181..6607bf4 100644 --- a/deps/jerry/docs/02.API-REFERENCE.md +++ b/deps/jerry/docs/02.API-REFERENCE.md @@ -11,6 +11,19 @@ Enum that contains the following elements: - JERRY_INIT_MEM_STATS_SEPARATE - dump memory statistics and reset peak values after parse - JERRY_INIT_DEBUGGER - deprecated, an unused placeholder now +## jerry_type_t + +Enum that contains a set of elements to represent JavaScript type: + + - JERRY_TYPE_NONE - no type information + - JERRY_TYPE_UNDEFINED - undefined value + - JERRY_TYPE_NULL - null value + - JERRY_TYPE_BOOLEAN - boolean value + - JERRY_TYPE_NUMBER - number value + - JERRY_TYPE_STRING - string value + - JERRY_TYPE_OBJECT - object value + - JERRY_TYPE_FUNCTION - function value + ## jerry_error_t Possible types of an error: @@ -23,6 +36,9 @@ Possible types of an error: - JERRY_ERROR_TYPE - type error - JERRY_ERROR_URI - URI error +There is also a special value `JERRY_ERROR_NONE` which is not an error type +this value can only be returned by the [jerry_get_error_type](#jerry_get_error_type). + ## jerry_feature_t Possible compile time enabled feature types: @@ -37,6 +53,69 @@ Possible compile time enabled feature types: - JERRY_FEATURE_SNAPSHOT_EXEC - executing snapshot files - JERRY_FEATURE_DEBUGGER - debugging - JERRY_FEATURE_VM_EXEC_STOP - stopping ECMAScript execution + - JERRY_FEATURE_JSON - JSON support + - JERRY_FEATURE_PROMISE - promise support + - JERRY_FEATURE_TYPEDARRAY - Typedarray support + - JERRY_FEATURE_DATE - Date support + - JERRY_FEATURE_REGEXP - RegExp support + - JERRY_FEATURE_LINE_INFO - line info available + +## jerry_parse_opts_t + +Option bits for [jerry_parse](#jerry_parse) and +[jerry_parse_function](#jerry_parse_function) functions: + + - JERRY_PARSE_NO_OPTS - no options passed + - JERRY_PARSE_STRICT_MODE - enable strict mode + +## jerry_generate_snapshot_opts_t + +Flags for [jerry_generate_snapshot](#jerry_generate_snapshot) and +[jerry_generate_function_snapshot](#jerry_generate_function_snapshot) functions: + + - JERRY_SNAPSHOT_SAVE_STATIC - generate static snapshot (see below) + - JERRY_SNAPSHOT_SAVE_STRICT - strict source code provided + +**Generate static snapshots** +Snapshots contain literal pools, and these literal pools contain references +to constant literals (strings, numbers, etc.). When a snapshot is executed, +these literals are converted to jerry values and the literal pool entries +are changed to their corresponding jerry value. To support this conversion, +the literals and literal pools are copied into RAM even if the +`JERRY_SNAPSHOT_EXEC_COPY_DATA` option is passed to +[jerry_exec_snapshot](#jerry_exec_snapshot). This non-negligible memory +consumption can be avoided by using static snapshots. The literals of +these snapshots are limited to magic strings and 28 bit signed integers, +so their constant pools do not need to be loaded into the memory. +Hence these snapshots can be executed from ROM. + +***Important note:*** The [jerry_exec_snapshot](#jerry_exec_snapshot) +function rejects static snaphots unless the `JERRY_SNAPSHOT_EXEC_ALLOW_STATIC` +option bit is set. The caller must also ensure that the same magic +strings are set by [jerry_register_magic_strings](#jerry_register_magic_strings) +when the snapshot is generated and executed. Furthermore the +`JERRY_SNAPSHOT_EXEC_COPY_DATA` option is not allowed. + +## jerry_exec_snapshot_opts_t + +Flags for [jerry_exec_snapshot](#jerry_exec_snapshot) and +[jerry_load_function_snapshot](#jerry_load_function_snapshot) functions: + + - JERRY_SNAPSHOT_EXEC_COPY_DATA - copy snapshot data into memory (see below) + - JERRY_SNAPSHOT_EXEC_ALLOW_STATIC - allow executing static snapshots + +**Copy snapshot data into memory** + +By default the snapshot buffer is expected to be present in memory until +[jerry_cleanup](#jerry_cleanup) is called. For example `static const` buffers +compiled into the application binary satisfy this requirement. + +If the snapshot buffer is freed after [jerry_exec_snapshot](#jerry_exec_snapshot) +is called the `JERRY_SNAPSHOT_EXEC_COPY_DATA` must be passed to copy the necessary +parts of the snapshot buffer into memory. + +The `JERRY_SNAPSHOT_EXEC_COPY_DATA` option is not allowed for static snapshots. + ## jerry_char_t @@ -106,17 +185,54 @@ typedef uint32_t jerry_value_t; **Summary** Structure that defines how a context data item will be initialized and deinitialized. JerryScript zeroes out the memory -for the item by default, and if the `init_cb` field is not NULL, it will be called with the pointer to the memory as -an additional custom initializer. +for the item by default, and if the `init_cb` field is not NULL, it will be called with the pointer to the memory as +an additional custom initializer. The `deinit_cb` (if non-`NULL`) is called during a call to `jerry_cleanup ()` to run +any custom deinitialization *before* the VM has been fully cleaned up. The `finalize_cb` (if non-`NULL`) is also called +during a call to `jerry_cleanup ()` to run any custom deinitialization *after* the VM has been fully cleaned up. **Prototype** ```c typedef struct { - void (*init_cb) (void *); /**< callback responsible for initializing a context item, or NULL */ - void (*deinit_cb) (void *); /**< callback responsible for deinitializing a context item */ - size_t bytes_needed; /**< number of bytes to allocate for this manager */ + /** + * Callback responsible for initializing a context item, or NULL to zero out the memory. This is called lazily, the + * first time jerry_get_context_data () is called with this manager. + * + * @param [in] data The buffer that JerryScript allocated for the manager. The buffer is zeroed out. The size is + * determined by the bytes_needed field. The buffer is kept alive until jerry_cleanup () is called. + */ + void (*init_cb) (void *data); + + /** + * Callback responsible for deinitializing a context item, or NULL. This is called as part of jerry_cleanup (), + * right *before* the VM has been cleaned up. This is a good place to release strong references to jerry_value_t's + * that the manager may be holding. + * Note: because the VM has not been fully cleaned up yet, jerry_object_native_info_t free_cb's can still get called + * *after* all deinit_cb's have been run. See finalize_cb for a callback that is guaranteed to run *after* all + * free_cb's have been run. + * + * @param [in] data The buffer that JerryScript allocated for the manager. + */ + void (*deinit_cb) (void *data); + + /** + * Callback responsible for finalizing a context item, or NULL. This is called as part of jerry_cleanup (), + * right *after* the VM has been cleaned up and destroyed and jerry_... APIs cannot be called any more. At this point, + * all values in the VM have been cleaned up. This is a good place to clean up native state that can only be cleaned + * up at the very end when there are no more VM values around that may need to access that state. + * + * @param [in] data The buffer that JerryScript allocated for the manager. After returning from this callback, + * the data pointer may no longer be used. + */ + void (*finalize_cb) (void *data); + + /** + * Number of bytes to allocate for this manager. This is the size of the buffer that JerryScript will allocate on + * behalf of the manager. The pointer to this buffer is passed into init_cb, deinit_cb and finalize_cb. It is also + * returned from the jerry_get_context_data () API. + */ + size_t bytes_needed; } jerry_context_data_manager_t; ``` @@ -274,6 +390,33 @@ typedef bool (*jerry_object_property_foreach_t) (const jerry_value_t property_na void *user_data_p); ``` +## jerry_objects_foreach_t + +**Summary** + +Function type applied for each object in the engine + +**Prototype** + +```c +typedef bool (*jerry_objects_foreach_t) (const jerry_value_t object, + void *user_data_p); +``` + +## jerry_objects_foreach_by_native_info_t + +**Summary** + +Function type applied for each matching object in the engine + +**Prototype** + +```c +typedef bool (*jerry_objects_foreach_by_native_info_t) (const jerry_value_t object, + void *object_data_p, + void *user_data_p); +``` + ## jerry_vm_exec_stop_callback_t **Summary** @@ -296,6 +439,26 @@ typedef jerry_value_t (*jerry_vm_exec_stop_callback_t) (void *user_p); - [jerry_set_vm_exec_stop_callback](#jerry_set_vm_exec_stop_callback) +## jerry_typedarray_type_t + +Enum which describes the TypedArray types. +Possible values: + + - JERRY_TYPEDARRAY_UINT8 - represents the Uint8Array TypedArray + - JERRY_TYPEDARRAY_UINT8CLAMPED - represents the Uint8ClampedArray TypedArray + - JERRY_TYPEDARRAY_INT8 - represents the Int8Array TypedArray + - JERRY_TYPEDARRAY_UINT16 - represents the Uint16Array TypedArray + - JERRY_TYPEDARRAY_INT16 - represents the Int16Array TypedArray + - JERRY_TYPEDARRAY_UINT32 - represents the Uint32Array TypedArray + - JERRY_TYPEDARRAY_INT32 - represents the Int32Array TypedArray + - JERRY_TYPEDARRAY_FLOAT32 - represents the Float32Array TypedArray + - JERRY_TYPEDARRAY_FLOAT64 - represents the Float64Array TypedArray + - JERRY_TYPEDARRAY_INVALID - represents an invalid TypedArray + +API functions can return the `JERRY_TYPEDARRAY_INVALID` value if the +TypedArray support is not in the engine. + + # General engine functions ## jerry_init @@ -652,8 +815,9 @@ main (void) **Summary** -Parse script and construct an EcmaScript function. The -lexical environment is set to the global lexical environment. +Parse script and construct an EcmaScript function. The lexical environment is +set to the global lexical environment. The resource name can be used by +debugging systems to provide line / backtrace info. *Note*: Returned value must be freed with [jerry_release_value](#jerry_release_value) when it is no longer needed. @@ -662,14 +826,18 @@ is no longer needed. ```c jerry_value_t -jerry_parse (const jerry_char_t *source_p, +jerry_parse (const jerry_char_t *resource_name_p, /**< resource name (usually a file name) */ + size_t resource_name_length, /**< length of resource name */ + const jerry_char_t *source_p, size_t source_size, - bool is_strict); + uint32_t parse_opts); ``` +- `resource_name_p` - resource name, usually a file name (must be a valid UTF8 string). +- `resource_name_length` - size of the resource name, in bytes. - `source_p` - string, containing source code to parse (must be a valid UTF8 string). - `source_size` - size of the string, in bytes. -- `is_strict` - defines strict mode. +- `parse_opts` - any combination of [jerry_parse_opts_t](#jerry_parse_opts_t) flags. - return value - function object value, if script was parsed successfully, - thrown error, otherwise @@ -690,7 +858,7 @@ main (void) const jerry_char_t script[] = "print ('Hello, World!');"; size_t script_size = strlen ((const char *) script); - jerry_value_t parsed_code = jerry_parse (script, script_size, false); + jerry_value_t parsed_code = jerry_parse (NULL, 0, script, script_size, JERRY_PARSE_NO_OPTS); jerry_release_value (parsed_code); jerry_cleanup (); @@ -701,40 +869,6 @@ main (void) - [jerry_run](#jerry_run) -## jerry_parse_named_resource - -**Summary** - -Parse script and construct an ECMAScript function. The lexical -environment is set to the global lexical environment. The resource -name (usually a file name) is also passed to this function which is -used by the debugger to find the source code. - -*Note*: The returned value must be freed with [jerry_release_value](#jerry_release_value) when it -is no longer needed. - -**Prototype** - -```c -jerry_value_t -jerry_parse_named_resource (const jerry_char_t *resource_name_p, /**< resource name (usually a file name) */ - size_t resource_name_length, /**< length of resource name */ - const jerry_char_t *source_p, /**< script source */ - size_t source_size, /**< script source size */ - bool is_strict) /**< strict mode */ -``` - -- `resource_name_p` - resource name, usually a file name (must be a valid UTF8 string). -- `resource_name_length` - size of the resource name, in bytes. -- `source_p` - string, containing source code to parse (must be a valid UTF8 string). -- `source_size` - size of the string, in bytes. -- `is_strict` - defines strict mode. -- return value - - function object value, if script was parsed successfully, - - thrown error, otherwise - -This function is identical to [jerry_parse](#jerry_parse), except that an additional filename parameter has been added. - ## jerry_parse_function **Summary** @@ -759,7 +893,7 @@ jerry_parse_function (const jerry_char_t *resource_name_p, /**< resource name (u size_t arg_list_size, /**< script source size */ const jerry_char_t *source_p, /**< script source */ size_t source_size, /**< script source size */ - bool is_strict) /**< strict mode */ + uint32_t parse_opts) /**< strict mode */ ``` - `resource_name_p` - resource name, usually a file name (must be a valid UTF8 string). @@ -768,7 +902,7 @@ jerry_parse_function (const jerry_char_t *resource_name_p, /**< resource name (u - `arg_list_size` - size of the argument list, in bytes. - `source_p` - string, containing source code to parse (must be a valid UTF8 string). - `source_size` - size of the string, in bytes. -- `is_strict` - defines strict mode. +- `parse_opts` - any combination of [jerry_parse_opts_t](#jerry_parse_opts_t) flags. - return value - function object value, if script was parsed successfully, - thrown error, otherwise @@ -811,7 +945,7 @@ main (void) jerry_init (JERRY_INIT_EMPTY); /* Setup Global scope code */ - jerry_value_t parsed_code = jerry_parse (script, script_size, false); + jerry_value_t parsed_code = jerry_parse (NULL, 0, script, script_size, JERRY_PARSE_NO_OPTS); if (!jerry_value_has_error_flag (parsed_code)) { @@ -901,7 +1035,7 @@ main (void) const jerry_char_t script[] = "new Promise(function(f,r) { f('Hello, World!'); }).then(function(x) { print(x); });"; size_t script_size = strlen ((const char *) script); - jerry_value_t parsed_code = jerry_parse (script, script_size, false); + jerry_value_t parsed_code = jerry_parse (NULL, 0, script, script_size, JERRY_PARSE_NO_OPTS); jerry_value_t script_value = jerry_run (parsed_code); jerry_value_t job_value = jerry_run_all_enqueued_jobs (); @@ -993,6 +1127,45 @@ jerry_value_is_array (const jerry_value_t value) - [jerry_release_value](#jerry_release_value) +## jerry_value_is_arraybuffer + +**Summary** + +Returns whether the given `jerry_value_t` is an ArrayBuffer object. + +**Prototype** + +```c +bool +jerry_value_is_arraybuffer (const jerry_value_t value) +``` + +- `value` - api value +- return value + - true, if the given `jerry_value_t` is an ArrayBuffer object. + - false, otherwise + +**Example** + +```c +{ + jerry_value_t value; + ... // create or acquire value + + if (jerry_value_is_arraybuffer (value)) + { + ... + } + + jerry_release_value (value); +} +``` + +**See also** + +- [jerry_create_arraybuffer](#jerry_create_arraybuffer) +- [jerry_create_arraybuffer_external](#jerry_create_arraybuffer_external) + ## jerry_value_is_boolean @@ -1308,6 +1481,45 @@ jerry_value_is_string (const jerry_value_t value) - [jerry_release_value](#jerry_release_value) +## jerry_value_is_typedarray + +**Summary** + +Checks whether the given `jerry_value_t` is a TypedArray object or not. + +**Prototype** + +```c +bool +jerry_value_is_typedarray (const jerry_value_t value) +``` + +- `value` - object to check +- return value + - true, if the given `jerry_value_t` is a TypedArray object. + - false, otherwise + +**Example** + +```c +{ + jerry_value_t value; + ... // create or acquire value + + if (jerry_value_is_typedarray (value)) + { + ... + } + + jerry_release_value (value); +} +``` + +**See also** + +- [jerry_create_typedarray](#jerry_create_typedarray) + + ## jerry_value_is_undefined **Summary** @@ -1346,6 +1558,44 @@ jerry_value_is_undefined (const jerry_value_t value) - [jerry_release_value](#jerry_release_value) +## jerry_value_get_type + +**Summary** + +Returns the JavaScript type +for a given value as a [jerry_type_t](#jerry_type_t) enum value. + +This is a similar operation as the 'typeof' operator +in the standard with an exception that the 'null' +value has its own enum value. + +**Prototype** + +```c +jerry_type_t +jerry_value_get_type (const jerry_value_t value); +``` + +**Example** + +```c +{ + jerry_value_t number = jerry_create_number (3.3); + + jerry_type_t type_info = jerry_value_get_type (number); + + if (type_info == JERRY_TYPE_NUMBER) + { + ... + } + + jerry_value_release (number); +} +``` + +**See also** +- [jerry_type_t](#jerry_type_t) + ## jerry_is_feature_enabled **Summary** @@ -1379,7 +1629,50 @@ jerry_is_feature_enabled (const jerry_feature_t feature); } ``` -# Error flag manipulation functions +# Error manipulation functions + +## jerry_get_error_type + +**Summary** + +Returns the type of the Error object if possible. + +If a non-error object is used as the input for the function the method +will return `JERRY_ERROR_NONE` indicating that the value was not +an Error object. However it is still possible that the value contains +error semantics. To correctly detect if a value have error use the +[jerry_value_has_error_flag](#jerry_value_has_error_flag) method. + +**Prototype** + +```c +jerry_error_t +jerry_get_error_type (const jerry_value_t value); +``` + +- `value` - api value (possible error object) +- return value + - JERRY_ERROR_NONE if the input is not an error object + - one of the [jerry_error_t](#jerry_error_t) value + +**Example** + +```c +{ + jerry_value_t error_obj = jerry_create_error (JERRY_ERROR_RANGE, + (const jerry_char_t *) "error msg"); + jerry_error_t error_type = jerry_get_error_type (error_obj); + + // error_type is now JERRY_ERROR_RANGE. + + jerry_release_value (error_obj); +} +``` + +**See also** + +- [jerry_create_error](#jerry_create_error) +- [jerry_value_has_error_flag](#jerry_value_has_error_flag) ## jerry_value_has_error_flag @@ -1418,22 +1711,26 @@ jerry_value_has_error_flag (const jerry_value_t value); **See also** - [jerry_value_t](#jerry_value_t) +- [jerry_value_has_abort_flag](#jerry_value_has_abort_flag) -## jerry_value_clear_error_flag +## jerry_value_has_abort_flag **Summary** -Clear the error flag. +Returns whether the given `jerry_value_t` has the error and abort flags set. **Prototype** ```c -void -jerry_value_clear_error_flag (jerry_value_t *value_p); +bool +jerry_value_has_abort_flag (const jerry_value_t value); ``` -- `value_p` - pointer to an api value +- `value` - api value +- return value + - true, if the given `jerry_value_t` has the error and abort flags set + - false, otherwise **Example** @@ -1442,7 +1739,10 @@ jerry_value_clear_error_flag (jerry_value_t *value_p); jerry_value_t value; ... // create or acquire value - jerry_value_clear_error_flag (&value); + if (jerry_value_has_abort_flag (value)) + { + ... + } jerry_release_value (value); } @@ -1451,19 +1751,20 @@ jerry_value_clear_error_flag (jerry_value_t *value_p); **See also** - [jerry_value_t](#jerry_value_t) +- [jerry_value_has_error_flag](#jerry_value_has_error_flag) -## jerry_value_set_error_flag +## jerry_value_clear_error_flag **Summary** -Set the error flag. +Clear both the error and abort flags. **Prototype** ```c void -jerry_value_set_error_flag (jerry_value_t *value_p); +jerry_value_clear_error_flag (jerry_value_t *value_p); ``` - `value_p` - pointer to an api value @@ -1475,7 +1776,7 @@ jerry_value_set_error_flag (jerry_value_t *value_p); jerry_value_t value; ... // create or acquire value - jerry_value_set_error_flag (&value); + jerry_value_clear_error_flag (&value); jerry_release_value (value); } @@ -1484,26 +1785,24 @@ jerry_value_set_error_flag (jerry_value_t *value_p); **See also** - [jerry_value_t](#jerry_value_t) +- [jerry_value_set_error_flag](#jerry_value_set_error_flag) +- [jerry_value_set_abort_flag](#jerry_value_set_abort_flag) -## jerry_get_value_without_error_flag +## jerry_value_set_error_flag **Summary** -If the input value is an error value, then return a new reference to its referenced value. -Otherwise, return a new reference to the value itself. - -*Note*: Returned value must be freed with [jerry_release_value](#jerry_release_value) -when it is no longer needed. +Set the error flag. **Prototype** ```c -jerry_value_t -jerry_get_value_without_error_flag (jerry_value_t value) +void +jerry_value_set_error_flag (jerry_value_t *value_p); ``` -- `value` - api value +- `value_p` - pointer to an api value **Example** @@ -1511,43 +1810,34 @@ jerry_get_value_without_error_flag (jerry_value_t value) { jerry_value_t value; ... // create or acquire value - + jerry_value_set_error_flag (&value); - - jerry_value_t real_value = jerry_get_value_without_error_flag (value); - ... // process the real_value. Different from `jerry_value_clear_error_flag`, - // the error `value` will not be automatically released after calling - // `jerry_get_value_without_error_flag`. jerry_release_value (value); - jerry_release_value (real_value); } ``` **See also** -- [jerry_acquire_value](#jerry_acquire_value) +- [jerry_value_t](#jerry_value_t) - [jerry_value_clear_error_flag](#jerry_value_clear_error_flag) +- [jerry_value_set_abort_flag](#jerry_value_set_abort_flag) -# Getter functions of 'jerry_value_t' - -Get raw data from API values. -## jerry_get_boolean_value +## jerry_value_set_abort_flag **Summary** -Gets the raw bool value from a `jerry_value_t`. +Set both the error and abort flags. **Prototype** ```c -bool -jerry_get_boolean_value (const jerry_value_t value); +void +jerry_value_set_abort_flag (jerry_value_t *value_p); ``` -- `value` - api value -- return value - boolean value represented by the argument. +- `value_p` - pointer to an api value **Example** @@ -1556,30 +1846,113 @@ jerry_get_boolean_value (const jerry_value_t value); jerry_value_t value; ... // create or acquire value - if (jerry_value_is_boolean (value)) - { - bool raw_value = jerry_get_boolean_value (value); - - ... // usage of raw value - - } + jerry_value_set_abort_flag (&value); jerry_release_value (value); } - ``` **See also** -- [jerry_value_is_boolean](#jerry_value_is_boolean) -- [jerry_release_value](#jerry_release_value) +- [jerry_value_t](#jerry_value_t) +- [jerry_value_clear_error_flag](#jerry_value_clear_error_flag) +- [jerry_value_set_error_flag](#jerry_value_set_error_flag) -## jerry_get_number_value +## jerry_get_value_without_error_flag **Summary** -Gets the number value of the given `jerry_value_t` parameter as a raw double. +If the input value is an error value, then return a new reference to its referenced value. +Otherwise, return a new reference to the value itself. + +*Note*: Returned value must be freed with [jerry_release_value](#jerry_release_value) +when it is no longer needed. + +**Prototype** + +```c +jerry_value_t +jerry_get_value_without_error_flag (jerry_value_t value) +``` + +- `value` - api value + +**Example** + +```c +{ + jerry_value_t value; + ... // create or acquire value + + jerry_value_set_error_flag (&value); + + jerry_value_t real_value = jerry_get_value_without_error_flag (value); + ... // process the real_value. Different from `jerry_value_clear_error_flag`, + // the error `value` will not be automatically released after calling + // `jerry_get_value_without_error_flag`. + + jerry_release_value (value); + jerry_release_value (real_value); +} +``` + +**See also** + +- [jerry_acquire_value](#jerry_acquire_value) +- [jerry_value_clear_error_flag](#jerry_value_clear_error_flag) + +# Getter functions of 'jerry_value_t' + +Get raw data from API values. + +## jerry_get_boolean_value + +**Summary** + +Gets the raw bool value from a `jerry_value_t`. + +**Prototype** + +```c +bool +jerry_get_boolean_value (const jerry_value_t value); +``` + +- `value` - api value +- return value - boolean value represented by the argument. + +**Example** + +```c +{ + jerry_value_t value; + ... // create or acquire value + + if (jerry_value_is_boolean (value)) + { + bool raw_value = jerry_get_boolean_value (value); + + ... // usage of raw value + + } + + jerry_release_value (value); +} + +``` + +**See also** + +- [jerry_value_is_boolean](#jerry_value_is_boolean) +- [jerry_release_value](#jerry_release_value) + + +## jerry_get_number_value + +**Summary** + +Gets the number value of the given `jerry_value_t` parameter as a raw double. **Prototype** @@ -1786,6 +2159,12 @@ enough for the whole string. *Note*: Does not put '\0' to the end of string, the return value identifies the number of valid bytes in the output buffer. +*Note*: If the size of the string in jerry value is larger than the size of the +target buffer, the copy will fail. To copy a substring the +[jerry_substring_to_char_buffer](#jerry_substring_to_char_buffer) API function +is recommended instead. + + **Prototype** ```c @@ -1821,6 +2200,7 @@ jerry_string_to_char_buffer (const jerry_value_t value, - [jerry_create_string](#jerry_create_string) - [jerry_get_string_size](#jerry_get_string_size) - [jerry_is_valid_cesu8_string](#jerry_is_valid_cesu8_string) +- [jerry_substring_to_char_buffer](#jerry_substring_to_char_buffer) ## jerry_string_to_utf8_char_buffer @@ -1835,6 +2215,11 @@ large enough for the whole string. *Note*: Does not put '\0' to the end of string, the return value identifies the number of valid bytes in the output buffer. +*Note*: If the size of the string in jerry value is larger than the size of the +target buffer, the copy will fail. To copy a substring the +[jerry_substring_to_utf8_char_buffer](#jerry_substring_to_utf8_char_buffer) +API function is recommended instead. + **Prototype** ```c @@ -1870,6 +2255,7 @@ jerry_string_to_utf8_char_buffer (const jerry_value_t value, - [jerry_create_string_from_utf8](#jerry_create_string_from_utf8) - [jerry_get_utf8_string_size](#jerry_get_utf8_string_size) - [jerry_is_valid_utf8_string](#jerry_is_valid_utf8_string) +- [jerry_substring_to_utf8_char_buffer](#jerry_substring_to_utf8_char_buffer) ## jerry_substring_to_char_buffer @@ -2391,6 +2777,92 @@ jerry_create_array (uint32_t size); - [jerry_get_property_by_index](#jerry_get_property_by_index) +## jerry_create_arraybuffer + +**Summary** + +Create a jerry_value_t representing an ArrayBuffer object. + +**Prototype** + +```c +jerry_value_t +jerry_create_arraybuffer (jerry_length_t size); +``` + + - `size` - size of the ArrayBuffer to create **in bytes** + - return value - the new ArrayBuffer as a `jerry_value_t` + +**Example** + +```c +{ + jerry_value_t buffer_value = jerry_create_arraybuffer (15); + + ... // use the ArrayBuffer + + jerry_release_value (buffer_value); +} +``` + +**See also** + +- [jerry_arraybuffer_read](#jerry_arraybuffer_read) +- [jerry_arraybuffer_write](#jerry_arraybuffer_write) +- [jerry_value_is_arraybuffer](#jerry_value_is_arraybuffer) +- [jerry_release_value](#jerry_release_value) + + +## jerry_create_arraybuffer_external + +**Summary** + +Creates a jerry_value_t representing an ArrayBuffer object with +user specified back-buffer. + +User must pass a buffer pointer which is at least `size` big. +After the object is not needed the GC will call the `free_cb` +so the user can release the buffer which was provided. + +**Prototype** + +```c +jerry_value_t +jerry_create_arraybuffer_external (const jerry_length_t size + uint8_t *buffer_p, + jerry_object_native_free_callback_t free_cb); +``` + +- `size` - size of the buffer to use **in bytes** (should not be 0) +- `buffer_p` - the buffer used for the Array Buffer object (should not be a null pointer) +- `free_cb` - the callback function called when the object is released +- return value + - the new ArrayBuffer as a `jerry_value_t` + - if the `size` is zero or `buffer_p` is a null pointer will return RangeError + +**Example** + +```c +{ + uint8_t buffer_p[15]; + jerry_value_t buffer_value = jerry_create_arraybuffer_external (15, buffer_p, NULL); + + ... // use the array buffer + + jerry_release_value (buffer_value); +} +``` + +**See also** + +- [jerry_get_arraybuffer_pointer](#jerry_get_arraybuffer_pointer) +- [jerry_arraybuffer_read](#jerry_arraybuffer_read) +- [jerry_arraybuffer_write](#jerry_arraybuffer_write) +- [jerry_value_is_arraybuffer](#jerry_value_is_arraybuffer) +- [jerry_release_value](#jerry_release_value) +- [jerry_object_native_free_callback_t](#jerry_object_native_free_callback_t) + + ## jerry_create_boolean **Summary** @@ -2430,6 +2902,11 @@ jerry_create_boolean (bool value); Create new JavaScript error object. +Important! The `error_type` argument *must not be* +`JERRY_ERROR_NONE`. +Creating an error with no error type is not valid. + + **Prototype** ```c @@ -2911,6 +3388,151 @@ jerry_create_string_sz (const jerry_char_t *str_p, - [jerry_create_string_from_utf8](#jerry_create_string_from_utf8) +## jerry_create_typedarray + +**Summary** + +Create a jerry_value_t representing an TypedArray object. + +For the new object the type of the TypedArray (see: [jerry_typedarray_type_t](#jerry_typedarray_type_t)) +and element count can be specified. + +**Prototype** + +```c +jerry_value_t +jerry_create_typedarray (jerry_typedarray_type_t type_name, jerry_length_t item_count); +``` + +- `type_name` - type of TypedArray to create +- `item_count` - number of items in the new TypedArray +- return value - the new TypedArray as a `jerry_value_t` + +**Example** + +```c +{ + jerry_value_t array = jerry_create_typedarray (JERRY_TYPEDARRAY_UINT16, 15); + + ... // use the TypedArray + + jerry_release_value (array); +} +``` + +**See also** + +- [jerry_typedarray_type_t](#jerry_typedarray_type_t) +- [jerry_value_is_typedarray](#jerry_value_is_typedarray) +- [jerry_release_value](#jerry_release_value) + + +## jerry_create_typedarray_for_arraybuffer + +**Summary** + +Create a jerry_value_t representing an TypedArray object using +an already existing ArrayBuffer object. + +For the new object the type of the TypedArray (see: [jerry_typedarray_type_t](#jerry_typedarray_type_t)) +and element count can be specified. + +The developer must ensure that the ArrayBuffer has the correct length for the given +type of TypedArray otherwise an error is generated. + +The JavaScript equivalent of this function is: `new %TypedArray%(arraybuffer)` where `%TypedArray%` is +one of the allowed TypedArray functions. + +**Prototype** + +```c +jerry_value_t +jerry_create_typedarray_for_arraybuffer (jerry_typedarray_type_t type_name, + const jerry_value_t arraybuffer); +``` + +- `type_name` - type of TypedArray to create +- `arraybuffer` - the ArrayBuffer to use for the new TypedArray +- return value + - the new TypedArray as a `jerry_value_t` + - Error if the ArrayBuffer does not have enough space for the given type of TypedArray + +**Example** + +```c +{ + jerry_value_t buffer = jerry_create_array_buffer (12 * 2); + jerry_value_t array = jerry_create_typedarray_for_arraybuffer (JERRY_TYPEDARRAY_UINT16, buffer); + jerry_release_value (buffer); + + ... // use the TypedArray + + jerry_release_value (array); +} +``` + +**See also** + +- [jerry_typedarray_type_t](#jerry_typedarray_type_t) +- [jerry_value_is_typedarray](#jerry_value_is_typedarray) +- [jerry_release_value](#jerry_release_value) + + +## jerry_create_typedarray_for_arraybuffer_sz + +**Summary** + +Create a jerry_value_t representing an TypedArray object using +an already existing ArrayBuffer object and by specifying the byteOffset, and length properties. + +For the new object the type of the TypedArray (see: [jerry_typedarray_type_t](#jerry_typedarray_type_t)) +and element count can be specified. + +The developer must ensure that the ArrayBuffer has the correct length for the given +type of TypedArray otherwise an error is generated. + +The JavaScript equivalent of this function is: `new %TypedArray%(arraybuffer, byteOffset, length)` where `%TypedArray%` is +one of the allowed TypedArray functions. + +**Prototype** + +```c +jerry_value_t +jerry_create_typedarray_for_arraybuffer_sz (jerry_typedarray_type_t type_name, + const jerry_value_t arraybuffer, + jerry_length_t byte_offset, + jerry_length_t length); +``` + +- `type_name` - type of TypedArray to create +- `arraybuffer` - the ArrayBuffer to use for the new TypedArray +- `byte_offset` - start offset to use for the ArrayBuffer +- `length` - number of elements to used from the ArrayBuffer (this is not the same as the byteLength) +- return value + - the new TypedArray as a `jerry_value_t` + - Error if the ArrayBuffer does not have enough space for the given type of TypedArray + +**Example** + +```c +{ + jerry_value_t buffer = jerry_create_array_buffer (12 * 2); + jerry_value_t array = jerry_create_typedarray_for_arraybuffer_sz (JERRY_TYPEDARRAY_UINT16, buffer, 4, 10); + jerry_release_value (buffer); + + ... // use the TypedArray + + jerry_release_value (array); +} +``` + +**See also** + +- [jerry_typedarray_type_t](#jerry_typedarray_type_t) +- [jerry_value_is_typedarray](#jerry_value_is_typedarray) +- [jerry_release_value](#jerry_release_value) + + ## jerry_create_undefined **Summary** @@ -4039,45 +4661,226 @@ bool foreach_function (const jerry_value_t prop_name, - [jerry_object_property_foreach_t](#jerry_object_property_foreach_t) - -# Input validator functions - -## jerry_is_valid_utf8_string +## jerry_objects_foreach **Summary** -Validate UTF-8 string. +Iterate over objects. + +*Note*: Values obtained in `foreach_p` must be retained using [jerry_acquire_value](#jerry_acquire_value). **Prototype** ```c -bool -jerry_is_valid_utf8_string (const jerry_char_t *utf8_buf_p, /**< UTF-8 string */ - jerry_size_t buf_size) /**< string size */ +bool jerry_objects_foreach (jerry_objects_foreach_t foreach_p, + void *user_data_p); ``` -- `utf8_buf_p` - UTF-8 input string -- `buf_size` - input string size +- `foreach_p` - function that will be invoked for each object. +- `user_data_p` - User data to pass to the function. +- return value + - `true`, if the search function terminated the traversal by returning `false` + - `false`, if the end of the list of objects was reached **Example** -[doctest]: # () - ```c -#include -#include "jerryscript.h" - -int -main (void) +typedef struct { - const jerry_char_t script[] = "print ('Hello, World!');"; - size_t script_size = strlen ((const char *) script); + jerry_value_t property_name; + jerry_value_t result; +} find_my_object_info_t; - if (jerry_is_valid_utf8_string (script, (jerry_size_t) script_size)) +/* + * Find the first object with the given property. + */ +static bool +find_my_object(const jerry_value_t candidate, + void *user_data_p) +{ + find_my_object_info_t *info_p = (find_my_object_info_t *) user_data_p; + jerry_value_t has_property = jerry_object_has_property (candidate, info_p->property_name); + bool keep_searching = (jerry_value_has_error_flag (has_property) || !jerry_get_boolean_value ()); + if (!keep_searching) { - jerry_run_simple (script, script_size, JERRY_INIT_EMPTY); + /* We found it, so we acquire the value and record it. */ + info_p->result = jerry_acquire_value (candidate); } -} + jerry_release_value (has_property); + return keep_searching; +} /* find_my_object */ + +{ + find_my_object_info_t search_info = + { + .property_name = jerry_create_string ("desired_property") + }; + + if (jerry_object_foreach (find_my_object, &search_info)) + { + /* The search was successful. Do something useful with search_info.result. */ + ... + + /* Release the found object after we're done using it. */ + jerry_release_value (search_info.result); + } + else + { + /* The search has failed. */ + } + + jerry_release_value (search_info.desired_property); +} +``` +**See also** + +- [jerry_objects_foreach_t](#jerry_objects_foreach_t) + +## jerry_objects_foreach_by_native_info + +**Summary** + +Iterate over objects matching a certain native data type. + +*Note*: Values obtained in `foreach_p` must be retained using [jerry_acquire_value](#jerry_acquire_value). + +**Prototype** + +```c +bool jerry_objects_foreach_by_native_info (const jerry_object_native_info_t *native_info_p, + jerry_objects_foreach_by_native_info_t foreach_p, + void *user_data_p); +``` + +- `native_info_p` - native pointer's type infomation. +- return value + - `true`, if the search function terminated the traversal by returning `false` + - `false`, if the end of the list of objects was reached + +**Example** + +```c +typedef struct +{ + int foo; + bool bar; +} native_obj_t; + +typedef struct +{ + jerry_value_t found_object; + void *match_data_p; +} find_object_data_t; + +static void native_freecb (void *native_p) +{ + ... // free the native pointer +} /* native_freecb */ + +// NOTE: The address (!) of type_info acts as a way to uniquely "identify" the +// C type `native_obj_t *`. +static const jerry_object_native_info_t native_obj_type_info = +{ + .free_cb = native_freecb +}; + +// Function creating JS object that is "backed" by a native_obj_t *: +{ + ... + + // construct object and native_set value: + jerry_value_t object = ...; + native_obj_t *native_obj_p = malloc (sizeof (*native_obj_p)); + jerry_set_object_native_pointer (object, native_obj_p, &native_obj_type_info); + + ... +} + +// Native method that retrieves the JavaScript object by way of its native data: +static bool find_object (const jerry_value_t candidate, void *data_p, void *user_data_p) +{ + find_object_data_t *find_data_p = (find_object_data_t *) user_data_p; + + if (find_data_p->match_data_p == data_p) + { + // If the object was found, acquire it and store it in the user data. + find_data_p->found_object = jerry_acquire_value (candidate); + + // Stop traversing over the objects. + return false; + } + + // Indicate that the object was not found, so traversal must continue. + return true; +} /* find_object */ +... +{ + find_object_data_t find_data = + { + .match_data = native_obj + }; + + if (jerry_objects_foreach_by_native_info (&native_obj_type_info, find_object, &find_data)) + { + // The object was found and is now stored in find_data.found_object. After using it, it must be released. + ... + jerry_release_value (find_data.found_object); + } + else + { + // The object was not found. + } + ... +} +``` + +**See also** + +- [jerry_create_object](#jerry_create_object) +- [jerry_set_object_native_pointer](#jerry_set_object_native_pointer) +- [jerry_get_object_native_pointer](#jerry_get_object_native_pointer) +- [jerry_object_native_info_t](#jerry_object_native_info_t) +- [jerry_objects_foreach](#jerry_objects_foreach) + + +# Input validator functions + +## jerry_is_valid_utf8_string + +**Summary** + +Validate UTF-8 string. + +**Prototype** + +```c +bool +jerry_is_valid_utf8_string (const jerry_char_t *utf8_buf_p, /**< UTF-8 string */ + jerry_size_t buf_size) /**< string size */ +``` + +- `utf8_buf_p` - UTF-8 input string +- `buf_size` - input string size + +**Example** + +[doctest]: # () + +```c +#include +#include "jerryscript.h" + +int +main (void) +{ + const jerry_char_t script[] = "print ('Hello, World!');"; + size_t script_size = strlen ((const char *) script); + + if (jerry_is_valid_utf8_string (script, (jerry_size_t) script_size)) + { + jerry_run_simple (script, script_size, JERRY_INIT_EMPTY); + } +} ``` **See also** @@ -4149,7 +4952,7 @@ main (void) # Snapshot functions -## jerry_parse_and_save_snapshot +## jerry_generate_snapshot **Summary** @@ -4158,26 +4961,28 @@ Generate snapshot from the specified source code. **Prototype** ```c -size_t -jerry_parse_and_save_snapshot (const jerry_char_t *source_p, - size_t source_size, - bool is_for_global, - bool is_strict, - uint32_t *buffer_p, - size_t buffer_size); +jerry_value_t +jerry_generate_snapshot (const jerry_char_t *resource_name_p, + size_t resource_name_length, + const jerry_char_t *source_p, + size_t source_size, + uint32_t generate_snapshot_opts, + uint32_t *buffer_p, + size_t buffer_size); ``` +- `resource_name_p` - resource (file) name of the source code. Currently unused, the debugger may use it in the future. +- `resource_name_length` - length of resource name. - `source_p` - script source, it must be a valid utf8 string. - `source_size` - script source size, in bytes. -- `is_for_global` - snapshot would be executed as global (true) or eval (false). -- `is_strict` - strict mode +- `generate_snapshot_opts` - any combination of [jerry_generate_snapshot_opts_t](#jerry_generate_snapshot_opts_t) flags. - `buffer_p` - buffer to save snapshot to. - `buffer_size` - the buffer's size. - return value - - the size of snapshot, if it was generated succesfully (i.e. there are no syntax errors in source - code, buffer size is sufficient, and snapshot support is enabled in current configuration through - JERRY_ENABLE_SNAPSHOT_SAVE) - - 0 otherwise. + - the size of the snapshot as a number value, if it was generated succesfully (i.e. there are no syntax + errors in source code, buffer size is sufficient, and snapshot support is enabled in current configuration + through JERRY_ENABLE_SNAPSHOT_SAVE) + - thrown error, otherwise. **Example** @@ -4195,12 +5000,17 @@ main (void) static uint32_t global_mode_snapshot_buffer[256]; const jerry_char_t *code_to_snapshot_p = (const jerry_char_t *) "(function () { return 'string from snapshot'; }) ();"; - size_t global_mode_snapshot_size = jerry_parse_and_save_snapshot (code_to_snapshot_p, - strlen ((const char *) code_to_snapshot_p), - true, - false, - global_mode_snapshot_buffer, - sizeof (global_mode_snapshot_buffer) / sizeof (uint32_t)); + jerry_value_t generate_result; + generate_result = jerry_generate_snapshot (NULL, + 0, + code_to_snapshot_p, + strlen ((const char *) code_to_snapshot_p), + 0, + global_mode_snapshot_buffer, + sizeof (global_mode_snapshot_buffer) / sizeof (uint32_t)); + + size_t snapshot_size = (size_t) jerry_get_number_value (generate_result); + jerry_release_value (generate_result); jerry_cleanup (); } @@ -4210,10 +5020,11 @@ main (void) - [jerry_init](#jerry_init) - [jerry_cleanup](#jerry_cleanup) +- [jerry_generate_function_snapshot](#jerry_generate_function_snapshot) - [jerry_exec_snapshot](#jerry_exec_snapshot) -## jerry_parse_and_save_function_snapshot +## jerry_generate_function_snapshot **Summary** @@ -4226,28 +5037,32 @@ passed as separated arguments. **Prototype** ```c -size_t -jerry_parse_and_save_function_snapshot (const jerry_char_t *source_p, - size_t source_size, - const jerry_char_t *args_p, - size_t args_size, - bool is_strict, - uint32_t *buffer_p, - size_t buffer_size) -``` - +jerry_value_t +jerry_generate_function_snapshot (const jerry_char_t *resource_name_p, + size_t resource_name_length, + const jerry_char_t *source_p, + size_t source_size, + const jerry_char_t *args_p, + size_t args_size, + uint32_t generate_snapshot_opts, + uint32_t *buffer_p, + size_t buffer_size) +``` + +- `resource_name_p` - resource (file) name of the source code. Currently unused, the debugger may use it in the future. +- `resource_name_length` - length of resource name. - `source_p` - script source, it must be a valid utf8 string. - `source_size` - script source size, in bytes. - `args_p` - function arguments, it must be a valid utf8 string. - `args_size` - function argument size, in bytes. -- `is_strict` - strict mode +- `generate_snapshot_opts` - any combination of [jerry_generate_snapshot_opts_t](#jerry_generate_snapshot_opts_t) flags. - `buffer_p` - buffer to save snapshot to. - `buffer_size` - the buffer's size. - return value - - the size of snapshot, if it was generated succesfully (i.e. there are no syntax errors in source - code, buffer size is sufficient, and snapshot support is enabled in current configuration through - JERRY_ENABLE_SNAPSHOT_SAVE) - - 0 otherwise. + - the size of the snapshot as a number value, if it was generated succesfully (i.e. there are no syntax + errors in source code, buffer size is sufficient, and snapshot support is enabled in current configuration + through JERRY_ENABLE_SNAPSHOT_SAVE) + - thrown error, otherwise. **Example** @@ -4266,13 +5081,19 @@ main (void) const jerry_char_t *args_p = (const jerry_char_t *) "a, b"; const jerry_char_t *src_p = (const jerry_char_t *) "return a + b;"; - size_t func_snapshot_size = jerry_parse_and_save_function_snapshot (src_p, - strlen ((const char *) src_p), - args_p, - strlen ((const char *) args_p), - false, - func_snapshot_buffer, - sizeof (func_snapshot_buffer) / sizeof (uint32_t)); + jerry_value_t generate_result; + generate_result = jerry_generate_function_snapshot (NULL, + 0, + src_p, + strlen ((const char *) src_p), + args_p, + strlen ((const char *) args_p), + 0, + func_snapshot_buffer, + sizeof (func_snapshot_buffer) / sizeof (uint32_t)); + + size_t snapshot_size = (size_t) jerry_get_number_value (generate_result); + jerry_release_value (generate_result); jerry_cleanup (); } @@ -4282,6 +5103,7 @@ main (void) - [jerry_init](#jerry_init) - [jerry_cleanup](#jerry_cleanup) +- [jerry_generate_snapshot](#jerry_generate_snapshot) - [jerry_load_function_snapshot_at](#jerry_load_function_snapshot_at) @@ -4300,15 +5122,14 @@ is no longer needed. jerry_value_t jerry_exec_snapshot (const uint32_t *snapshot_p, size_t snapshot_size, - bool copy_bytecode); + size_t func_index, + uint32_t exec_snapshot_opts); ``` - `snapshot_p` - pointer to snapshot - `snapshot_size` - size of snapshot -- `copy_bytecode` - flag, indicating whether the passed snapshot buffer should be copied to the - engine's memory. If set the engine should not reference the buffer after the function returns - (in this case, the passed buffer could be freed after the call). Otherwise (if the flag is not - set) - the buffer could only be freed after the engine stops (i.e. after call to jerry_cleanup). +- `func_index` - index of executed function +- `exec_snapshot_opts` - any combination of [jerry_exec_snapshot_opts_t](#jerry_exec_snapshot_opts_t) flags. - return value - result of bytecode, if run was successful - thrown error, otherwise @@ -4328,100 +5149,30 @@ main (void) const jerry_char_t *code_to_snapshot_p = (const jerry_char_t *) "(function () { return 'string from snapshot'; }) ();"; jerry_init (JERRY_INIT_EMPTY); - size_t global_mode_snapshot_size = jerry_parse_and_save_snapshot (code_to_snapshot_p, - strlen ((const char *) code_to_snapshot_p), - true, - false, - global_mode_snapshot_buffer, - sizeof (global_mode_snapshot_buffer) / sizeof (uint32_t)); - jerry_cleanup (); - - jerry_init (JERRY_INIT_EMPTY); - - jerry_value_t res = jerry_exec_snapshot (global_mode_snapshot_buffer, - global_mode_snapshot_size, - false); - jerry_release_value (res); - - jerry_cleanup (); -} -``` - -**See also** - -- [jerry_init](#jerry_init) -- [jerry_cleanup](#jerry_cleanup) -- [jerry_exec_snapshot_at](#jerry_exec_snapshot_at) -- [jerry_parse_and_save_snapshot](#jerry_parse_and_save_snapshot) - - -## jerry_exec_snapshot_at - -**Summary** - -Execute the selected snapshot function from the specified buffer. - -Same function as [jerry_exec_snapshot](#jerry_exec_snapshot) except -the executed function index can be specified. - -*Note*: Returned value must be freed with [jerry_release_value](#jerry_release_value) when it -is no longer needed. - -**Prototype** - -```c -jerry_value_t -jerry_exec_snapshot_at (const uint32_t *snapshot_p, - size_t snapshot_size, - size_t func_index, - bool copy_bytecode); -``` - -- `snapshot_p` - pointer to snapshot -- `snapshot_size` - size of snapshot -- `func_index` - index of executed function -- `copy_bytecode` - flag, indicating whether the passed snapshot buffer should be copied to the - engine's memory. If set the engine should not reference the buffer after the function returns - (in this case, the passed buffer could be freed after the call). Otherwise (if the flag is not - set) - the buffer could only be freed after the engine stops (i.e. after call to jerry_cleanup). -- return value - - result of bytecode, if run was successful - - thrown error, otherwise - -**Example** - -[doctest]: # () -```c -#include -#include "jerryscript.h" + jerry_value_t generate_result; + generate_result = jerry_generate_snapshot (NULL, + 0, + code_to_snapshot_p, + strlen ((const char *) code_to_snapshot_p), + 0, + global_mode_snapshot_buffer, + sizeof (global_mode_snapshot_buffer) / sizeof (uint32_t)); -int -main (void) -{ - static uint32_t global_mode_snapshot_buffer[256]; - const jerry_char_t *code_to_snapshot_p = (const jerry_char_t *) "(function () { return 'string from snapshot'; }) ();"; + size_t global_mode_snapshot_size = (size_t) jerry_get_number_value (generate_result); + jerry_release_value (generate_result); - jerry_init (JERRY_INIT_EMPTY); - size_t global_mode_snapshot_size = jerry_parse_and_save_snapshot (code_to_snapshot_p, - strlen ((const char *) code_to_snapshot_p), - true, - false, - global_mode_snapshot_buffer, - sizeof (global_mode_snapshot_buffer) / sizeof (uint32_t)); jerry_cleanup (); jerry_init (JERRY_INIT_EMPTY); - jerry_value_t res = jerry_exec_snapshot_at (global_mode_snapshot_buffer, - global_mode_snapshot_size, - 0, - false); - + jerry_value_t res = jerry_exec_snapshot (global_mode_snapshot_buffer, + global_mode_snapshot_size, + 0, + 0); jerry_release_value (res); jerry_cleanup (); - return 0; } ``` @@ -4429,11 +5180,10 @@ main (void) - [jerry_init](#jerry_init) - [jerry_cleanup](#jerry_cleanup) -- [jerry_exec_snapshot](#jerry_exec_snapshot) - [jerry_parse_and_save_snapshot](#jerry_parse_and_save_snapshot) -## jerry_load_function_snapshot_at +## jerry_load_function_snapshot **Summary** @@ -4448,19 +5198,16 @@ is no longer needed. ```c jerry_value_t -jerry_load_function_snapshot_at (const uint32_t *snapshot_p, - size_t snapshot_size, - size_t func_index, - bool copy_bytecode); +jerry_load_function_snapshot (const uint32_t *snapshot_p, + size_t snapshot_size, + size_t func_index, + uint32_t exec_snapshot_opts); ``` - `snapshot_p` - pointer to snapshot - `snapshot_size` - size of snapshot - `func_index` - index of function to load -- `copy_bytecode` - flag, indicating whether the passed snapshot buffer should be copied to the - engine's memory. If set the engine should not reference the buffer after the function returns - (in this case, the passed buffer could be freed after the call). Otherwise (if the flag is not - set) - the buffer could only be freed after the engine stops (i.e. after call to jerry_cleanup). +- `exec_snapshot_opts` - any combination of [jerry_exec_snapshot_opts_t](#jerry_exec_snapshot_opts_t) flags. - return value - function object built from the snapshot - thrown error, otherwise @@ -4481,21 +5228,29 @@ main (void) const jerry_char_t *src_p = (const jerry_char_t *) "return a + b;"; jerry_init (JERRY_INIT_EMPTY); - size_t snapshot_size = jerry_parse_and_save_function_snapshot (src_p, - strlen ((const char *) src_p), - args_p, - strlen ((const char *) args_p), - false, - snapshot_buffer, - sizeof (snapshot_buffer) / sizeof (uint32_t)); + + jerry_value_t generate_result; + generate_result = jerry_generate_function_snapshot (NULL, + 0, + src_p, + strlen ((const char *) src_p), + args_p, + strlen ((const char *) args_p), + false, + snapshot_buffer, + sizeof (snapshot_buffer) / sizeof (uint32_t)); + + size_t snapshot_size = (size_t) jerry_get_number_value (generate_result); + jerry_release_value (generate_result); + jerry_cleanup (); jerry_init (JERRY_INIT_EMPTY); - jerry_value_t func = jerry_load_function_snapshot_at (snapshot_buffer, - snapshot_size, - 0, - false); + jerry_value_t func = jerry_load_function_snapshot (snapshot_buffer, + snapshot_size, + 0, + 0); /* 'func' can be used now as a function object */ jerry_value_t this_value = jerry_create_undefined (); @@ -4665,7 +5420,7 @@ main (void) // Inifinte loop. const char *src_p = "while(true) {}"; - jerry_value_t src = jerry_parse ((jerry_char_t *) src_p, strlen (src_p), false); + jerry_value_t src = jerry_parse (NULL, 0, (jerry_char_t *) src_p, strlen (src_p), JERRY_PARSE_NO_OPTS); jerry_release_value (jerry_run (src)); jerry_release_value (src); jerry_cleanup (); @@ -4679,3 +5434,455 @@ main (void) - [jerry_parse](#jerry_parse) - [jerry_run](#jerry_run) - [jerry_vm_exec_stop_callback_t](#jerry_vm_exec_stop_callback_t) + +## jerry_get_backtrace + +**Summary** + +Get backtrace. The backtrace is an array of strings where +each string contains the position of the corresponding frame. +The array length is zero if the backtrace is not available. + +This function is typically called from native callbacks. + +**Prototype** + +```c +jerry_value_t +jerry_get_backtrace (uint32_t max_depth); +``` + +- `max_depth` - backtrace collection stops after reaching this value, 0 = unlimited +- return value + - a new array + +**See also** + +- [jerry_create_external_function](#jerry_create_external_function) + + +# ArrayBuffer and TypedArray functions + +## jerry_get_arraybuffer_byte_length + +**Summary** + +Get the byte length property of the ArrayBuffer. This is the +same value which was passed to the ArrayBuffer constructor call. + +**Prototype** + +```c +jerry_length_t +jerry_get_arraybuffer_byte_length (const jerry_value_t value); +``` + +- `value` - ArrayBuffer object +- return value + - size of the ArrayBuffer in bytes + - 0 if the `value` parameter is not an ArrayBuffer + +**Example** + +```c +{ + jerry_value_t buffer = jerry_create_arraybuffer (15); + jerry_length_t length = jerry_get_arraybuffer_byte_length (buffer); + // length should be 15 + + jerry_release_value (buffer); +} +``` + +**See also** +- [jerry_create_arraybuffer](#jerry_create_arraybuffer) + + +## jerry_arraybuffer_read + +**Summary** + +Copy the portion of the ArrayBuffer into a user provided buffer. +The start offset of the read operation can be specified. + +The number bytes to be read can be specified via the `buf_size` +parameter. It is not possible to read more than the length of +the ArrayBuffer. + +Function returns the number of bytes read from the ArrayBuffer +(and written to the buffer parameter). This value is +calculated in the following way: `min(array buffer length - offset, buf_size)`. + +**Prototype** + +```c +jerry_length_t +jerry_arraybuffer_read (const jerry_value_t value, + jerry_length_t offset, + uint8_t *buf_p, + jerry_length_t buf_size); +``` + +- `value` - ArrayBuffer to read from +- `offset` - start offset of the read operation +- `buf_p` - buffer to read the data to +- `buf_size` - maximum number of bytes to read into the buffer +- return value + - number of bytes written into the buffer (read from the ArrayBuffer) + - 0 if the `value` is not an ArrayBuffer object + - 0 if the `buf_size` is zero or there is nothing to read + +**Example** + +```c +{ + uint8_t data[20]; + jerry_value_t buffer; + // ... create the ArrayBuffer or acuiqre it from somewhere. + + jerry_value_t bytes_read; + + // read 10 bytes from the start of the ArrayBuffer. + bytes_read = jerry_arraybuffer_read (buffer, 0, data, 10); + // read the next 10 bytes + bytes_read += jerry_arraybuffer_read (buffer, bytes_read, data + bytes_read, 10); + + // process the data variable + + jerry_release_value (buffer); +} +``` + +**See also** + +- [jerry_create_arraybuffer](#jerry_create_arraybuffer) +- [jerry_arraybuffer_write](#jerry_arraybuffer_write) +- [jerry_get_arraybuffer_byte_length](#jerry_get_arraybuffer_byte_length) + + +## jerry_arraybuffer_write + +**Summary** + +Copy the contents of a buffer into the ArrayBuffer. +The start offset of the write operation can be specified. + +The number bytes to be written can be specified via the `buf_size` +parameter. It is not possible to write more than the length of +the ArrayBuffer. + +Function returns the number of bytes written into the ArrayBuffer +(and read from the buffer parameter). This value is +calculated in the following way: `min(array buffer length - offset, buf_size)`. + +**Prototype** + +```c +jerry_length_t +jerry_arraybuffer_write (const jerry_value_t value, + jerry_length_t offset, + const uint8_t *buf_p, + jerry_length_t buf_size); +``` + +- `value` - ArrayBuffer to write to +- `offset` - start offset of the write operation +- `buf_p` - buffer to read the data from +- `buf_size` - maximum number of bytes to write into the ArrayBuffer +- return value + - number of bytes written into the ArrayBuffer (read from the buffer parameter) + - 0 if the `value` is not an ArrayBuffer object + - 0 if the `buf_size` is zero or there is nothing to write + +**Example** + +```c +{ + uint8_t data[20]; + + // fill the data with values + for (int i = 0; i < 20; i++) + { + data[i] = (uint8_t) (i * 2); + } + + jerry_value_t buffer; + // ... create the ArrayBuffer or acquire it from somewhere. + + jerry_value_t bytes_written; + + // write 10 bytes from to the start of the ArrayBuffer. + bytes_written = jerry_arraybuffer_write (buffer, 0, data, 10); + // read the next 10 bytes + bytes_written += jerry_arraybuffer_write (buffer, bytes_written, data + bytes_written, 10); + + // use the ArrayBuffer + + jerry_release_value (buffer); +} +``` + +**See also** + +- [jerry_create_arraybuffer](#jerry_create_arraybuffer) +- [jerry_arraybuffer_write](#jerry_arraybuffer_write) +- [jerry_get_arraybuffer_byte_length](#jerry_get_arraybuffer_byte_length) + + +## jerry_get_arraybuffer_pointer + +**Summary** + +The function allows access to the contents of the Array Buffer directly. +Only allowed for Array Buffers which were created with +[jerry_create_arraybuffer_external](#jerry_create_arraybuffer_external) +function calls. In any other case this function will return `NULL`. + +After using the pointer the [jerry_release_value](#jerry_release_value) +function must be called. + +**WARNING!** This operation is for expert use only! The programmer must +ensure that the returned memory area is used correctly. That is +there is no out of bounds reads or writes. + +**Prototype** + +```c +uint8_t * +jerry_get_arraybuffer_pointer (const jerry_value_t value); +``` + +- `value` - Array Buffer object. +- return value + - pointer to the Array Buffer's data area. + - NULL if the `value` is not an Array Buffer object with external memory. + +**Example** + +```c +{ + jerry_value_t buffer; + + // acquire buffer somewhere which was created by a jerry_create_array_buffer_external call. + + uint8_t *const data = jerry_get_arraybuffer_pointer (buffer); + + for (int i = 0; i < 22; i++) + { + data[i] = (uint8_t) (i + 4); + } + + // required after jerry_get_arraybuffer_pointer call. + jerry_release_value (buffer); + + // use the Array Buffer + + // release buffer as it is not needed after this point + jerry_release_value (buffer); +} +``` + +**See also** + +- [jerry_create_arraybuffer_external](#jerry_create_arraybuffer_external) + + +## jerry_get_typedarray_type + +**Summary** + +Get the type of the TypedArray. + +The returned type is one of the [jerry_typedarray_type_t](#jerry_typedarray_type_t) +enum value. + +**Prototype** + +```c +jerry_typedarray_type_t +jerry_get_typedarray_type (jerry_value_t value); +``` + +- `value` - TypedArray object to query for type. +- return + - the type of the TypedArray + - JERRY_TYPEDARRAY_INVALID if the object was not a TypedArray + +**Example** + +```c +{ + jerry_typedarray_type_t expected_type = JERRY_TYPEDARRAY_UINT32; + jerry_value_t typedarray = jerry_create_typedarray (expected_klass, 25); + + jerry_typedarray_type_t type = jerry_get_typedarray_type (typedarray); + + // 'type' is now JERRY_TYPEDARRAY_UINT32 + + jerry_release_value (typedarray); +} +``` + +**See also** + +- [jerry_create_typedarray](#jerry_create_typedarray) +- [jerry_typedarray_type_t](#jerry_typedarray_type_t) + + +## jerry_get_typedarray_length + +**Summary** + +Get the element count of the TypedArray as specified during creation. + +This is not the same as the byteLength property of a TypedArray object. + +**Prototype** + +``` +jerry_length_t +jerry_get_typedarray_length (jerry_value_t value); +``` + +- `value` - TypedArray object to query +- return + - length (element count) of the TypedArray object + - 0 if the object is not a TypedArray + +**Example** + +```c +{ + jerry_value_t array = jerry_create_typedarray (JERRY_TYPEDARRAY_INT32, 21); + + jerry_length_t element_count = jerry_get_typedarray_length (array); + + // element_count is now 21. + + jerry_release_value (array); +} +``` + +**See also** + +- [jerry_create_typedarray](#jerry_create_typedarray) + + +## jerry_get_typedarray_buffer + +**Summary** + +Get the ArrayBuffer object used by a TypedArray object. +Additionally returns the byteLength and byteOffset properties +of the TypedArray object. + +For the returned ArrayBuffer the [jerry_release_value](#jerry_release_value) +must be called. + +**Prototype** + +```c +jerry_value_t jerry_get_typedarray_buffer (jerry_value_t value, + jerry_length_t *byteOffset, + jerry_length_t *byteLength); +``` + +- `value` - TypedArray to get the ArrayBuffer from +- `byteOffset` - (Optional) returns the start offset of the ArrayBuffer for the TypedArray +- `byteLength` - (Optional) returns the number of bytes used from the ArrayBuffer for the TypedArray +- return + - TypedArray object's underlying ArrayBuffer object + - TypeError if the `value` is not a TypedArray object + +**Example** + +```c +{ + jerry_value_t array = jerry_create_typedarray (JERRY_TYPEDARRAY_INT16, 11); + + jerry_length_t byteLength = 0; + jerry_length_t byteOffset = 0; + jerry_value_t buffer = jerry_get_typedarray_buffer (array, &byteOffset, &byteLength); + + // buffer is an ArrayBuffer object and ArrayBuffer operations can be performed on it + // byteLength is 11 * 2 (2 as the TypedArray stores Int16 that is 2 byte elements) + // byteOffset is 0 + + jerry_release_value (buffer); + jerry_release_value (array); +} +``` + +**See also** + +- [jerry_create_typedarray](#jerry_create_typedarray) + +# JSON functions + +## jerry_json_parse + +**Summary** + +Returns the same result as JSON.parse ecmascript function. + +**Prototype** + +```c +jerry_value_t jerry_json_parse (const jerry_char_t *string_p, jerry_size_t string_size) +``` + +- `string_p` - a JSON string +- `string_size` - size of the string +- return + - jerry_value_t containing the same as json.parse() + - jerry_value_t containing error massage + +**Example** + +```c +{ + const char *data = "{\"name\": \"John\", \"age\": 5}"; + jerry_size_t str_length = (jerry_size_t)strlen (data); + jerry_value_t parsed_json = jerry_json_parse ((jerry_char_t*)data, str_length); + + // parsed_json now conatins all data stored in data_in_json + + jerry_release_value (parsed_json); +} +``` + +## jerry_stringify + + **Summary** + + Returns the same value as JSON.stringify() ecmascript function. + + **Prototype** + +```c +jerry_value_t jerry_json_stringfy (const jerry_value_t object_to_stringify) +``` + +- `object_to_stringify` - a jerry_value_t object to stringify +- return + - jerry_value_t containing the same as json.stringify() + - jerry_value_t containing error massage + +**Example** + +```c +{ + jerry_value_t obj = jerry_create_object (); + jerry_value_t key = jerry_create_string ((const jerry_char_t *) "name"); + jerry_value_t value = jerry_create_string ((const jerry_char_t *) "John"); + jerry_set_property (obj, key, value); + jerry_value_t stringified = jerry_json_stringfy (obj); + + //stringified now contains a json formated string + + jerry_release_value (obj); + jerry_release_value (key); + jerry_release_value (value); + jerry_release_value (stringified); +} +``` \ No newline at end of file diff --git a/deps/jerry/docs/03.API-EXAMPLE.md b/deps/jerry/docs/03.API-EXAMPLE.md index e5ca6da..fc691a0 100644 --- a/deps/jerry/docs/03.API-EXAMPLE.md +++ b/deps/jerry/docs/03.API-EXAMPLE.md @@ -55,7 +55,7 @@ main (void) jerryx_handler_print); /* Setup Global scope code */ - jerry_value_t parsed_code = jerry_parse (script, script_size, false); + jerry_value_t parsed_code = jerry_parse (NULL, 0, script, script_size, JERRY_PARSE_NO_OPTS); if (!jerry_value_has_error_flag (parsed_code)) { diff --git a/deps/jerry/docs/04.INTERNALS.md b/deps/jerry/docs/04.INTERNALS.md index 45d3a26..4e9038a 100644 --- a/deps/jerry/docs/04.INTERNALS.md +++ b/deps/jerry/docs/04.INTERNALS.md @@ -31,7 +31,7 @@ The interactions between the major components shown on the following figure. # Byte-code -This section describes the compact byte-code (CBC) byte-code representation. The key focus is reducing memory consumption of the byte-code representation without sacrificing considerable performance. Other byte-code representations often focus on performance only so inventing this representation is an original research. +This section describes the compact byte-code (CBC) representation. The key focus is reducing memory consumption of the byte-code representation without sacrificing considerable performance. Other byte-code representations often focus on performance only so inventing this representation is an original research. CBC is a CISC like instruction set which assigns shorter instructions for frequent operations. Many instructions represent multiple atomic tasks which reduces the byte code size. This technique is basically a data compression method. diff --git a/deps/jerry/docs/05.PORT-API.md b/deps/jerry/docs/05.PORT-API.md index 4974d54..69f7337 100644 --- a/deps/jerry/docs/05.PORT-API.md +++ b/deps/jerry/docs/05.PORT-API.md @@ -112,6 +112,15 @@ Allow user to provide external buffer for jerry instance (which includes an isol struct jerry_instance_t *jerry_port_get_current_instance (void); ``` +## Sleep + +```c +/** + * Makes the process sleep for a given time. + */ +void jerry_port_sleep (uint32_t sleep_time); +``` + # How to port JerryScript This section describes a basic port implementation which was created for Unix based systems. @@ -231,3 +240,32 @@ jerry_port_get_current_instance (void) return current_instance_p; } /* jerry_port_get_current_instance */ ``` + +## Sleep + +```c +#include "jerryscript-port.h" +#include "jerryscript-port-default.h" + +#ifdef HAVE_TIME_H +#include +#elif defined (HAVE_UNISTD_H) +#include +#endif /* HAVE_TIME_H */ + +#ifdef JERRY_DEBUGGER +void jerry_port_sleep (uint32_t sleep_time) +{ +#ifdef HAVE_TIME_H + nanosleep (&(const struct timespec) + { + sleep_time / 1000, (sleep_time % 1000) * 1000000L /* Seconds, nanoseconds */ + } + , NULL); +#elif defined (HAVE_UNISTD_H) + usleep ((useconds_t) sleep_time * 1000); +#endif /* HAVE_TIME_H */ + (void) sleep_time; +} /* jerry_port_sleep */ +#endif /* JERRY_DEBUGGER */ +``` diff --git a/deps/jerry/docs/07.DEBUGGER.md b/deps/jerry/docs/07.DEBUGGER.md index 3249d02..84653f2 100644 --- a/deps/jerry/docs/07.DEBUGGER.md +++ b/deps/jerry/docs/07.DEBUGGER.md @@ -69,14 +69,9 @@ The debugger can be enabled by calling the `jerry_debugger_init (uint16_t port)` function after the `jerry_init ()` function. It initializes the debugger and blocks until a client connects. -When the debugger is enabled it is recommended to use -`jerry_parse_named_resource ()` instead of `jerry_parse ()` because -the resource name (usually a file name) is also passed to this -function. This resource name is used by the client to identify -the corresponding resource. In general it is always recommended to -use `jerry_parse_named_resource ()` when the resource name is -available because it silently ignores the resource name if the -debugger is disabled. +The resource name provided to `jerry_parse ()` is used by the client +to identify the resource name of the source code. This resource name +is usually a file name. ## JerryScript debugger C-API interface @@ -304,11 +299,11 @@ wait_for_source_callback (const jerry_char_t *resource_name_p, /**< resource nam size_t source_size, /**< source code size */ void *user_p __attribute__((unused))) /**< user pointer */ { - jerry_value_t ret_val = jerry_parse_named_resource (resource_name_p, - resource_name_size, - source_p, - source_size, - false); + jerry_value_t ret_val = jerry_parse (resource_name_p, + resource_name_size, + source_p, + source_size, + JERRY_PARSE_NO_OPTS); if (!jerry_value_has_error_flag (ret_val)) { diff --git a/deps/jerry/docs/08.CODING-STANDARDS.md b/deps/jerry/docs/08.CODING-STANDARDS.md index 46fa983..6fc43bb 100644 --- a/deps/jerry/docs/08.CODING-STANDARDS.md +++ b/deps/jerry/docs/08.CODING-STANDARDS.md @@ -704,7 +704,7 @@ typedef struct /* Field descriptions do not start with capital letters * and there is no full stop at the end. */ field1_t field1; /**< description of field 1 */ - field2_t field2; /**< description of field 1 */ + field2_t field2; /**< description of field 2 */ field_n_t field_n; /**< description of field n */ } structure_name_t; diff --git a/deps/jerry/jerry-core/CMakeLists.txt b/deps/jerry/jerry-core/CMakeLists.txt index 1368895..dff2438 100644 --- a/deps/jerry/jerry-core/CMakeLists.txt +++ b/deps/jerry/jerry-core/CMakeLists.txt @@ -17,23 +17,25 @@ set(JERRY_CORE_NAME jerry-core) project (${JERRY_CORE_NAME} C) # Optional features -set(FEATURE_CPOINTER_32_BIT OFF CACHE BOOL "Enable 32 bit compressed pointers?") -set(FEATURE_DEBUGGER OFF CACHE BOOL "Enable JerryScript debugger?") -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?") -set(FEATURE_PARSER_DUMP OFF CACHE BOOL "Enable parser byte-code dumps?") -set(FEATURE_PROFILE "es5.1" CACHE STRING "Use default or other profile?") -set(FEATURE_REGEXP_DUMP OFF CACHE BOOL "Enable regexp byte-code dumps?") -set(FEATURE_SNAPSHOT_EXEC OFF CACHE BOOL "Enable executing snapshot files?") -set(FEATURE_SNAPSHOT_SAVE OFF CACHE BOOL "Enable saving snapshot files?") -set(FEATURE_SYSTEM_ALLOCATOR OFF CACHE BOOL "Enable system allocator?") -set(FEATURE_VALGRIND OFF CACHE BOOL "Enable Valgrind support?") -set(FEATURE_VALGRIND_FREYA OFF CACHE BOOL "Enable Valgrind-Freya support?") -set(FEATURE_VM_EXEC_STOP OFF CACHE BOOL "Enable VM execution stopping?") -set(MEM_HEAP_SIZE_KB "512" CACHE STRING "Size of memory heap, in kilobytes") +set(FEATURE_CPOINTER_32_BIT OFF CACHE BOOL "Enable 32 bit compressed pointers?") +set(FEATURE_DEBUGGER OFF CACHE BOOL "Enable JerryScript debugger?") +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_LINE_INFO OFF CACHE BOOL "Enable line info?") +set(FEATURE_MEM_STATS OFF CACHE BOOL "Enable memory statistics?") +set(FEATURE_MEM_STRESS_TEST OFF CACHE BOOL "Enable mem-stress test?") +set(FEATURE_PARSER_DUMP OFF CACHE BOOL "Enable parser byte-code dumps?") +set(FEATURE_PROFILE "es5.1" CACHE STRING "Use default or other profile?") +set(FEATURE_REGEXP_STRICT_MODE OFF CACHE BOOL "Enable regexp strict mode?") +set(FEATURE_REGEXP_DUMP OFF CACHE BOOL "Enable regexp byte-code dumps?") +set(FEATURE_SNAPSHOT_EXEC OFF CACHE BOOL "Enable executing snapshot files?") +set(FEATURE_SNAPSHOT_SAVE OFF CACHE BOOL "Enable saving snapshot files?") +set(FEATURE_SYSTEM_ALLOCATOR OFF CACHE BOOL "Enable system allocator?") +set(FEATURE_VALGRIND OFF CACHE BOOL "Enable Valgrind support?") +set(FEATURE_VALGRIND_FREYA OFF CACHE BOOL "Enable Valgrind-Freya support?") +set(FEATURE_VM_EXEC_STOP OFF CACHE BOOL "Enable VM execution stopping?") +set(MEM_HEAP_SIZE_KB "512" CACHE STRING "Size of memory heap, in kilobytes") # Option overrides if(FEATURE_SYSTEM_ALLOCATOR) @@ -57,23 +59,25 @@ if(JERRY_CMDLINE_SNAPSHOT) endif() # Status messages -message(STATUS "FEATURE_CPOINTER_32_BIT " ${FEATURE_CPOINTER_32_BIT} ${FEATURE_CPOINTER_32_BIT_MESSAGE}) -message(STATUS "FEATURE_DEBUGGER " ${FEATURE_DEBUGGER}) -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}) -message(STATUS "FEATURE_PARSER_DUMP " ${FEATURE_PARSER_DUMP} ${FEATURE_PARSER_DUMP_MESSAGE}) -message(STATUS "FEATURE_PROFILE " ${FEATURE_PROFILE}) -message(STATUS "FEATURE_REGEXP_DUMP " ${FEATURE_REGEXP_DUMP}) -message(STATUS "FEATURE_SNAPSHOT_EXEC " ${FEATURE_SNAPSHOT_EXEC} ${FEATURE_SNAPSHOT_EXEC_MESSAGE}) -message(STATUS "FEATURE_SNAPSHOT_SAVE " ${FEATURE_SNAPSHOT_SAVE} ${FEATURE_SNAPSHOT_SAVE_MESSAGE}) -message(STATUS "FEATURE_SYSTEM_ALLOCATOR " ${FEATURE_SYSTEM_ALLOCATOR}) -message(STATUS "FEATURE_VALGRIND " ${FEATURE_VALGRIND}) -message(STATUS "FEATURE_VALGRIND_FREYA " ${FEATURE_VALGRIND_FREYA}) -message(STATUS "FEATURE_VM_EXEC_STOP " ${FEATURE_VM_EXEC_STOP}) -message(STATUS "MEM_HEAP_SIZE_KB " ${MEM_HEAP_SIZE_KB}) +message(STATUS "FEATURE_CPOINTER_32_BIT " ${FEATURE_CPOINTER_32_BIT} ${FEATURE_CPOINTER_32_BIT_MESSAGE}) +message(STATUS "FEATURE_DEBUGGER " ${FEATURE_DEBUGGER}) +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_LINE_INFO " ${FEATURE_LINE_INFO}) +message(STATUS "FEATURE_MEM_STATS " ${FEATURE_MEM_STATS}) +message(STATUS "FEATURE_MEM_STRESS_TEST " ${FEATURE_MEM_STRESS_TEST}) +message(STATUS "FEATURE_PARSER_DUMP " ${FEATURE_PARSER_DUMP} ${FEATURE_PARSER_DUMP_MESSAGE}) +message(STATUS "FEATURE_PROFILE " ${FEATURE_PROFILE}) +message(STATUS "FEATURE_REGEXP_STRICT_MODE " ${FEATURE_REGEXP_STRICT_MODE}) +message(STATUS "FEATURE_REGEXP_DUMP " ${FEATURE_REGEXP_DUMP}) +message(STATUS "FEATURE_SNAPSHOT_EXEC " ${FEATURE_SNAPSHOT_EXEC} ${FEATURE_SNAPSHOT_EXEC_MESSAGE}) +message(STATUS "FEATURE_SNAPSHOT_SAVE " ${FEATURE_SNAPSHOT_SAVE} ${FEATURE_SNAPSHOT_SAVE_MESSAGE}) +message(STATUS "FEATURE_SYSTEM_ALLOCATOR " ${FEATURE_SYSTEM_ALLOCATOR}) +message(STATUS "FEATURE_VALGRIND " ${FEATURE_VALGRIND}) +message(STATUS "FEATURE_VALGRIND_FREYA " ${FEATURE_VALGRIND_FREYA}) +message(STATUS "FEATURE_VM_EXEC_STOP " ${FEATURE_VM_EXEC_STOP}) +message(STATUS "MEM_HEAP_SIZE_KB " ${MEM_HEAP_SIZE_KB}) # Include directories set(INCLUDE_CORE @@ -172,6 +176,11 @@ if(NOT FEATURE_JS_PARSER) set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_DISABLE_JS_PARSER) endif() +# JS line info +if(FEATURE_LINE_INFO) + set(DEFINES_JERRY ${DEFINES_JERRY} JERRY_ENABLE_LINE_INFO) +endif() + # Memory statistics if(FEATURE_MEM_STATS) set(DEFINES_JERRY ${DEFINES_JERRY} JMEM_STATS) @@ -224,6 +233,11 @@ 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 strict mode +if(FEATURE_REGEXP_STRICT_MODE) + set(DEFINES_JERRY ${DEFINES_JERRY} ENABLE_REGEXP_STRICT_MODE) +endif() + # RegExp byte-code dumps if(FEATURE_REGEXP_DUMP) set(DEFINES_JERRY ${DEFINES_JERRY} REGEXP_DUMP_BYTE_CODE) diff --git a/deps/jerry/jerry-core/api/jerry-debugger.c b/deps/jerry/jerry-core/api/jerry-debugger.c index 0e9802f..627727b 100644 --- a/deps/jerry/jerry-core/api/jerry-debugger.c +++ b/deps/jerry/jerry-core/api/jerry-debugger.c @@ -43,7 +43,7 @@ jerry_debugger_stop (void) if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE)) { - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_STOP); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = NULL; } #endif /* JERRY_DEBUGGER */ @@ -59,7 +59,7 @@ jerry_debugger_continue (void) if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE)) { - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_VM_STOP); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = NULL; } #endif /* JERRY_DEBUGGER */ @@ -77,11 +77,11 @@ jerry_debugger_stop_at_breakpoint (bool enable_stop_at_breakpoint) /**< enable/d { if (enable_stop_at_breakpoint) { - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_IGNORE); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_IGNORE); } else { - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_VM_IGNORE); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_IGNORE); } } #else /* !JERRY_DEBUGGER */ @@ -122,7 +122,7 @@ jerry_debugger_wait_for_client_source (jerry_debugger_wait_for_source_callback_t if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) && !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_BREAKPOINT_MODE)) { - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_CLIENT_SOURCE_MODE); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_CLIENT_SOURCE_MODE); jerry_debugger_uint8_data_t *client_source_data_p = NULL; jerry_debugger_wait_for_source_status_t ret_type = JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED; @@ -142,8 +142,7 @@ jerry_debugger_wait_for_client_source (jerry_debugger_wait_for_source_callback_t if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONTEXT_RESET_MODE)) { ret_type = JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED; - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) - & ~JERRY_DEBUGGER_CONTEXT_RESET_MODE); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_CONTEXT_RESET_MODE); break; } @@ -151,8 +150,7 @@ jerry_debugger_wait_for_client_source (jerry_debugger_wait_for_source_callback_t if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CLIENT_NO_SOURCE)) { ret_type = JERRY_DEBUGGER_SOURCE_END; - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) - & ~JERRY_DEBUGGER_CLIENT_SOURCE_MODE); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_CLIENT_SOURCE_MODE); break; } diff --git a/deps/jerry/jerry-core/api/jerry-snapshot.c b/deps/jerry/jerry-core/api/jerry-snapshot.c index e67dc73..d9afd12 100644 --- a/deps/jerry/jerry-core/api/jerry-snapshot.c +++ b/deps/jerry/jerry-core/api/jerry-snapshot.c @@ -13,15 +13,16 @@ * limitations under the License. */ +#include "ecma-conversion.h" #include "ecma-exceptions.h" #include "ecma-function-object.h" #include "ecma-helpers.h" +#include "ecma-lex-env.h" #include "ecma-literal-storage.h" #include "jcontext.h" #include "jerryscript.h" #include "jerry-snapshot.h" #include "js-parser.h" -#include "ecma-lex-env.h" #include "lit-char-helpers.h" #include "re-compiler.h" @@ -74,7 +75,7 @@ snapshot_check_global_flags (uint32_t global_flags) /**< global flags */ typedef struct { size_t snapshot_buffer_write_offset; - bool snapshot_error_occured; + ecma_value_t snapshot_error; bool regex_found; } snapshot_globals_t; @@ -111,33 +112,44 @@ snapshot_write_to_buffer_by_offset (uint8_t *buffer_p, /**< buffer */ } /* snapshot_write_to_buffer_by_offset */ /** - * Snapshot callback for byte codes. + * Maximum snapshot write buffer offset. + */ +#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT32 +#define JERRY_SNAPSHOT_MAXIMUM_WRITE_OFFSET (0x7fffff >> 1) +#else +#define JERRY_SNAPSHOT_MAXIMUM_WRITE_OFFSET (UINT32_MAX >> 1) +#endif + +/** + * Save snapshot helper. * * @return start offset */ -static uint16_t +static uint32_t snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled code */ uint8_t *snapshot_buffer_p, /**< snapshot buffer */ size_t snapshot_buffer_size, /**< snapshot buffer size */ snapshot_globals_t *globals_p) /**< snapshot globals */ { - if (globals_p->snapshot_error_occured) + const jerry_char_t *error_buffer_too_small_p = (const jerry_char_t *) "Snapshot buffer too small."; + + if (!ecma_is_value_empty (globals_p->snapshot_error)) { return 0; } JERRY_ASSERT ((globals_p->snapshot_buffer_write_offset & (JMEM_ALIGNMENT - 1)) == 0); - if ((globals_p->snapshot_buffer_write_offset >> JMEM_ALIGNMENT_LOG) > 0xffffu) + if (globals_p->snapshot_buffer_write_offset > JERRY_SNAPSHOT_MAXIMUM_WRITE_OFFSET) { - globals_p->snapshot_error_occured = true; + const char *error_message_p = "Maximum snapshot size reached."; + globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p); return 0; } /* The snapshot generator always parses a single file, * so the base always starts right after the snapshot header. */ - size_t buffer_offset = globals_p->snapshot_buffer_write_offset - sizeof (jerry_snapshot_header_t); - uint16_t start_offset = (uint16_t) (buffer_offset >> JMEM_ALIGNMENT_LOG); + uint32_t start_offset = (uint32_t) (globals_p->snapshot_buffer_write_offset - sizeof (jerry_snapshot_header_t)); uint8_t *copied_code_start_p = snapshot_buffer_p + globals_p->snapshot_buffer_write_offset; ecma_compiled_code_t *copied_code_p = (ecma_compiled_code_t *) copied_code_start_p; @@ -148,15 +160,14 @@ snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled /* Regular expression. */ if (globals_p->snapshot_buffer_write_offset + sizeof (ecma_compiled_code_t) > snapshot_buffer_size) { - globals_p->snapshot_error_occured = true; + globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, error_buffer_too_small_p); return 0; } globals_p->snapshot_buffer_write_offset += sizeof (ecma_compiled_code_t); - jmem_cpointer_t pattern_cp = ((re_compiled_code_t *) compiled_code_p)->pattern_cp; - ecma_string_t *pattern_string_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, - pattern_cp); + ecma_value_t pattern = ((re_compiled_code_t *) compiled_code_p)->pattern; + ecma_string_t *pattern_string_p = ecma_get_string_from_value (pattern); ecma_length_t pattern_size = 0; @@ -170,11 +181,17 @@ snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled buffer_p, buffer_size)) { - globals_p->snapshot_error_occured = true; + globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, error_buffer_too_small_p); + /* cannot return inside ECMA_FINALIZE_UTF8_STRING */ } ECMA_FINALIZE_UTF8_STRING (buffer_p, buffer_size); + if (!ecma_is_value_empty (globals_p->snapshot_error)) + { + return 0; + } + globals_p->regex_found = true; globals_p->snapshot_buffer_write_offset = JERRY_ALIGNUP (globals_p->snapshot_buffer_write_offset, JMEM_ALIGNMENT); @@ -199,57 +216,211 @@ snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled compiled_code_p, ((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG)) { - globals_p->snapshot_error_occured = true; + globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, error_buffer_too_small_p); return 0; } /* Sub-functions and regular expressions are stored recursively. */ - uint8_t *src_buffer_p = (uint8_t *) compiled_code_p; - uint8_t *dst_buffer_p = (uint8_t *) copied_code_p; - jmem_cpointer_t *src_literal_start_p; - jmem_cpointer_t *dst_literal_start_p; + uint8_t *buffer_p = (uint8_t *) copied_code_p; + ecma_value_t *literal_start_p; uint32_t const_literal_end; uint32_t literal_end; if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { - src_literal_start_p = (jmem_cpointer_t *) (src_buffer_p + sizeof (cbc_uint16_arguments_t)); - dst_literal_start_p = (jmem_cpointer_t *) (dst_buffer_p + sizeof (cbc_uint16_arguments_t)); + literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint16_arguments_t)); - cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) src_buffer_p; - literal_end = args_p->literal_end; - const_literal_end = args_p->const_literal_end; + cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p; + literal_end = (uint32_t) (args_p->literal_end - args_p->register_end); + const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end); } else { - src_literal_start_p = (jmem_cpointer_t *) (src_buffer_p + sizeof (cbc_uint8_arguments_t)); - dst_literal_start_p = (jmem_cpointer_t *) (dst_buffer_p + sizeof (cbc_uint8_arguments_t)); + literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint8_arguments_t)); - cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) src_buffer_p; - literal_end = args_p->literal_end; - const_literal_end = args_p->const_literal_end; + cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p; + literal_end = (uint32_t) (args_p->literal_end - args_p->register_end); + const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end); } for (uint32_t i = const_literal_end; i < literal_end; i++) { - ecma_compiled_code_t *bytecode_p = ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, - src_literal_start_p[i]); + ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, + literal_start_p[i]); if (bytecode_p == compiled_code_p) { - dst_literal_start_p[i] = start_offset; + literal_start_p[i] = 0; } else { - dst_literal_start_p[i] = snapshot_add_compiled_code (bytecode_p, + uint32_t offset = snapshot_add_compiled_code (bytecode_p, + snapshot_buffer_p, + snapshot_buffer_size, + globals_p); + + JERRY_ASSERT (!ecma_is_value_empty (globals_p->snapshot_error) || offset > start_offset); + + literal_start_p[i] = offset - start_offset; + } + } + + return start_offset; +} /* snapshot_add_compiled_code */ + +/** + * Create unsupported literal error. + */ +static void +static_snapshot_error_unsupported_literal (snapshot_globals_t *globals_p, /**< snapshot globals */ + ecma_value_t literal) /**< literal form the literal pool */ +{ + const char *error_prefix_p = "Unsupported static snapshot literal: "; + + ecma_string_t *error_message_p = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *) error_prefix_p, + (lit_utf8_size_t) strlen (error_prefix_p)); + + literal = ecma_op_to_string (literal); + JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (literal)); + + ecma_string_t *literal_string_p = ecma_get_string_from_value (literal); + error_message_p = ecma_concat_ecma_strings (error_message_p, literal_string_p); + ecma_deref_ecma_string (literal_string_p); + + ecma_object_t *error_object_p = ecma_new_standard_error_with_message (ECMA_ERROR_RANGE, error_message_p); + ecma_deref_ecma_string (error_message_p); + + globals_p->snapshot_error = ecma_create_error_object_reference (error_object_p); +} /* static_snapshot_error_unsupported_literal */ + +/** + * Save static snapshot helper. + * + * @return start offset + */ +static uint32_t +static_snapshot_add_compiled_code (ecma_compiled_code_t *compiled_code_p, /**< compiled code */ + uint8_t *snapshot_buffer_p, /**< snapshot buffer */ + size_t snapshot_buffer_size, /**< snapshot buffer size */ + snapshot_globals_t *globals_p) /**< snapshot globals */ +{ + if (!ecma_is_value_empty (globals_p->snapshot_error)) + { + return 0; + } + + JERRY_ASSERT ((globals_p->snapshot_buffer_write_offset & (JMEM_ALIGNMENT - 1)) == 0); + + if (globals_p->snapshot_buffer_write_offset >= JERRY_SNAPSHOT_MAXIMUM_WRITE_OFFSET) + { + const char *error_message_p = "Maximum snapshot size reached."; + globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p); + return 0; + } + + /* The snapshot generator always parses a single file, + * so the base always starts right after the snapshot header. */ + uint32_t start_offset = (uint32_t) (globals_p->snapshot_buffer_write_offset - sizeof (jerry_snapshot_header_t)); + + uint8_t *copied_code_start_p = snapshot_buffer_p + globals_p->snapshot_buffer_write_offset; + ecma_compiled_code_t *copied_code_p = (ecma_compiled_code_t *) copied_code_start_p; + + if (!(compiled_code_p->status_flags & CBC_CODE_FLAGS_FUNCTION)) + { + /* Regular expression literals are not supported. */ + const char *error_message_p = "Regular expression literals are not supported."; + globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p); + return 0; + } + + if (!snapshot_write_to_buffer_by_offset (snapshot_buffer_p, + snapshot_buffer_size, + &globals_p->snapshot_buffer_write_offset, + compiled_code_p, + ((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG)) + { + const char *error_message_p = "Snapshot buffer too small."; + globals_p->snapshot_error = jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p); + return 0; + } + + /* Sub-functions and regular expressions are stored recursively. */ + uint8_t *buffer_p = (uint8_t *) copied_code_p; + ecma_value_t *literal_start_p; + uint32_t argument_end; + uint32_t const_literal_end; + uint32_t literal_end; + + ((ecma_compiled_code_t *) copied_code_p)->status_flags |= CBC_CODE_FLAGS_STATIC_FUNCTION; + + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) + { + literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint16_arguments_t)); + + cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p; + argument_end = args_p->argument_end; + literal_end = (uint32_t) (args_p->literal_end - args_p->register_end); + const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end); + } + else + { + literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint8_arguments_t)); + + cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p; + argument_end = args_p->argument_end; + literal_end = (uint32_t) (args_p->literal_end - args_p->register_end); + const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end); + } + + for (uint32_t i = 0; i < const_literal_end; i++) + { + if (!ecma_is_value_direct (literal_start_p[i]) + && !ecma_is_value_direct_string (literal_start_p[i])) + { + static_snapshot_error_unsupported_literal (globals_p, literal_start_p[i]); + return 0; + } + } + + for (uint32_t i = const_literal_end; i < literal_end; i++) + { + ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, + literal_start_p[i]); + + if (bytecode_p == compiled_code_p) + { + literal_start_p[i] = 0; + } + else + { + uint32_t offset = static_snapshot_add_compiled_code (bytecode_p, snapshot_buffer_p, snapshot_buffer_size, globals_p); + + JERRY_ASSERT (!ecma_is_value_empty (globals_p->snapshot_error) || offset > start_offset); + + literal_start_p[i] = offset - start_offset; + } + } + + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED) + { + buffer_p += ((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG; + literal_start_p = ((ecma_value_t *) buffer_p) - argument_end; + + for (uint32_t i = 0; i < argument_end; i++) + { + if (!ecma_is_value_direct_string (literal_start_p[i])) + { + static_snapshot_error_unsupported_literal (globals_p, literal_start_p[i]); + return 0; + } } } return start_offset; -} /* snapshot_add_compiled_code */ +} /* static_snapshot_add_compiled_code */ /** * Set the uint16_t offsets in the code area. @@ -268,39 +439,55 @@ jerry_snapshot_set_offsets (uint32_t *buffer_p, /**< buffer */ if (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) { - jmem_cpointer_t *literal_start_p; + ecma_value_t *literal_start_p; uint32_t argument_end; - uint32_t register_end; uint32_t const_literal_end; if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { - literal_start_p = (jmem_cpointer_t *) (((uint8_t *) buffer_p) + sizeof (cbc_uint16_arguments_t)); + literal_start_p = (ecma_value_t *) (((uint8_t *) buffer_p) + sizeof (cbc_uint16_arguments_t)); cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p; argument_end = args_p->argument_end; - register_end = args_p->register_end; - const_literal_end = args_p->const_literal_end; + const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end); } else { - literal_start_p = (jmem_cpointer_t *) (((uint8_t *) buffer_p) + sizeof (cbc_uint8_arguments_t)); + literal_start_p = (ecma_value_t *) (((uint8_t *) buffer_p) + sizeof (cbc_uint8_arguments_t)); cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p; argument_end = args_p->argument_end; - register_end = args_p->register_end; - const_literal_end = args_p->const_literal_end; + const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end); } - uint32_t register_clear_start = 0; + for (uint32_t i = 0; i < const_literal_end; i++) + { + if (ecma_is_value_string (literal_start_p[i]) + || ecma_is_value_float_number (literal_start_p[i])) + { + lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p; + + while (current_p->literal_id != literal_start_p[i]) + { + current_p++; + } + + literal_start_p[i] = current_p->literal_offset; + } + } - if ((bytecode_p->status_flags & CBC_CODE_FLAGS_ARGUMENTS_NEEDED) - && !(bytecode_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE)) + if (bytecode_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED) { + uint8_t *byte_p = (uint8_t *) bytecode_p; + byte_p += ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; + literal_start_p = ((ecma_value_t *) byte_p) - argument_end; + for (uint32_t i = 0; i < argument_end; i++) { - if (literal_start_p[i] != JMEM_CP_NULL) + if (literal_start_p[i] != ECMA_VALUE_EMPTY) { + JERRY_ASSERT (ecma_is_value_string (literal_start_p[i])); + lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p; while (current_p->literal_id != literal_start_p[i]) @@ -311,28 +498,6 @@ jerry_snapshot_set_offsets (uint32_t *buffer_p, /**< buffer */ literal_start_p[i] = current_p->literal_offset; } } - - register_clear_start = argument_end; - } - - for (uint32_t i = register_clear_start; i < register_end; i++) - { - literal_start_p[i] = JMEM_CP_NULL; - } - - for (uint32_t i = register_end; i < const_literal_end; i++) - { - lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p; - - if (literal_start_p[i] != JMEM_CP_NULL) - { - while (current_p->literal_id != literal_start_p[i]) - { - current_p++; - } - - literal_start_p[i] = current_p->literal_offset; - } } /* Set reference counter to 1. */ @@ -365,12 +530,10 @@ jerry_snapshot_set_offsets (uint32_t *buffer_p, /**< buffer */ static ecma_compiled_code_t * snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of the * current primary function */ - size_t offset, /**< byte code offset */ const uint8_t *literal_base_p, /**< literal start */ - const uint8_t *number_base_p, /**< literal number start */ bool copy_bytecode) /**< byte code should be copied to memory */ { - ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) (base_addr_p + offset); + ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) base_addr_p; uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION)) @@ -397,23 +560,36 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th } size_t header_size; - uint32_t literal_end; + uint32_t argument_end = 0; uint32_t const_literal_end; + uint32_t literal_end; if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { uint8_t *byte_p = (uint8_t *) bytecode_p; cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) byte_p; - literal_end = args_p->literal_end; - const_literal_end = args_p->const_literal_end; + + if (bytecode_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED) + { + argument_end = args_p->argument_end; + } + + const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end); + literal_end = (uint32_t) (args_p->literal_end - args_p->register_end); header_size = sizeof (cbc_uint16_arguments_t); } else { uint8_t *byte_p = (uint8_t *) bytecode_p; cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) byte_p; - literal_end = args_p->literal_end; - const_literal_end = args_p->const_literal_end; + + if (bytecode_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED) + { + argument_end = args_p->argument_end; + } + + const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end); + literal_end = (uint32_t) (args_p->literal_end - args_p->register_end); header_size = sizeof (cbc_uint8_arguments_t); } @@ -426,29 +602,46 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th jmem_stats_allocate_byte_code_bytes (code_size); #endif /* JMEM_STATS */ - memcpy (bytecode_p, base_addr_p + offset, code_size); + memcpy (bytecode_p, base_addr_p, code_size); } else { - code_size = (uint32_t) (header_size + literal_end * sizeof (jmem_cpointer_t)); + uint32_t start_offset = (uint32_t) (header_size + literal_end * sizeof (ecma_value_t)); + + uint8_t *real_bytecode_p = ((uint8_t *) bytecode_p) + start_offset; + uint32_t new_code_size = (uint32_t) (start_offset + 1 + sizeof (uint8_t *)); - uint8_t *real_bytecode_p = ((uint8_t *) bytecode_p) + code_size; - uint32_t total_size = JERRY_ALIGNUP (code_size + 1 + sizeof (uint8_t *), JMEM_ALIGNMENT); + if (argument_end != 0) + { + new_code_size += (uint32_t) (argument_end * sizeof (ecma_value_t)); + } + + new_code_size = JERRY_ALIGNUP (new_code_size, JMEM_ALIGNMENT); - bytecode_p = (ecma_compiled_code_t *) jmem_heap_alloc_block (total_size); + bytecode_p = (ecma_compiled_code_t *) jmem_heap_alloc_block (new_code_size); #ifdef JMEM_STATS - jmem_stats_allocate_byte_code_bytes (total_size); + jmem_stats_allocate_byte_code_bytes (new_code_size); #endif /* JMEM_STATS */ - memcpy (bytecode_p, base_addr_p + offset, code_size); + memcpy (bytecode_p, base_addr_p, start_offset); - bytecode_p->size = (uint16_t) (total_size >> JMEM_ALIGNMENT_LOG); + bytecode_p->size = (uint16_t) (new_code_size >> JMEM_ALIGNMENT_LOG); - uint8_t *instructions_p = ((uint8_t *) bytecode_p); + uint8_t *byte_p = (uint8_t *) bytecode_p; - instructions_p[code_size] = CBC_SET_BYTECODE_PTR; - memcpy (instructions_p + code_size + 1, &real_bytecode_p, sizeof (uint8_t *)); + if (argument_end != 0) + { + uint32_t argument_size = (uint32_t) (argument_end * sizeof (ecma_value_t)); + memcpy (byte_p + new_code_size - argument_size, + base_addr_p + code_size - argument_size, + argument_size); + } + + byte_p[start_offset] = CBC_SET_BYTECODE_PTR; + memcpy (byte_p + start_offset + 1, &real_bytecode_p, sizeof (uint8_t *)); + + code_size = new_code_size; } JERRY_ASSERT (bytecode_p->refs == 1); @@ -457,36 +650,49 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th bytecode_p->status_flags = (uint16_t) (bytecode_p->status_flags | CBC_CODE_FLAGS_DEBUGGER_IGNORE); #endif /* JERRY_DEBUGGER */ - jmem_cpointer_t *literal_start_p = (jmem_cpointer_t *) (((uint8_t *) bytecode_p) + header_size); + ecma_value_t *literal_start_p = (ecma_value_t *) (((uint8_t *) bytecode_p) + header_size); for (uint32_t i = 0; i < const_literal_end; i++) { - literal_start_p[i] = ecma_snapshot_get_literal (literal_base_p, - number_base_p, - literal_start_p[i]); + if ((literal_start_p[i] & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET) + { + literal_start_p[i] = ecma_snapshot_get_literal (literal_base_p, literal_start_p[i]); + } } for (uint32_t i = const_literal_end; i < literal_end; i++) { - size_t literal_offset = ((size_t) literal_start_p[i]) << JMEM_ALIGNMENT_LOG; + size_t literal_offset = (size_t) literal_start_p[i]; - if (literal_offset == offset) + if (literal_offset == 0) { /* Self reference */ - ECMA_SET_NON_NULL_POINTER (literal_start_p[i], - bytecode_p); + ECMA_SET_INTERNAL_VALUE_POINTER (literal_start_p[i], + bytecode_p); } else { ecma_compiled_code_t *literal_bytecode_p; - literal_bytecode_p = snapshot_load_compiled_code (base_addr_p, - literal_offset, + literal_bytecode_p = snapshot_load_compiled_code (base_addr_p + literal_offset, literal_base_p, - number_base_p, copy_bytecode); - ECMA_SET_NON_NULL_POINTER (literal_start_p[i], - literal_bytecode_p); + ECMA_SET_INTERNAL_VALUE_POINTER (literal_start_p[i], + literal_bytecode_p); + } + } + + if (argument_end != 0) + { + literal_start_p = (ecma_value_t *) (((uint8_t *) bytecode_p) + code_size); + literal_start_p -= argument_end; + + for (uint32_t i = 0; i < argument_end; i++) + { + if ((literal_start_p[i] & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET) + { + literal_start_p[i] = ecma_snapshot_get_literal (literal_base_p, literal_start_p[i]); + } } } @@ -496,25 +702,34 @@ snapshot_load_compiled_code (const uint8_t *base_addr_p, /**< base address of th #endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ #ifdef JERRY_ENABLE_SNAPSHOT_SAVE + /** * Generate snapshot from specified source and arguments * - * @return size of snapshot, if it was generated succesfully + * @return size of snapshot (a number value), if it was generated succesfully * (i.e. there are no syntax errors in source code, buffer size is sufficient, * and snapshot support is enabled in current configuration through JERRY_ENABLE_SNAPSHOT_SAVE), - * 0 - otherwise. + * error object otherwise */ -static size_t -jerry_parse_and_save_snapshot_with_args (const jerry_char_t *source_p, /**< script source */ - size_t source_size, /**< script source size */ - const jerry_char_t *args_p, /**< arguments string */ - size_t args_size, /**< arguments string size */ - bool is_for_global, /**< snapshot would be executed as global (true) - * or eval (false) */ - bool is_strict, /**< strict mode */ - uint32_t *buffer_p, /**< buffer to save snapshot to */ - size_t buffer_size) /**< the buffer's size */ +static jerry_value_t +jerry_generate_snapshot_with_args (const jerry_char_t *resource_name_p, /**< script resource name */ + size_t resource_name_length, /**< script resource name length */ + const jerry_char_t *source_p, /**< script source */ + size_t source_size, /**< script source size */ + const jerry_char_t *args_p, /**< arguments string */ + size_t args_size, /**< arguments string size */ + uint32_t generate_snapshot_opts, /**< jerry_generate_snapshot_opts_t option bits */ + uint32_t *buffer_p, /**< buffer to save snapshot to */ + size_t buffer_size) /**< the buffer's size */ { + /* Currently unused arguments. */ + JERRY_UNUSED (resource_name_p); + JERRY_UNUSED (resource_name_length); + +#ifdef JERRY_ENABLE_LINE_INFO + JERRY_CONTEXT (resource_name) = ECMA_VALUE_UNDEFINED; +#endif /* JERRY_ENABLE_LINE_INFO */ + snapshot_globals_t globals; ecma_value_t parse_status; ecma_compiled_code_t *bytecode_data_p; @@ -522,27 +737,33 @@ jerry_parse_and_save_snapshot_with_args (const jerry_char_t *source_p, /**< scri JMEM_ALIGNMENT); globals.snapshot_buffer_write_offset = aligned_header_size; - globals.snapshot_error_occured = false; + globals.snapshot_error = ECMA_VALUE_EMPTY; globals.regex_found = false; parse_status = parser_parse_script (args_p, args_size, source_p, source_size, - is_strict, + (generate_snapshot_opts & JERRY_SNAPSHOT_SAVE_STRICT) != 0, &bytecode_data_p); if (ECMA_IS_VALUE_ERROR (parse_status)) { - ecma_free_value (JERRY_CONTEXT (error_value)); - return 0; + return ecma_create_error_reference (JERRY_CONTEXT (error_value), true); } - snapshot_add_compiled_code (bytecode_data_p, (uint8_t *) buffer_p, buffer_size, &globals); + if (generate_snapshot_opts & JERRY_SNAPSHOT_SAVE_STATIC) + { + static_snapshot_add_compiled_code (bytecode_data_p, (uint8_t *) buffer_p, buffer_size, &globals); + } + else + { + snapshot_add_compiled_code (bytecode_data_p, (uint8_t *) buffer_p, buffer_size, &globals); + } - if (globals.snapshot_error_occured) + if (!ecma_is_value_empty (globals.snapshot_error)) { - return 0; + return globals.snapshot_error; } jerry_snapshot_header_t header; @@ -553,27 +774,31 @@ jerry_parse_and_save_snapshot_with_args (const jerry_char_t *source_p, /**< scri header.number_of_funcs = 1; header.func_offsets[0] = aligned_header_size; - if (!is_for_global) - { - header.func_offsets[0] |= JERRY_SNAPSHOT_EVAL_CONTEXT; - } - lit_mem_to_snapshot_id_map_entry_t *lit_map_p = NULL; - uint32_t literals_num; + uint32_t literals_num = 0; - if (!ecma_save_literals_for_snapshot (buffer_p, - buffer_size, - &globals.snapshot_buffer_write_offset, - &lit_map_p, - &literals_num)) + if (!(generate_snapshot_opts & JERRY_SNAPSHOT_SAVE_STATIC)) { - JERRY_ASSERT (lit_map_p == NULL); - return 0; - } + ecma_collection_header_t *lit_pool_p = ecma_new_values_collection (); + + ecma_save_literals_add_compiled_code (bytecode_data_p, lit_pool_p); + + if (!ecma_save_literals_for_snapshot (lit_pool_p, + buffer_p, + buffer_size, + &globals.snapshot_buffer_write_offset, + &lit_map_p, + &literals_num)) + { + JERRY_ASSERT (lit_map_p == NULL); + const char *error_message_p = "Cannot allocate memory for literals."; + return jerry_create_error (JERRY_ERROR_COMMON, (const jerry_char_t *) error_message_p); + } - jerry_snapshot_set_offsets (buffer_p + (aligned_header_size / sizeof (uint32_t)), - (uint32_t) (header.lit_table_offset - aligned_header_size), - lit_map_p); + jerry_snapshot_set_offsets (buffer_p + (aligned_header_size / sizeof (uint32_t)), + (uint32_t) (header.lit_table_offset - aligned_header_size), + lit_map_p); + } size_t header_offset = 0; @@ -590,47 +815,58 @@ jerry_parse_and_save_snapshot_with_args (const jerry_char_t *source_p, /**< scri ecma_bytecode_deref (bytecode_data_p); - return globals.snapshot_buffer_write_offset; -} /* jerry_parse_and_save_snapshot_with_args */ + return ecma_make_number_value ((ecma_number_t) globals.snapshot_buffer_write_offset); +} /* jerry_generate_snapshot_with_args */ + #endif /* JERRY_ENABLE_SNAPSHOT_SAVE */ /** - * Generate snapshot from specified source + * Generate snapshot from specified source and arguments * - * @return size of snapshot, if it was generated succesfully + * @return size of snapshot (a number value), if it was generated succesfully * (i.e. there are no syntax errors in source code, buffer size is sufficient, * and snapshot support is enabled in current configuration through JERRY_ENABLE_SNAPSHOT_SAVE), - * 0 - otherwise. + * error object otherwise */ -size_t -jerry_parse_and_save_snapshot (const jerry_char_t *source_p, /**< script source */ - size_t source_size, /**< script source size */ - bool is_for_global, /**< snapshot would be executed as global (true) - * or eval (false) */ - bool is_strict, /**< strict mode */ - uint32_t *buffer_p, /**< buffer to save snapshot to */ - size_t buffer_size) /**< the buffer's size */ +jerry_value_t +jerry_generate_snapshot (const jerry_char_t *resource_name_p, /**< script resource name */ + size_t resource_name_length, /**< script resource name length */ + const jerry_char_t *source_p, /**< script source */ + size_t source_size, /**< script source size */ + uint32_t generate_snapshot_opts, /**< jerry_generate_snapshot_opts_t option bits */ + uint32_t *buffer_p, /**< buffer to save snapshot to */ + size_t buffer_size) /**< the buffer's size */ { #ifdef JERRY_ENABLE_SNAPSHOT_SAVE - return jerry_parse_and_save_snapshot_with_args (source_p, - source_size, - NULL, - 0, - is_for_global, - is_strict, - buffer_p, - buffer_size); + uint32_t allowed_opts = (JERRY_SNAPSHOT_SAVE_STATIC | JERRY_SNAPSHOT_SAVE_STRICT); + + if ((generate_snapshot_opts & ~(allowed_opts)) != 0) + { + const char *error_message_p = "Unsupported generate snapshot flags specified."; + return jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p); + } + + return jerry_generate_snapshot_with_args (resource_name_p, + resource_name_length, + source_p, + source_size, + NULL, + 0, + generate_snapshot_opts, + buffer_p, + buffer_size); #else /* !JERRY_ENABLE_SNAPSHOT_SAVE */ + JERRY_UNUSED (resource_name_p); + JERRY_UNUSED (resource_name_length); JERRY_UNUSED (source_p); JERRY_UNUSED (source_size); - JERRY_UNUSED (is_for_global); - JERRY_UNUSED (is_strict); + JERRY_UNUSED (generate_snapshot_opts); JERRY_UNUSED (buffer_p); JERRY_UNUSED (buffer_size); return 0; #endif /* JERRY_ENABLE_SNAPSHOT_SAVE */ -} /* jerry_parse_and_save_snapshot */ +} /* jerry_generate_snapshot */ #ifdef JERRY_ENABLE_SNAPSHOT_EXEC /** @@ -643,27 +879,30 @@ jerry_parse_and_save_snapshot (const jerry_char_t *source_p, /**< script source * thrown error - otherwise */ static jerry_value_t -jerry_snapshot_result_at (const uint32_t *snapshot_p, /**< snapshot */ - size_t snapshot_size, /**< size of snapshot */ - size_t func_index, /**< index of primary function */ - bool copy_bytecode, /**< flag, indicating whether the passed snapshot - * buffer should be copied to the engine's memory. - * If set the engine should not reference the buffer - * after the function returns (in this case, the passed - * buffer could be freed after the call). - * Otherwise (if the flag is not set) - the buffer could only be - * freed after the engine stops (i.e. after call to jerry_cleanup). */ - bool as_function) /** < specify if the loaded snapshot should be returned as a function */ +jerry_snapshot_result (const uint32_t *snapshot_p, /**< snapshot */ + size_t snapshot_size, /**< size of snapshot */ + size_t func_index, /**< index of primary function */ + uint32_t exec_snapshot_opts, /**< jerry_exec_snapshot_opts_t option bits */ + bool as_function) /** < specify if the loaded snapshot should be returned as a function */ { JERRY_ASSERT (snapshot_p != NULL); + uint32_t allowed_opts = (JERRY_SNAPSHOT_EXEC_COPY_DATA | JERRY_SNAPSHOT_EXEC_ALLOW_STATIC); + + if ((exec_snapshot_opts & ~(allowed_opts)) != 0) + { + ecma_raise_range_error (ECMA_ERR_MSG ("Unsupported exec snapshot flags specified.")); + return ecma_create_error_reference_from_context (); + } + static const char * const invalid_version_error_p = "Invalid snapshot version or unsupported features present"; static const char * const invalid_format_error_p = "Invalid snapshot format"; const uint8_t *snapshot_data_p = (uint8_t *) snapshot_p; if (snapshot_size <= sizeof (jerry_snapshot_header_t)) { - return ecma_raise_type_error (invalid_format_error_p); + ecma_raise_type_error (invalid_format_error_p); + return ecma_create_error_reference_from_context (); } const jerry_snapshot_header_t *header_p = (const jerry_snapshot_header_t *) snapshot_data_p; @@ -672,39 +911,53 @@ jerry_snapshot_result_at (const uint32_t *snapshot_p, /**< snapshot */ || header_p->version != JERRY_SNAPSHOT_VERSION || !snapshot_check_global_flags (header_p->global_flags)) { - return ecma_raise_type_error (invalid_version_error_p); + ecma_raise_type_error (invalid_version_error_p); + return ecma_create_error_reference_from_context (); } - if (header_p->lit_table_offset >= snapshot_size) + if (header_p->lit_table_offset > snapshot_size) { - return ecma_raise_type_error (invalid_version_error_p); + ecma_raise_type_error (invalid_version_error_p); + return ecma_create_error_reference_from_context (); } if (func_index >= header_p->number_of_funcs) { - return ecma_raise_range_error (ECMA_ERR_MSG ("Function index is higher than maximum")); + ecma_raise_range_error (ECMA_ERR_MSG ("Function index is higher than maximum")); + return ecma_create_error_reference_from_context (); } JERRY_ASSERT ((header_p->lit_table_offset % sizeof (uint32_t)) == 0); - const uint8_t *literal_base_p; - const uint8_t *number_base_p; + uint32_t func_offset = header_p->func_offsets[func_index]; + ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) (snapshot_data_p + func_offset); - literal_base_p = ecma_snapshot_get_literals_base ((uint32_t *) (snapshot_data_p + header_p->lit_table_offset), - &number_base_p); + if (bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION) + { + if (!(exec_snapshot_opts & JERRY_SNAPSHOT_EXEC_ALLOW_STATIC)) + { + ecma_raise_common_error (ECMA_ERR_MSG ("Static snapshots not allowed")); + return ecma_create_error_reference_from_context (); + } - ecma_compiled_code_t *bytecode_p; + if (exec_snapshot_opts & JERRY_SNAPSHOT_EXEC_COPY_DATA) + { + ecma_raise_common_error (ECMA_ERR_MSG ("Static snapshots cannot be copied into memory")); + return ecma_create_error_reference_from_context (); + } + } + else + { + const uint8_t *literal_base_p = (uint8_t *) (snapshot_data_p + header_p->lit_table_offset); - uint32_t func_offset = header_p->func_offsets[func_index] & ~JERRY_SNAPSHOT_EVAL_CONTEXT; - bytecode_p = snapshot_load_compiled_code (snapshot_data_p + func_offset, - 0, - literal_base_p, - number_base_p, - copy_bytecode); + bytecode_p = snapshot_load_compiled_code ((const uint8_t *) bytecode_p, + literal_base_p, + (exec_snapshot_opts & JERRY_SNAPSHOT_EXEC_COPY_DATA) != 0); - if (bytecode_p == NULL) - { - return ecma_raise_type_error (invalid_format_error_p); + if (bytecode_p == NULL) + { + return ecma_raise_type_error (invalid_format_error_p); + } } ecma_value_t ret_val; @@ -714,62 +967,31 @@ jerry_snapshot_result_at (const uint32_t *snapshot_p, /**< snapshot */ ecma_object_t *lex_env_p = ecma_get_global_environment (); ecma_object_t *func_obj_p = ecma_op_create_function_object (lex_env_p, bytecode_p); - ecma_bytecode_deref (bytecode_p); + if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) + { + ecma_bytecode_deref (bytecode_p); + } ret_val = ecma_make_object_value (func_obj_p); } - else if (header_p->func_offsets[func_index] & JERRY_SNAPSHOT_EVAL_CONTEXT) - { - ret_val = vm_run_eval (bytecode_p, false); - } else { ret_val = vm_run_global (bytecode_p); - ecma_bytecode_deref (bytecode_p); + if (!(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) + { + ecma_bytecode_deref (bytecode_p); + } } if (ECMA_IS_VALUE_ERROR (ret_val)) { - return ecma_create_error_reference (JERRY_CONTEXT (error_value)); + return ecma_create_error_reference_from_context (); } return ret_val; -} /* jerry_snapshot_result_at */ +} /* jerry_snapshot_result */ #endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ -/** - * Execute snapshot from specified buffer - * - * Note: - * returned value must be freed with jerry_release_value, when it is no longer needed. - * - * @return result of bytecode - if run was successful - * thrown error - otherwise - */ -jerry_value_t -jerry_exec_snapshot_at (const uint32_t *snapshot_p, /**< snapshot */ - size_t snapshot_size, /**< size of snapshot */ - size_t func_index, /**< index of primary function */ - bool copy_bytecode) /**< flag, indicating whether the passed snapshot - * buffer should be copied to the engine's memory. - * If set the engine should not reference the buffer - * after the function returns (in this case, the passed - * buffer could be freed after the call). - * Otherwise (if the flag is not set) - the buffer could only be - * freed after the engine stops (i.e. after call to jerry_cleanup). */ -{ -#ifdef JERRY_ENABLE_SNAPSHOT_EXEC - return jerry_snapshot_result_at (snapshot_p, snapshot_size, func_index, copy_bytecode, false); -#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ - JERRY_UNUSED (snapshot_p); - JERRY_UNUSED (snapshot_size); - JERRY_UNUSED (func_index); - JERRY_UNUSED (copy_bytecode); - - return ECMA_VALUE_FALSE; -#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ -} /* jerry_exec_snapshot_at */ - /** * Execute snapshot from specified buffer * @@ -782,20 +1004,16 @@ jerry_exec_snapshot_at (const uint32_t *snapshot_p, /**< snapshot */ jerry_value_t jerry_exec_snapshot (const uint32_t *snapshot_p, /**< snapshot */ size_t snapshot_size, /**< size of snapshot */ - bool copy_bytecode) /**< flag, indicating whether the passed snapshot - * buffer should be copied to the engine's memory. - * If set the engine should not reference the buffer - * after the function returns (in this case, the passed - * buffer could be freed after the call). - * Otherwise (if the flag is not set) - the buffer could only be - * freed after the engine stops (i.e. after call to jerry_cleanup). */ + size_t func_index, /**< index of primary function */ + uint32_t exec_snapshot_opts) /**< jerry_exec_snapshot_opts_t option bits */ { #ifdef JERRY_ENABLE_SNAPSHOT_EXEC - return jerry_exec_snapshot_at (snapshot_p, snapshot_size, 0, copy_bytecode); + return jerry_snapshot_result (snapshot_p, snapshot_size, func_index, exec_snapshot_opts, false); #else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ JERRY_UNUSED (snapshot_p); JERRY_UNUSED (snapshot_size); - JERRY_UNUSED (copy_bytecode); + JERRY_UNUSED (func_index); + JERRY_UNUSED (exec_snapshot_opts); return ECMA_VALUE_FALSE; #endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ @@ -813,8 +1031,8 @@ jerry_exec_snapshot (const uint32_t *snapshot_p, /**< snapshot */ static void scan_snapshot_functions (const uint8_t *buffer_p, /**< snapshot buffer start */ const uint8_t *buffer_end_p, /**< snapshot buffer end */ - const uint8_t *literal_base_p, /**< start of literal data */ - const uint8_t *number_base_p) /**< start of number data */ + ecma_collection_header_t *lit_pool_p, /**< list of known values */ + const uint8_t *literal_base_p) /**< start of literal data */ { JERRY_ASSERT (buffer_end_p > buffer_p); @@ -823,31 +1041,54 @@ scan_snapshot_functions (const uint8_t *buffer_p, /**< snapshot buffer start */ ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) buffer_p; uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; - if (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) + if ((bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) + && !(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) { - jmem_cpointer_t *literal_start_p; + ecma_value_t *literal_start_p; + uint32_t argument_end; uint32_t const_literal_end; if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { - literal_start_p = (jmem_cpointer_t *) (buffer_p + sizeof (cbc_uint16_arguments_t)); + literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint16_arguments_t)); cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p; - const_literal_end = args_p->const_literal_end; + argument_end = args_p->argument_end; + const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end); } else { - literal_start_p = (jmem_cpointer_t *) (buffer_p + sizeof (cbc_uint8_arguments_t)); + literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint8_arguments_t)); cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p; - const_literal_end = args_p->const_literal_end; + argument_end = args_p->argument_end; + const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end); } for (uint32_t i = 0; i < const_literal_end; i++) { - if (literal_start_p[i] != JMEM_CP_NULL) + if ((literal_start_p[i] & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET) + { + ecma_value_t lit_value = ecma_snapshot_get_literal (literal_base_p, literal_start_p[i]); + literal_start_p[i] = lit_value; + ecma_save_literals_append_value (lit_value, lit_pool_p); + } + } + + if (bytecode_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED) + { + uint8_t *byte_p = (uint8_t *) bytecode_p; + byte_p += ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; + literal_start_p = ((ecma_value_t *) byte_p) - argument_end; + + for (uint32_t i = 0; i < argument_end; i++) { - literal_start_p[i] = ecma_snapshot_get_literal (literal_base_p, number_base_p, literal_start_p[i]); + if ((literal_start_p[i] & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET) + { + ecma_value_t lit_value = ecma_snapshot_get_literal (literal_base_p, literal_start_p[i]); + literal_start_p[i] = lit_value; + ecma_save_literals_append_value (lit_value, lit_pool_p); + } } } } @@ -862,7 +1103,7 @@ scan_snapshot_functions (const uint8_t *buffer_p, /**< snapshot buffer start */ */ static void update_literal_offsets (uint8_t *buffer_p, /**< snapshot buffer start */ - const uint8_t *buffer_end_p, /**< snapshot buffer start */ + const uint8_t *buffer_end_p, /**< snapshot buffer end */ lit_mem_to_snapshot_id_map_entry_t *lit_map_p) /**< literal map */ { JERRY_ASSERT (buffer_end_p > buffer_p); @@ -872,29 +1113,34 @@ update_literal_offsets (uint8_t *buffer_p, /**< snapshot buffer start */ ecma_compiled_code_t *bytecode_p = (ecma_compiled_code_t *) buffer_p; uint32_t code_size = ((uint32_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; - if (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) + if ((bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) + && !(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) { - jmem_cpointer_t *literal_start_p; + ecma_value_t *literal_start_p; + uint32_t argument_end; uint32_t const_literal_end; if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { - literal_start_p = (jmem_cpointer_t *) (buffer_p + sizeof (cbc_uint16_arguments_t)); + literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint16_arguments_t)); cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) buffer_p; - const_literal_end = args_p->const_literal_end; + argument_end = args_p->argument_end; + const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end); } else { - literal_start_p = (jmem_cpointer_t *) (buffer_p + sizeof (cbc_uint8_arguments_t)); + literal_start_p = (ecma_value_t *) (buffer_p + sizeof (cbc_uint8_arguments_t)); cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) buffer_p; - const_literal_end = args_p->const_literal_end; + argument_end = args_p->argument_end; + const_literal_end = (uint32_t) (args_p->const_literal_end - args_p->register_end); } for (uint32_t i = 0; i < const_literal_end; i++) { - if (literal_start_p[i] != JMEM_CP_NULL) + if (ecma_is_value_string (literal_start_p[i]) + || ecma_is_value_float_number (literal_start_p[i])) { lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p; @@ -906,6 +1152,28 @@ update_literal_offsets (uint8_t *buffer_p, /**< snapshot buffer start */ literal_start_p[i] = current_p->literal_offset; } } + + if (bytecode_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED) + { + uint8_t *byte_p = (uint8_t *) bytecode_p; + byte_p += ((size_t) bytecode_p->size) << JMEM_ALIGNMENT_LOG; + literal_start_p = ((ecma_value_t *) byte_p) - argument_end; + + for (uint32_t i = 0; i < argument_end; i++) + { + if (literal_start_p[i] != ECMA_VALUE_EMPTY) + { + lit_mem_to_snapshot_id_map_entry_t *current_p = lit_map_p; + + while (current_p->literal_id != literal_start_p[i]) + { + current_p++; + } + + literal_start_p[i] = current_p->literal_offset; + } + } + } } buffer_p += code_size; @@ -940,11 +1208,14 @@ jerry_merge_snapshots (const uint32_t **inp_buffers_p, /**< array of (pointers t return 0; } + ecma_collection_header_t *lit_pool_p = ecma_new_values_collection (); + for (uint32_t i = 0; i < number_of_snapshots; i++) { if (inp_buffer_sizes_p[i] < sizeof (jerry_snapshot_header_t)) { *error_p = "invalid snapshot file"; + ecma_free_values_collection (lit_pool_p, ECMA_COLLECTION_NO_COPY); return 0; } @@ -955,18 +1226,15 @@ jerry_merge_snapshots (const uint32_t **inp_buffers_p, /**< array of (pointers t || !snapshot_check_global_flags (header_p->global_flags)) { *error_p = "invalid snapshot version or unsupported features present"; + ecma_free_values_collection (lit_pool_p, ECMA_COLLECTION_NO_COPY); return 0; } merged_global_flags |= header_p->global_flags; - uint32_t start_offset = header_p->func_offsets[0] & ~JERRY_SNAPSHOT_EVAL_CONTEXT; + uint32_t start_offset = header_p->func_offsets[0]; const uint8_t *data_p = (const uint8_t *) inp_buffers_p[i]; - const uint8_t *literal_base_p; - const uint8_t *number_base_p; - - literal_base_p = ecma_snapshot_get_literals_base ((uint32_t *) (data_p + header_p->lit_table_offset), - &number_base_p); + const uint8_t *literal_base_p = (uint8_t *) (data_p + header_p->lit_table_offset); JERRY_ASSERT (header_p->number_of_funcs > 0); @@ -975,8 +1243,8 @@ jerry_merge_snapshots (const uint32_t **inp_buffers_p, /**< array of (pointers t scan_snapshot_functions (data_p + start_offset, data_p + header_p->lit_table_offset, - literal_base_p, - number_base_p); + lit_pool_p, + literal_base_p); } JERRY_ASSERT (number_of_funcs > 0); @@ -986,6 +1254,7 @@ jerry_merge_snapshots (const uint32_t **inp_buffers_p, /**< array of (pointers t if (functions_size >= out_buffer_size) { *error_p = "output buffer is too small"; + ecma_free_values_collection (lit_pool_p, ECMA_COLLECTION_NO_COPY); return 0; } @@ -1000,7 +1269,8 @@ jerry_merge_snapshots (const uint32_t **inp_buffers_p, /**< array of (pointers t lit_mem_to_snapshot_id_map_entry_t *lit_map_p; uint32_t literals_num; - if (!ecma_save_literals_for_snapshot (out_buffer_p, + if (!ecma_save_literals_for_snapshot (lit_pool_p, + out_buffer_p, out_buffer_size, &functions_size, &lit_map_p, @@ -1018,7 +1288,7 @@ jerry_merge_snapshots (const uint32_t **inp_buffers_p, /**< array of (pointers t { const jerry_snapshot_header_t *current_header_p = (const jerry_snapshot_header_t *) inp_buffers_p[i]; - uint32_t start_offset = current_header_p->func_offsets[0] & ~JERRY_SNAPSHOT_EVAL_CONTEXT; + uint32_t start_offset = current_header_p->func_offsets[0]; memcpy (dst_p, ((const uint8_t *) inp_buffers_p[i]) + start_offset, @@ -1041,7 +1311,10 @@ jerry_merge_snapshots (const uint32_t **inp_buffers_p, /**< array of (pointers t JERRY_ASSERT ((uint32_t) (dst_p - (uint8_t *) out_buffer_p) == header_p->lit_table_offset); - jmem_heap_free_block (lit_map_p, literals_num * sizeof (lit_mem_to_snapshot_id_map_entry_t)); + if (lit_map_p != NULL) + { + jmem_heap_free_block (lit_map_p, literals_num * sizeof (lit_mem_to_snapshot_id_map_entry_t)); + } *error_p = NULL; return functions_size; @@ -1310,6 +1583,11 @@ jerry_parse_and_save_literals (const jerry_char_t *source_p, /**< script source #ifdef JERRY_ENABLE_SNAPSHOT_SAVE ecma_value_t parse_status; ecma_compiled_code_t *bytecode_data_p; + +#ifdef JERRY_ENABLE_LINE_INFO + JERRY_CONTEXT (resource_name) = ECMA_VALUE_UNDEFINED; +#endif /* JERRY_ENABLE_LINE_INFO */ + parse_status = parser_parse_script (NULL, 0, source_p, @@ -1325,35 +1603,35 @@ jerry_parse_and_save_literals (const jerry_char_t *source_p, /**< script source ecma_free_value (parse_status); + ecma_collection_header_t *lit_pool_p = ecma_new_values_collection (); + ecma_save_literals_add_compiled_code (bytecode_data_p, lit_pool_p); + ecma_bytecode_deref (bytecode_data_p); - ecma_lit_storage_item_t *string_list_p = JERRY_CONTEXT (string_list_first_p); lit_utf8_size_t literal_count = 0; + ecma_value_t *iterator_p = ecma_collection_iterator_init (lit_pool_p); /* Count the valid and non-magic identifiers in the list. */ - while (string_list_p != NULL) + while (iterator_p != NULL) { - for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++) + if (ecma_is_value_string (*iterator_p)) { - if (string_list_p->values[i] != JMEM_CP_NULL) + ecma_string_t *literal_p = ecma_get_string_from_value (*iterator_p); + + /* We don't save a literal which isn't a valid identifier or it's a magic string. */ + if (ecma_get_string_magic (literal_p) == LIT_MAGIC_STRING__COUNT + && ecma_string_is_valid_identifier (literal_p)) { - ecma_string_t *literal_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, - string_list_p->values[i]); - /* We don't save a literal which isn't a valid identifier - or it's a magic string. */ - if (ecma_get_string_magic (literal_p) == LIT_MAGIC_STRING__COUNT - && ecma_string_is_valid_identifier (literal_p)) - { - literal_count++; - } + literal_count++; } } - string_list_p = JMEM_CP_GET_POINTER (ecma_lit_storage_item_t, string_list_p->next_cp); + iterator_p = ecma_collection_iterator_next (iterator_p); } if (literal_count == 0) { + ecma_free_values_collection (lit_pool_p, ECMA_COLLECTION_NO_COPY); return 0; } @@ -1365,28 +1643,26 @@ jerry_parse_and_save_literals (const jerry_char_t *source_p, /**< script source JMEM_DEFINE_LOCAL_ARRAY (literal_array, literal_count, ecma_string_t *); lit_utf8_size_t literal_idx = 0; - string_list_p = JERRY_CONTEXT (string_list_first_p); + iterator_p = ecma_collection_iterator_init (lit_pool_p); - while (string_list_p != NULL) + while (iterator_p != NULL) { - for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++) + if (ecma_is_value_string (*iterator_p)) { - if (string_list_p->values[i] != JMEM_CP_NULL) - { - ecma_string_t *literal_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, - string_list_p->values[i]); + ecma_string_t *literal_p = ecma_get_string_from_value (*iterator_p); - if (ecma_get_string_magic (literal_p) == LIT_MAGIC_STRING__COUNT - && ecma_string_is_valid_identifier (literal_p)) - { - literal_array[literal_idx++] = literal_p; - } + if (ecma_get_string_magic (literal_p) == LIT_MAGIC_STRING__COUNT + && ecma_string_is_valid_identifier (literal_p)) + { + literal_array[literal_idx++] = literal_p; } } - string_list_p = JMEM_CP_GET_POINTER (ecma_lit_storage_item_t, string_list_p->next_cp); + iterator_p = ecma_collection_iterator_next (iterator_p); } + ecma_free_values_collection (lit_pool_p, ECMA_COLLECTION_NO_COPY); + /* Sort the strings by size at first, then lexicographically. */ jerry_save_literals_sort (literal_array, literal_count); @@ -1485,57 +1761,81 @@ jerry_parse_and_save_literals (const jerry_char_t *source_p, /**< script source #endif /* JERRY_ENABLE_SNAPSHOT_SAVE */ } /* jerry_parse_and_save_literals */ -size_t jerry_parse_and_save_function_snapshot (const jerry_char_t *source_p, /**< function body source */ - size_t source_size, /**< function body size */ - const jerry_char_t *args_p, /**< arguments string */ - size_t args_size, /**< arguments string size */ - bool is_strict, /**< strict mode */ - uint32_t *buffer_p, /**< buffer to save snapshot to */ - size_t buffer_size) /**< the buffer's size */ +/** + * Generate snapshot function from specified source and arguments + * + * @return size of snapshot (a number value), if it was generated succesfully + * (i.e. there are no syntax errors in source code, buffer size is sufficient, + * and snapshot support is enabled in current configuration through JERRY_ENABLE_SNAPSHOT_SAVE), + * error object otherwise + */ +jerry_value_t +jerry_generate_function_snapshot (const jerry_char_t *resource_name_p, /**< script resource name */ + size_t resource_name_length, /**< script resource name length */ + const jerry_char_t *source_p, /**< script source */ + size_t source_size, /**< script source size */ + const jerry_char_t *args_p, /**< arguments string */ + size_t args_size, /**< arguments string size */ + uint32_t generate_snapshot_opts, /**< jerry_generate_snapshot_opts_t option bits */ + uint32_t *buffer_p, /**< buffer to save snapshot to */ + size_t buffer_size) /**< the buffer's size */ { #ifdef JERRY_ENABLE_SNAPSHOT_SAVE - return jerry_parse_and_save_snapshot_with_args (source_p, - source_size, - args_p, - args_size, - true, - is_strict, - buffer_p, - buffer_size); + uint32_t allowed_opts = (JERRY_SNAPSHOT_SAVE_STATIC | JERRY_SNAPSHOT_SAVE_STRICT); + + if ((generate_snapshot_opts & ~(allowed_opts)) != 0) + { + const char *error_message_p = "Unsupported generate snapshot flags specified."; + return jerry_create_error (JERRY_ERROR_RANGE, (const jerry_char_t *) error_message_p); + } + + return jerry_generate_snapshot_with_args (resource_name_p, + resource_name_length, + source_p, + source_size, + args_p, + args_size, + generate_snapshot_opts, + buffer_p, + buffer_size); #else /* !JERRY_ENABLE_SNAPSHOT_SAVE */ + JERRY_UNUSED (resource_name_p); + JERRY_UNUSED (resource_name_length); JERRY_UNUSED (source_p); JERRY_UNUSED (source_size); JERRY_UNUSED (args_p); JERRY_UNUSED (args_size); - JERRY_UNUSED (is_strict); + JERRY_UNUSED (generate_snapshot_opts); JERRY_UNUSED (buffer_p); JERRY_UNUSED (buffer_size); return 0; #endif /* JERRY_ENABLE_SNAPSHOT_SAVE */ -} /* jerry_parse_and_save_function_snapshot */ - -jerry_value_t jerry_load_function_snapshot_at (const uint32_t *function_snapshot_p, /**< snapshot of the function(s) */ - const size_t function_snapshot_size, /**< size of the snapshot */ - size_t func_index, /**< index of the function to load */ - bool copy_bytecode) /**< flag, indicating whether the passed snapshot - * buffer should be copied to the engine's memory. - * If set the engine should not reference - * the buffer after the function returns - * (in this case, the passed buffer could be freed - * after the call). - * Otherwise (if the flag is not set) - the buffer - * could only be freed after the engine stops - * (i.e. after call to jerry_cleanup). */ +} /* jerry_generate_function_snapshot */ + +/** + * Load function from specified snapshot buffer + * + * Note: + * returned value must be freed with jerry_release_value, when it is no longer needed. + * + * @return result of bytecode - if run was successful + * thrown error - otherwise + */ +jerry_value_t +jerry_load_function_snapshot (const uint32_t *function_snapshot_p, /**< snapshot of the function(s) */ + const size_t function_snapshot_size, /**< size of the snapshot */ + size_t func_index, /**< index of the function to load */ + uint32_t exec_snapshot_opts) /**< jerry_exec_snapshot_opts_t option bits */ { #ifdef JERRY_ENABLE_SNAPSHOT_EXEC - return jerry_snapshot_result_at (function_snapshot_p, function_snapshot_size, func_index, copy_bytecode, true); + return jerry_snapshot_result (function_snapshot_p, function_snapshot_size, func_index, exec_snapshot_opts, true); #else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ JERRY_UNUSED (function_snapshot_p); JERRY_UNUSED (function_snapshot_size); JERRY_UNUSED (func_index); - JERRY_UNUSED (copy_bytecode); + JERRY_UNUSED (exec_snapshot_opts); return ECMA_VALUE_FALSE; #endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ -} /* jerry_load_function_snapshot_at */ +} /* jerry_load_function_snapshot */ diff --git a/deps/jerry/jerry-core/api/jerry-snapshot.h b/deps/jerry/jerry-core/api/jerry-snapshot.h index 8a91a43..9198557 100644 --- a/deps/jerry/jerry-core/api/jerry-snapshot.h +++ b/deps/jerry/jerry-core/api/jerry-snapshot.h @@ -33,11 +33,6 @@ typedef struct uint32_t func_offsets[1]; /**< function offsets (lowest bit: global(0) or eval(1) context) */ } jerry_snapshot_header_t; -/** - * Evaluate this function on the top of the scope chain. - */ -#define JERRY_SNAPSHOT_EVAL_CONTEXT 0x1u - /** * Jerry snapshot magic marker. */ @@ -46,7 +41,7 @@ typedef struct /** * Jerry snapshot format version. */ -#define JERRY_SNAPSHOT_VERSION (8u) +#define JERRY_SNAPSHOT_VERSION (12u) /** * Snapshot configuration flags. diff --git a/deps/jerry/jerry-core/api/jerry.c b/deps/jerry/jerry-core/api/jerry.c index 58351d1..3ae749b 100644 --- a/deps/jerry/jerry-core/api/jerry.c +++ b/deps/jerry/jerry-core/api/jerry.c @@ -18,6 +18,7 @@ #include "debugger.h" #include "ecma-alloc.h" #include "ecma-array-object.h" +#include "ecma-arraybuffer-object.h" #include "ecma-builtin-helpers.h" #include "ecma-builtins.h" #include "ecma-exceptions.h" @@ -31,6 +32,7 @@ #include "ecma-objects.h" #include "ecma-objects-general.h" #include "ecma-promise-object.h" +#include "ecma-typedarray-object.h" #include "jcontext.h" #include "jerryscript.h" #include "jmem.h" @@ -40,7 +42,8 @@ JERRY_STATIC_ASSERT (sizeof (jerry_value_t) == sizeof (ecma_value_t), size_of_jerry_value_t_must_be_equal_to_size_of_ecma_value_t); -JERRY_STATIC_ASSERT ((int) ECMA_ERROR_COMMON == (int) JERRY_ERROR_COMMON +JERRY_STATIC_ASSERT ((int) ECMA_ERROR_NONE == (int) JERRY_ERROR_NONE + && (int) ECMA_ERROR_COMMON == (int) JERRY_ERROR_COMMON && (int) ECMA_ERROR_EVAL == (int) JERRY_ERROR_EVAL && (int) ECMA_ERROR_RANGE == (int) JERRY_ERROR_RANGE && (int) ECMA_ERROR_REFERENCE == (int) JERRY_ERROR_REFERENCE @@ -81,10 +84,10 @@ static const char * const wrong_args_msg_p = "wrong type of argument"; * Assert that it is correct to call API in current state. * * Note: - * By convention, there can be some states when API could not be invoked. + * By convention, there are some states when API could not be invoked. * - * While, API can be invoked jerry_api_available flag is set, - * and while it is incorrect to invoke API - it is not set. + * The API can be and only be invoked when the ECMA_STATUS_API_AVAILABLE + * flag is set. * * This procedure checks whether the API is available, and terminates * the engine if it is unavailable. Otherwise it is a no-op. @@ -97,7 +100,7 @@ static const char * const wrong_args_msg_p = "wrong type of argument"; static inline void __attr_always_inline___ jerry_assert_api_available (void) { - if (unlikely (!JERRY_CONTEXT (jerry_api_available))) + if (unlikely (!(JERRY_CONTEXT (status_flags) & ECMA_STATUS_API_AVAILABLE))) { /* Terminates the execution. */ JERRY_UNREACHABLE (); @@ -110,7 +113,7 @@ jerry_assert_api_available (void) static inline void __attr_always_inline___ jerry_make_api_available (void) { - JERRY_CONTEXT (jerry_api_available) = true; + JERRY_CONTEXT (status_flags) |= ECMA_STATUS_API_AVAILABLE; } /* jerry_make_api_available */ /** @@ -119,7 +122,7 @@ jerry_make_api_available (void) static inline void __attr_always_inline___ jerry_make_api_unavailable (void) { - JERRY_CONTEXT (jerry_api_available) = false; + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_API_AVAILABLE; } /* jerry_make_api_unavailable */ /** @@ -151,7 +154,7 @@ jerry_return (jerry_value_t value) /**< return value */ { if (ECMA_IS_VALUE_ERROR (value)) { - value = ecma_create_error_reference (JERRY_CONTEXT (error_value)); + value = ecma_create_error_reference_from_context (); } return value; @@ -166,7 +169,7 @@ static inline jerry_value_t __attr_always_inline___ jerry_throw (jerry_value_t value) /**< return value */ { JERRY_ASSERT (ECMA_IS_VALUE_ERROR (value)); - return ecma_create_error_reference (JERRY_CONTEXT (error_value)); + return ecma_create_error_reference_from_context (); } /* jerry_throw */ /** @@ -175,7 +178,7 @@ jerry_throw (jerry_value_t value) /**< return value */ void jerry_init (jerry_init_flag_t flags) /**< combination of Jerry flags */ { - if (unlikely (JERRY_CONTEXT (jerry_api_available))) + if (unlikely (JERRY_CONTEXT (status_flags) & ECMA_STATUS_API_AVAILABLE)) { /* This function cannot be called twice unless jerry_cleanup is called. */ JERRY_UNREACHABLE (); @@ -207,18 +210,35 @@ jerry_cleanup (void) } #endif /* JERRY_DEBUGGER */ + for (jerry_context_data_header_t *this_p = JERRY_CONTEXT (context_data_p); + this_p != NULL; + this_p = this_p->next_p) + { + if (this_p->manager_p->deinit_cb) + { + this_p->manager_p->deinit_cb (JERRY_CONTEXT_DATA_HEADER_USER_DATA (this_p)); + } + } + +#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN + ecma_free_all_enqueued_jobs (); +#endif /* CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ + ecma_finalize (); + jerry_make_api_unavailable (); + for (jerry_context_data_header_t *this_p = JERRY_CONTEXT (context_data_p), *next_p = NULL; this_p != NULL; this_p = next_p) { next_p = this_p->next_p; - this_p->manager_p->deinit_cb (JERRY_CONTEXT_DATA_HEADER_USER_DATA (this_p)); + if (this_p->manager_p->finalize_cb) + { + this_p->manager_p->finalize_cb (JERRY_CONTEXT_DATA_HEADER_USER_DATA (this_p)); + } jmem_heap_free_block (this_p, sizeof (jerry_context_data_header_t) + this_p->manager_p->bytes_needed); } - ecma_finalize (); jmem_finalize (); - jerry_make_api_unavailable (); } /* jerry_cleanup */ /** @@ -310,7 +330,8 @@ jerry_get_memory_stats (jerry_heap_stats_t *out_stats_p) /**< [out] heap memory return false; } - jmem_heap_stats_t jmem_heap_stats = {0}; + jmem_heap_stats_t jmem_heap_stats; + memset (&jmem_heap_stats, 0, sizeof (jmem_heap_stats)); jmem_heap_get_stats (&jmem_heap_stats); *out_stats_p = (jerry_heap_stats_t) @@ -343,7 +364,7 @@ jerry_run_simple (const jerry_char_t *script_source_p, /**< script source */ jerry_init (flags); - jerry_value_t parse_ret_val = jerry_parse (script_source_p, script_source_size, false); + jerry_value_t parse_ret_val = jerry_parse (NULL, 0, script_source_p, script_source_size, JERRY_PARSE_NO_OPTS); if (!ecma_is_value_error_reference (parse_ret_val)) { @@ -371,13 +392,34 @@ jerry_run_simple (const jerry_char_t *script_source_p, /**< script source */ * thrown error - otherwise */ jerry_value_t -jerry_parse (const jerry_char_t *source_p, /**< script source */ +jerry_parse (const jerry_char_t *resource_name_p, /**< resource name (usually a file name) */ + size_t resource_name_length, /**< length of resource name */ + const jerry_char_t *source_p, /**< script source */ size_t source_size, /**< script source size */ - bool is_strict) /**< strict mode */ + uint32_t parse_opts) /**< jerry_parse_opts_t option bits */ { +#if defined JERRY_DEBUGGER && !defined JERRY_DISABLE_JS_PARSER + if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) + && resource_name_length > 0) + { + jerry_debugger_send_string (JERRY_DEBUGGER_SOURCE_CODE_NAME, + JERRY_DEBUGGER_NO_SUBTYPE, + resource_name_p, + resource_name_length); + } +#else /* !(JERRY_DEBUGGER && !JERRY_DISABLE_JS_PARSER) */ + JERRY_UNUSED (resource_name_p); + JERRY_UNUSED (resource_name_length); +#endif /* JERRY_DEBUGGER && !JERRY_DISABLE_JS_PARSER */ + #ifndef JERRY_DISABLE_JS_PARSER jerry_assert_api_available (); +#if defined JERRY_ENABLE_LINE_INFO && !defined JERRY_DISABLE_JS_PARSER + JERRY_CONTEXT (resource_name) = ecma_find_or_create_literal_string (resource_name_p, + (lit_utf8_size_t) resource_name_length); +#endif /* JERRY_ENABLE_LINE_INFO && !JERRY_DISABLE_JS_PARSER */ + ecma_compiled_code_t *bytecode_data_p; ecma_value_t parse_status; @@ -385,12 +427,12 @@ jerry_parse (const jerry_char_t *source_p, /**< script source */ 0, source_p, source_size, - is_strict, + (parse_opts & JERRY_PARSE_STRICT_MODE) != 0, &bytecode_data_p); if (ECMA_IS_VALUE_ERROR (parse_status)) { - return ecma_create_error_reference (JERRY_CONTEXT (error_value)); + return ecma_create_error_reference_from_context (); } ecma_free_value (parse_status); @@ -404,44 +446,12 @@ jerry_parse (const jerry_char_t *source_p, /**< script source */ #else /* JERRY_DISABLE_JS_PARSER */ JERRY_UNUSED (source_p); JERRY_UNUSED (source_size); - JERRY_UNUSED (is_strict); + JERRY_UNUSED (parse_opts); return jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("The parser has been disabled."))); #endif /* !JERRY_DISABLE_JS_PARSER */ } /* jerry_parse */ -/** - * Parse script and construct an ECMAScript function. The lexical - * environment is set to the global lexical environment. The name - * (usually a file name) is also passed to this function which is - * used by the debugger to find the source code. - * - * @return function object value - if script was parsed successfully, - * thrown error - otherwise - */ -jerry_value_t -jerry_parse_named_resource (const jerry_char_t *resource_name_p, /**< resource name (usually a file name) */ - size_t resource_name_length, /**< length of resource name */ - const jerry_char_t *source_p, /**< script source */ - size_t source_size, /**< script source size */ - bool is_strict) /**< strict mode */ -{ -#if defined JERRY_DEBUGGER && !defined JERRY_DISABLE_JS_PARSER - if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) - { - jerry_debugger_send_string (JERRY_DEBUGGER_SOURCE_CODE_NAME, - JERRY_DEBUGGER_NO_SUBTYPE, - resource_name_p, - resource_name_length); - } -#else /* !(JERRY_DEBUGGER && !JERRY_DISABLE_JS_PARSER) */ - JERRY_UNUSED (resource_name_p); - JERRY_UNUSED (resource_name_length); -#endif /* JERRY_DEBUGGER && !JERRY_DISABLE_JS_PARSER */ - - return jerry_parse (source_p, source_size, is_strict); -} /* jerry_parse_named_resource */ - /** * Parse function and construct an EcmaScript function. The lexical * environment is set to the global lexical environment. @@ -456,7 +466,7 @@ jerry_parse_function (const jerry_char_t *resource_name_p, /**< resource name (u size_t arg_list_size, /**< script source size */ const jerry_char_t *source_p, /**< script source */ size_t source_size, /**< script source size */ - bool is_strict) /**< strict mode */ + uint32_t parse_opts) /**< jerry_parse_opts_t option bits */ { #if defined JERRY_DEBUGGER && !defined JERRY_DISABLE_JS_PARSER if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) @@ -477,6 +487,11 @@ jerry_parse_function (const jerry_char_t *resource_name_p, /**< resource name (u ecma_compiled_code_t *bytecode_data_p; ecma_value_t parse_status; +#ifdef JERRY_ENABLE_LINE_INFO + JERRY_CONTEXT (resource_name) = ecma_find_or_create_literal_string (resource_name_p, + (lit_utf8_size_t) resource_name_length); +#endif /* JERRY_ENABLE_LINE_INFO */ + if (arg_list_p == NULL) { /* Must not be a NULL value. */ @@ -487,12 +502,12 @@ jerry_parse_function (const jerry_char_t *resource_name_p, /**< resource name (u arg_list_size, source_p, source_size, - is_strict, + (parse_opts & JERRY_PARSE_STRICT_MODE) != 0, &bytecode_data_p); if (ECMA_IS_VALUE_ERROR (parse_status)) { - return ecma_create_error_reference (JERRY_CONTEXT (error_value)); + return ecma_create_error_reference_from_context (); } ecma_free_value (parse_status); @@ -508,7 +523,7 @@ jerry_parse_function (const jerry_char_t *resource_name_p, /**< resource name (u JERRY_UNUSED (arg_list_size); JERRY_UNUSED (source_p); JERRY_UNUSED (source_size); - JERRY_UNUSED (is_strict); + JERRY_UNUSED (parse_opts); return jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("The parser has been disabled."))); #endif /* !JERRY_DISABLE_JS_PARSER */ @@ -551,11 +566,7 @@ jerry_run (const jerry_value_t func_val) /**< function to run */ return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p))); } - const ecma_compiled_code_t *bytecode_data_p; - bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp); - - return jerry_return (vm_run_global (bytecode_data_p)); + return jerry_return (vm_run_global (ecma_op_function_get_compiled_code (ext_func_p))); } /* jerry_run */ /** @@ -763,6 +774,60 @@ jerry_value_is_undefined (const jerry_value_t value) /**< api value */ return ecma_is_value_undefined (jerry_get_arg_value (value)); } /* jerry_value_is_undefined */ +/** + * Perform the base type of the JavaScript value. + * + * @return jerry_type_t value + */ +jerry_type_t +jerry_value_get_type (const jerry_value_t value) /**< input value to check */ +{ + jerry_assert_api_available (); + + jerry_value_t argument = jerry_get_arg_value (value); + lit_magic_string_id_t lit_id = ecma_get_typeof_lit_id (argument); + + JERRY_ASSERT (lit_id != LIT_MAGIC_STRING__EMPTY); + + switch (lit_id) + { + case LIT_MAGIC_STRING_UNDEFINED: + { + return JERRY_TYPE_UNDEFINED; + } + case LIT_MAGIC_STRING_BOOLEAN: + { + return JERRY_TYPE_BOOLEAN; + } + case LIT_MAGIC_STRING_NUMBER: + { + return JERRY_TYPE_NUMBER; + } + case LIT_MAGIC_STRING_STRING: + { + return JERRY_TYPE_STRING; + } + case LIT_MAGIC_STRING_FUNCTION: + { + return JERRY_TYPE_FUNCTION; + } + case LIT_MAGIC_STRING_OBJECT: + { + /* Based on the ECMA 262 5.1 standard the 'null' value is an object. + * Thus we'll do an extra check for 'null' here. + */ + return ecma_is_value_null (argument) ? JERRY_TYPE_NULL : JERRY_TYPE_OBJECT; + } + default: + { + JERRY_UNREACHABLE (); + break; + } + } + + return JERRY_TYPE_NONE; +} /* jerry_value_get_type */ + /** * Check if the specified feature is enabled. * @@ -804,11 +869,29 @@ bool jerry_is_feature_enabled (const jerry_feature_t feature) #ifdef JERRY_VM_EXEC_STOP || feature == JERRY_FEATURE_VM_EXEC_STOP #endif /* JERRY_VM_EXEC_STOP */ +#ifndef CONFIG_DISABLE_JSON_BUILTIN + || feature == JERRY_FEATURE_JSON +#endif /* !CONFIG_DISABLE_JSON_BUILTIN */ +#ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN + || feature == JERRY_FEATURE_PROMISE +#endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ +#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN + || feature == JERRY_FEATURE_TYPEDARRAY +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ +#ifndef CONFIG_DISABLE_DATE_BUILTIN + || feature == JERRY_FEATURE_DATE +#endif /* !CONFIG_DISABLE_DATE_BUILTIN */ +#ifndef CONFIG_DISABLE_REGEXP_BUILTIN + || feature == JERRY_FEATURE_REGEXP +#endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */ +#ifdef JERRY_ENABLE_LINE_INFO + || feature == JERRY_FEATURE_LINE_INFO +#endif /* JERRY_ENABLE_LINE_INFO */ ); } /* jerry_is_feature_enabled */ /** - * Check if the specified value is an error value. + * Check if the specified value is an error or abort value. * * @return true - if the error flag of the specified value is true, * false - otherwise @@ -821,6 +904,27 @@ jerry_value_has_error_flag (const jerry_value_t value) /**< api value */ return ecma_is_value_error_reference (value); } /* jerry_value_has_error_flag */ +/** + * Check if the specified value is an abort value. + * + * @return true - if both the error and abort flags of the specified value are true, + * false - otherwise + */ +bool +jerry_value_has_abort_flag (const jerry_value_t value) /**< api value */ +{ + jerry_assert_api_available (); + + if (!ecma_is_value_error_reference (value)) + { + return false; + } + + ecma_error_reference_t *error_ref_p = ecma_get_error_reference_from_value (value); + + return (error_ref_p->refs_and_flags & ECMA_ERROR_REF_ABORT) != 0; +} /* jerry_value_has_abort_flag */ + /** * Clear the error flag */ @@ -831,24 +935,56 @@ jerry_value_clear_error_flag (jerry_value_t *value_p) if (ecma_is_value_error_reference (*value_p)) { - *value_p = ecma_clear_error_reference (*value_p); + *value_p = ecma_clear_error_reference (*value_p, false); } } /* jerry_value_clear_error_flag */ /** - * Set the error flag. + * Set the error flag if the value is not an error reference. */ void jerry_value_set_error_flag (jerry_value_t *value_p) { jerry_assert_api_available (); - if (!ecma_is_value_error_reference (*value_p)) + if (unlikely (ecma_is_value_error_reference (*value_p))) { - *value_p = ecma_create_error_reference (*value_p); + /* This is a rare case so it is optimized for + * binary size rather than performance. */ + if (!jerry_value_has_abort_flag (*value_p)) + { + return; + } + + jerry_value_clear_error_flag (value_p); } + + *value_p = ecma_create_error_reference (*value_p, true); } /* jerry_value_set_error_flag */ +/** + * Set both the abort and error flags if the value is not an error reference. + */ +void +jerry_value_set_abort_flag (jerry_value_t *value_p) +{ + jerry_assert_api_available (); + + if (unlikely (ecma_is_value_error_reference (*value_p))) + { + /* This is a rare case so it is optimized for + * binary size rather than performance. */ + if (jerry_value_has_abort_flag (*value_p)) + { + return; + } + + jerry_value_clear_error_flag (value_p); + } + + *value_p = ecma_create_error_reference (*value_p, false); +} /* jerry_value_set_abort_flag */ + /** * If the input value is an error value, then return a new reference to its referenced value. * Otherwise, return a new reference to the value itself. @@ -863,6 +999,28 @@ jerry_value_t jerry_get_value_without_error_flag (jerry_value_t value) /**< api return jerry_acquire_value (jerry_get_arg_value (value)); } /* jerry_get_value_without_error_flag */ +/** + * Return the type of the Error object if possible. + * + * @return one of the jerry_error_t value as the type of the Error object + * JERRY_ERROR_NONE - if the input value is not an Error object + */ +jerry_error_t +jerry_get_error_type (const jerry_value_t value) /**< api value */ +{ + jerry_value_t object = jerry_get_arg_value (value); + + if (!ecma_is_value_object (object)) + { + return JERRY_ERROR_NONE; + } + + ecma_object_t *object_p = ecma_get_object_from_value (object); + ecma_standard_error_t error_type = ecma_get_error_type (object_p); + + return (jerry_error_t) error_type; +} /* jerry_get_error_type */ + /** * Get boolean from the specified value. * @@ -1467,6 +1625,11 @@ jerry_get_utf8_string_length (const jerry_value_t value) /**< input string */ * Returns 0, if the value parameter is not a string or * the buffer is not large enough for the whole string. * + * Note: + * If the size of the string in jerry value is larger than the size of the + * target buffer, the copy will fail. + * To copy substring use jerry_substring_to_char_buffer() instead. + * * @return number of bytes, actually copied to the buffer. */ jerry_size_t @@ -1503,6 +1666,11 @@ jerry_string_to_char_buffer (const jerry_value_t value, /**< input string value * Returns 0, if the value parameter is not a string or the buffer * is not large enough for the whole string. * + * Note: + * If the size of the string in jerry value is larger than the size of the + * target buffer, the copy will fail. + * To copy a substring use jerry_substring_to_utf8_char_buffer() instead. + * * @return number of bytes copied to the buffer. */ jerry_size_t @@ -1703,11 +1871,12 @@ jerry_delete_property_by_index (const jerry_value_t obj_val, /**< object value * return false; } - ecma_string_t str_idx; - ecma_init_ecma_string_from_uint32 (&str_idx, index); + ecma_string_t *str_idx_p = ecma_new_ecma_string_from_uint32 (index); ecma_value_t ret_value = ecma_op_object_delete (ecma_get_object_from_value (obj_value), - &str_idx, + str_idx_p, false); + ecma_deref_ecma_string (str_idx_p); + return ecma_is_value_true (ret_value); } /* jerry_delete_property_by_index */ @@ -1762,9 +1931,9 @@ jerry_get_property_by_index (const jerry_value_t obj_val, /**< object value */ return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p))); } - ecma_string_t str_idx; - ecma_init_ecma_string_from_uint32 (&str_idx, index); - ecma_value_t ret_value = ecma_op_object_get (ecma_get_object_from_value (obj_value), &str_idx); + ecma_string_t *str_idx_p = ecma_new_ecma_string_from_uint32 (index); + ecma_value_t ret_value = ecma_op_object_get (ecma_get_object_from_value (obj_value), str_idx_p); + ecma_deref_ecma_string (str_idx_p); return jerry_return (ret_value); } /* jerry_get_property_by_index */ @@ -2319,6 +2488,70 @@ jerry_set_object_native_handle (const jerry_value_t obj_val, /**< object to set } } /* jerry_set_object_native_handle */ +/** + * Traverse objects. + * + * @return true - traversal was interrupted by the callback. + * false - otherwise - traversal visited all objects. + */ +bool jerry_objects_foreach (jerry_objects_foreach_t foreach_p, + void *user_data_p) +{ + jerry_assert_api_available (); + + JERRY_ASSERT (foreach_p != NULL); + + for (ecma_object_t *iter_p = JERRY_CONTEXT (ecma_gc_objects_p); + iter_p != NULL; + iter_p = ECMA_GET_POINTER (ecma_object_t, iter_p->gc_next_cp)) + { + if (!ecma_is_lexical_environment (iter_p) + && !foreach_p (ecma_make_object_value (iter_p), user_data_p)) + { + return true; + } + } + + return false; +} /* jerry_objects_foreach */ + +/** + * Traverse objects having a given native type info. + * + * @return true - traversal was interrupted by the callback. + * false - otherwise - traversal visited all objects. + */ +bool +jerry_objects_foreach_by_native_info (const jerry_object_native_info_t *native_info_p, + jerry_objects_foreach_by_native_info_t foreach_p, + void *user_data_p) +{ + jerry_assert_api_available (); + + JERRY_ASSERT (native_info_p != NULL); + JERRY_ASSERT (foreach_p != NULL); + + ecma_native_pointer_t *native_pointer_p; + + for (ecma_object_t *iter_p = JERRY_CONTEXT (ecma_gc_objects_p); + iter_p != NULL; + iter_p = ECMA_GET_POINTER (ecma_object_t, iter_p->gc_next_cp)) + { + if (!ecma_is_lexical_environment (iter_p)) + { + native_pointer_p = ecma_get_native_pointer_value (iter_p, LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER); + if (native_pointer_p + && ((const jerry_object_native_info_t *) native_pointer_p->u.info_p) == native_info_p + && !foreach_p (ecma_make_object_value (iter_p), native_pointer_p->data_p, user_data_p)) + { + return true; + } + } + } + + return false; +} /* jerry_objects_foreach_by_native_info */ + /** * Get native pointer and its type information, associated with specified object. * @@ -2419,19 +2652,18 @@ jerry_foreach_object_property (const jerry_value_t obj_val, /**< object value */ return false; } - ecma_collection_iterator_t names_iter; ecma_object_t *object_p = ecma_get_object_from_value (obj_value); ecma_collection_header_t *names_p = ecma_op_object_get_property_names (object_p, false, true, true); - ecma_collection_iterator_init (&names_iter, names_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (names_p); ecma_value_t property_value = ECMA_VALUE_EMPTY; bool continuous = true; - while (continuous - && ecma_collection_iterator_next (&names_iter)) + while (continuous && ecma_value_p != NULL) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*names_iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + property_value = ecma_op_object_get (object_p, property_name_p); if (ECMA_IS_VALUE_ERROR (property_value)) @@ -2439,11 +2671,13 @@ jerry_foreach_object_property (const jerry_value_t obj_val, /**< object value */ break; } - continuous = foreach_p (*names_iter.current_value_p, property_value, user_data_p); + continuous = foreach_p (*ecma_value_p, property_value, user_data_p); ecma_free_value (property_value); + + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); } - ecma_free_values_collection (names_p, true); + ecma_free_values_collection (names_p, 0); if (!ECMA_IS_VALUE_ERROR (property_value)) { @@ -2624,6 +2858,637 @@ jerry_set_vm_exec_stop_callback (jerry_vm_exec_stop_callback_t stop_cb, /**< per #endif /* JERRY_VM_EXEC_STOP */ } /* jerry_set_vm_exec_stop_callback */ +/** + * Get backtrace. The backtrace is an array of strings where + * each string contains the position of the corresponding frame. + * The array length is zero if the backtrace is not available. + * + * @return array value + */ +jerry_value_t +jerry_get_backtrace (uint32_t max_depth) +{ + return vm_get_backtrace (max_depth); +} /* jerry_get_backtrace */ + +/** + * Check if the given value is an ArrayBuffer object. + * + * @return true - if it is an ArrayBuffer object + * false - otherwise + */ +bool +jerry_value_is_arraybuffer (const jerry_value_t value) /**< value to check if it is an ArrayBuffer */ +{ + jerry_assert_api_available (); + +#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN + jerry_value_t buffer = jerry_get_arg_value (value); + return ecma_is_arraybuffer (buffer); +#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + JERRY_UNUSED (value); + return false; +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ +} /* jerry_value_is_arraybuffer */ + +/** + * Creates an ArrayBuffer object with the given length (size). + * + * Notes: + * * the length is specified in bytes. + * * returned value must be freed with jerry_release_value, when it is no longer needed. + * * if the typed arrays are disabled this will return a TypeError. + * + * @return value of the constructed ArrayBuffer object + */ +jerry_value_t +jerry_create_arraybuffer (const jerry_length_t size) /**< size of the ArrayBuffer to create */ +{ + jerry_assert_api_available (); + +#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN + return jerry_return (ecma_make_object_value (ecma_arraybuffer_new_object (size))); +#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + JERRY_UNUSED (size); + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer not supported."))); +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ +} /* jerry_create_arraybuffer */ + +/** + * Creates an ArrayBuffer object with user specified buffer. + * + * Notes: + * * the size is specified in bytes. + * * the buffer passed should be at least the specified bytes big. + * * if the typed arrays are disabled this will return a TypeError. + * * if the size is zero or the buffer_p is a null pointer this will return a RangeError. + * + * @return value of the construced ArrayBuffer object + */ +jerry_value_t +jerry_create_arraybuffer_external (const jerry_length_t size, /**< size of the buffer to used */ + uint8_t *buffer_p, /**< buffer to use as the ArrayBuffer's backing */ + jerry_object_native_free_callback_t free_cb) /**< buffer free callback */ +{ + jerry_assert_api_available (); + +#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN + if (size == 0 || buffer_p == NULL) + { + return jerry_throw (ecma_raise_range_error (ECMA_ERR_MSG ("invalid buffer size or storage reference"))); + } + + ecma_object_t *arraybuffer = ecma_arraybuffer_new_object_external (size, + buffer_p, + (ecma_object_native_free_callback_t) free_cb); + return jerry_return (ecma_make_object_value (arraybuffer)); +#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + JERRY_UNUSED (size); + JERRY_UNUSED (buffer_p); + JERRY_UNUSED (free_cb); + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("ArrayBuffer not supported."))); +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ +} /* jerry_create_arraybuffer_external */ + +/** + * Copy bytes into the ArrayBuffer from a buffer. + * + * Note: + * * if the object passed is not an ArrayBuffer will return 0. + * + * @return number of bytes copied into the ArrayBuffer. + */ +jerry_length_t +jerry_arraybuffer_write (const jerry_value_t value, /**< target ArrayBuffer */ + jerry_length_t offset, /**< start offset of the ArrayBuffer */ + const uint8_t *buf_p, /**< buffer to copy from */ + jerry_length_t buf_size) /**< number of bytes to copy from the buffer */ +{ + jerry_assert_api_available (); + +#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN + jerry_value_t buffer = jerry_get_arg_value (value); + + if (!ecma_is_arraybuffer (buffer)) + { + return 0; + } + + ecma_object_t *buffer_p = ecma_get_object_from_value (buffer); + jerry_length_t length = ecma_arraybuffer_get_length (buffer_p); + + if (offset >= length) + { + return 0; + } + + jerry_length_t copy_count = JERRY_MIN (length - offset, buf_size); + + if (copy_count > 0) + { + lit_utf8_byte_t *mem_buffer_p = ecma_arraybuffer_get_buffer (buffer_p); + + memcpy ((void *) (mem_buffer_p + offset), (void *) buf_p, copy_count); + } + + return copy_count; +#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + JERRY_UNUSED (value); + JERRY_UNUSED (offset); + JERRY_UNUSED (buf_p); + JERRY_UNUSED (buf_size); + return 0; +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ +} /* jerry_arraybuffer_write */ + +/** + * Copy bytes from a buffer into an ArrayBuffer. + * + * Note: + * * if the object passed is not an ArrayBuffer will return 0. + * + * @return number of bytes read from the ArrayBuffer. + */ +jerry_length_t +jerry_arraybuffer_read (const jerry_value_t value, /**< ArrayBuffer to read from */ + jerry_length_t offset, /**< start offset of the ArrayBuffer */ + uint8_t *buf_p, /**< destination buffer to copy to */ + jerry_length_t buf_size) /**< number of bytes to copy into the buffer */ +{ + jerry_assert_api_available (); + +#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN + jerry_value_t buffer = jerry_get_arg_value (value); + + if (!ecma_is_arraybuffer (buffer)) + { + return 0; + } + + ecma_object_t *buffer_p = ecma_get_object_from_value (buffer); + jerry_length_t length = ecma_arraybuffer_get_length (buffer_p); + + if (offset >= length) + { + return 0; + } + + jerry_length_t copy_count = JERRY_MIN (length - offset, buf_size); + + if (copy_count > 0) + { + lit_utf8_byte_t *mem_buffer_p = ecma_arraybuffer_get_buffer (buffer_p); + + memcpy ((void *) buf_p, (void *) (mem_buffer_p + offset), copy_count); + } + + return copy_count; +#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + JERRY_UNUSED (value); + JERRY_UNUSED (offset); + JERRY_UNUSED (buf_p); + JERRY_UNUSED (buf_size); + return 0; +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ +} /* jerry_arraybuffer_read */ + +/** + * Get the length (size) of the ArrayBuffer in bytes. + * + * Note: + * This is the 'byteLength' property of an ArrayBuffer. + * + * @return the length of the ArrayBuffer in bytes. + */ +jerry_length_t +jerry_get_arraybuffer_byte_length (const jerry_value_t value) /**< ArrayBuffer */ +{ + jerry_assert_api_available (); + +#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN + jerry_value_t buffer = jerry_get_arg_value (value); + if (ecma_is_arraybuffer (buffer)) + { + ecma_object_t *buffer_p = ecma_get_object_from_value (buffer); + return ecma_arraybuffer_get_length (buffer_p); + } +#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + JERRY_UNUSED (value); +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + return 0; +} /* jerry_get_arraybuffer_byte_length */ + +/** + * Get a pointer for the start of the ArrayBuffer. + * + * Note: + * * Only valid for ArrayBuffers created with jerry_create_arraybuffer_external. + * * This is a high-risk operation as the bounds are not checked + * when accessing the pointer elements. + * * jerry_release_value must be called on the ArrayBuffer when the pointer is no longer needed. + * + * @return pointer to the back-buffer of the ArrayBuffer. + * pointer is NULL if the parameter is not an ArrayBuffer with external memory + or it is not an ArrayBuffer at all. + */ +uint8_t * +jerry_get_arraybuffer_pointer (const jerry_value_t value) /**< Array Buffer to use */ +{ + jerry_assert_api_available (); +#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN + jerry_value_t buffer = jerry_get_arg_value (value); + + if (!ecma_is_arraybuffer (buffer)) + { + return NULL; + } + + ecma_object_t *buffer_p = ecma_get_object_from_value (buffer); + if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (buffer_p)) + { + jerry_acquire_value (value); + lit_utf8_byte_t *mem_buffer_p = ecma_arraybuffer_get_buffer (buffer_p); + return (uint8_t *const) mem_buffer_p; + } +#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + JERRY_UNUSED (value); +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + + return NULL; +} /* jerry_get_arraybuffer_pointer */ + + +/** + * TypedArray related functions + */ + +/** + * Check if the given value is a TypedArray object. + * + * @return true - if it is a TypedArray object + * false - otherwise + */ +bool +jerry_value_is_typedarray (jerry_value_t value) /**< value to check if it is a TypedArray */ +{ + jerry_assert_api_available (); + +#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN + jerry_value_t array = jerry_get_arg_value (value); + return ecma_is_typedarray (array); +#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + JERRY_UNUSED (value); + return false; +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ +} /* jerry_value_is_typedarray */ + +#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN +typedef struct +{ + jerry_typedarray_type_t api_type; + ecma_builtin_id_t prototype_id; + lit_magic_string_id_t lit_id; + uint8_t element_size_shift; +} jerry_typedarray_mapping_t; + +static jerry_typedarray_mapping_t jerry_typedarray_mappings[] = +{ +#define TYPEDARRAY_ENTRY(NAME, LIT_NAME, SIZE_SHIFT) \ + { JERRY_TYPEDARRAY_ ## NAME, ECMA_BUILTIN_ID_ ## NAME ## ARRAY_PROTOTYPE, \ + LIT_MAGIC_STRING_ ## LIT_NAME ## _ARRAY_UL, SIZE_SHIFT } + + TYPEDARRAY_ENTRY (UINT8, UINT8, 0), + TYPEDARRAY_ENTRY (UINT8CLAMPED, UINT8_CLAMPED, 0), + TYPEDARRAY_ENTRY (INT8, INT8, 0), + TYPEDARRAY_ENTRY (UINT16, UINT16, 1), + TYPEDARRAY_ENTRY (INT16, INT16, 1), + TYPEDARRAY_ENTRY (UINT32, UINT32, 2), + TYPEDARRAY_ENTRY (INT32, INT32, 2), + TYPEDARRAY_ENTRY (FLOAT32, FLOAT32, 2), +#if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 + TYPEDARRAY_ENTRY (FLOAT64, FLOAT64, 3), +#endif + +#undef TYPEDARRAY_ENTRY +}; + +/** + * Helper function to get the TypedArray prototype, literal id, and element size shift + * information. + * + * @return true - if the TypedArray information was found + * false - if there is no such TypedArray type + */ +static bool +jerry_typedarray_find_by_type (jerry_typedarray_type_t type_name, /**< type of the TypedArray */ + ecma_builtin_id_t *prototype_id, /**< [out] found prototype object id */ + lit_magic_string_id_t *lit_id, /**< [out] found literal id */ + uint8_t *element_size_shift) /**< [out] found element size shift value */ +{ + JERRY_ASSERT (prototype_id != NULL); + JERRY_ASSERT (lit_id != NULL); + JERRY_ASSERT (element_size_shift != NULL); + + for (uint32_t i = 0; i < sizeof (jerry_typedarray_mappings) / sizeof (jerry_typedarray_mappings[0]); i++) + { + if (type_name == jerry_typedarray_mappings[i].api_type) + { + *prototype_id = jerry_typedarray_mappings[i].prototype_id; + *lit_id = jerry_typedarray_mappings[i].lit_id; + *element_size_shift = jerry_typedarray_mappings[i].element_size_shift; + return true; + } + } + + return false; +} /* jerry_typedarray_find_by_type */ + +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + +/** + * Create a TypedArray object with a given type and length. + * + * Notes: + * * returns TypeError if an incorrect type (type_name) is specified. + * * byteOffset property will be set to 0. + * * byteLength property will be a multiple of the length parameter (based on the type). + * + * @return - new TypedArray object + */ +jerry_value_t +jerry_create_typedarray (jerry_typedarray_type_t type_name, /**< type of TypedArray to create */ + jerry_length_t length) /**< element count of the new TypedArray */ +{ + jerry_assert_api_available (); + +#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN + ecma_builtin_id_t prototype_id = 0; + lit_magic_string_id_t lit_id = 0; + uint8_t element_size_shift = 0; + + if (!jerry_typedarray_find_by_type (type_name, &prototype_id, &lit_id, &element_size_shift)) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("incorrect type for TypedArray."))); + } + + ecma_object_t *prototype_obj_p = ecma_builtin_get (prototype_id); + + ecma_value_t array_value = ecma_typedarray_create_object_with_length (length, + prototype_obj_p, + element_size_shift, + lit_id); + ecma_deref_object (prototype_obj_p); + + JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (array_value)); + + return array_value; +#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + JERRY_UNUSED (type_name); + JERRY_UNUSED (length); + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("TypedArray not supported."))); +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ +} /* jerry_create_typedarray */ + +/** + * Create a TypedArray object using the given arraybuffer and size information. + * + * Notes: + * * returns TypeError if an incorrect type (type_name) is specified. + * * this is the 'new %TypedArray%(arraybuffer, byteOffset, length)' equivalent call. + * + * @return - new TypedArray object + */ +jerry_value_t +jerry_create_typedarray_for_arraybuffer_sz (jerry_typedarray_type_t type_name, /**< type of TypedArray to create */ + const jerry_value_t arraybuffer, /**< ArrayBuffer to use */ + jerry_length_t byte_offset, /**< offset for the ArrayBuffer */ + jerry_length_t length) /**< number of elements to use from ArrayBuffer */ +{ + jerry_assert_api_available (); + +#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN + ecma_builtin_id_t prototype_id = 0; + lit_magic_string_id_t lit_id = 0; + uint8_t element_size_shift = 0; + + if (!jerry_typedarray_find_by_type (type_name, &prototype_id, &lit_id, &element_size_shift)) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("incorrect type for TypedArray."))); + } + + jerry_value_t buffer = jerry_get_arg_value (arraybuffer); + if (!ecma_is_arraybuffer (buffer)) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an ArrayBuffer"))); + } + + ecma_object_t *prototype_obj_p = ecma_builtin_get (prototype_id); + ecma_value_t arguments_p[3] = + { + arraybuffer, + ecma_make_uint32_value (byte_offset), + ecma_make_uint32_value (length) + }; + + ecma_value_t array_value = ecma_op_create_typedarray (arguments_p, 3, prototype_obj_p, element_size_shift, lit_id); + ecma_free_value (arguments_p[1]); + ecma_free_value (arguments_p[2]); + ecma_deref_object (prototype_obj_p); + + return jerry_return (array_value); +#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + JERRY_UNUSED (type_name); + JERRY_UNUSED (arraybuffer); + JERRY_UNUSED (byte_offset); + JERRY_UNUSED (length); + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("TypedArray not supported."))); +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ +} /* jerry_create_typedarray_for_arraybuffer_sz */ + +/** + * Create a TypedArray object using the given arraybuffer and size information. + * + * Notes: + * * returns TypeError if an incorrect type (type_name) is specified. + * * this is the 'new %TypedArray%(arraybuffer)' equivalent call. + * + * @return - new TypedArray object + */ +jerry_value_t +jerry_create_typedarray_for_arraybuffer (jerry_typedarray_type_t type_name, /**< type of TypedArray to create */ + const jerry_value_t arraybuffer) /**< ArrayBuffer to use */ +{ + jerry_assert_api_available (); + jerry_length_t byteLength = jerry_get_arraybuffer_byte_length (arraybuffer); + return jerry_create_typedarray_for_arraybuffer_sz (type_name, arraybuffer, 0, byteLength); +} /* jerry_create_typedarray_for_arraybuffer */ + +/** + * Get the type of the TypedArray. + * + * @return - type of the TypedArray + * - JERRY_TYPEDARRAY_INVALID if the argument is not a TypedArray + */ +jerry_typedarray_type_t +jerry_get_typedarray_type (jerry_value_t value) /**< object to get the TypedArray type */ +{ + jerry_assert_api_available (); + +#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN + jerry_value_t array = jerry_get_arg_value (value); + if (!ecma_is_typedarray (array)) + { + return JERRY_TYPEDARRAY_INVALID; + } + + ecma_object_t *array_p = ecma_get_object_from_value (array); + + lit_magic_string_id_t class_name_id = ecma_object_get_class_name (array_p); + for (uint32_t i = 0; i < sizeof (jerry_typedarray_mappings) / sizeof (jerry_typedarray_mappings[0]); i++) + { + if (class_name_id == jerry_typedarray_mappings[i].lit_id) + { + return jerry_typedarray_mappings[i].api_type; + } + } +#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + JERRY_UNUSED (value); +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + + return JERRY_TYPEDARRAY_INVALID; +} /* jerry_get_typedarray_type */ + +/** + * Get the element count of the TypedArray. + * + * @return length of the TypedArray. + */ +jerry_length_t +jerry_get_typedarray_length (jerry_value_t value) /**< TypedArray to query */ +{ + jerry_assert_api_available (); + +#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN + jerry_value_t array = jerry_get_arg_value (value); + if (ecma_is_typedarray (array)) + { + ecma_object_t *array_p = ecma_get_object_from_value (array); + return ecma_typedarray_get_length (array_p); + } +#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + JERRY_UNUSED (value); +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + + return 0; +} /* jerry_get_typedarray_length */ + +/** + * Get the underlying ArrayBuffer from a TypedArray. + * + * Additionally the byteLength and byteOffset properties are also returned + * which were specified when the TypedArray was created. + * + * Note: + * the returned value must be freed with a jerry_release_value call + * + * @return ArrayBuffer of a TypedArray + * TypeError if the object is not a TypedArray. + */ +jerry_value_t +jerry_get_typedarray_buffer (jerry_value_t value, /**< TypedArray to get the arraybuffer from */ + jerry_length_t *byte_offset, /**< [out] byteOffset property */ + jerry_length_t *byte_length) /**< [out] byteLength property */ +{ + jerry_assert_api_available (); + +#ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN + jerry_value_t array = jerry_get_arg_value (value); + if (!ecma_is_typedarray (array)) + { + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Object is not a TypedArray."))); + } + + ecma_object_t *array_p = ecma_get_object_from_value (array); + uint8_t shift = ecma_typedarray_get_element_size_shift (array_p); + + if (byte_length != NULL) + { + *byte_length = (jerry_length_t) (ecma_typedarray_get_length (array_p) << shift); + } + + if (byte_offset != NULL) + { + *byte_offset = (jerry_length_t) ecma_typedarray_get_offset (array_p); + } + + ecma_object_t *arraybuffer_p = ecma_typedarray_get_arraybuffer (array_p); + ecma_ref_object (arraybuffer_p); + return jerry_return (ecma_make_object_value (arraybuffer_p)); +#else /* CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ + JERRY_UNUSED (value); + JERRY_UNUSED (byte_length); + JERRY_UNUSED (byte_offset); + return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("TypedArray is not supported."))); +#endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ +} /* jerry_get_typedarray_buffer */ + +/** + * Create an object from JSON + * + * Note: + * The returned value must be freed with jerry_release_value + * @return jerry_value_t from json formated string or an error massage + */ +jerry_value_t +jerry_json_parse (const jerry_char_t *string_p, /**< json string */ + jerry_size_t string_size) /**< json string size */ +{ + jerry_assert_api_available (); + +#ifndef CONFIG_DISABLE_JSON_BUILTIN + ecma_value_t ret_value = ecma_builtin_json_parse_buffer (string_p, string_size); + + if (ecma_is_value_undefined (ret_value)) + { + ret_value = jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("JSON string parse error."))); + } + + return ret_value; +#else /* CONFIG_DISABLE_JSON_BUILTIN */ + JERRY_UNUSED (string_p); + JERRY_UNUSED (string_size); + + return jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("The JSON has been disabled."))); +#endif /* !CONFIG_DISABLE_JSON_BUILTIN */ +} /* jerry_json_parse */ + +/** + * Create a Json formated string from an object + * + * Note: + * The returned value must be freed with jerry_release_value + * @return json formated jerry_value_t or an error massage + */ +jerry_value_t +jerry_json_stringfy (const jerry_value_t object_to_stringify) /**< a jerry_object_t to stringify */ +{ + jerry_assert_api_available (); +#ifndef CONFIG_DISABLE_JSON_BUILTIN + ecma_value_t ret_value = ecma_builtin_json_string_from_object (object_to_stringify); + + if (ecma_is_value_undefined (ret_value)) + { + ret_value = jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("JSON stringify error."))); + } + + return ret_value; +#else /* CONFIG_DISABLE_JSON_BUILTIN */ + JERRY_UNUSED (object_to_stringify); + + return jerry_throw (ecma_raise_syntax_error (ECMA_ERR_MSG ("The JSON has been disabled."))); +#endif /* !CONFIG_DISABLE_JSON_BUILTIN */ +} /* jerry_json_stringfy */ + /** * @} */ diff --git a/deps/jerry/jerry-core/debugger/debugger-ws.c b/deps/jerry/jerry-core/debugger/debugger-ws.c index 4117249..a19f4e8 100644 --- a/deps/jerry/jerry-core/debugger/debugger-ws.c +++ b/deps/jerry/jerry-core/debugger/debugger-ws.c @@ -24,6 +24,13 @@ #include #include +/* JerryScript debugger protocol is a simplified version of RFC-6455 (WebSockets). */ + +/** + * Last fragment of a Websocket package. + */ +#define JERRY_DEBUGGER_WEBSOCKET_FIN_BIT 0x80 + /** * Masking-key is available. */ @@ -39,17 +46,38 @@ */ #define JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK 0x7fu +/** + * Size of websocket header size. + */ +#define JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE 2 + /** * Payload mask size in bytes of a websocket package. */ #define JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE 4 /** - * + * Maximum message size with 1 byte size field. + */ +#define JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX 125 + +/** + * Waiting for data from the client. */ #define JERRY_DEBUGGER_RECEIVE_DATA_MODE \ (JERRY_DEBUGGER_BREAKPOINT_MODE | JERRY_DEBUGGER_CLIENT_SOURCE_MODE) +/** + * WebSocket opcode types. + */ +typedef enum +{ + JERRY_DEBUGGER_WEBSOCKET_TEXT_FRAME = 1, /**< text frame */ + JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME = 2, /**< binary frame */ + JERRY_DEBUGGER_WEBSOCKET_CLOSE_CONNECTION = 8, /**< close connection */ + JERRY_DEBUGGER_WEBSOCKET_PING = 9, /**< ping (keep alive) frame */ + JERRY_DEBUGGER_WEBSOCKET_PONG = 10, /**< reply to ping frame */ +} jerry_websocket_opcode_type_t; /** * Header for incoming packets. @@ -69,7 +97,7 @@ jerry_debugger_close_connection_tcp (bool log_error) /**< log error */ { JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); - JERRY_CONTEXT (debugger_flags) = (uint8_t) JERRY_DEBUGGER_VM_IGNORE; + JERRY_CONTEXT (debugger_flags) = JERRY_DEBUGGER_VM_IGNORE; if (log_error) { @@ -314,6 +342,25 @@ jerry_debugger_accept_connection (void) struct sockaddr_in addr; socklen_t sin_size = sizeof (struct sockaddr_in); + uint8_t *payload_p = JERRY_CONTEXT (debugger_send_buffer) + JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE; + JERRY_CONTEXT (debugger_send_buffer_payload_p) = payload_p; + + uint8_t max_send_size = (JERRY_DEBUGGER_MAX_BUFFER_SIZE - JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE); + if (max_send_size > JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX) + { + max_send_size = JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX; + } + JERRY_CONTEXT (debugger_max_send_size) = max_send_size; + + uint8_t receive_header_size = (JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE + JERRY_DEBUGGER_WEBSOCKET_MASK_SIZE); + uint8_t max_receive_size = (uint8_t) (JERRY_DEBUGGER_MAX_BUFFER_SIZE - receive_header_size); + + if (max_receive_size > JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX) + { + max_receive_size = JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX; + } + JERRY_CONTEXT (debugger_max_receive_size) = max_receive_size; + addr.sin_family = AF_INET; addr.sin_port = htons (JERRY_CONTEXT (debugger_port)); addr.sin_addr.s_addr = INADDR_ANY; @@ -360,7 +407,7 @@ jerry_debugger_accept_connection (void) close (server_socket); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_CONNECTED); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_CONNECTED); bool is_handshake_ok = false; @@ -377,7 +424,7 @@ jerry_debugger_accept_connection (void) return false; } - if (!jerry_debugger_send_configuration (JERRY_DEBUGGER_MAX_RECEIVE_SIZE)) + if (!jerry_debugger_send_configuration (max_receive_size)) { return false; } @@ -399,7 +446,7 @@ jerry_debugger_accept_connection (void) jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Connected from: %s\n", inet_ntoa (addr.sin_addr)); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_STOP); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = NULL; return true; @@ -420,14 +467,17 @@ jerry_debugger_close_connection (void) * @return true - if the data was sent successfully to the debugger client, * false - otherwise */ -inline bool __attr_always_inline___ +bool jerry_debugger_send (size_t data_size) /**< data size */ { - return jerry_debugger_send_tcp (JERRY_CONTEXT (debugger_send_buffer), data_size); -} /* jerry_debugger_send */ + JERRY_ASSERT (data_size <= JERRY_CONTEXT (debugger_max_send_size)); + + uint8_t *header_p = JERRY_CONTEXT (debugger_send_buffer); + header_p[0] = JERRY_DEBUGGER_WEBSOCKET_FIN_BIT | JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME; + header_p[1] = (uint8_t) data_size; -JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MAX_RECEIVE_SIZE < 126, - maximum_debug_message_receive_size_must_be_smaller_than_126); + return jerry_debugger_send_tcp (header_p, data_size + JERRY_DEBUGGER_WEBSOCKET_HEADER_SIZE); +} /* jerry_debugger_send */ /** * Receive message from the client. @@ -443,8 +493,9 @@ bool jerry_debugger_receive (jerry_debugger_uint8_data_t **message_data_p) /**< [out] data received from client */ { JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); + JERRY_ASSERT (JERRY_CONTEXT (debugger_max_receive_size) <= JERRY_DEBUGGER_WEBSOCKET_ONE_BYTE_LEN_MAX); - JERRY_ASSERT (message_data_p != NULL ? (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_RECEIVE_DATA_MODE) + JERRY_ASSERT (message_data_p != NULL ? !!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_RECEIVE_DATA_MODE) : !(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_RECEIVE_DATA_MODE)); JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY; @@ -487,7 +538,7 @@ jerry_debugger_receive (jerry_debugger_uint8_data_t **message_data_p) /**< [out] } if ((recv_buffer_p[0] & ~JERRY_DEBUGGER_WEBSOCKET_OPCODE_MASK) != JERRY_DEBUGGER_WEBSOCKET_FIN_BIT - || (recv_buffer_p[1] & JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK) > JERRY_DEBUGGER_MAX_RECEIVE_SIZE + || (recv_buffer_p[1] & JERRY_DEBUGGER_WEBSOCKET_LENGTH_MASK) > JERRY_CONTEXT (debugger_max_receive_size) || !(recv_buffer_p[1] & JERRY_DEBUGGER_WEBSOCKET_MASK_BIT)) { jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Unsupported Websocket message.\n"); diff --git a/deps/jerry/jerry-core/debugger/debugger-ws.h b/deps/jerry/jerry-core/debugger/debugger-ws.h index f3af65b..3a7c97c 100644 --- a/deps/jerry/jerry-core/debugger/debugger-ws.h +++ b/deps/jerry/jerry-core/debugger/debugger-ws.h @@ -27,42 +27,6 @@ */ #define JERRY_DEBUGGER_MAX_BUFFER_SIZE 128 -/** - * Maximum number of bytes can be received in a single message. - */ -#define JERRY_DEBUGGER_MAX_SEND_SIZE (JERRY_DEBUGGER_MAX_BUFFER_SIZE - 1) - -/** - * Maximum number of bytes can be received in a single message. - */ -#define JERRY_DEBUGGER_MAX_RECEIVE_SIZE (JERRY_DEBUGGER_MAX_BUFFER_SIZE - 6) - -/** - * Last fragment of a Websocket package. - */ -#define JERRY_DEBUGGER_WEBSOCKET_FIN_BIT 0x80 - -/** - * WebSocket opcode types. - */ -typedef enum -{ - JERRY_DEBUGGER_WEBSOCKET_TEXT_FRAME = 1, /**< text frame */ - JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME = 2, /**< binary frame */ - JERRY_DEBUGGER_WEBSOCKET_CLOSE_CONNECTION = 8, /**< close connection */ - JERRY_DEBUGGER_WEBSOCKET_PING = 9, /**< ping (keep alive) frame */ - JERRY_DEBUGGER_WEBSOCKET_PONG = 10, /**< reply to ping frame */ -} jerry_websocket_opcode_type_t; - -/** - * Header for outgoing packets. - */ -typedef struct -{ - uint8_t ws_opcode; /**< Websocket opcode */ - uint8_t size; /**< size of the message */ -} jerry_debugger_send_header_t; - /** * Incoming message: next message of string data. */ @@ -80,24 +44,6 @@ typedef struct uint32_t uint8_offset; /**< current offset in the client source */ } jerry_debugger_uint8_data_t; -/** - * Initialize the header of an outgoing message. - */ -#define JERRY_DEBUGGER_INIT_SEND_MESSAGE(message_p) \ - (message_p)->header.ws_opcode = JERRY_DEBUGGER_WEBSOCKET_FIN_BIT | JERRY_DEBUGGER_WEBSOCKET_BINARY_FRAME - -/** - * Set the size of an outgoing message from type. - */ -#define JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE(message_p, type) \ - (message_p)->header.size = (uint8_t) (sizeof (type) - sizeof (jerry_debugger_send_header_t)) - -/** - * Set the size of an outgoing message. - */ -#define JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE(message_p, byte_size) \ - (message_p)->header.size = (uint8_t) (byte_size) - bool jerry_debugger_accept_connection (void); void jerry_debugger_close_connection (void); diff --git a/deps/jerry/jerry-core/debugger/debugger.c b/deps/jerry/jerry-core/debugger/debugger.c index bc4c5b9..0a128b3 100644 --- a/deps/jerry/jerry-core/debugger/debugger.c +++ b/deps/jerry/jerry-core/debugger/debugger.c @@ -24,17 +24,20 @@ #ifdef JERRY_DEBUGGER -#ifdef HAVE_TIME_H -#include -#elif defined (HAVE_UNISTD_H) -#include -#endif /* HAVE_TIME_H */ +/** + * The number of message types in the debugger should reflect the + * debugger versioning. + */ +JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 27 + && JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 19 + && JERRY_DEBUGGER_VERSION == 3, + debugger_version_correlates_to_message_type_count); /** * Type cast the debugger send buffer into a specific type. */ #define JERRY_DEBUGGER_SEND_BUFFER_AS(type, name_p) \ - type *name_p = (type *) (&JERRY_CONTEXT (debugger_send_buffer)) + type *name_p = (type *) (JERRY_CONTEXT (debugger_send_buffer_payload_p)) /** * Type cast the debugger receive buffer into a specific type. @@ -71,7 +74,7 @@ jerry_debugger_free_unreferenced_byte_code (void) * Send backtrace. */ static void -jerry_debugger_send_backtrace (uint8_t *recv_buffer_p) /**< pointer the the received data */ +jerry_debugger_send_backtrace (uint8_t *recv_buffer_p) /**< pointer to the received data */ { JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_get_backtrace_t, get_backtrace_p); @@ -85,13 +88,13 @@ jerry_debugger_send_backtrace (uint8_t *recv_buffer_p) /**< pointer the the rece JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_backtrace_t, backtrace_p); - JERRY_DEBUGGER_INIT_SEND_MESSAGE (backtrace_p); - JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (backtrace_p, jerry_debugger_send_backtrace_t); backtrace_p->type = JERRY_DEBUGGER_BACKTRACE; vm_frame_ctx_t *frame_ctx_p = JERRY_CONTEXT (vm_top_context_p); - uint32_t current_frame = 0; + size_t current_frame = 0; + const size_t max_frame_count = JERRY_DEBUGGER_SEND_MAX (jerry_debugger_frame_t); + const size_t max_message_size = JERRY_DEBUGGER_SEND_SIZE (max_frame_count, jerry_debugger_frame_t); while (frame_ctx_p != NULL && max_depth > 0) { @@ -101,9 +104,9 @@ jerry_debugger_send_backtrace (uint8_t *recv_buffer_p) /**< pointer the the rece continue; } - if (current_frame >= JERRY_DEBUGGER_SEND_MAX (jerry_debugger_frame_t)) + if (current_frame >= max_frame_count) { - if (!jerry_debugger_send (sizeof (jerry_debugger_send_backtrace_t))) + if (!jerry_debugger_send (max_message_size)) { return; } @@ -126,16 +129,15 @@ jerry_debugger_send_backtrace (uint8_t *recv_buffer_p) /**< pointer the the rece size_t message_size = current_frame * sizeof (jerry_debugger_frame_t); - JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE (backtrace_p, 1 + message_size); backtrace_p->type = JERRY_DEBUGGER_BACKTRACE_END; jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + message_size); } /* jerry_debugger_send_backtrace */ /** - * Send result of evaluated expression. + * Send result of evaluated expression or throw an error. * - * @return true - if no error is occured + * @return true - if execution should be resumed * false - otherwise */ static bool @@ -145,15 +147,39 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_IGNORE)); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_IGNORE); - ecma_value_t result = ecma_op_eval_chars_buffer (eval_string_p, eval_string_size, true, false); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_VM_IGNORE); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_IGNORE); + ecma_value_t result = ecma_op_eval_chars_buffer (eval_string_p + 1, eval_string_size - 1, true, false); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_IGNORE); if (!ECMA_IS_VALUE_ERROR (result)) { - ecma_value_t to_string_value = ecma_op_to_string (result); - ecma_free_value (result); - result = to_string_value; + if (eval_string_p[0] != JERRY_DEBUGGER_EVAL_EVAL) + { + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN); + JERRY_CONTEXT (error_value) = result; + + /* Stop where the error is caught. */ + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); + JERRY_CONTEXT (debugger_stop_context) = NULL; + + if (eval_string_p[0] == JERRY_DEBUGGER_EVAL_THROW) + { + JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + } + else + { + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + } + + return true; + } + + if (!ecma_is_value_string (result)) + { + ecma_value_t to_string_value = ecma_op_to_string (result); + ecma_free_value (result); + result = to_string_value; + } } ecma_value_t message = result; @@ -166,12 +192,8 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s if (ecma_is_value_object (result)) { - ecma_string_t *message_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE); - message = ecma_op_object_find (ecma_get_object_from_value (result), - message_string_p); - - ecma_deref_ecma_string (message_string_p); + ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE)); if (!ecma_is_value_string (message) || ecma_string_is_empty (ecma_get_string_from_value (message))) @@ -181,15 +203,16 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s ecma_free_value (result); const lit_utf8_byte_t *string_p = lit_get_magic_string_utf8 (id); - return jerry_debugger_send_string (JERRY_DEBUGGER_EVAL_RESULT, - type, - string_p, - strlen ((const char *) string_p)); + jerry_debugger_send_string (JERRY_DEBUGGER_EVAL_RESULT, + type, + string_p, + strlen ((const char *) string_p)); + return false; } } else { - /* Primitve type. */ + /* Primitive type. */ message = ecma_op_to_string (result); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (message)); } @@ -200,12 +223,12 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s ecma_string_t *string_p = ecma_get_string_from_value (message); ECMA_STRING_TO_UTF8_STRING (string_p, buffer_p, buffer_size); - bool success = jerry_debugger_send_string (JERRY_DEBUGGER_EVAL_RESULT, type, buffer_p, buffer_size); + jerry_debugger_send_string (JERRY_DEBUGGER_EVAL_RESULT, type, buffer_p, buffer_size); ECMA_FINALIZE_UTF8_STRING (buffer_p, buffer_size); ecma_free_value (message); - return success; + return false; } /* jerry_debugger_send_eval */ /** @@ -215,15 +238,7 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s void jerry_debugger_sleep (void) { -#ifdef HAVE_TIME_H - nanosleep (&(const struct timespec) - { - JERRY_DEBUGGER_TIMEOUT / 1000, (JERRY_DEBUGGER_TIMEOUT % 1000) * 1000000L /* Seconds, nanoseconds */ - } - , NULL); -#elif defined (HAVE_UNISTD_H) - usleep ((useconds_t) JERRY_DEBUGGER_TIMEOUT * 1000); -#endif /* HAVE_TIME_H */ + jerry_port_sleep (JERRY_DEBUGGER_TIMEOUT); } /* jerry_debugger_sleep */ /** @@ -244,7 +259,7 @@ jerry_debugger_sleep (void) * false - otherwise */ inline bool __attr_always_inline___ -jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the received data */ +jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer to the received data */ uint32_t message_size, /**< message size */ bool *resume_exec_p, /**< pointer to the resume exec flag */ uint8_t *expected_message_type_p, /**< message type */ @@ -308,16 +323,20 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec return true; } - bool result = false; + bool result; + if (*expected_message_type_p == JERRY_DEBUGGER_EVAL_PART) { - result = jerry_debugger_send_eval (string_p, uint8_data_p->uint8_size); + if (jerry_debugger_send_eval (string_p, uint8_data_p->uint8_size)) + { + *resume_exec_p = true; + } + result = (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) != 0; } else { result = true; - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) - & ~JERRY_DEBUGGER_CLIENT_SOURCE_MODE); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_CLIENT_SOURCE_MODE); *resume_exec_p = true; } @@ -398,7 +417,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec { JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_STOP); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = NULL; *resume_exec_p = false; return true; @@ -408,7 +427,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec { JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_VM_STOP); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = NULL; *resume_exec_p = true; return true; @@ -418,7 +437,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec { JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_STOP); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = NULL; *resume_exec_p = true; return true; @@ -428,12 +447,25 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec { JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_VM_STOP); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); JERRY_CONTEXT (debugger_stop_context) = JERRY_CONTEXT (vm_top_context_p); *resume_exec_p = true; return true; } + case JERRY_DEBUGGER_FINISH: + { + JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); + + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP); + + /* This will point to the current context's parent (where the function was called) + * and in case of NULL the result will the same as in case of STEP. */ + JERRY_CONTEXT (debugger_stop_context) = JERRY_CONTEXT (vm_top_context_p->prev_context_p); + *resume_exec_p = true; + return true; + } + case JERRY_DEBUGGER_GET_BACKTRACE: { JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_get_backtrace_t); @@ -447,20 +479,51 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_exception_config_t); JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_exception_config_t, exception_config_p); - uint8_t debugger_flags = JERRY_CONTEXT (debugger_flags); - if (exception_config_p->enable == 0) { - debugger_flags = (uint8_t) (debugger_flags | JERRY_DEBUGGER_VM_IGNORE_EXCEPTION); + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION); jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Stop at exception disabled\n"); } else { - debugger_flags = (uint8_t) (debugger_flags & ~JERRY_DEBUGGER_VM_IGNORE_EXCEPTION); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION); jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Stop at exception enabled\n"); } - JERRY_CONTEXT (debugger_flags) = debugger_flags; + return true; + } + + case JERRY_DEBUGGER_PARSER_CONFIG: + { + JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_parser_config_t); + JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_parser_config_t, parser_config_p); + + if (parser_config_p->enable_wait != 0) + { + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_PARSER_WAIT); + jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Waiting after parsing enabled\n"); + } + else + { + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_PARSER_WAIT); + jerry_port_log (JERRY_LOG_LEVEL_DEBUG, "Waiting after parsing disabled\n"); + } + + return true; + } + + case JERRY_DEBUGGER_PARSER_RESUME: + { + JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); + + if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_PARSER_WAIT_MODE)) + { + jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Not in parser wait mode\n"); + jerry_debugger_close_connection (); + return false; + } + + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_PARSER_WAIT_MODE); return true; } @@ -478,7 +541,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec uint32_t eval_size; memcpy (&eval_size, eval_first_p->eval_size, sizeof (uint32_t)); - if (eval_size <= JERRY_DEBUGGER_MAX_RECEIVE_SIZE - sizeof (jerry_debugger_receive_eval_first_t)) + if (eval_size <= JERRY_CONTEXT (debugger_max_receive_size) - sizeof (jerry_debugger_receive_eval_first_t)) { if (eval_size != message_size - sizeof (jerry_debugger_receive_eval_first_t)) { @@ -487,7 +550,12 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec return false; } - return jerry_debugger_send_eval ((lit_utf8_byte_t *) (eval_first_p + 1), eval_size); + if (jerry_debugger_send_eval ((lit_utf8_byte_t *) (eval_first_p + 1), eval_size)) + { + *resume_exec_p = true; + } + + return (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) != 0; } jerry_debugger_uint8_data_t *eval_uint8_data_p; @@ -505,6 +573,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec *message_data_p = eval_uint8_data_p; *expected_message_type_p = JERRY_DEBUGGER_EVAL_PART; + return true; } @@ -529,8 +598,10 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec uint32_t client_source_size; memcpy (&client_source_size, client_source_first_p->code_size, sizeof (uint32_t)); - if (client_source_size <= JERRY_DEBUGGER_MAX_RECEIVE_SIZE - sizeof (jerry_debugger_receive_client_source_first_t) - && client_source_size != message_size - sizeof (jerry_debugger_receive_client_source_first_t)) + uint32_t header_size = sizeof (jerry_debugger_receive_client_source_first_t); + + if (client_source_size <= JERRY_CONTEXT (debugger_max_receive_size) - header_size + && client_source_size != message_size - header_size) { jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid message size\n"); jerry_debugger_close_connection (); @@ -559,8 +630,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec } else { - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) - & ~JERRY_DEBUGGER_CLIENT_SOURCE_MODE); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_CLIENT_SOURCE_MODE); *resume_exec_p = true; } return true; @@ -577,8 +647,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_CLIENT_SOURCE_MODE); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_CLIENT_NO_SOURCE); + JERRY_DEBUGGER_UPDATE_FLAGS (JERRY_DEBUGGER_CLIENT_NO_SOURCE, JERRY_DEBUGGER_CLIENT_SOURCE_MODE); *resume_exec_p = true; @@ -596,8 +665,7 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_CLIENT_SOURCE_MODE); - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_CONTEXT_RESET_MODE); + JERRY_DEBUGGER_UPDATE_FLAGS (JERRY_DEBUGGER_CONTEXT_RESET_MODE, JERRY_DEBUGGER_CLIENT_SOURCE_MODE); *resume_exec_p = true; @@ -625,8 +693,6 @@ jerry_debugger_breakpoint_hit (uint8_t message_type) /**< message type */ JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_breakpoint_hit_t, breakpoint_hit_p); - JERRY_DEBUGGER_INIT_SEND_MESSAGE (breakpoint_hit_p); - JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (breakpoint_hit_p, jerry_debugger_send_breakpoint_hit_t); breakpoint_hit_p->type = message_type; vm_frame_ctx_t *frame_ctx_p = JERRY_CONTEXT (vm_top_context_p); @@ -643,7 +709,7 @@ jerry_debugger_breakpoint_hit (uint8_t message_type) /**< message type */ return; } - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) | JERRY_DEBUGGER_BREAKPOINT_MODE); + JERRY_DEBUGGER_UPDATE_FLAGS (JERRY_DEBUGGER_BREAKPOINT_MODE, JERRY_DEBUGGER_VM_EXCEPTION_THROWN); jerry_debugger_uint8_data_t *uint8_data = NULL; @@ -658,7 +724,7 @@ jerry_debugger_breakpoint_hit (uint8_t message_type) /**< message type */ uint8_data->uint8_size + sizeof (jerry_debugger_uint8_data_t)); } - JERRY_CONTEXT (debugger_flags) = (uint8_t) (JERRY_CONTEXT (debugger_flags) & ~JERRY_DEBUGGER_BREAKPOINT_MODE); + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_BREAKPOINT_MODE); JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY; } /* jerry_debugger_breakpoint_hit */ @@ -673,8 +739,6 @@ jerry_debugger_send_type (jerry_debugger_header_type_t type) /**< message type * JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_type_t, message_type_p); - JERRY_DEBUGGER_INIT_SEND_MESSAGE (message_type_p); - JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (message_type_p, jerry_debugger_send_type_t); message_type_p->type = (uint8_t) type; jerry_debugger_send (sizeof (jerry_debugger_send_type_t)); @@ -701,12 +765,11 @@ jerry_debugger_send_configuration (uint8_t max_message_size) /**< maximum messag endian_data.uint16_value = 1; - JERRY_DEBUGGER_INIT_SEND_MESSAGE (configuration_p); - JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (configuration_p, jerry_debugger_send_configuration_t); configuration_p->type = JERRY_DEBUGGER_CONFIGURATION; configuration_p->max_message_size = max_message_size; configuration_p->cpointer_size = sizeof (jmem_cpointer_t); configuration_p->little_endian = (endian_data.uint8_value[0] == 1); + configuration_p->version = JERRY_DEBUGGER_VERSION; return jerry_debugger_send (sizeof (jerry_debugger_send_configuration_t)); } /* jerry_debugger_send_configuration */ @@ -723,8 +786,6 @@ jerry_debugger_send_data (jerry_debugger_header_type_t type, /**< message type * JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_type_t, message_type_p); - JERRY_DEBUGGER_INIT_SEND_MESSAGE (message_type_p); - JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE (message_type_p, 1 + size); message_type_p->type = type; memcpy (message_type_p + 1, data, size); @@ -745,40 +806,42 @@ jerry_debugger_send_string (uint8_t message_type, /**< message type */ { JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); - const size_t max_fragment_len = JERRY_DEBUGGER_SEND_MAX (uint8_t); + const size_t max_byte_count = JERRY_DEBUGGER_SEND_MAX (uint8_t); + const size_t max_message_size = JERRY_DEBUGGER_SEND_SIZE (max_byte_count, uint8_t); JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_string_t, message_string_p); - JERRY_DEBUGGER_INIT_SEND_MESSAGE (message_string_p); - JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (message_string_p, jerry_debugger_send_string_t); message_string_p->type = message_type; - while (string_length > max_fragment_len) + if (sub_type != JERRY_DEBUGGER_NO_SUBTYPE) + { + string_length += 1; + } + + while (string_length > max_byte_count) { - memcpy (message_string_p->string, string_p, max_fragment_len); + memcpy (message_string_p->string, string_p, max_byte_count); - if (!jerry_debugger_send (sizeof (jerry_debugger_send_string_t))) + if (!jerry_debugger_send (max_message_size)) { return false; } - string_length -= max_fragment_len; - string_p += max_fragment_len; + string_length -= max_byte_count; + string_p += max_byte_count; } - if (sub_type != JERRY_DEBUGGER_NO_SUBTYPE) - { - string_length += 1; - } - - JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE (message_string_p, 1 + string_length); message_string_p->type = (uint8_t) (message_type + 1); - memcpy (message_string_p->string, string_p, string_length); if (sub_type != JERRY_DEBUGGER_NO_SUBTYPE) { + memcpy (message_string_p->string, string_p, string_length - 1); message_string_p->string[string_length - 1] = sub_type; } + else + { + memcpy (message_string_p->string, string_p, string_length); + } return jerry_debugger_send (sizeof (jerry_debugger_send_type_t) + string_length); } /* jerry_debugger_send_string */ @@ -797,8 +860,6 @@ jerry_debugger_send_function_cp (jerry_debugger_header_type_t type, /**< message JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_byte_code_cp_t, byte_code_cp_p); - JERRY_DEBUGGER_INIT_SEND_MESSAGE (byte_code_cp_p); - JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (byte_code_cp_p, jerry_debugger_send_byte_code_cp_t); byte_code_cp_p->type = (uint8_t) type; jmem_cpointer_t compiled_code_cp; @@ -822,8 +883,6 @@ jerry_debugger_send_parse_function (uint32_t line, /**< line */ JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_parse_function_t, message_parse_function_p); - JERRY_DEBUGGER_INIT_SEND_MESSAGE (message_parse_function_p); - JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (message_parse_function_p, jerry_debugger_send_parse_function_t); message_parse_function_p->type = JERRY_DEBUGGER_PARSE_FUNCTION; memcpy (message_parse_function_p->line, &line, sizeof (uint32_t)); memcpy (message_parse_function_p->column, &column, sizeof (uint32_t)); @@ -840,8 +899,6 @@ jerry_debugger_send_memstats (void) JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_memstats_t, memstats_p); - JERRY_DEBUGGER_INIT_SEND_MESSAGE (memstats_p); - JERRY_DEBUGGER_SET_SEND_MESSAGE_SIZE_FROM_TYPE (memstats_p, jerry_debugger_send_memstats_t); memstats_p->type = JERRY_DEBUGGER_MEMSTATS_RECEIVE; @@ -941,12 +998,9 @@ jerry_debugger_exception_object_to_string (ecma_value_t exception_obj_value) /** lit_utf8_byte_t data[16]; memcpy (data, lit_get_magic_string_utf8 (string_id), size); - ecma_string_t message_string; - ecma_init_ecma_magic_string (&message_string, LIT_MAGIC_STRING_MESSAGE); - ecma_property_t *property_p; property_p = ecma_find_named_property (ecma_get_object_from_value (exception_obj_value), - &message_string); + ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE)); if (property_p == NULL || ECMA_PROPERTY_GET_TYPE (*property_p) != ECMA_PROPERTY_TYPE_NAMEDDATA) diff --git a/deps/jerry/jerry-core/debugger/debugger.h b/deps/jerry/jerry-core/debugger/debugger.h index e403940..94d7014 100644 --- a/deps/jerry/jerry-core/debugger/debugger.h +++ b/deps/jerry/jerry-core/debugger/debugger.h @@ -23,6 +23,11 @@ /* JerryScript debugger protocol is a simplified version of RFC-6455 (WebSockets). */ +/** + * JerryScript debugger protocol version. + */ +#define JERRY_DEBUGGER_VERSION (3) + /** * Frequency of calling jerry_debugger_receive() by the VM. */ @@ -48,10 +53,16 @@ /** * Calculate the maximum number of items for a given type - * which can be transmitted by one message. + * which can be transmitted in one message. */ #define JERRY_DEBUGGER_SEND_MAX(type) \ - ((JERRY_DEBUGGER_MAX_SEND_SIZE - sizeof (jerry_debugger_send_header_t) - 1) / sizeof (type)) + ((size_t) ((JERRY_CONTEXT (debugger_max_send_size) - sizeof (jerry_debugger_send_type_t)) / sizeof (type))) + +/** + * Calculate the size of a message when a count number of items transmitted. + */ +#define JERRY_DEBUGGER_SEND_SIZE(count, type) \ + ((size_t) ((count * sizeof (type)) + sizeof (jerry_debugger_send_type_t))) /** * Debugger operation modes: @@ -85,21 +96,45 @@ typedef enum { JERRY_DEBUGGER_CONNECTED = 1u << 0, /**< debugger is connected */ JERRY_DEBUGGER_BREAKPOINT_MODE = 1u << 1, /**< debugger waiting at a breakpoint */ - JERRY_DEBUGGER_VM_STOP = 1u << 2, /**< stop at the next breakpoint regardless it is enabled */ + JERRY_DEBUGGER_VM_STOP = 1u << 2, /**< stop at the next breakpoint even if disabled */ JERRY_DEBUGGER_VM_IGNORE = 1u << 3, /**< ignore all breakpoints */ - JERRY_DEBUGGER_VM_IGNORE_EXCEPTION = 1u << 4, /**< debugger stop at an exception */ - JERRY_DEBUGGER_CLIENT_SOURCE_MODE = 1u << 5, /**< debugger waiting for client code */ - JERRY_DEBUGGER_CLIENT_NO_SOURCE = 1u << 6, /**< debugger leaving the client source loop */ - JERRY_DEBUGGER_CONTEXT_RESET_MODE = 1u << 7, /**< debugger and engine reinitialization mode */ + JERRY_DEBUGGER_VM_IGNORE_EXCEPTION = 1u << 4, /**< debugger doesn't stop at any exception */ + JERRY_DEBUGGER_VM_EXCEPTION_THROWN = 1u << 5, /**< no need to stop for this exception */ + JERRY_DEBUGGER_PARSER_WAIT = 1u << 6, /**< debugger should wait after parsing is completed */ + JERRY_DEBUGGER_PARSER_WAIT_MODE = 1u << 7, /**< debugger is waiting after parsing is completed */ + JERRY_DEBUGGER_CLIENT_SOURCE_MODE = 1u << 8, /**< debugger waiting for client code */ + JERRY_DEBUGGER_CLIENT_NO_SOURCE = 1u << 9, /**< debugger leaving the client source loop */ + JERRY_DEBUGGER_CONTEXT_RESET_MODE = 1u << 10, /**< debugger and engine reinitialization mode */ } jerry_debugger_flags_t; +/** + * Set debugger flags. + */ +#define JERRY_DEBUGGER_SET_FLAGS(flags) \ + JERRY_CONTEXT (debugger_flags) = (JERRY_CONTEXT (debugger_flags) | (uint32_t) (flags)) + +/** + * Clear debugger flags. + */ +#define JERRY_DEBUGGER_CLEAR_FLAGS(flags) \ + JERRY_CONTEXT (debugger_flags) = (JERRY_CONTEXT (debugger_flags) & (uint32_t) ~(flags)) + +/** + * Set and clear debugger flags. + */ +#define JERRY_DEBUGGER_UPDATE_FLAGS(flags_to_set, flags_to_clear) \ + JERRY_CONTEXT (debugger_flags) = ((JERRY_CONTEXT (debugger_flags) | (uint32_t) (flags_to_set)) \ + & (uint32_t) ~(flags_to_clear)) + /** * Types for the package. */ typedef enum { /* Messages sent by the server to client. */ + /* This is a handshake message, sent once during initialization. */ JERRY_DEBUGGER_CONFIGURATION = 1, /**< debugger configuration */ + /* These messages are sent by the parser. */ JERRY_DEBUGGER_PARSE_ERROR = 2, /**< parse error */ JERRY_DEBUGGER_BYTE_CODE_CP = 3, /**< byte code compressed pointer */ JERRY_DEBUGGER_PARSE_FUNCTION = 4, /**< parsing a new function */ @@ -111,19 +146,23 @@ typedef enum JERRY_DEBUGGER_SOURCE_CODE_NAME_END = 10, /**< source code name last fragment */ JERRY_DEBUGGER_FUNCTION_NAME = 11, /**< function name fragment */ JERRY_DEBUGGER_FUNCTION_NAME_END = 12, /**< function name last fragment */ - JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP = 13, /**< invalidate byte code compressed pointer */ - JERRY_DEBUGGER_MEMSTATS_RECEIVE = 14, /**< memstats sent to the client*/ - JERRY_DEBUGGER_BREAKPOINT_HIT = 15, /**< notify breakpoint hit */ - JERRY_DEBUGGER_EXCEPTION_HIT = 16, /**< notify exception hit */ - JERRY_DEBUGGER_EXCEPTION_STR = 17, /**< exception string fragment */ - JERRY_DEBUGGER_EXCEPTION_STR_END = 18, /**< exception string last fragment */ - JERRY_DEBUGGER_BACKTRACE = 19, /**< backtrace data */ - JERRY_DEBUGGER_BACKTRACE_END = 20, /**< last backtrace data */ - JERRY_DEBUGGER_EVAL_RESULT = 21, /**< eval result */ - JERRY_DEBUGGER_EVAL_RESULT_END = 22, /**< last part of eval result */ - JERRY_DEBUGGER_WAIT_FOR_SOURCE = 23, /**< engine waiting for a source code */ - JERRY_DEBUGGER_OUTPUT_RESULT = 24, /**< output sent by the program to the debugger */ - JERRY_DEBUGGER_OUTPUT_RESULT_END = 25, /**< last output result data */ + JERRY_DEBUGGER_WAITING_AFTER_PARSE = 13, /**< engine waiting for a parser resume */ + /* These messages are generic messages. */ + JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP = 14, /**< invalidate byte code compressed pointer */ + JERRY_DEBUGGER_MEMSTATS_RECEIVE = 15, /**< memstats sent to the client */ + JERRY_DEBUGGER_BREAKPOINT_HIT = 16, /**< notify breakpoint hit */ + JERRY_DEBUGGER_EXCEPTION_HIT = 17, /**< notify exception hit */ + JERRY_DEBUGGER_EXCEPTION_STR = 18, /**< exception string fragment */ + JERRY_DEBUGGER_EXCEPTION_STR_END = 19, /**< exception string last fragment */ + JERRY_DEBUGGER_BACKTRACE = 20, /**< backtrace data */ + JERRY_DEBUGGER_BACKTRACE_END = 21, /**< last backtrace data */ + JERRY_DEBUGGER_EVAL_RESULT = 22, /**< eval result */ + JERRY_DEBUGGER_EVAL_RESULT_END = 23, /**< last part of eval result */ + JERRY_DEBUGGER_WAIT_FOR_SOURCE = 24, /**< engine waiting for source code */ + JERRY_DEBUGGER_OUTPUT_RESULT = 25, /**< output sent by the program to the debugger */ + JERRY_DEBUGGER_OUTPUT_RESULT_END = 26, /**< last output result data */ + + JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT, /**< number of different type of output messages by the debugger */ /* Messages sent by the client to server. */ @@ -131,36 +170,53 @@ typedef enum JERRY_DEBUGGER_FREE_BYTE_CODE_CP = 1, /**< free byte code compressed pointer */ JERRY_DEBUGGER_UPDATE_BREAKPOINT = 2, /**< update breakpoint status */ JERRY_DEBUGGER_EXCEPTION_CONFIG = 3, /**< exception handler config */ - JERRY_DEBUGGER_MEMSTATS = 4, /**< list memory statistics */ - JERRY_DEBUGGER_STOP = 5, /**< stop execution */ - JERRY_DEBUGGER_CLIENT_SOURCE = 6, /**< first message of client source */ - JERRY_DEBUGGER_CLIENT_SOURCE_PART = 7, /**< next message of client source */ - JERRY_DEBUGGER_NO_MORE_SOURCES = 8, /**< no more sources notification */ - JERRY_DEBUGGER_CONTEXT_RESET = 9, /**< context reset request */ + JERRY_DEBUGGER_PARSER_CONFIG = 4, /**< parser config */ + JERRY_DEBUGGER_MEMSTATS = 5, /**< list memory statistics */ + JERRY_DEBUGGER_STOP = 6, /**< stop execution */ + /* The following message is only available in waiting after parse mode. */ + JERRY_DEBUGGER_PARSER_RESUME = 7, /**< stop waiting after parse */ + /* The following four messages are only available in client switch mode. */ + JERRY_DEBUGGER_CLIENT_SOURCE = 8, /**< first message of client source */ + JERRY_DEBUGGER_CLIENT_SOURCE_PART = 9, /**< next message of client source */ + JERRY_DEBUGGER_NO_MORE_SOURCES = 10, /**< no more sources notification */ + JERRY_DEBUGGER_CONTEXT_RESET = 11, /**< context reset request */ /* The following messages are only available in breakpoint * mode and they switch the engine to run mode. */ - JERRY_DEBUGGER_CONTINUE = 10, /**< continue execution */ - JERRY_DEBUGGER_STEP = 11, /**< next breakpoint, step into functions */ - JERRY_DEBUGGER_NEXT = 12, /**< next breakpoint in the same context */ + JERRY_DEBUGGER_CONTINUE = 12, /**< continue execution */ + JERRY_DEBUGGER_STEP = 13, /**< next breakpoint, step into functions */ + JERRY_DEBUGGER_NEXT = 14, /**< next breakpoint in the same context */ + JERRY_DEBUGGER_FINISH = 15, /**< Continue running just after the function in the current stack frame returns */ /* The following messages are only available in breakpoint * mode and this mode is kept after the message is processed. */ - JERRY_DEBUGGER_GET_BACKTRACE = 13, /**< get backtrace */ - JERRY_DEBUGGER_EVAL = 14, /**< first message of evaluating a string */ - JERRY_DEBUGGER_EVAL_PART = 15, /**< next message of evaluating a string */ + JERRY_DEBUGGER_GET_BACKTRACE = 16, /**< get backtrace */ + JERRY_DEBUGGER_EVAL = 17, /**< first message of evaluating a string */ + JERRY_DEBUGGER_EVAL_PART = 18, /**< next message of evaluating a string */ + + JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT, /**< number of different type of input messages */ } jerry_debugger_header_type_t; /** - * Subtypes of eval_result. - */ + * Subtypes of eval. + */ +typedef enum +{ + JERRY_DEBUGGER_EVAL_EVAL = 0, /**< evaluate expression */ + JERRY_DEBUGGER_EVAL_THROW = 1, /**< evaluate expression and throw the result */ + JERRY_DEBUGGER_EVAL_ABORT = 2, /**< evaluate expression and abrot with the result */ +} jerry_debugger_eval_type_t; + +/** + * Subtypes of eval_result. + */ typedef enum { JERRY_DEBUGGER_EVAL_OK = 1, /**< eval result, no error */ - JERRY_DEBUGGER_EVAL_ERROR = 2, /**< eval result when an error is occured */ -} jerry_debugger_eval_subtype_t; + JERRY_DEBUGGER_EVAL_ERROR = 2, /**< eval result when an error has occurred */ +} jerry_debugger_eval_result_type_t; /** - * Subtypes of output_result. - */ + * Subtypes of output_result. + */ typedef enum { JERRY_DEBUGGER_OUTPUT_OK = 1, /**< output result, no error */ @@ -184,11 +240,11 @@ typedef struct */ typedef struct { - jerry_debugger_send_header_t header; /**< message header */ uint8_t type; /**< type of the message */ uint8_t max_message_size; /**< maximum incoming message size */ uint8_t cpointer_size; /**< size of compressed pointers */ uint8_t little_endian; /**< little endian machine */ + uint8_t version; /**< debugger version */ } jerry_debugger_send_configuration_t; /** @@ -196,7 +252,6 @@ typedef struct */ typedef struct { - jerry_debugger_send_header_t header; /**< message header */ uint8_t type; /**< type of the message */ } jerry_debugger_send_type_t; @@ -213,9 +268,8 @@ typedef struct */ typedef struct { - jerry_debugger_send_header_t header; /**< message header */ uint8_t type; /**< type of the message */ - uint8_t string[JERRY_DEBUGGER_SEND_MAX (uint8_t)]; /**< string data */ + uint8_t string[]; /**< string data */ } jerry_debugger_send_string_t; /** @@ -223,7 +277,6 @@ typedef struct */ typedef struct { - jerry_debugger_send_header_t header; /**< message header */ uint8_t type; /**< type of the message */ uint8_t line[sizeof (uint32_t)]; /**< value data */ uint8_t column[sizeof (uint32_t)]; /**< value data */ @@ -234,7 +287,6 @@ typedef struct */ typedef struct { - jerry_debugger_send_header_t header; /**< message header */ uint8_t type; /**< type of the message */ uint8_t byte_code_cp[sizeof (jmem_cpointer_t)]; /**< byte code compressed pointer */ } jerry_debugger_send_byte_code_cp_t; @@ -264,7 +316,6 @@ typedef struct */ typedef struct { - jerry_debugger_send_header_t header; /**< message header */ uint8_t type; /**< type of the message */ uint8_t allocated_bytes[sizeof (uint32_t)]; /**< allocated bytes */ uint8_t byte_code_bytes[sizeof (uint32_t)]; /**< byte code bytes */ @@ -278,7 +329,6 @@ typedef struct */ typedef struct { - jerry_debugger_send_header_t header; /**< message header */ uint8_t type; /**< type of the message */ uint8_t byte_code_cp[sizeof (jmem_cpointer_t)]; /**< byte code compressed pointer */ uint8_t offset[sizeof (uint32_t)]; /**< breakpoint offset */ @@ -298,17 +348,28 @@ typedef struct */ typedef struct { - jerry_debugger_send_header_t header; /**< message header */ uint8_t type; /**< type of the message */ - jerry_debugger_frame_t frames[JERRY_DEBUGGER_SEND_MAX (jerry_debugger_frame_t)]; /**< frames */ + jerry_debugger_frame_t frames[]; /**< frames */ } jerry_debugger_send_backtrace_t; +/** + * Incoming message: set behaviour when exception occures. + */ typedef struct { uint8_t type; /**< type of the message */ uint8_t enable; /**< non-zero: enable stop at exception */ } jerry_debugger_receive_exception_config_t; +/** + * Incoming message: set parser configuration. + */ +typedef struct +{ + uint8_t type; /**< type of the message */ + uint8_t enable_wait; /**< non-zero: wait after parsing is completed */ +} jerry_debugger_receive_parser_config_t; + /** * Incoming message: get backtrace. */ diff --git a/deps/jerry/jerry-core/ecma/base/ecma-alloc.c b/deps/jerry/jerry-core/ecma/base/ecma-alloc.c index 004c6d8..4b7b5d5 100644 --- a/deps/jerry/jerry-core/ecma/base/ecma-alloc.c +++ b/deps/jerry/jerry-core/ecma/base/ecma-alloc.c @@ -81,8 +81,6 @@ JERRY_STATIC_ASSERT (sizeof (ecma_extended_object_t) - sizeof (ecma_object_t) <= DEALLOC (ecma_type) DECLARE_ROUTINES_FOR (number) -DECLARE_ROUTINES_FOR (collection_header) -DECLARE_ROUTINES_FOR (collection_chunk) /** * Allocate memory for ecma-object diff --git a/deps/jerry/jerry-core/ecma/base/ecma-alloc.h b/deps/jerry/jerry-core/ecma/base/ecma-alloc.h index 22d0d06..512aee8 100644 --- a/deps/jerry/jerry-core/ecma/base/ecma-alloc.h +++ b/deps/jerry/jerry-core/ecma/base/ecma-alloc.h @@ -61,30 +61,6 @@ ecma_number_t *ecma_alloc_number (void); */ void ecma_dealloc_number (ecma_number_t *number_p); -/** - * Allocate memory for header of a collection - * - * @return pointer to allocated memory - */ -ecma_collection_header_t *ecma_alloc_collection_header (void); - -/** - * Dealloc memory from the collection's header - */ -void ecma_dealloc_collection_header (ecma_collection_header_t *collection_header_p); - -/** - * Allocate memory for non-first chunk of a collection - * - * @return pointer to allocated memory - */ -ecma_collection_chunk_t *ecma_alloc_collection_chunk (void); - -/** - * Dealloc memory from non-first chunk of a collection - */ -void ecma_dealloc_collection_chunk (ecma_collection_chunk_t *collection_chunk_p); - /** * Allocate memory for ecma-string descriptor * diff --git a/deps/jerry/jerry-core/ecma/base/ecma-gc.c b/deps/jerry/jerry-core/ecma/base/ecma-gc.c index 1f5bf2a..6bd2c53 100644 --- a/deps/jerry/jerry-core/ecma/base/ecma-gc.c +++ b/deps/jerry/jerry-core/ecma/base/ecma-gc.c @@ -157,7 +157,7 @@ ecma_gc_mark_property (ecma_property_pair_t *property_pair_p, /**< property pair { case ECMA_PROPERTY_TYPE_NAMEDDATA: { - if (ECMA_PROPERTY_GET_NAME_TYPE (property) == ECMA_STRING_CONTAINER_MAGIC_STRING + if (ECMA_PROPERTY_GET_NAME_TYPE (property) == ECMA_DIRECT_STRING_MAGIC && property_pair_p->names_cp[index] >= LIT_NEED_MARK_MAGIC_STRING__COUNT) { break; @@ -192,8 +192,8 @@ ecma_gc_mark_property (ecma_property_pair_t *property_pair_p, /**< property pair } case ECMA_PROPERTY_TYPE_SPECIAL: { - JERRY_ASSERT (ECMA_PROPERTY_GET_SPECIAL_PROPERTY_TYPE (&property) == ECMA_SPECIAL_PROPERTY_DELETED - || ECMA_PROPERTY_GET_SPECIAL_PROPERTY_TYPE (&property) == ECMA_SPECIAL_PROPERTY_HASHMAP); + JERRY_ASSERT (property == ECMA_PROPERTY_TYPE_HASHMAP + || property == ECMA_PROPERTY_TYPE_DELETED); break; } default: @@ -257,19 +257,21 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ } /* Mark all reactions. */ - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, ((ecma_promise_object_t *) ext_object_p)->fulfill_reactions); + ecma_value_t *ecma_value_p; + ecma_value_p = ecma_collection_iterator_init (((ecma_promise_object_t *) ext_object_p)->fulfill_reactions); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_gc_set_object_visited (ecma_get_object_from_value (*iter.current_value_p)); + ecma_gc_set_object_visited (ecma_get_object_from_value (*ecma_value_p)); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); } - ecma_collection_iterator_init (&iter, ((ecma_promise_object_t *) ext_object_p)->reject_reactions); + ecma_value_p = ecma_collection_iterator_init (((ecma_promise_object_t *) ext_object_p)->reject_reactions); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_gc_set_object_visited (ecma_get_object_from_value (*iter.current_value_p)); + ecma_gc_set_object_visited (ecma_get_object_from_value (*ecma_value_p)); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); } } @@ -379,10 +381,15 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */ { ecma_property_header_t *prop_iter_p = ecma_get_property_list (object_p); + if (prop_iter_p != NULL && prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP) + { + prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, + prop_iter_p->next_property_cp); + } + while (prop_iter_p != NULL) { - JERRY_ASSERT (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_HASHMAP - || ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); + JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); ecma_gc_mark_property ((ecma_property_pair_t *) prop_iter_p, 0); ecma_gc_mark_property ((ecma_property_pair_t *) prop_iter_p, 1); @@ -471,7 +478,7 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ jmem_cpointer_t name_cp = prop_pair_p->names_cp[i]; /* Call the native's free callback. */ - if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_STRING_CONTAINER_MAGIC_STRING + if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC && (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE || name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER)) { @@ -484,10 +491,6 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ } } - /* Both must be deleted. */ - JERRY_ASSERT (prop_iter_p->types[0] == ECMA_PROPERTY_TYPE_DELETED - && prop_iter_p->types[1] == ECMA_PROPERTY_TYPE_DELETED); - prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, prop_iter_p->next_property_cp); @@ -554,8 +557,10 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ case LIT_MAGIC_STRING_REGEXP_UL: { - ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, - ext_object_p->u.class_prop.u.value); + ecma_compiled_code_t *bytecode_p; + bytecode_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (ecma_compiled_code_t, + ext_object_p->u.class_prop.u.value); + if (bytecode_p != NULL) { ecma_bytecode_deref (bytecode_p); @@ -566,18 +571,38 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ case LIT_MAGIC_STRING_ARRAY_BUFFER_UL: { ecma_length_t arraybuffer_length = ext_object_p->u.class_prop.u.length; - size_t size = sizeof (ecma_extended_object_t) + arraybuffer_length; + size_t size; + + if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p)) + { + size = sizeof (ecma_arraybuffer_external_info); + + /* Call external free callback if any. */ + ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p; + JERRY_ASSERT (array_p != NULL); + + if (array_p->free_cb != NULL) + { + (array_p->free_cb) (array_p->buffer_p); + } + } + else + { + size = sizeof (ecma_extended_object_t) + arraybuffer_length; + } + ecma_dealloc_extended_object (object_p, size); return; } - #endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ #ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN case LIT_MAGIC_STRING_PROMISE_UL: { ecma_free_value_if_not_object (ext_object_p->u.class_prop.u.value); - ecma_free_values_collection (((ecma_promise_object_t *) object_p)->fulfill_reactions, false); - ecma_free_values_collection (((ecma_promise_object_t *) object_p)->reject_reactions, false); + ecma_free_values_collection (((ecma_promise_object_t *) object_p)->fulfill_reactions, + ECMA_COLLECTION_NO_REF_OBJECTS); + ecma_free_values_collection (((ecma_promise_object_t *) object_p)->reject_reactions, + ECMA_COLLECTION_NO_REF_OBJECTS); ecma_dealloc_extended_object (object_p, sizeof (ecma_promise_object_t)); return; } @@ -606,10 +631,22 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ /* Function with byte-code (not a built-in function). */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (ext_func_p->u.function.bytecode_cp != ECMA_NULL_POINTER) + { + ecma_bytecode_deref (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, + ext_func_p->u.function.bytecode_cp)); + ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); + } + else + { + ecma_dealloc_extended_object (object_p, sizeof (ecma_static_function_t)); + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ ecma_bytecode_deref (ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, ext_func_p->u.function.bytecode_cp)); - ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t)); +#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ return; } @@ -618,12 +655,24 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ { ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; - ecma_bytecode_deref (ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, - arrow_func_p->bytecode_cp)); - ecma_free_value_if_not_object (arrow_func_p->this_binding); +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (arrow_func_p->bytecode_cp != ECMA_NULL_POINTER) + { + ecma_bytecode_deref (ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, + arrow_func_p->bytecode_cp)); + ecma_dealloc_extended_object (object_p, sizeof (ecma_arrow_function_t)); + } + else + { + ecma_dealloc_extended_object (object_p, sizeof (ecma_static_arrow_function_t)); + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ + ecma_bytecode_deref (ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, + arrow_func_p->bytecode_cp)); ecma_dealloc_extended_object (object_p, sizeof (ecma_arrow_function_t)); +#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ return; } #endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ @@ -637,18 +686,18 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ case ECMA_PSEUDO_ARRAY_ARGUMENTS: { ecma_length_t formal_params_number = ext_object_p->u.pseudo_array.u1.length; - jmem_cpointer_t *arg_Literal_p = (jmem_cpointer_t *) (ext_object_p + 1); + ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1); for (ecma_length_t i = 0; i < formal_params_number; i++) { - if (arg_Literal_p[i] != JMEM_CP_NULL) + if (arg_Literal_p[i] != ECMA_VALUE_EMPTY) { - ecma_string_t *name_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, arg_Literal_p[i]); + ecma_string_t *name_p = ecma_get_string_from_value (arg_Literal_p[i]); ecma_deref_ecma_string (name_p); } } - size_t formal_params_size = formal_params_number * sizeof (jmem_cpointer_t); + size_t formal_params_size = formal_params_number * sizeof (ecma_value_t); ecma_dealloc_extended_object (object_p, sizeof (ecma_extended_object_t) + formal_params_size); return; } @@ -880,7 +929,7 @@ ecma_free_unused_memory (jmem_free_unused_memory_severity_t severity) /**< sever { --JERRY_CONTEXT (ecma_prop_hashmap_alloc_state); } - JERRY_CONTEXT (ecma_prop_hashmap_alloc_last_is_hs_gc) = false; + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_HIGH_SEV_GC; #endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */ /* @@ -899,14 +948,14 @@ ecma_free_unused_memory (jmem_free_unused_memory_severity_t severity) /**< sever JERRY_ASSERT (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_HIGH); #ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE - if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_last_is_hs_gc)) + if (JERRY_CONTEXT (status_flags) & ECMA_STATUS_HIGH_SEV_GC) { JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) = ECMA_PROP_HASHMAP_ALLOC_MAX; } else if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) < ECMA_PROP_HASHMAP_ALLOC_MAX) { ++JERRY_CONTEXT (ecma_prop_hashmap_alloc_state); - JERRY_CONTEXT (ecma_prop_hashmap_alloc_last_is_hs_gc) = true; + JERRY_CONTEXT (status_flags) |= ECMA_STATUS_HIGH_SEV_GC; } #endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */ diff --git a/deps/jerry/jerry-core/ecma/base/ecma-globals.h b/deps/jerry/jerry-core/ecma/base/ecma-globals.h index 9620a99..794bb67 100644 --- a/deps/jerry/jerry-core/ecma/base/ecma-globals.h +++ b/deps/jerry/jerry-core/ecma/base/ecma-globals.h @@ -64,23 +64,39 @@ typedef enum ECMA_INIT_MEM_STATS = (1u << 2), /**< dump memory statistics */ } ecma_init_flag_t; +/** + * JerryScript status flags. + */ +typedef enum +{ + ECMA_STATUS_API_AVAILABLE = (1u << 0), /**< api available */ + ECMA_STATUS_DIRECT_EVAL = (1u << 1), /**< eval is called directly */ +#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE + ECMA_STATUS_HIGH_SEV_GC = (1u << 2), /**< last gc run was a high severity run */ +#endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */ + ECMA_STATUS_EXCEPTION = (1u << 3), /**< last exception is a normal exception */ +} ecma_status_flag_t; + /** * Type of ecma value */ typedef enum { ECMA_TYPE_DIRECT = 0, /**< directly encoded value, a 28 bit signed integer or a simple value */ - ECMA_TYPE_FLOAT = 1, /**< pointer to a 64 or 32 bit floating point number */ - ECMA_TYPE_STRING = 2, /**< pointer to description of a string */ + ECMA_TYPE_STRING = 1, /**< pointer to description of a string */ + ECMA_TYPE_FLOAT = 2, /**< pointer to a 64 or 32 bit floating point number */ ECMA_TYPE_OBJECT = 3, /**< pointer to description of an object */ + ECMA_TYPE_DIRECT_STRING = 5, /**< directly encoded string values */ ECMA_TYPE_ERROR = 7, /**< pointer to description of an error reference */ + ECMA_TYPE_COLLECTION_CHUNK = ECMA_TYPE_ERROR, /**< pointer to description of a collection chunk */ + ECMA_TYPE_SNAPSHOT_OFFSET = ECMA_TYPE_ERROR, /**< offset to a snapshot number/string */ ECMA_TYPE___MAX = ECMA_TYPE_ERROR /** highest value for ecma types */ } ecma_type_t; /** * Description of an ecma value * - * Bit-field structure: type (2) | error (1) | value (29) + * Bit-field structure: type (3) | value (29) */ typedef uint32_t ecma_value_t; @@ -99,12 +115,12 @@ typedef int32_t ecma_integer_value_t; #endif /* UINTPTR_MAX <= UINT32_MAX */ /** - * Mask for ecma types in ecma_type_t + * Mask for ecma types in ecma_value_t */ #define ECMA_VALUE_TYPE_MASK 0x7u /** - * Shift for value part in ecma_type_t + * Shift for value part in ecma_value_t */ #define ECMA_VALUE_SHIFT 3 @@ -258,20 +274,6 @@ typedef struct } u; } ecma_native_pointer_t; -/** - * Special property identifiers. - */ -typedef enum -{ - ECMA_SPECIAL_PROPERTY_DELETED, /**< deleted property */ - - /* Note: when new special types are added - * ECMA_PROPERTY_IS_PROPERTY_PAIR must be updated as well. */ - ECMA_SPECIAL_PROPERTY_HASHMAP, /**< hashmap property */ - - ECMA_SPECIAL_PROPERTY__COUNT /**< Number of special property types */ -} ecma_internal_property_id_t; - /** * Property's 'Writable' attribute's values description. */ @@ -334,32 +336,6 @@ typedef enum */ #define ECMA_PROPERTY_FLAG_SHIFT 2 -/** - * Define special property type. - */ -#define ECMA_SPECIAL_PROPERTY_VALUE(type) \ - ((uint8_t) (ECMA_PROPERTY_TYPE_SPECIAL | ((type) << ECMA_PROPERTY_FLAG_SHIFT))) - -/** - * Type of deleted property. - */ -#define ECMA_PROPERTY_TYPE_DELETED ECMA_SPECIAL_PROPERTY_VALUE (ECMA_SPECIAL_PROPERTY_DELETED) - -/** - * Type of hash-map property. - */ -#define ECMA_PROPERTY_TYPE_HASHMAP ECMA_SPECIAL_PROPERTY_VALUE (ECMA_SPECIAL_PROPERTY_HASHMAP) - -/** - * Type of property not found. - */ -#define ECMA_PROPERTY_TYPE_NOT_FOUND ECMA_PROPERTY_TYPE_DELETED - -/** - * Type of property not found and no more searching in the proto chain. - */ -#define ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP ECMA_PROPERTY_TYPE_HASHMAP - /** * Property flag list (for ECMA_PROPERTY_TYPE_NAMEDDATA * and ECMA_PROPERTY_TYPE_NAMEDACCESSOR). @@ -407,9 +383,52 @@ typedef enum #define ECMA_PROPERTY_NAME_TYPE_SHIFT (ECMA_PROPERTY_FLAG_SHIFT + 4) /** - * Property name is a generic string. + * Special property identifiers. + */ +typedef enum +{ + /* Note: when new special types are added + * ECMA_PROPERTY_IS_PROPERTY_PAIR must be updated as well. */ + ECMA_SPECIAL_PROPERTY_HASHMAP, /**< hashmap property */ + ECMA_SPECIAL_PROPERTY_DELETED, /**< deleted property */ + + ECMA_SPECIAL_PROPERTY__COUNT /**< Number of special property types */ +} ecma_internal_property_id_t; + +/** + * Define special property type. + */ +#define ECMA_SPECIAL_PROPERTY_VALUE(type) \ + ((uint8_t) (ECMA_PROPERTY_TYPE_SPECIAL | ((type) << ECMA_PROPERTY_NAME_TYPE_SHIFT))) + +/** + * Type of deleted property. */ -#define ECMA_PROPERTY_NAME_TYPE_STRING 3 +#define ECMA_PROPERTY_TYPE_DELETED ECMA_SPECIAL_PROPERTY_VALUE (ECMA_SPECIAL_PROPERTY_DELETED) + +/** + * Type of hash-map property. + */ +#define ECMA_PROPERTY_TYPE_HASHMAP ECMA_SPECIAL_PROPERTY_VALUE (ECMA_SPECIAL_PROPERTY_HASHMAP) + +/** + * Name constant of a deleted property. + */ +#ifdef JERRY_CPOINTER_32_BIT +#define ECMA_PROPERTY_DELETED_NAME 0xffffffffu +#else /* !JERRY_CPOINTER_32_BIT */ +#define ECMA_PROPERTY_DELETED_NAME 0xffffu +#endif /* JERRY_CPOINTER_32_BIT */ + +/** + * Type of property not found. + */ +#define ECMA_PROPERTY_TYPE_NOT_FOUND ECMA_PROPERTY_TYPE_HASHMAP + +/** + * Type of property not found and no more searching in the proto chain. + */ +#define ECMA_PROPERTY_TYPE_NOT_FOUND_AND_STOP ECMA_PROPERTY_TYPE_DELETED /** * Abstract property representation. @@ -512,12 +531,6 @@ typedef struct #define ECMA_PROPERTY_IS_NAMED_PROPERTY(property) \ (ECMA_PROPERTY_GET_TYPE (property) != ECMA_PROPERTY_TYPE_SPECIAL) -/** - * Returns the internal property type - */ -#define ECMA_PROPERTY_GET_SPECIAL_PROPERTY_TYPE(property_p) \ - ((ecma_internal_property_id_t) (*(property_p) >> ECMA_PROPERTY_FLAG_SHIFT)) - /** * Add the offset part to a property for computing its property data pointer. */ @@ -711,6 +724,8 @@ typedef struct struct { uint16_t class_id; /**< class id of the object */ + uint16_t extra_info; /**< extra information for the object + e.g. array buffer type info (external/internal) */ /* * Description of extra fields. These extra fields depends on the class_id. @@ -782,6 +797,33 @@ typedef struct ecma_built_in_props_t built_in; /**< built-in object part */ } ecma_extended_built_in_object_t; +/** + * Compiled byte code data. + */ +typedef struct +{ + uint16_t size; /**< real size >> JMEM_ALIGNMENT_LOG */ + uint16_t refs; /**< reference counter for the byte code */ + uint16_t status_flags; /**< various status flags: + * CBC_CODE_FLAGS_FUNCTION flag tells whether + * the byte code is function or regular expression. + * If function, the other flags must be CBC_CODE_FLAGS... + * If regexp, the other flags must be RE_FLAG... */ +} ecma_compiled_code_t; + +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + +/** + * Description of static function objects. + */ +typedef struct +{ + ecma_extended_object_t header; + const ecma_compiled_code_t *bytecode_p; +} ecma_static_function_t; + +#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ + #ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION /** @@ -795,6 +837,19 @@ typedef struct jmem_cpointer_t bytecode_cp; /**< function byte code */ } ecma_arrow_function_t; +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + +/** + * Description of static arrow function objects. + */ +typedef struct +{ + ecma_arrow_function_t header; + const ecma_compiled_code_t *bytecode_p; +} ecma_static_arrow_function_t; + +#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ + #endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ /** @@ -1018,46 +1073,142 @@ typedef double ecma_number_t; */ #define ECMA_STRING_NOT_ARRAY_INDEX UINT32_MAX +/* + * Ecma-collection: a growable list of ecma-values. Currently the list is + * a chain list, where appending new items at the end is cheap operation. + * + * Enumerating elements is also cheap, since each page is terminated by a + * special ecma-value: collection-type. This type has a pointer to the next + * chunk. The last chunk is terminated by a NULL pointer. There when the + * next value is requested from the iterator it simply checks the next + * memory location. If it is not a collection-type value, it returns with + * the value. Otherwise it gets the start address of the next chunk, and + * return the value there. + * + * The collection-type value is always the last item of a collection chunk, + * even if the chunk is not completely filled with values (this is only true + * for the last chunk). Each chunk must have at least one non collection-type + * value as well. + */ + +/** + * Collection flags. + */ +typedef enum +{ + ECMA_COLLECTION_NO_REF_OBJECTS = (1u << 0), /**< do not increase the refcount of objects */ + ECMA_COLLECTION_NO_COPY = (1u << 1), /**< do not copy values */ +} ecma_collection_flag_t; + /** * Description of a collection's header. */ typedef struct { - /** Number of elements in the collection */ - ecma_length_t unit_number; - - /** Compressed pointer to first chunk with collection's data */ - jmem_cpointer_t first_chunk_cp; - - /** Compressed pointer to last chunk with collection's data */ - jmem_cpointer_t last_chunk_cp; + jmem_cpointer_t first_chunk_cp; /**< compressed pointer to first chunk with collection's data */ + jmem_cpointer_t last_chunk_cp; /**< compressed pointer to last chunk with collection's data */ + ecma_length_t item_count; /**< number of items in the collection */ } ecma_collection_header_t; /** - * Description of non-first chunk in a collection's chain of chunks + * Maximum number of items stored by a collection chunk (excluding the last collection-type value). + */ +#define ECMA_COLLECTION_CHUNK_ITEMS 5 + +/** + * Collection chunk item. */ typedef struct { - /** Characters */ - lit_utf8_byte_t data[ sizeof (uint64_t) - sizeof (jmem_cpointer_t) ]; - - /** Compressed pointer to next chunk */ - jmem_cpointer_t next_chunk_cp; + ecma_value_t items[ECMA_COLLECTION_CHUNK_ITEMS + 1]; /**< ecma-value list, where the last value is a special + * collection-type value which points to the next chunk, + * so the chunk area is enlarged by one for this value */ } ecma_collection_chunk_t; +/** + * Direct string types (2 bit). + */ +typedef enum +{ + ECMA_DIRECT_STRING_PTR = 0, /**< string is a string pointer, only used by property names */ + ECMA_DIRECT_STRING_MAGIC = 1, /**< string is a magic string */ + ECMA_DIRECT_STRING_UINT = 2, /**< string is an unsigned int */ + ECMA_DIRECT_STRING_MAGIC_EX = 3, /**< string is an extended magic string */ +} ecma_direct_string_type_t; + +/** + * Maximum value of the immediate part of a direct magic string. + * Must be compatible with the immediate property name. + */ +#ifdef JERRY_CPOINTER_32_BIT +#define ECMA_DIRECT_STRING_MAX_IMM 0x07ffffff +#else /* !JERRY_CPOINTER_32_BIT */ +#define ECMA_DIRECT_STRING_MAX_IMM 0x0000ffff +#endif /* JERRY_CPOINTER_32_BIT */ + +/** + * Shift for direct string value part in ecma_value_t. + */ +#define ECMA_DIRECT_STRING_SHIFT (ECMA_VALUE_SHIFT + 2) + +/** + * Full mask for direct strings. + */ +#define ECMA_DIRECT_STRING_MASK ((uintptr_t) (ECMA_DIRECT_TYPE_MASK | (0x3u << ECMA_VALUE_SHIFT))) + +/** + * Create an ecma direct string. + */ +#define ECMA_CREATE_DIRECT_STRING(type, value) \ + ((uintptr_t) (ECMA_TYPE_DIRECT_STRING | ((type) << ECMA_VALUE_SHIFT) | (value) << ECMA_DIRECT_STRING_SHIFT)) + +/** + * Checks whether the string is direct. + */ +#define ECMA_IS_DIRECT_STRING(string_p) \ + ((((uintptr_t) (string_p)) & 0x1) != 0) + +/** + * Checks whether the string is direct. + */ +#define ECMA_IS_DIRECT_STRING_WITH_TYPE(string_p, type) \ + ((((uintptr_t) (string_p)) & ECMA_DIRECT_STRING_MASK) == ECMA_CREATE_DIRECT_STRING (type, 0)) + +/** + * Returns the type of a direct string. + */ +#define ECMA_GET_DIRECT_STRING_TYPE(string_p) \ + ((((uintptr_t) (string_p)) >> ECMA_VALUE_SHIFT) & 0x3) + +/** + * Shift applied to type conversions. + */ +#define ECMA_STRING_TYPE_CONVERSION_SHIFT (ECMA_PROPERTY_NAME_TYPE_SHIFT - ECMA_VALUE_SHIFT) + +/** + * Converts direct string type to property name type. + */ +#define ECMA_DIRECT_STRING_TYPE_TO_PROP_NAME_TYPE(string_p) \ + ((((uintptr_t) (string_p)) & (0x3 << ECMA_VALUE_SHIFT)) << ECMA_STRING_TYPE_CONVERSION_SHIFT) + +/** + * Returns the value of a direct string. + */ +#define ECMA_GET_DIRECT_STRING_VALUE(string_p) \ + (((uintptr_t) (string_p)) >> ECMA_DIRECT_STRING_SHIFT) + /** * Identifier for ecma-string's actual data container */ typedef enum { - ECMA_STRING_CONTAINER_UINT32_IN_DESC, /**< actual data is UInt32-represeneted Number - stored locally in the string's descriptor */ - ECMA_STRING_CONTAINER_MAGIC_STRING, /**< the ecma-string is equal to one of ECMA magic strings */ - ECMA_STRING_CONTAINER_MAGIC_STRING_EX, /**< the ecma-string is equal to one of external magic strings */ ECMA_STRING_CONTAINER_HEAP_UTF8_STRING, /**< actual data is on the heap as an utf-8 (cesu8) string * maximum size is 2^16. */ ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING, /**< actual data is on the heap as an utf-8 (cesu8) string * maximum size is 2^32. */ + ECMA_STRING_CONTAINER_UINT32_IN_DESC, /**< actual data is UInt32-represeneted Number + stored locally in the string's descriptor */ + ECMA_STRING_CONTAINER_MAGIC_STRING_EX, /**< the ecma-string is equal to one of external magic strings */ ECMA_STRING_LITERAL_NUMBER, /**< a literal number which is used solely by the literal storage * so no string processing function supports this type except @@ -1126,9 +1277,8 @@ typedef struct lit_utf8_size_t long_utf8_string_size; /**< size of this long utf-8 string in bytes */ uint32_t uint32_number; /**< uint32-represented number placed locally in the descriptor */ - uint32_t magic_string_id; /**< identifier of a magic string (lit_magic_string_id_t) */ uint32_t magic_string_ex_id; /**< identifier of an external magic string (lit_magic_string_ex_id_t) */ - ecma_value_t lit_number; /**< literal number (note: not a regular string type) */ + ecma_value_t lit_number; /**< number (see ECMA_STRING_LITERAL_NUMBER) */ uint32_t common_uint32_field; /**< for zeroing and comparison in some cases */ } u; } ecma_string_t; @@ -1143,27 +1293,28 @@ typedef struct } ecma_long_string_t; /** - * Representation of a thrown value on API level. + * Abort flag for error reference. */ -typedef struct -{ - uint32_t refs; /**< reference counter */ - ecma_value_t value; /**< referenced value */ -} ecma_error_reference_t; +#define ECMA_ERROR_REF_ABORT 0x1 /** - * Compiled byte code data. + * Value for increasing or decreasing the reference counter. + */ +#define ECMA_ERROR_REF_ONE (1u << 1) + +/** + * Maximum value of the reference counter. + */ +#define ECMA_ERROR_MAX_REF (UINT32_MAX - 1u) + +/** + * Representation of a thrown value on API level. */ typedef struct { - uint16_t size; /**< real size >> JMEM_ALIGNMENT_LOG */ - uint16_t refs; /**< reference counter for the byte code */ - uint16_t status_flags; /**< various status flags: - * CBC_CODE_FLAGS_FUNCTION flag tells whether - * the byte code is function or regular expression. - * If function, the other flags must be CBC_CODE_FLAGS... - * If regexp, the other flags must be RE_FLAG... */ -} ecma_compiled_code_t; + uint32_t refs_and_flags; /**< reference counter */ + ecma_value_t value; /**< referenced value */ +} ecma_error_reference_t; #ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE @@ -1226,6 +1377,33 @@ typedef struct #ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN +/** + * Extra information for ArrayBuffers. + */ +typedef enum +{ + ECMA_ARRAYBUFFER_INTERNAL_MEMORY = 0u, /* ArrayBuffer memory is handled internally. */ + ECMA_ARRAYBUFFER_EXTERNAL_MEMORY = (1u << 0), /* ArrayBuffer created via jerry_create_arraybuffer_external. */ +} ecma_arraybuffer_extra_flag_t; + +#define ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY(object_p) \ + ((((ecma_extended_object_t *) object_p)->u.class_prop.extra_info & ECMA_ARRAYBUFFER_EXTERNAL_MEMORY) != 0) + +/** + * Struct to store information for ArrayBuffers with external memory. + * + * The following elements are stored in Jerry memory. + * + * buffer_p - pointer to the external memory. + * free_cb - pointer to a callback function which is called when the ArrayBuffer is freed. + */ +typedef struct +{ + ecma_extended_object_t extended_object; /**< extended object part */ + void *buffer_p; /**< external buffer pointer */ + ecma_object_native_free_callback_t free_cb; /**< the free callback for the above buffer pointer */ +} ecma_arraybuffer_external_info; + /** * Some internal properties of TypedArray object. * It is only used when the offset is not 0, and diff --git a/deps/jerry/jerry-core/ecma/base/ecma-helpers-external-pointers.c b/deps/jerry/jerry-core/ecma/base/ecma-helpers-external-pointers.c index 6a5ad2b..bb77067 100644 --- a/deps/jerry/jerry-core/ecma/base/ecma-helpers-external-pointers.c +++ b/deps/jerry/jerry-core/ecma/base/ecma-helpers-external-pointers.c @@ -45,10 +45,9 @@ ecma_create_native_property (ecma_object_t *obj_p, /**< object to create propert JERRY_ASSERT (id == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE || id == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER); - ecma_string_t name; - ecma_init_ecma_magic_string (&name, id); + ecma_string_t *name_p = ecma_get_magic_string (id); + ecma_property_t *property_p = ecma_find_named_property (obj_p, name_p); - ecma_property_t *property_p = ecma_find_named_property (obj_p, &name); bool is_new = (property_p == NULL); ecma_native_pointer_t *native_pointer_p; @@ -56,7 +55,7 @@ ecma_create_native_property (ecma_object_t *obj_p, /**< object to create propert if (is_new) { ecma_property_value_t *value_p; - value_p = ecma_create_named_data_property (obj_p, &name, ECMA_PROPERTY_FLAG_WRITABLE, NULL); + value_p = ecma_create_named_data_property (obj_p, name_p, ECMA_PROPERTY_FLAG_WRITABLE, NULL); native_pointer_p = jmem_heap_alloc_block (sizeof (ecma_native_pointer_t)); @@ -69,8 +68,6 @@ ecma_create_native_property (ecma_object_t *obj_p, /**< object to create propert native_pointer_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_native_pointer_t, value_p->value); } - JERRY_ASSERT (ECMA_STRING_IS_REF_EQUALS_TO_ONE (&name)); - native_pointer_p->data_p = data_p; native_pointer_p->u.info_p = info_p; @@ -130,12 +127,7 @@ ecma_get_native_pointer_value (ecma_object_t *obj_p, /**< object to get property JERRY_ASSERT (id == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE || id == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER); - ecma_string_t name; - ecma_init_ecma_magic_string (&name, id); - - ecma_property_t *property_p = ecma_find_named_property (obj_p, &name); - - JERRY_ASSERT (ECMA_STRING_IS_REF_EQUALS_TO_ONE (&name)); + ecma_property_t *property_p = ecma_find_named_property (obj_p, ecma_get_magic_string (id)); if (property_p == NULL) { diff --git a/deps/jerry/jerry-core/ecma/base/ecma-helpers-string.c b/deps/jerry/jerry-core/ecma/base/ecma-helpers-string.c index e9b0e8d..5b538bb 100644 --- a/deps/jerry/jerry-core/ecma/base/ecma-helpers-string.c +++ b/deps/jerry/jerry-core/ecma/base/ecma-helpers-string.c @@ -42,41 +42,19 @@ JERRY_STATIC_ASSERT ((ECMA_STRING_MAX_REF | ECMA_STRING_CONTAINER_MASK) == UINT1 JERRY_STATIC_ASSERT (ECMA_STRING_NOT_ARRAY_INDEX == UINT32_MAX, ecma_string_not_array_index_must_be_equal_to_uint32_max); -static void -ecma_init_ecma_string_from_magic_string_id (ecma_string_t *string_p, - lit_magic_string_id_t magic_string_id); +JERRY_STATIC_ASSERT ((ECMA_TYPE_DIRECT_STRING & 0x1) != 0, + ecma_type_direct_string_must_be_odd_number); -static void -ecma_init_ecma_string_from_magic_string_ex_id (ecma_string_t *string_p, - lit_magic_string_ex_id_t magic_string_ex_id); +JERRY_STATIC_ASSERT (LIT_MAGIC_STRING__COUNT <= ECMA_DIRECT_STRING_MAX_IMM, + all_magic_strings_must_be_encoded_as_direct_string); -/** - * Initialize ecma-string descriptor with specified magic string - */ -static void -ecma_init_ecma_string_from_magic_string_id (ecma_string_t *string_p, /**< descriptor to initialize */ - lit_magic_string_id_t magic_string_id) /**< identifier of - the magic string */ -{ - string_p->refs_and_container = ECMA_STRING_CONTAINER_MAGIC_STRING | ECMA_STRING_REF_ONE; - string_p->hash = (lit_string_hash_t) magic_string_id; - - string_p->u.magic_string_id = magic_string_id; -} /* ecma_init_ecma_string_from_magic_string_id */ +JERRY_STATIC_ASSERT ((int) ECMA_DIRECT_STRING_UINT == (int) ECMA_STRING_CONTAINER_UINT32_IN_DESC + && (int) ECMA_DIRECT_STRING_MAGIC_EX == (int) ECMA_STRING_CONTAINER_MAGIC_STRING_EX, + ecma_direct_and_container_types_must_match); -/** - * Initialize external ecma-string descriptor with specified magic string - */ -static void -ecma_init_ecma_string_from_magic_string_ex_id (ecma_string_t *string_p, /**< descriptor to initialize */ - lit_magic_string_ex_id_t magic_string_ex_id) /**< identifier of - the external magic string */ -{ - string_p->refs_and_container = ECMA_STRING_CONTAINER_MAGIC_STRING_EX | ECMA_STRING_REF_ONE; - string_p->hash = (lit_string_hash_t) (LIT_MAGIC_STRING__COUNT + magic_string_ex_id); +JERRY_STATIC_ASSERT (ECMA_PROPERTY_NAME_TYPE_SHIFT > ECMA_VALUE_SHIFT, + ecma_property_name_type_shift_must_be_greater_than_ecma_value_shift); - string_p->u.magic_string_ex_id = magic_string_ex_id; -} /* ecma_init_ecma_string_from_magic_string_ex_id */ /** * Convert a string to an unsigned 32 bit value if possible @@ -141,6 +119,62 @@ ecma_string_to_array_index (const lit_utf8_byte_t *string_p, /**< utf-8 string * return true; } /* ecma_string_to_array_index */ +/** + * Returns the characters and size of a string. + * + * Note: + * UINT type is not supported + * + * @return byte array start - if the byte array of a string is available + * NULL - otherwise + */ +static const lit_utf8_byte_t * +ecma_string_get_chars_fast (const ecma_string_t *string_p, /**< ecma-string */ + lit_utf8_size_t *size_p) /**< [out] size of the ecma string */ +{ + if (ECMA_IS_DIRECT_STRING (string_p)) + { + if (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_MAGIC) + { + lit_magic_string_id_t id = (lit_magic_string_id_t) ECMA_GET_DIRECT_STRING_VALUE (string_p); + + *size_p = lit_get_magic_string_size (id); + return lit_get_magic_string_utf8 (id); + } + + JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_MAGIC_EX); + + lit_magic_string_ex_id_t id = (lit_magic_string_ex_id_t) ECMA_GET_DIRECT_STRING_VALUE (string_p); + + *size_p = lit_get_magic_string_ex_size (id); + return lit_get_magic_string_ex_utf8 (id); + } + + JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE); + + switch (ECMA_STRING_GET_CONTAINER (string_p)) + { + case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: + { + *size_p = string_p->u.utf8_string.size; + return (const lit_utf8_byte_t *) (string_p + 1); + } + case ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING: + { + *size_p = string_p->u.long_utf8_string_size; + ecma_long_string_t *long_string_p = (ecma_long_string_t *) string_p; + return (const lit_utf8_byte_t *) (long_string_p + 1); + } + default: + { + JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); + + *size_p = lit_get_magic_string_ex_size (string_p->u.magic_string_ex_id); + return lit_get_magic_string_ex_utf8 (string_p->u.magic_string_ex_id); + } + } +} /* ecma_string_get_chars_fast */ + /** * Allocate new ecma-string and fill it with characters from the utf8 string * @@ -178,7 +212,7 @@ ecma_new_ecma_string_from_utf8 (const lit_utf8_byte_t *string_p, /**< utf-8 stri if (magic_string_ex_id < lit_get_magic_string_ex_count ()) { - return ecma_get_magic_string_ex (magic_string_ex_id); + return ecma_new_ecma_string_from_magic_string_ex_id (magic_string_ex_id); } } @@ -346,44 +380,42 @@ ecma_new_ecma_string_from_code_unit (ecma_char_t code_unit) /**< code unit */ } /* ecma_new_ecma_string_from_code_unit */ /** - * Initialize an ecma-string with an ecma-number + * Allocate new ecma-string and fill it with ecma-number + * + * @return pointer to ecma-string descriptor */ -inline void __attr_always_inline___ -ecma_init_ecma_string_from_uint32 (ecma_string_t *string_desc_p, /**< ecma-string */ - uint32_t uint32_number) /**< uint32 value of the string */ +ecma_string_t * +ecma_new_ecma_string_from_uint32 (uint32_t uint32_number) /**< uint32 value of the string */ { - string_desc_p->refs_and_container = ECMA_STRING_CONTAINER_UINT32_IN_DESC | ECMA_STRING_REF_ONE; - string_desc_p->hash = (lit_string_hash_t) uint32_number; + if (likely (uint32_number <= ECMA_DIRECT_STRING_MAX_IMM)) + { + return (ecma_string_t *) ECMA_CREATE_DIRECT_STRING (ECMA_DIRECT_STRING_UINT, (uintptr_t) uint32_number); + } - string_desc_p->u.uint32_number = uint32_number; -} /* ecma_init_ecma_string_from_uint32 */ + ecma_string_t *string_p = ecma_alloc_string (); -/** - * Initialize a magic ecma-string - */ -void -ecma_init_ecma_magic_string (ecma_string_t *string_desc_p, /**< ecma-string */ - lit_magic_string_id_t id) /**< literal id */ -{ - string_desc_p->refs_and_container = ECMA_STRING_CONTAINER_MAGIC_STRING | ECMA_STRING_REF_ONE; - string_desc_p->hash = (lit_string_hash_t) id; + string_p->refs_and_container = ECMA_STRING_CONTAINER_UINT32_IN_DESC | ECMA_STRING_REF_ONE; + string_p->hash = (lit_string_hash_t) uint32_number; + string_p->u.uint32_number = uint32_number; - string_desc_p->u.magic_string_id = (uint32_t) id; -} /* ecma_init_ecma_magic_string */ + return string_p; +} /* ecma_new_ecma_string_from_uint32 */ /** - * Allocate new ecma-string and fill it with ecma-number + * Returns the constant assigned to the uint32 number. + * + * Note: + * Calling ecma_deref_ecma_string on the returned pointer is optional. * * @return pointer to ecma-string descriptor */ ecma_string_t * -ecma_new_ecma_string_from_uint32 (uint32_t uint32_number) /**< uint32 value of the string */ +ecma_get_ecma_string_from_uint32 (uint32_t uint32_number) { - ecma_string_t *string_desc_p = ecma_alloc_string (); + JERRY_ASSERT (uint32_number <= ECMA_DIRECT_STRING_MAX_IMM); - ecma_init_ecma_string_from_uint32 (string_desc_p, uint32_number); - return string_desc_p; -} /* ecma_new_ecma_string_from_uint32 */ + return (ecma_string_t *) ECMA_CREATE_DIRECT_STRING (ECMA_DIRECT_STRING_UINT, (uintptr_t) uint32_number); +} /* ecma_get_ecma_string_from_uint32 */ /** * Allocate new ecma-string and fill it with ecma-number @@ -434,20 +466,19 @@ ecma_new_ecma_string_from_number (ecma_number_t num) /**< ecma-number */ } /* ecma_new_ecma_string_from_number */ /** - * Allocate new ecma-string and fill it with reference to ECMA magic string + * Returns the constant assigned to the magic string id. + * + * Note: + * Calling ecma_deref_ecma_string on the returned pointer is optional. * * @return pointer to ecma-string descriptor */ -ecma_string_t * -ecma_new_ecma_string_from_magic_string_id (lit_magic_string_id_t id) /**< identifier of magic string */ +inline ecma_string_t * __attr_always_inline___ +ecma_get_magic_string (lit_magic_string_id_t id) /**< identifier of magic string */ { JERRY_ASSERT (id < LIT_MAGIC_STRING__COUNT); - - ecma_string_t *string_desc_p = ecma_alloc_string (); - ecma_init_ecma_string_from_magic_string_id (string_desc_p, id); - - return string_desc_p; -} /* ecma_new_ecma_string_from_magic_string_id */ + return (ecma_string_t *) ECMA_CREATE_DIRECT_STRING (ECMA_DIRECT_STRING_MAGIC, (uintptr_t) id); +} /* ecma_get_magic_string */ /** * Allocate new ecma-string and fill it with reference to ECMA magic string @@ -459,25 +490,19 @@ ecma_new_ecma_string_from_magic_string_ex_id (lit_magic_string_ex_id_t id) /**< { JERRY_ASSERT (id < lit_get_magic_string_ex_count ()); - ecma_string_t *string_desc_p = ecma_alloc_string (); - ecma_init_ecma_string_from_magic_string_ex_id (string_desc_p, id); - - return string_desc_p; -} /* ecma_new_ecma_string_from_magic_string_ex_id */ + if (likely (id <= ECMA_DIRECT_STRING_MAX_IMM)) + { + return (ecma_string_t *) ECMA_CREATE_DIRECT_STRING (ECMA_DIRECT_STRING_MAGIC_EX, (uintptr_t) id); + } -/** - * Allocate new ecma-string and fill it with reference to length magic string - * - * @return pointer to ecma-string descriptor - */ -ecma_string_t * -ecma_new_ecma_length_string (void) -{ ecma_string_t *string_desc_p = ecma_alloc_string (); - ecma_init_ecma_magic_string (string_desc_p, LIT_MAGIC_STRING_LENGTH); + + string_desc_p->refs_and_container = ECMA_STRING_CONTAINER_MAGIC_STRING_EX | ECMA_STRING_REF_ONE; + string_desc_p->hash = (lit_string_hash_t) (LIT_MAGIC_STRING__COUNT + id); + string_desc_p->u.magic_string_ex_id = id; return string_desc_p; -} /* ecma_new_ecma_length_string */ +} /* ecma_new_ecma_string_from_magic_string_ex_id */ /** * Append a cesu8 string after an ecma-string @@ -498,7 +523,6 @@ ecma_append_chars_to_string (ecma_string_t *string1_p, /**< base ecma-string */ if (unlikely (ecma_string_is_empty (string1_p))) { - ecma_deref_ecma_string (string1_p); return ecma_new_ecma_string_from_utf8 (cesu8_string2_p, cesu8_string2_size); } @@ -511,52 +535,85 @@ ecma_append_chars_to_string (ecma_string_t *string1_p, /**< base ecma-string */ bool string1_is_uint32 = false; bool string1_rehash_needed = false; - switch (ECMA_STRING_GET_CONTAINER (string1_p)) + if (ECMA_IS_DIRECT_STRING (string1_p)) { - case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: - { - cesu8_string1_p = (lit_utf8_byte_t *) (string1_p + 1); - cesu8_string1_size = string1_p->u.utf8_string.size; - cesu8_string1_length = string1_p->u.utf8_string.length; - break; - } - case ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING: - { - ecma_long_string_t *long_string_desc_p = (ecma_long_string_t *) string1_p; + string1_rehash_needed = true; - cesu8_string1_p = (lit_utf8_byte_t *) (long_string_desc_p + 1); - cesu8_string1_size = string1_p->u.long_utf8_string_size; - cesu8_string1_length = long_string_desc_p->long_utf8_string_length; - break; - } - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: - { - cesu8_string1_size = ecma_uint32_to_utf8_string (string1_p->u.uint32_number, - uint32_to_string_buffer, - ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32); - cesu8_string1_p = uint32_to_string_buffer; - cesu8_string1_length = cesu8_string1_size; - string1_is_uint32 = true; - string1_rehash_needed = true; - break; - } - case ECMA_STRING_CONTAINER_MAGIC_STRING: + switch (ECMA_GET_DIRECT_STRING_TYPE (string1_p)) { - cesu8_string1_p = lit_get_magic_string_utf8 (string1_p->u.magic_string_id); - cesu8_string1_size = lit_get_magic_string_size (string1_p->u.magic_string_id); - cesu8_string1_length = cesu8_string1_size; - string1_rehash_needed = true; - break; + case ECMA_DIRECT_STRING_MAGIC: + { + lit_magic_string_id_t id = (lit_magic_string_id_t) ECMA_GET_DIRECT_STRING_VALUE (string1_p); + cesu8_string1_p = lit_get_magic_string_utf8 (id); + cesu8_string1_size = lit_get_magic_string_size (id); + cesu8_string1_length = cesu8_string1_size; + break; + } + case ECMA_DIRECT_STRING_UINT: + { + cesu8_string1_size = ecma_uint32_to_utf8_string ((uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string1_p), + uint32_to_string_buffer, + ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32); + cesu8_string1_p = uint32_to_string_buffer; + cesu8_string1_length = cesu8_string1_size; + string1_is_uint32 = true; + break; + } + default: + { + JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string1_p) == ECMA_DIRECT_STRING_MAGIC_EX); + + lit_magic_string_ex_id_t id = (lit_magic_string_ex_id_t) ECMA_GET_DIRECT_STRING_VALUE (string1_p); + cesu8_string1_p = lit_get_magic_string_ex_utf8 (id); + cesu8_string1_size = lit_get_magic_string_ex_size (id); + cesu8_string1_length = lit_utf8_string_length (cesu8_string1_p, cesu8_string1_size); + break; + } } - default: + } + else + { + JERRY_ASSERT (string1_p->refs_and_container >= ECMA_STRING_REF_ONE); + + switch (ECMA_STRING_GET_CONTAINER (string1_p)) { - JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); + case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: + { + cesu8_string1_p = (lit_utf8_byte_t *) (string1_p + 1); + cesu8_string1_size = string1_p->u.utf8_string.size; + cesu8_string1_length = string1_p->u.utf8_string.length; + break; + } + case ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING: + { + ecma_long_string_t *long_string_desc_p = (ecma_long_string_t *) string1_p; - cesu8_string1_p = lit_get_magic_string_ex_utf8 (string1_p->u.magic_string_id); - cesu8_string1_size = lit_get_magic_string_ex_size (string1_p->u.magic_string_id); - cesu8_string1_length = lit_utf8_string_length (cesu8_string1_p, cesu8_string1_size); - string1_rehash_needed = true; - break; + cesu8_string1_p = (lit_utf8_byte_t *) (long_string_desc_p + 1); + cesu8_string1_size = string1_p->u.long_utf8_string_size; + cesu8_string1_length = long_string_desc_p->long_utf8_string_length; + break; + } + case ECMA_STRING_CONTAINER_UINT32_IN_DESC: + { + cesu8_string1_size = ecma_uint32_to_utf8_string (string1_p->u.uint32_number, + uint32_to_string_buffer, + ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32); + cesu8_string1_p = uint32_to_string_buffer; + cesu8_string1_length = cesu8_string1_size; + string1_is_uint32 = true; + string1_rehash_needed = true; + break; + } + default: + { + JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); + + cesu8_string1_p = lit_get_magic_string_ex_utf8 (string1_p->u.magic_string_ex_id); + cesu8_string1_size = lit_get_magic_string_ex_size (string1_p->u.magic_string_ex_id); + cesu8_string1_length = lit_utf8_string_length (cesu8_string1_p, cesu8_string1_size); + string1_rehash_needed = true; + break; + } } } @@ -609,7 +666,7 @@ ecma_append_chars_to_string (ecma_string_t *string1_p, /**< base ecma-string */ if (magic_string_ex_id < lit_get_magic_string_ex_count ()) { ecma_deref_ecma_string (string1_p); - return ecma_get_magic_string_ex (magic_string_ex_id); + return ecma_new_ecma_string_from_magic_string_ex_id (magic_string_ex_id); } } @@ -641,12 +698,17 @@ ecma_append_chars_to_string (ecma_string_t *string1_p, /**< base ecma-string */ data_p = (lit_utf8_byte_t *) (long_string_desc_p + 1); } - lit_string_hash_t hash_start = string1_p->hash; + lit_string_hash_t hash_start; if (string1_rehash_needed) { hash_start = lit_utf8_string_calc_hash (cesu8_string1_p, cesu8_string1_size); } + else + { + JERRY_ASSERT (!ECMA_IS_DIRECT_STRING (string1_p)); + hash_start = string1_p->hash; + } string_desc_p->hash = lit_utf8_string_hash_combine (hash_start, cesu8_string2_p, cesu8_string2_size); @@ -670,12 +732,10 @@ ecma_string_t * ecma_concat_ecma_strings (ecma_string_t *string1_p, /**< first ecma-string */ ecma_string_t *string2_p) /**< second ecma-string */ { - JERRY_ASSERT (string1_p != NULL - && string2_p != NULL); + JERRY_ASSERT (string1_p != NULL && string2_p != NULL); if (unlikely (ecma_string_is_empty (string1_p))) { - ecma_deref_ecma_string (string1_p); ecma_ref_ecma_string (string2_p); return string2_p; } @@ -690,48 +750,79 @@ ecma_concat_ecma_strings (ecma_string_t *string1_p, /**< first ecma-string */ lit_utf8_byte_t uint32_to_string_buffer[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32]; - switch (ECMA_STRING_GET_CONTAINER (string2_p)) + if (ECMA_IS_DIRECT_STRING (string2_p)) { - case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: - { - cesu8_string2_p = (lit_utf8_byte_t *) (string2_p + 1); - cesu8_string2_size = string2_p->u.utf8_string.size; - cesu8_string2_length = string2_p->u.utf8_string.length; - break; - } - case ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING: + switch (ECMA_GET_DIRECT_STRING_TYPE (string2_p)) { - ecma_long_string_t *long_string_desc_p = (ecma_long_string_t *) string2_p; + case ECMA_DIRECT_STRING_MAGIC: + { + lit_magic_string_id_t id = (lit_magic_string_id_t) ECMA_GET_DIRECT_STRING_VALUE (string2_p); + cesu8_string2_p = lit_get_magic_string_utf8 (id); + cesu8_string2_size = lit_get_magic_string_size (id); + cesu8_string2_length = cesu8_string2_size; + break; + } + case ECMA_DIRECT_STRING_UINT: + { + cesu8_string2_size = ecma_uint32_to_utf8_string ((uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string2_p), + uint32_to_string_buffer, + ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32); + cesu8_string2_p = uint32_to_string_buffer; + cesu8_string2_length = cesu8_string2_size; + break; + } + default: + { + JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string2_p) == ECMA_DIRECT_STRING_MAGIC_EX); - cesu8_string2_p = (lit_utf8_byte_t *) (long_string_desc_p + 1); - cesu8_string2_size = string2_p->u.long_utf8_string_size; - cesu8_string2_length = long_string_desc_p->long_utf8_string_length; - break; - } - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: - { - cesu8_string2_size = ecma_uint32_to_utf8_string (string2_p->u.uint32_number, - uint32_to_string_buffer, - ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32); - cesu8_string2_p = uint32_to_string_buffer; - cesu8_string2_length = cesu8_string2_size; - break; - } - case ECMA_STRING_CONTAINER_MAGIC_STRING: - { - cesu8_string2_p = lit_get_magic_string_utf8 (string2_p->u.magic_string_id); - cesu8_string2_size = lit_get_magic_string_size (string2_p->u.magic_string_id); - cesu8_string2_length = cesu8_string2_size; - break; + lit_magic_string_ex_id_t id = (lit_magic_string_ex_id_t) ECMA_GET_DIRECT_STRING_VALUE (string2_p); + cesu8_string2_p = lit_get_magic_string_ex_utf8 (id); + cesu8_string2_size = lit_get_magic_string_ex_size (id); + cesu8_string2_length = lit_utf8_string_length (cesu8_string2_p, cesu8_string2_size); + break; + } } - default: + } + else + { + JERRY_ASSERT (string2_p->refs_and_container >= ECMA_STRING_REF_ONE); + + switch (ECMA_STRING_GET_CONTAINER (string2_p)) { - JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string2_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); + case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: + { + cesu8_string2_p = (lit_utf8_byte_t *) (string2_p + 1); + cesu8_string2_size = string2_p->u.utf8_string.size; + cesu8_string2_length = string2_p->u.utf8_string.length; + break; + } + case ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING: + { + ecma_long_string_t *long_string_desc_p = (ecma_long_string_t *) string2_p; - cesu8_string2_p = lit_get_magic_string_ex_utf8 (string2_p->u.magic_string_id); - cesu8_string2_size = lit_get_magic_string_ex_size (string2_p->u.magic_string_id); - cesu8_string2_length = lit_utf8_string_length (cesu8_string2_p, cesu8_string2_size); - break; + cesu8_string2_p = (lit_utf8_byte_t *) (long_string_desc_p + 1); + cesu8_string2_size = string2_p->u.long_utf8_string_size; + cesu8_string2_length = long_string_desc_p->long_utf8_string_length; + break; + } + case ECMA_STRING_CONTAINER_UINT32_IN_DESC: + { + cesu8_string2_size = ecma_uint32_to_utf8_string (string2_p->u.uint32_number, + uint32_to_string_buffer, + ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32); + cesu8_string2_p = uint32_to_string_buffer; + cesu8_string2_length = cesu8_string2_size; + break; + } + default: + { + JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string2_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); + + cesu8_string2_p = lit_get_magic_string_ex_utf8 (string2_p->u.magic_string_ex_id); + cesu8_string2_size = lit_get_magic_string_ex_size (string2_p->u.magic_string_ex_id); + cesu8_string2_length = lit_utf8_string_length (cesu8_string2_p, cesu8_string2_size); + break; + } } } @@ -753,8 +844,7 @@ ecma_append_magic_string_to_string (ecma_string_t *string1_p, { if (unlikely (ecma_string_is_empty (string1_p))) { - ecma_deref_ecma_string (string1_p); - return ecma_new_ecma_string_from_magic_string_id (string2_id); + return ecma_get_magic_string (string2_id); } const lit_utf8_byte_t *cesu8_string2_p = lit_get_magic_string_utf8 (string2_id); @@ -770,6 +860,12 @@ void ecma_ref_ecma_string (ecma_string_t *string_p) /**< string descriptor */ { JERRY_ASSERT (string_p != NULL); + + if (ECMA_IS_DIRECT_STRING (string_p)) + { + return; + } + JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE); if (likely (string_p->refs_and_container < ECMA_STRING_MAX_REF)) @@ -791,6 +887,12 @@ void ecma_deref_ecma_string (ecma_string_t *string_p) /**< ecma-string */ { JERRY_ASSERT (string_p != NULL); + + if (ECMA_IS_DIRECT_STRING (string_p)) + { + return; + } + JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE); /* Decrease reference counter. */ @@ -829,7 +931,6 @@ ecma_deref_ecma_string (ecma_string_t *string_p) /**< ecma-string */ return; } case ECMA_STRING_CONTAINER_UINT32_IN_DESC: - case ECMA_STRING_CONTAINER_MAGIC_STRING: case ECMA_STRING_CONTAINER_MAGIC_STRING_EX: { /* only the string descriptor itself should be freed */ @@ -837,7 +938,7 @@ ecma_deref_ecma_string (ecma_string_t *string_p) /**< ecma-string */ } case ECMA_STRING_LITERAL_NUMBER: { - ecma_fast_free_value (string_p->u.lit_number); + ecma_free_value (string_p->u.lit_number); break; } default: @@ -854,43 +955,33 @@ ecma_deref_ecma_string (ecma_string_t *string_p) /**< ecma-string */ * Convert ecma-string to number */ ecma_number_t -ecma_string_to_number (const ecma_string_t *str_p) /**< ecma-string */ +ecma_string_to_number (const ecma_string_t *string_p) /**< ecma-string */ { - JERRY_ASSERT (str_p != NULL); + JERRY_ASSERT (string_p != NULL); - switch (ECMA_STRING_GET_CONTAINER (str_p)) + if (ECMA_IS_DIRECT_STRING (string_p)) { - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: + if (ECMA_IS_DIRECT_STRING_WITH_TYPE (string_p, ECMA_DIRECT_STRING_UINT)) { - return ((ecma_number_t) str_p->u.uint32_number); + return (ecma_number_t) ECMA_GET_DIRECT_STRING_VALUE (string_p); } + } + else if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC) + { + return ((ecma_number_t) string_p->u.uint32_number); + } - case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: - case ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING: - case ECMA_STRING_CONTAINER_MAGIC_STRING: - case ECMA_STRING_CONTAINER_MAGIC_STRING_EX: - { - ecma_number_t num; - - ECMA_STRING_TO_UTF8_STRING (str_p, str_buffer_p, str_buffer_size); - - if (str_buffer_size == 0) - { - return ECMA_NUMBER_ZERO; - } - - num = ecma_utf8_string_to_number (str_buffer_p, str_buffer_size); - - ECMA_FINALIZE_UTF8_STRING (str_buffer_p, str_buffer_size); + lit_utf8_size_t size; + const lit_utf8_byte_t *chars_p = ecma_string_get_chars_fast (string_p, &size); - return num; - } + JERRY_ASSERT (chars_p != NULL); - default: - { - JERRY_UNREACHABLE (); - } + if (size == 0) + { + return ECMA_NUMBER_ZERO; } + + return ecma_utf8_string_to_number (chars_p, size); } /* ecma_string_to_number */ /** @@ -902,14 +993,22 @@ ecma_string_to_number (const ecma_string_t *str_p) /**< ecma-string */ inline uint32_t __attr_always_inline___ ecma_string_get_array_index (const ecma_string_t *str_p) /**< ecma-string */ { - const ecma_string_container_t type = ECMA_STRING_GET_CONTAINER (str_p); + if (ECMA_IS_DIRECT_STRING (str_p)) + { + if (ECMA_IS_DIRECT_STRING_WITH_TYPE (str_p, ECMA_DIRECT_STRING_UINT)) + { + /* Value cannot be equal to the maximum value of a 32 bit unsigned number. */ + return (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (str_p); + } + + return ECMA_STRING_NOT_ARRAY_INDEX; + } - if (type == ECMA_STRING_CONTAINER_UINT32_IN_DESC) + if (ECMA_STRING_GET_CONTAINER (str_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC) { - /* When the uint32_number is equal to the maximum value of 32 bit - * unsigned integer number, it is also an invalid array index. - * The comparison to ECMA_STRING_NOT_ARRAY_INDEX will be true - * in this case. */ + /* When the uint32_number is equal to the maximum value of 32 bit unsigned integer number, + * it is also an invalid array index. The comparison to ECMA_STRING_NOT_ARRAY_INDEX will + * be true in this case. */ return str_p->u.uint32_number; } @@ -923,57 +1022,46 @@ ecma_string_get_array_index (const ecma_string_t *str_p) /**< ecma-string */ * @return number of bytes, actually copied to the buffer. */ lit_utf8_size_t __attr_return_value_should_be_checked___ -ecma_string_copy_to_cesu8_buffer (const ecma_string_t *string_desc_p, /**< ecma-string descriptor */ +ecma_string_copy_to_cesu8_buffer (const ecma_string_t *string_p, /**< ecma-string descriptor */ lit_utf8_byte_t *buffer_p, /**< destination buffer pointer * (can be NULL if buffer_size == 0) */ lit_utf8_size_t buffer_size) /**< size of buffer */ { - JERRY_ASSERT (string_desc_p != NULL); - JERRY_ASSERT (string_desc_p->refs_and_container >= ECMA_STRING_REF_ONE); + JERRY_ASSERT (string_p != NULL); JERRY_ASSERT (buffer_p != NULL || buffer_size == 0); - JERRY_ASSERT (ecma_string_get_size (string_desc_p) <= buffer_size); + JERRY_ASSERT (ecma_string_get_size (string_p) <= buffer_size); lit_utf8_size_t size; - switch (ECMA_STRING_GET_CONTAINER (string_desc_p)) + if (ECMA_IS_DIRECT_STRING (string_p)) { - case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: - { - size = string_desc_p->u.utf8_string.size; - memcpy (buffer_p, string_desc_p + 1, size); - break; - } - case ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING: - { - size = string_desc_p->u.long_utf8_string_size; - memcpy (buffer_p, ((ecma_long_string_t *) string_desc_p) + 1, size); - break; - } - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: + if (ECMA_IS_DIRECT_STRING_WITH_TYPE (string_p, ECMA_DIRECT_STRING_UINT)) { - const uint32_t uint32_number = string_desc_p->u.uint32_number; + uint32_t uint32_number = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p); size = ecma_uint32_to_utf8_string (uint32_number, buffer_p, buffer_size); - break; - } - case ECMA_STRING_CONTAINER_MAGIC_STRING: - { - const lit_magic_string_id_t id = string_desc_p->u.magic_string_id; - size = lit_get_magic_string_size (id); - memcpy (buffer_p, lit_get_magic_string_utf8 (id), size); - break; + JERRY_ASSERT (size <= buffer_size); + return size; } - default: - { - JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_desc_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); + } + else + { + JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE); - const lit_magic_string_ex_id_t id = string_desc_p->u.magic_string_ex_id; - size = lit_get_magic_string_ex_size (id); - memcpy (buffer_p, lit_get_magic_string_ex_utf8 (id), size); - break; + if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC) + { + uint32_t uint32_number = string_p->u.uint32_number; + size = ecma_uint32_to_utf8_string (uint32_number, buffer_p, buffer_size); + JERRY_ASSERT (size <= buffer_size); + return size; } } + const lit_utf8_byte_t *chars_p = ecma_string_get_chars_fast (string_p, &size); + + JERRY_ASSERT (chars_p != NULL); JERRY_ASSERT (size <= buffer_size); + + memcpy (buffer_p, chars_p, size); return size; } /* ecma_string_copy_to_cesu8_buffer */ @@ -984,60 +1072,60 @@ ecma_string_copy_to_cesu8_buffer (const ecma_string_t *string_desc_p, /**< ecma- * @return number of bytes, actually copied to the buffer. */ lit_utf8_size_t __attr_return_value_should_be_checked___ -ecma_string_copy_to_utf8_buffer (const ecma_string_t *string_desc_p, /**< ecma-string descriptor */ +ecma_string_copy_to_utf8_buffer (const ecma_string_t *string_p, /**< ecma-string descriptor */ lit_utf8_byte_t *buffer_p, /**< destination buffer pointer * (can be NULL if buffer_size == 0) */ lit_utf8_size_t buffer_size) /**< size of buffer */ { - JERRY_ASSERT (string_desc_p != NULL); - JERRY_ASSERT (string_desc_p->refs_and_container >= ECMA_STRING_REF_ONE); + JERRY_ASSERT (string_p != NULL); JERRY_ASSERT (buffer_p != NULL || buffer_size == 0); - JERRY_ASSERT (ecma_string_get_utf8_size (string_desc_p) <= buffer_size); + JERRY_ASSERT (ecma_string_get_utf8_size (string_p) <= buffer_size); lit_utf8_size_t size; - switch (ECMA_STRING_GET_CONTAINER (string_desc_p)) + if (ECMA_IS_DIRECT_STRING (string_p)) { - case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: - { - size = lit_convert_cesu8_string_to_utf8_string ((lit_utf8_byte_t *) (string_desc_p + 1), - string_desc_p->u.utf8_string.size, - buffer_p, - buffer_size); - break; - } - case ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING: + if (ECMA_IS_DIRECT_STRING_WITH_TYPE (string_p, ECMA_DIRECT_STRING_UINT)) { - size = lit_convert_cesu8_string_to_utf8_string ((lit_utf8_byte_t *) (((ecma_long_string_t *) string_desc_p) + 1), - string_desc_p->u.long_utf8_string_size, - buffer_p, - buffer_size); - break; + uint32_t uint32_number = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p); + size = ecma_uint32_to_utf8_string (uint32_number, buffer_p, buffer_size); + JERRY_ASSERT (size <= buffer_size); + return size; } - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: + } + else + { + JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE); + + if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC) { - const uint32_t uint32_number = string_desc_p->u.uint32_number; + uint32_t uint32_number = string_p->u.uint32_number; size = ecma_uint32_to_utf8_string (uint32_number, buffer_p, buffer_size); - break; + JERRY_ASSERT (size <= buffer_size); + return size; } - case ECMA_STRING_CONTAINER_MAGIC_STRING: - { - const lit_magic_string_id_t id = string_desc_p->u.magic_string_id; - size = lit_get_magic_string_size (id); - memcpy (buffer_p, lit_get_magic_string_utf8 (id), size); - break; - } - default: - { - JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_desc_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); + } - const lit_magic_string_ex_id_t id = string_desc_p->u.magic_string_ex_id; - size = lit_convert_cesu8_string_to_utf8_string (lit_get_magic_string_ex_utf8 (id), - lit_get_magic_string_ex_size (id), - buffer_p, - buffer_size); - break; - } + uint8_t flags = ECMA_STRING_FLAG_IS_ASCII; + const lit_utf8_byte_t *chars_p = ecma_string_get_chars (string_p, &size, &flags); + + JERRY_ASSERT (chars_p != NULL); + + if (flags & ECMA_STRING_FLAG_IS_ASCII) + { + JERRY_ASSERT (size <= buffer_size); + memcpy (buffer_p, chars_p, size); + return size; + } + + size = lit_convert_cesu8_string_to_utf8_string (chars_p, + size, + buffer_p, + buffer_size); + + if (flags & ECMA_STRING_FLAG_MUST_BE_FREED) + { + jmem_heap_free_block ((void *) chars_p, size); } JERRY_ASSERT (size <= buffer_size); @@ -1060,7 +1148,6 @@ ecma_substring_copy_to_cesu8_buffer (const ecma_string_t *string_desc_p, /**< ec lit_utf8_size_t buffer_size) /**< size of buffer */ { JERRY_ASSERT (string_desc_p != NULL); - JERRY_ASSERT (string_desc_p->refs_and_container >= ECMA_STRING_REF_ONE); JERRY_ASSERT (buffer_p != NULL || buffer_size == 0); ecma_length_t string_length = ecma_string_get_length (string_desc_p); @@ -1271,45 +1358,35 @@ ecma_string_to_utf8_bytes (const ecma_string_t *string_desc_p, /**< ecma-string } /* ecma_string_to_utf8_bytes */ /** - * Lengths for numeric string values - */ -static const uint32_t nums_with_ascending_length[] = -{ - 1u, - 10u, - 100u, - 1000u, - 10000u, - 100000u, - 1000000u, - 10000000u, - 100000000u, - 1000000000u -}; - -/** - * Maximum length of numeric strings - */ -static const uint32_t max_uint32_len = (uint32_t) (sizeof (nums_with_ascending_length) / sizeof (uint32_t)); - -/** - * Get size of the number stored locally in the string's descriptor + * Get size of the uint32 number stored locally in the string's descriptor * * Note: the represented number size and length are equal * * @return size in bytes */ static inline ecma_length_t __attr_always_inline___ -ecma_string_get_number_in_desc_size (const uint32_t uint32_number) /**< number in the string-descriptor */ +ecma_string_get_uint32_size (const uint32_t uint32_number) /**< number in the string-descriptor */ { + uint32_t prev_number = 1; + uint32_t next_number = 100; ecma_length_t size = 1; - while (size < max_uint32_len && uint32_number >= nums_with_ascending_length[size]) + const uint32_t max_size = 9; + + while (size < max_size && uint32_number >= next_number) + { + prev_number = next_number; + next_number *= 100; + size += 2; + } + + if (uint32_number >= prev_number * 10) { size++; } + return size; -} /* ecma_string_get_number_in_desc_size */ +} /* ecma_string_get_uint32_size */ /** * Checks whether the given string is a sequence of ascii characters. @@ -1317,78 +1394,134 @@ ecma_string_get_number_in_desc_size (const uint32_t uint32_number) /**< number i #define ECMA_STRING_IS_ASCII(char_p, size) ((size) == lit_utf8_string_length ((char_p), (size))) /** - * Returns with the raw byte array of the string, if it is available. + * Returns with the cesu8 character array of a string. * - * @return byte array start - if the byte array of a string is available - * NULL - otherwise + * Note: + * - This function returns with a newly allocated buffer for uint32 strings, + * which must be freed. + * - The ASCII check only happens if the flags parameter gets + * 'ECMA_STRING_FLAG_IS_ASCII' as an input. + * + * @return start of cesu8 characters */ const lit_utf8_byte_t * -ecma_string_raw_chars (const ecma_string_t *string_p, /**< ecma-string */ +ecma_string_get_chars (const ecma_string_t *string_p, /**< ecma-string */ lit_utf8_size_t *size_p, /**< [out] size of the ecma string */ - bool *is_ascii_p) /**< [out] true, if the string is an ascii - * character sequence (size == length) - * false, otherwise */ + uint8_t *flags_p) /**< [in,out] flags: ECMA_STRING_FLAG_EMPTY, + ECMA_STRING_FLAG_IS_ASCII, + ECMA_STRING_FLAG_MUST_BE_FREED */ { ecma_length_t length; lit_utf8_size_t size; const lit_utf8_byte_t *result_p; - switch (ECMA_STRING_GET_CONTAINER (string_p)) + if (ECMA_IS_DIRECT_STRING (string_p)) { - case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: + switch (ECMA_GET_DIRECT_STRING_TYPE (string_p)) { - size = string_p->u.utf8_string.size; - length = string_p->u.utf8_string.length; - result_p = (const lit_utf8_byte_t *) (string_p + 1); - break; - } - case ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING: - { - size = string_p->u.long_utf8_string_size; - ecma_long_string_t *long_string_p = (ecma_long_string_t *) string_p; - length = long_string_p->long_utf8_string_length; - result_p = (const lit_utf8_byte_t *) (long_string_p + 1); - break; - } - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: - { - size = (lit_utf8_size_t) ecma_string_get_number_in_desc_size (string_p->u.uint32_number); + case ECMA_DIRECT_STRING_MAGIC: + { + lit_magic_string_id_t id = (lit_magic_string_id_t) ECMA_GET_DIRECT_STRING_VALUE (string_p); - /* All numbers must be ascii strings. */ - JERRY_ASSERT (ecma_string_get_length (string_p) == size); + size = lit_get_magic_string_size (id); + length = size; - length = size; - result_p = NULL; - break; - } - case ECMA_STRING_CONTAINER_MAGIC_STRING: - { - size = lit_get_magic_string_size (string_p->u.magic_string_id); + result_p = lit_get_magic_string_utf8 (id); - length = size; - result_p = lit_get_magic_string_utf8 (string_p->u.magic_string_id); + /* All magic strings must be ascii strings. */ + JERRY_ASSERT (ECMA_STRING_IS_ASCII (result_p, size)); + break; + } + case ECMA_DIRECT_STRING_UINT: + { + uint32_t uint32_number = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p); + size = (lit_utf8_size_t) ecma_string_get_uint32_size (uint32_number); - /* All magic strings must be ascii strings. */ - JERRY_ASSERT (ECMA_STRING_IS_ASCII (result_p, size)); - break; + result_p = (const lit_utf8_byte_t *) jmem_heap_alloc_block (size); + length = ecma_uint32_to_utf8_string (uint32_number, (lit_utf8_byte_t *) result_p, size); + JERRY_ASSERT (length == size); + *flags_p |= ECMA_STRING_FLAG_MUST_BE_FREED; + break; + } + default: + { + JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_MAGIC_EX); + + lit_magic_string_ex_id_t id = (lit_magic_string_ex_id_t) ECMA_GET_DIRECT_STRING_VALUE (string_p); + + size = lit_get_magic_string_ex_size (id); + result_p = lit_get_magic_string_ex_utf8 (id); + length = 0; + + if (unlikely (*flags_p & ECMA_STRING_FLAG_IS_ASCII)) + { + length = lit_utf8_string_length (result_p, size); + } + break; + } } - default: + } + else + { + JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE); + + switch (ECMA_STRING_GET_CONTAINER (string_p)) { - JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); + case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: + { + size = string_p->u.utf8_string.size; + length = string_p->u.utf8_string.length; + result_p = (const lit_utf8_byte_t *) (string_p + 1); + break; + } + case ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING: + { + size = string_p->u.long_utf8_string_size; + ecma_long_string_t *long_string_p = (ecma_long_string_t *) string_p; + length = long_string_p->long_utf8_string_length; + result_p = (const lit_utf8_byte_t *) (long_string_p + 1); + break; + } + case ECMA_STRING_CONTAINER_UINT32_IN_DESC: + { + size = (lit_utf8_size_t) ecma_string_get_uint32_size (string_p->u.uint32_number); - size = lit_get_magic_string_ex_size (string_p->u.magic_string_ex_id); - length = lit_utf8_string_length (lit_get_magic_string_ex_utf8 (string_p->u.magic_string_ex_id), - lit_get_magic_string_ex_size (string_p->u.magic_string_ex_id)); + result_p = (const lit_utf8_byte_t *) jmem_heap_alloc_block (size); + length = ecma_uint32_to_utf8_string (string_p->u.uint32_number, (lit_utf8_byte_t *) result_p, size); + JERRY_ASSERT (length == size); + *flags_p |= ECMA_STRING_FLAG_MUST_BE_FREED; + break; - result_p = lit_get_magic_string_ex_utf8 (string_p->u.magic_string_ex_id); - break; + } + default: + { + JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); + + size = lit_get_magic_string_ex_size (string_p->u.magic_string_ex_id); + length = 0; + + if (unlikely (*flags_p & ECMA_STRING_FLAG_IS_ASCII)) + { + length = lit_utf8_string_length (lit_get_magic_string_ex_utf8 (string_p->u.magic_string_ex_id), size); + } + + result_p = lit_get_magic_string_ex_utf8 (string_p->u.magic_string_ex_id); + break; + } } } *size_p = size; - *is_ascii_p = (length == size); + if (*flags_p & ECMA_STRING_FLAG_IS_ASCII) + { + if (length != size) + { + *flags_p = (uint8_t) (*flags_p & ~ECMA_STRING_FLAG_IS_ASCII); + } + } + return result_p; -} /* ecma_string_raw_chars */ +} /* ecma_string_get_chars */ /** * Checks whether the string equals to the magic string id. @@ -1400,8 +1533,7 @@ inline bool __attr_always_inline___ ecma_compare_ecma_string_to_magic_id (const ecma_string_t *string_p, /**< property name */ lit_magic_string_id_t id) /**< magic string id */ { - return (string_p->u.magic_string_id == id - && ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING); + return (string_p == ecma_get_magic_string (id)); } /* ecma_compare_ecma_string_to_magic_id */ /** @@ -1428,6 +1560,16 @@ ecma_string_is_length (const ecma_string_t *string_p) /**< property name */ return ecma_compare_ecma_string_to_magic_id (string_p, LIT_MAGIC_STRING_LENGTH); } /* ecma_string_is_length */ + +static inline ecma_string_t * __attr_always_inline___ +ecma_property_to_string (ecma_property_t property, /**< property name type */ + jmem_cpointer_t prop_name_cp) /**< property name compressed pointer */ +{ + uintptr_t property_string = ((uintptr_t) (property)) & (0x3 << ECMA_PROPERTY_NAME_TYPE_SHIFT); + property_string = (property_string >> ECMA_STRING_TYPE_CONVERSION_SHIFT) | ECMA_TYPE_DIRECT_STRING; + return (ecma_string_t *) (property_string | (((uintptr_t) prop_name_cp) << ECMA_DIRECT_STRING_SHIFT)); +} /* ecma_property_to_string */ + /** * Converts a string into a property name * @@ -1437,38 +1579,13 @@ inline jmem_cpointer_t __attr_always_inline___ ecma_string_to_property_name (ecma_string_t *prop_name_p, /**< property name */ ecma_property_t *name_type_p) /**< [out] property name type */ { - ecma_string_container_t container = ECMA_STRING_GET_CONTAINER (prop_name_p); - - switch (container) + if (ECMA_IS_DIRECT_STRING (prop_name_p)) { - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: - case ECMA_STRING_CONTAINER_MAGIC_STRING: - case ECMA_STRING_CONTAINER_MAGIC_STRING_EX: - { -#ifdef JERRY_CPOINTER_32_BIT - - *name_type_p = (ecma_property_t) (container << ECMA_PROPERTY_NAME_TYPE_SHIFT); - return (jmem_cpointer_t) prop_name_p->u.common_uint32_field; - -#else /* !JERRY_CPOINTER_32_BIT */ - - if (prop_name_p->u.common_uint32_field < (UINT16_MAX + 1)) - { - *name_type_p = (ecma_property_t) (container << ECMA_PROPERTY_NAME_TYPE_SHIFT); - return (jmem_cpointer_t) prop_name_p->u.common_uint32_field; - } - -#endif /* JERRY_CPOINTER_32_BIT */ - - break; - } - default: - { - break; - } + *name_type_p = (ecma_property_t) ECMA_DIRECT_STRING_TYPE_TO_PROP_NAME_TYPE (prop_name_p); + return (jmem_cpointer_t) ECMA_GET_DIRECT_STRING_VALUE (prop_name_p); } - *name_type_p = ECMA_PROPERTY_NAME_TYPE_STRING << ECMA_PROPERTY_NAME_TYPE_SHIFT; + *name_type_p = ECMA_DIRECT_STRING_PTR << ECMA_PROPERTY_NAME_TYPE_SHIFT; ecma_ref_ecma_string (prop_name_p); @@ -1481,37 +1598,20 @@ ecma_string_to_property_name (ecma_string_t *prop_name_p, /**< property name */ * Converts a property name into a string * * @return the string pointer + * string must be released with ecma_deref_ecma_string */ ecma_string_t * ecma_string_from_property_name (ecma_property_t property, /**< property name type */ jmem_cpointer_t prop_name_cp) /**< property name compressed pointer */ { - /* If string_buf_p is NULL this function returns with a new string - * instance which needs to be released with ecma_deref_ecma_string. */ - - switch (ECMA_PROPERTY_GET_NAME_TYPE (property)) + if (ECMA_PROPERTY_GET_NAME_TYPE (property) != ECMA_DIRECT_STRING_PTR) { - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: - { - return ecma_new_ecma_string_from_uint32 ((uint32_t) prop_name_cp); - } - case ECMA_STRING_CONTAINER_MAGIC_STRING: - { - return ecma_new_ecma_string_from_magic_string_id ((lit_magic_string_id_t) prop_name_cp); - } - case ECMA_STRING_CONTAINER_MAGIC_STRING_EX: - { - return ecma_new_ecma_string_from_magic_string_ex_id ((lit_magic_string_ex_id_t) prop_name_cp); - } - default: - { - JERRY_ASSERT (ECMA_PROPERTY_GET_NAME_TYPE (property) == ECMA_PROPERTY_NAME_TYPE_STRING); - - ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_name_cp); - ecma_ref_ecma_string (prop_name_p); - return prop_name_p; - } + return ecma_property_to_string (property, prop_name_cp); } + + ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_name_cp); + ecma_ref_ecma_string (prop_name_p); + return prop_name_p; } /* ecma_string_from_property_name */ /** @@ -1525,14 +1625,14 @@ ecma_string_get_property_name_hash (ecma_property_t property, /**< property name { switch (ECMA_PROPERTY_GET_NAME_TYPE (property)) { - case ECMA_STRING_CONTAINER_MAGIC_STRING_EX: + case ECMA_DIRECT_STRING_PTR: { - return (lit_string_hash_t) (LIT_MAGIC_STRING__COUNT + prop_name_cp); + ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_name_cp); + return prop_name_p->hash; } - case ECMA_PROPERTY_NAME_TYPE_STRING: + case ECMA_DIRECT_STRING_MAGIC_EX: { - ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_name_cp); - return ecma_string_hash (prop_name_p); + return (lit_string_hash_t) (LIT_MAGIC_STRING__COUNT + prop_name_cp); } default: { @@ -1553,17 +1653,15 @@ ecma_string_get_property_index (ecma_property_t property, /**< property name typ { switch (ECMA_PROPERTY_GET_NAME_TYPE (property)) { - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: + case ECMA_DIRECT_STRING_UINT: { return (uint32_t) prop_name_cp; } -#ifndef JERRY_CPOINTER_32_BIT - case ECMA_PROPERTY_NAME_TYPE_STRING: + case ECMA_DIRECT_STRING_PTR: { ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_name_cp); return ecma_string_get_array_index (prop_name_p); } -#endif /* !JERRY_CPOINTER_32_BIT */ default: { return ECMA_STRING_NOT_ARRAY_INDEX; @@ -1582,25 +1680,18 @@ ecma_string_compare_to_property_name (ecma_property_t property, /**< property na jmem_cpointer_t prop_name_cp, /**< property name compressed pointer */ const ecma_string_t *string_p) /**< other string */ { - uint32_t property_name_type = ECMA_PROPERTY_GET_NAME_TYPE (property); - - switch (property_name_type) + if (ECMA_PROPERTY_GET_NAME_TYPE (property) != ECMA_DIRECT_STRING_PTR) { - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: - case ECMA_STRING_CONTAINER_MAGIC_STRING: - case ECMA_STRING_CONTAINER_MAGIC_STRING_EX: - { - return (ECMA_STRING_GET_CONTAINER (string_p) == property_name_type - && string_p->u.common_uint32_field == (uint32_t) prop_name_cp); - } - default: - { - JERRY_ASSERT (property_name_type == ECMA_PROPERTY_NAME_TYPE_STRING); + return ecma_property_to_string (property, prop_name_cp) == string_p; + } - ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_name_cp); - return ecma_compare_ecma_strings (prop_name_p, string_p); - } + if (ECMA_IS_DIRECT_STRING (string_p)) + { + return false; } + + ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, prop_name_cp); + return ecma_compare_ecma_non_direct_strings (prop_name_p, string_p); } /* ecma_string_compare_to_property_name */ /** @@ -1613,8 +1704,8 @@ ecma_string_compare_to_property_name (ecma_property_t property, /**< property na * false - otherwise */ static bool __attr_noinline___ -ecma_compare_ecma_strings_longpath (const ecma_string_t *string1_p, /* ecma-string */ - const ecma_string_t *string2_p) /* ecma-string */ +ecma_compare_ecma_strings_longpath (const ecma_string_t *string1_p, /**< ecma-string */ + const ecma_string_t *string2_p) /**< ecma-string */ { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_GET_CONTAINER (string2_p)); @@ -1647,14 +1738,14 @@ ecma_compare_ecma_strings_longpath (const ecma_string_t *string1_p, /* ecma-stri } /* ecma_compare_ecma_strings_longpath */ /** - * Compare ecma-string to ecma-string + * Compare two ecma-strings * * @return true - if strings are equal; * false - otherwise */ inline bool __attr_always_inline___ -ecma_compare_ecma_strings (const ecma_string_t *string1_p, /* ecma-string */ - const ecma_string_t *string2_p) /* ecma-string */ +ecma_compare_ecma_strings (const ecma_string_t *string1_p, /**< ecma-string */ + const ecma_string_t *string2_p) /**< ecma-string */ { JERRY_ASSERT (string1_p != NULL && string2_p != NULL); @@ -1664,6 +1755,12 @@ ecma_compare_ecma_strings (const ecma_string_t *string1_p, /* ecma-string */ return true; } + /* Either string is direct, return with false. */ + if (ECMA_IS_DIRECT_STRING (((uintptr_t) string1_p) | ((uintptr_t) string2_p))) + { + return false; + } + if (string1_p->hash != string2_p->hash) { return false; @@ -1676,7 +1773,7 @@ ecma_compare_ecma_strings (const ecma_string_t *string1_p, /* ecma-string */ return false; } - if (string1_container < ECMA_STRING_CONTAINER_HEAP_UTF8_STRING) + if (string1_container >= ECMA_STRING_CONTAINER_UINT32_IN_DESC) { return string1_p->u.common_uint32_field == string2_p->u.common_uint32_field; } @@ -1684,6 +1781,45 @@ ecma_compare_ecma_strings (const ecma_string_t *string1_p, /* ecma-string */ return ecma_compare_ecma_strings_longpath (string1_p, string2_p); } /* ecma_compare_ecma_strings */ +/** + * Compare two non-direct ecma-strings + * + * @return true - if strings are equal; + * false - otherwise + */ +inline bool __attr_always_inline___ +ecma_compare_ecma_non_direct_strings (const ecma_string_t *string1_p, /**< ecma-string */ + const ecma_string_t *string2_p) /**< ecma-string */ +{ + JERRY_ASSERT (string1_p != NULL && string2_p != NULL); + JERRY_ASSERT (!ECMA_IS_DIRECT_STRING (string1_p) && !ECMA_IS_DIRECT_STRING (string2_p)); + + /* Fast paths first. */ + if (string1_p == string2_p) + { + return true; + } + + if (string1_p->hash != string2_p->hash) + { + return false; + } + + ecma_string_container_t string1_container = ECMA_STRING_GET_CONTAINER (string1_p); + + if (string1_container != ECMA_STRING_GET_CONTAINER (string2_p)) + { + return false; + } + + if (string1_container >= ECMA_STRING_CONTAINER_UINT32_IN_DESC) + { + return string1_p->u.common_uint32_field == string2_p->u.common_uint32_field; + } + + return ecma_compare_ecma_strings_longpath (string1_p, string2_p); +} /* ecma_compare_ecma_non_direct_strings */ + /** * Relational compare of ecma-strings. * @@ -1710,79 +1846,65 @@ ecma_compare_ecma_strings_relational (const ecma_string_t *string1_p, /**< ecma- lit_utf8_byte_t uint32_to_string_buffer1[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32]; lit_utf8_byte_t uint32_to_string_buffer2[ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32]; - switch (ECMA_STRING_GET_CONTAINER (string1_p)) + if (ECMA_IS_DIRECT_STRING (string1_p)) { - case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: + if (ECMA_GET_DIRECT_STRING_TYPE (string1_p) != ECMA_DIRECT_STRING_UINT) { - utf8_string1_p = (lit_utf8_byte_t *) (string1_p + 1); - utf8_string1_size = string1_p->u.utf8_string.size; - break; + utf8_string1_p = ecma_string_get_chars_fast (string1_p, &utf8_string1_size); } - case ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING: - { - utf8_string1_p = (lit_utf8_byte_t *) (((ecma_long_string_t *) string1_p) + 1); - utf8_string1_size = string1_p->u.long_utf8_string_size; - break; - } - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: + else { - utf8_string1_size = ecma_uint32_to_utf8_string (string1_p->u.uint32_number, + utf8_string1_size = ecma_uint32_to_utf8_string ((uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string1_p), uint32_to_string_buffer1, ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32); utf8_string1_p = uint32_to_string_buffer1; - break; } - case ECMA_STRING_CONTAINER_MAGIC_STRING: + } + else + { + JERRY_ASSERT (string1_p->refs_and_container >= ECMA_STRING_REF_ONE); + + if (ECMA_STRING_GET_CONTAINER (string1_p) != ECMA_STRING_CONTAINER_UINT32_IN_DESC) { - utf8_string1_p = lit_get_magic_string_utf8 (string1_p->u.magic_string_id); - utf8_string1_size = lit_get_magic_string_size (string1_p->u.magic_string_id); - break; + utf8_string1_p = ecma_string_get_chars_fast (string1_p, &utf8_string1_size); } - default: + else { - JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string1_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); - - utf8_string1_p = lit_get_magic_string_ex_utf8 (string1_p->u.magic_string_id); - utf8_string1_size = lit_get_magic_string_ex_size (string1_p->u.magic_string_id); - break; + utf8_string1_size = ecma_uint32_to_utf8_string (string1_p->u.uint32_number, + uint32_to_string_buffer1, + ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32); + utf8_string1_p = uint32_to_string_buffer1; } } - switch (ECMA_STRING_GET_CONTAINER (string2_p)) + if (ECMA_IS_DIRECT_STRING (string2_p)) { - case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: - { - utf8_string2_p = (lit_utf8_byte_t *) (string2_p + 1); - utf8_string2_size = string2_p->u.utf8_string.size; - break; - } - case ECMA_STRING_CONTAINER_HEAP_LONG_UTF8_STRING: + if (ECMA_GET_DIRECT_STRING_TYPE (string2_p) != ECMA_DIRECT_STRING_UINT) { - utf8_string2_p = (lit_utf8_byte_t *) (((ecma_long_string_t *) string2_p) + 1); - utf8_string2_size = string2_p->u.long_utf8_string_size; - break; + utf8_string2_p = ecma_string_get_chars_fast (string2_p, &utf8_string2_size); } - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: + else { - utf8_string2_size = ecma_uint32_to_utf8_string (string2_p->u.uint32_number, + utf8_string2_size = ecma_uint32_to_utf8_string ((uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string2_p), uint32_to_string_buffer2, ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32); utf8_string2_p = uint32_to_string_buffer2; - break; } - case ECMA_STRING_CONTAINER_MAGIC_STRING: + } + else + { + JERRY_ASSERT (string2_p->refs_and_container >= ECMA_STRING_REF_ONE); + + if (ECMA_STRING_GET_CONTAINER (string2_p) != ECMA_STRING_CONTAINER_UINT32_IN_DESC) { - utf8_string2_p = lit_get_magic_string_utf8 (string2_p->u.magic_string_id); - utf8_string2_size = lit_get_magic_string_size (string2_p->u.magic_string_id); - break; + utf8_string2_p = ecma_string_get_chars_fast (string2_p, &utf8_string2_size); } - default: + else { - JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string2_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); - - utf8_string2_p = lit_get_magic_string_ex_utf8 (string2_p->u.magic_string_id); - utf8_string2_size = lit_get_magic_string_ex_size (string2_p->u.magic_string_id); - break; + utf8_string2_size = ecma_uint32_to_utf8_string (string2_p->u.uint32_number, + uint32_to_string_buffer2, + ECMA_MAX_CHARS_IN_STRINGIFIED_UINT32); + utf8_string2_p = uint32_to_string_buffer2; } } @@ -1792,6 +1914,56 @@ ecma_compare_ecma_strings_relational (const ecma_string_t *string1_p, /**< ecma- utf8_string2_size); } /* ecma_compare_ecma_strings_relational */ +/* + * Special value to represent that no size is available. + */ +#define ECMA_STRING_NO_ASCII_SIZE 0xffff + +/** + * Return the size of uint32 and magic strings. + * The length of these strings are equal to thier size. + * + * @return number of characters in the string + */ +static ecma_length_t +ecma_string_get_ascii_size (const ecma_string_t *string_p) /**< ecma-string */ +{ + if (ECMA_IS_DIRECT_STRING (string_p)) + { + switch (ECMA_GET_DIRECT_STRING_TYPE (string_p)) + { + case ECMA_DIRECT_STRING_MAGIC: + { + lit_magic_string_id_t id = (lit_magic_string_id_t) ECMA_GET_DIRECT_STRING_VALUE (string_p); + + JERRY_ASSERT (ECMA_STRING_IS_ASCII (lit_get_magic_string_utf8 (id), + lit_get_magic_string_size (id))); + return lit_get_magic_string_size (id); + } + case ECMA_DIRECT_STRING_UINT: + { + uint32_t uint32_number = (uint32_t) ECMA_GET_DIRECT_STRING_VALUE (string_p); + return ecma_string_get_uint32_size (uint32_number); + } + default: + { + JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_MAGIC_EX); + + return ECMA_STRING_NO_ASCII_SIZE; + } + } + } + + JERRY_ASSERT (string_p->refs_and_container >= ECMA_STRING_REF_ONE); + + if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC) + { + return ecma_string_get_uint32_size (string_p->u.uint32_number); + } + + return ECMA_STRING_NO_ASCII_SIZE; +} /* ecma_string_get_ascii_size */ + /** * Get length of ecma-string * @@ -1800,6 +1972,22 @@ ecma_compare_ecma_strings_relational (const ecma_string_t *string1_p, /**< ecma- ecma_length_t ecma_string_get_length (const ecma_string_t *string_p) /**< ecma-string */ { + ecma_length_t length = ecma_string_get_ascii_size (string_p); + + if (length != ECMA_STRING_NO_ASCII_SIZE) + { + return length; + } + + if (ECMA_IS_DIRECT_STRING (string_p)) + { + JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_MAGIC_EX); + + lit_magic_string_ex_id_t id = (lit_magic_string_ex_id_t) ECMA_GET_DIRECT_STRING_VALUE (string_p); + return lit_utf8_string_length (lit_get_magic_string_ex_utf8 (id), + lit_get_magic_string_ex_size (id)); + } + switch (ECMA_STRING_GET_CONTAINER (string_p)) { case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: @@ -1810,16 +1998,6 @@ ecma_string_get_length (const ecma_string_t *string_p) /**< ecma-string */ { return (ecma_length_t) (((ecma_long_string_t *) string_p)->long_utf8_string_length); } - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: - { - return ecma_string_get_number_in_desc_size (string_p->u.uint32_number); - } - case ECMA_STRING_CONTAINER_MAGIC_STRING: - { - JERRY_ASSERT (ECMA_STRING_IS_ASCII (lit_get_magic_string_utf8 (string_p->u.magic_string_id), - lit_get_magic_string_size (string_p->u.magic_string_id))); - return lit_get_magic_string_size (string_p->u.magic_string_id); - } default: { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); @@ -1838,6 +2016,22 @@ ecma_string_get_length (const ecma_string_t *string_p) /**< ecma-string */ ecma_length_t ecma_string_get_utf8_length (const ecma_string_t *string_p) /**< ecma-string */ { + ecma_length_t length = ecma_string_get_ascii_size (string_p); + + if (length != ECMA_STRING_NO_ASCII_SIZE) + { + return length; + } + + if (ECMA_IS_DIRECT_STRING (string_p)) + { + JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_MAGIC_EX); + + lit_magic_string_ex_id_t id = (lit_magic_string_ex_id_t) ECMA_GET_DIRECT_STRING_VALUE (string_p); + return lit_get_utf8_length_of_cesu8_string (lit_get_magic_string_ex_utf8 (id), + lit_get_magic_string_ex_size (id)); + } + switch (ECMA_STRING_GET_CONTAINER (string_p)) { case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: @@ -1861,16 +2055,6 @@ ecma_string_get_utf8_length (const ecma_string_t *string_p) /**< ecma-string */ return lit_get_utf8_length_of_cesu8_string ((const lit_utf8_byte_t *) (string_p + 1), (lit_utf8_size_t) string_p->u.long_utf8_string_size); } - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: - { - return ecma_string_get_number_in_desc_size (string_p->u.uint32_number); - } - case ECMA_STRING_CONTAINER_MAGIC_STRING: - { - JERRY_ASSERT (ECMA_STRING_IS_ASCII (lit_get_magic_string_utf8 (string_p->u.magic_string_id), - lit_get_magic_string_size (string_p->u.magic_string_id))); - return lit_get_magic_string_size (string_p->u.magic_string_id); - } default: { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); @@ -1889,6 +2073,21 @@ ecma_string_get_utf8_length (const ecma_string_t *string_p) /**< ecma-string */ lit_utf8_size_t ecma_string_get_size (const ecma_string_t *string_p) /**< ecma-string */ { + ecma_length_t length = ecma_string_get_ascii_size (string_p); + + if (length != ECMA_STRING_NO_ASCII_SIZE) + { + return length; + } + + if (ECMA_IS_DIRECT_STRING (string_p)) + { + JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_MAGIC_EX); + + lit_magic_string_ex_id_t id = (lit_magic_string_ex_id_t) ECMA_GET_DIRECT_STRING_VALUE (string_p); + return lit_get_magic_string_ex_size (id); + } + switch (ECMA_STRING_GET_CONTAINER (string_p)) { case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: @@ -1899,14 +2098,6 @@ ecma_string_get_size (const ecma_string_t *string_p) /**< ecma-string */ { return (lit_utf8_size_t) string_p->u.long_utf8_string_size; } - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: - { - return (lit_utf8_size_t) ecma_string_get_number_in_desc_size (string_p->u.uint32_number); - } - case ECMA_STRING_CONTAINER_MAGIC_STRING: - { - return lit_get_magic_string_size (string_p->u.magic_string_id); - } default: { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); @@ -1923,6 +2114,22 @@ ecma_string_get_size (const ecma_string_t *string_p) /**< ecma-string */ lit_utf8_size_t ecma_string_get_utf8_size (const ecma_string_t *string_p) /**< ecma-string */ { + ecma_length_t length = ecma_string_get_ascii_size (string_p); + + if (length != ECMA_STRING_NO_ASCII_SIZE) + { + return length; + } + + if (ECMA_IS_DIRECT_STRING (string_p)) + { + JERRY_ASSERT (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_MAGIC_EX); + + lit_magic_string_ex_id_t id = (lit_magic_string_ex_id_t) ECMA_GET_DIRECT_STRING_VALUE (string_p); + return lit_get_utf8_size_of_cesu8_string (lit_get_magic_string_ex_utf8 (id), + lit_get_magic_string_ex_size (id)); + } + switch (ECMA_STRING_GET_CONTAINER (string_p)) { case ECMA_STRING_CONTAINER_HEAP_UTF8_STRING: @@ -1946,14 +2153,6 @@ ecma_string_get_utf8_size (const ecma_string_t *string_p) /**< ecma-string */ return lit_get_utf8_size_of_cesu8_string ((const lit_utf8_byte_t *) (string_p + 1), (lit_utf8_size_t) string_p->u.long_utf8_string_size); } - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: - { - return (lit_utf8_size_t) ecma_string_get_number_in_desc_size (string_p->u.uint32_number); - } - case ECMA_STRING_CONTAINER_MAGIC_STRING: - { - return lit_get_magic_string_size (string_p->u.magic_string_id); - } default: { JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING_EX); @@ -1976,58 +2175,27 @@ ecma_string_get_char_at_pos (const ecma_string_t *string_p, /**< ecma-string */ JERRY_ASSERT (index < ecma_string_get_length (string_p)); lit_utf8_size_t buffer_size; - bool is_ascii; - const lit_utf8_byte_t *chars_p = ecma_string_raw_chars (string_p, &buffer_size, &is_ascii); + uint8_t flags = ECMA_STRING_FLAG_IS_ASCII; + const lit_utf8_byte_t *chars_p = ecma_string_get_chars (string_p, &buffer_size, &flags); - if (chars_p != NULL) + ecma_char_t ch; + if (flags & ECMA_STRING_FLAG_IS_ASCII) { - if (is_ascii) - { - return chars_p[index]; - } - - return lit_utf8_string_code_unit_at (chars_p, buffer_size, index); + ch = chars_p[index]; + } + else + { + ch = lit_utf8_string_code_unit_at (chars_p, buffer_size, index); } - ecma_char_t ch; - - JMEM_DEFINE_LOCAL_ARRAY (utf8_str_p, buffer_size, lit_utf8_byte_t); - - ecma_string_to_utf8_bytes (string_p, utf8_str_p, buffer_size); - - JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC); - /* Both above must be ascii strings. */ - JERRY_ASSERT (is_ascii); - - ch = utf8_str_p[index]; - - JMEM_FINALIZE_LOCAL_ARRAY (utf8_str_p); + if (flags & ECMA_STRING_FLAG_MUST_BE_FREED) + { + jmem_heap_free_block ((void *) chars_p, buffer_size); + } return ch; } /* ecma_string_get_char_at_pos */ -/** - * Get specified magic string - * - * @return ecma-string containing specified magic string - */ -ecma_string_t * -ecma_get_magic_string (lit_magic_string_id_t id) /**< magic string id */ -{ - return ecma_new_ecma_string_from_magic_string_id (id); -} /* ecma_get_magic_string */ - -/** - * Get specified external magic string - * - * @return ecma-string containing specified external magic string - */ -ecma_string_t * -ecma_get_magic_string_ex (lit_magic_string_ex_id_t id) /**< external magic string id */ -{ - return ecma_new_ecma_string_from_magic_string_ex_id (id); -} /* ecma_get_magic_string_ex */ - /** * Check if passed string equals to one of magic strings * and if equal magic string was found, return it's id in 'out_id_p' argument. @@ -2038,9 +2206,9 @@ ecma_get_magic_string_ex (lit_magic_string_ex_id_t id) /**< external magic strin lit_magic_string_id_t ecma_get_string_magic (const ecma_string_t *string_p) /**< ecma-string */ { - if (ECMA_STRING_GET_CONTAINER (string_p) == ECMA_STRING_CONTAINER_MAGIC_STRING) + if (ECMA_IS_DIRECT_STRING_WITH_TYPE (string_p, ECMA_DIRECT_STRING_MAGIC)) { - return (lit_magic_string_id_t) string_p->u.magic_string_id; + return (lit_magic_string_id_t) ECMA_GET_DIRECT_STRING_VALUE (string_p); } return LIT_MAGIC_STRING__COUNT; @@ -2054,7 +2222,19 @@ ecma_get_string_magic (const ecma_string_t *string_p) /**< ecma-string */ inline lit_string_hash_t __attr_always_inline___ ecma_string_hash (const ecma_string_t *string_p) /**< ecma-string to calculate hash for */ { - return (string_p->hash); + if (!ECMA_IS_DIRECT_STRING (string_p)) + { + return (string_p->hash); + } + + lit_string_hash_t hash = (lit_string_hash_t) ECMA_GET_DIRECT_STRING_VALUE (string_p); + + if (ECMA_GET_DIRECT_STRING_TYPE (string_p) == ECMA_DIRECT_STRING_MAGIC_EX) + { + hash = (lit_string_hash_t) (hash + LIT_MAGIC_STRING__COUNT); + } + + return hash; } /* ecma_string_hash */ /** diff --git a/deps/jerry/jerry-core/ecma/base/ecma-helpers-value.c b/deps/jerry/jerry-core/ecma/base/ecma-helpers-value.c index eff51c7..ae596e0 100644 --- a/deps/jerry/jerry-core/ecma/base/ecma-helpers-value.c +++ b/deps/jerry/jerry-core/ecma/base/ecma-helpers-value.c @@ -21,6 +21,8 @@ #include "jrt-bit-fields.h" #include "vm-defines.h" +#include "ecma-function-object.h" + /** \addtogroup ecma ECMA * @{ * @@ -77,6 +79,7 @@ ecma_pointer_to_ecma_value (const void *ptr) /**< pointer */ { #ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY + JERRY_ASSERT (ptr != NULL); uintptr_t uint_ptr = (uintptr_t) ptr; JERRY_ASSERT ((uint_ptr & ECMA_VALUE_TYPE_MASK) == 0); return (ecma_value_t) uint_ptr; @@ -99,10 +102,11 @@ static inline void * __attr_pure___ __attr_always_inline___ ecma_get_pointer_from_ecma_value (ecma_value_t value) /**< value */ { #ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY - return (void *) (uintptr_t) ((value) & ~ECMA_VALUE_TYPE_MASK); + void *ptr = (void *) (uintptr_t) ((value) & ~ECMA_VALUE_TYPE_MASK); + JERRY_ASSERT (ptr != NULL); + return ptr; #else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ - return ECMA_GET_NON_NULL_POINTER (ecma_number_t, - value >> ECMA_VALUE_SHIFT); + return ECMA_GET_NON_NULL_POINTER (void, value >> ECMA_VALUE_SHIFT); #endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ } /* ecma_get_pointer_from_ecma_value */ @@ -292,6 +296,9 @@ ecma_is_value_number (ecma_value_t value) /**< ecma value */ || ecma_is_value_float_number (value)); } /* ecma_is_value_number */ +JERRY_STATIC_ASSERT ((ECMA_TYPE_STRING | 0x4) == ECMA_TYPE_DIRECT_STRING, + ecma_type_string_and_direct_string_must_have_one_bit_difference); + /** * Check if the value is ecma-string. * @@ -301,9 +308,21 @@ ecma_is_value_number (ecma_value_t value) /**< ecma value */ inline bool __attr_const___ __attr_always_inline___ ecma_is_value_string (ecma_value_t value) /**< ecma value */ { - return (ecma_get_value_type_field (value) == ECMA_TYPE_STRING); + return ((value & (ECMA_VALUE_TYPE_MASK - 0x4)) == ECMA_TYPE_STRING); } /* ecma_is_value_string */ +/** + * Check if the value is direct_ecma-string. + * + * @return true - if the value contains ecma-string value, + * false - otherwise + */ +inline bool __attr_const___ __attr_always_inline___ +ecma_is_value_direct_string (ecma_value_t value) /**< ecma value */ +{ + return (ecma_get_value_type_field (value) == ECMA_TYPE_DIRECT_STRING); +} /* ecma_is_value_direct_string */ + /** * Check if the value is object. * @@ -319,7 +338,7 @@ ecma_is_value_object (ecma_value_t value) /**< ecma value */ /** * Check if the value is error reference. * - * @return true - if the value contains object value, + * @return true - if the value contains an error reference, * false - otherwise */ inline bool __attr_const___ __attr_always_inline___ @@ -328,6 +347,18 @@ ecma_is_value_error_reference (ecma_value_t value) /**< ecma value */ return (ecma_get_value_type_field (value) == ECMA_TYPE_ERROR); } /* ecma_is_value_error_reference */ +/** + * Check if the value is collection chunk. + * + * @return true - if the value contains a collection chunk, + * false - otherwise + */ +inline bool __attr_const___ __attr_always_inline___ +ecma_is_value_collection_chunk (ecma_value_t value) /**< ecma value */ +{ + return (ecma_get_value_type_field (value) == ECMA_TYPE_COLLECTION_CHUNK); +} /* ecma_is_value_collection_chunk */ + /** * Debug assertion that specified value's type is one of ECMA-defined * script-visible types, i.e.: undefined, null, boolean, number, string, object. @@ -487,9 +518,23 @@ ecma_make_string_value (const ecma_string_t *ecma_string_p) /**< string to refer { JERRY_ASSERT (ecma_string_p != NULL); + if ((((uintptr_t) ecma_string_p) & ECMA_VALUE_TYPE_MASK) != 0) + { + return (ecma_value_t) (uintptr_t) ecma_string_p; + } + return ecma_pointer_to_ecma_value (ecma_string_p) | ECMA_TYPE_STRING; } /* ecma_make_string_value */ +/** + * String value constructor + */ +inline ecma_value_t __attr_pure___ __attr_always_inline___ +ecma_make_magic_string_value (lit_magic_string_id_t id) /**< magic string id */ +{ + return (ecma_value_t) ECMA_CREATE_DIRECT_STRING (ECMA_DIRECT_STRING_MAGIC, (uintptr_t) id); +} /* ecma_make_magic_string_value */ + /** * Object value constructor */ @@ -512,6 +557,27 @@ ecma_make_error_reference_value (const ecma_error_reference_t *error_ref_p) /**< return ecma_pointer_to_ecma_value (error_ref_p) | ECMA_TYPE_ERROR; } /* ecma_make_error_reference_value */ +/** + * Collection chunk constructor + */ +inline ecma_value_t __attr_pure___ __attr_always_inline___ +ecma_make_collection_chunk_value (const ecma_collection_chunk_t *collection_chunk_p) /**< collection chunk */ +{ +#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY + + uintptr_t uint_ptr = (uintptr_t) collection_chunk_p; + JERRY_ASSERT ((uint_ptr & ECMA_VALUE_TYPE_MASK) == 0); + return ((ecma_value_t) uint_ptr) | ECMA_TYPE_COLLECTION_CHUNK; + +#else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ + + jmem_cpointer_t ptr_cp; + ECMA_SET_POINTER (ptr_cp, collection_chunk_p); + return (((ecma_value_t) ptr_cp) << ECMA_VALUE_SHIFT) | ECMA_TYPE_COLLECTION_CHUNK; + +#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ +} /* ecma_make_collection_chunk_value */ + /** * Get integer value from an integer ecma value * @@ -557,7 +623,12 @@ ecma_get_number_from_value (ecma_value_t value) /**< ecma value */ inline ecma_string_t *__attr_pure___ __attr_always_inline___ ecma_get_string_from_value (ecma_value_t value) /**< ecma value */ { - JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_STRING); + JERRY_ASSERT (ecma_is_value_string (value)); + + if ((value & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_DIRECT_STRING) + { + return (ecma_string_t *) (uintptr_t) value; + } return (ecma_string_t *) ecma_get_pointer_from_ecma_value (value); } /* ecma_get_string_from_value */ @@ -570,7 +641,7 @@ ecma_get_string_from_value (ecma_value_t value) /**< ecma value */ inline ecma_object_t *__attr_pure___ __attr_always_inline___ ecma_get_object_from_value (ecma_value_t value) /**< ecma value */ { - JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_OBJECT); + JERRY_ASSERT (ecma_is_value_object (value)); return (ecma_object_t *) ecma_get_pointer_from_ecma_value (value); } /* ecma_get_object_from_value */ @@ -588,6 +659,23 @@ ecma_get_error_reference_from_value (ecma_value_t value) /**< ecma value */ return (ecma_error_reference_t *) ecma_get_pointer_from_ecma_value (value); } /* ecma_get_error_reference_from_value */ +/** + * Get pointer to collection chunk from ecma value + * + * @return the pointer + */ +inline ecma_collection_chunk_t *__attr_pure___ __attr_always_inline___ +ecma_get_collection_chunk_from_value (ecma_value_t value) /**< ecma value */ +{ + JERRY_ASSERT (ecma_get_value_type_field (value) == ECMA_TYPE_COLLECTION_CHUNK); + +#ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY + return (ecma_collection_chunk_t *) (uintptr_t) ((value) & ~ECMA_VALUE_TYPE_MASK); +#else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ + return ECMA_GET_POINTER (ecma_collection_chunk_t, value >> ECMA_VALUE_SHIFT); +#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ +} /* ecma_get_collection_chunk_from_value */ + /** * Invert a boolean value * @@ -612,6 +700,7 @@ ecma_copy_value (ecma_value_t value) /**< value description */ switch (ecma_get_value_type_field (value)) { case ECMA_TYPE_DIRECT: + case ECMA_TYPE_DIRECT_STRING: { return value; } @@ -802,6 +891,7 @@ ecma_free_value (ecma_value_t value) /**< value description */ switch (ecma_get_value_type_field (value)) { case ECMA_TYPE_DIRECT: + case ECMA_TYPE_DIRECT_STRING: { /* no memory is allocated */ break; @@ -865,6 +955,55 @@ ecma_free_value_if_not_object (ecma_value_t value) /**< value description */ } } /* ecma_free_value_if_not_object */ +/** + * Get the literal id associated with the given ecma_value type. + * This operation is equivalent to the JavaScript 'typeof' operator. + * + * @returns one of the following value: + * - LIT_MAGIC_STRING_UNDEFINED + * - LIT_MAGIC_STRING_OBJECT + * - LIT_MAGIC_STRING_BOOLEAN + * - LIT_MAGIC_STRING_NUMBER + * - LIT_MAGIC_STRING_STRING + * - LIT_MAGIC_STRING_FUNCTION + */ +lit_magic_string_id_t +ecma_get_typeof_lit_id (ecma_value_t value) /**< input ecma value */ +{ + lit_magic_string_id_t ret_value = LIT_MAGIC_STRING__EMPTY; + + if (ecma_is_value_undefined (value)) + { + ret_value = LIT_MAGIC_STRING_UNDEFINED; + } + else if (ecma_is_value_null (value)) + { + ret_value = LIT_MAGIC_STRING_OBJECT; + } + else if (ecma_is_value_boolean (value)) + { + ret_value = LIT_MAGIC_STRING_BOOLEAN; + } + else if (ecma_is_value_number (value)) + { + ret_value = LIT_MAGIC_STRING_NUMBER; + } + else if (ecma_is_value_string (value)) + { + ret_value = LIT_MAGIC_STRING_STRING; + } + else + { + JERRY_ASSERT (ecma_is_value_object (value)); + + ret_value = ecma_op_is_callable (value) ? LIT_MAGIC_STRING_FUNCTION : LIT_MAGIC_STRING_OBJECT; + } + + JERRY_ASSERT (ret_value != LIT_MAGIC_STRING__EMPTY); + + return ret_value; +} /* ecma_get_typeof_lit_id */ + /** * @} * @} diff --git a/deps/jerry/jerry-core/ecma/base/ecma-helpers-values-collection.c b/deps/jerry/jerry-core/ecma/base/ecma-helpers-values-collection.c index f02ee84..c473991 100644 --- a/deps/jerry/jerry-core/ecma/base/ecma-helpers-values-collection.c +++ b/deps/jerry/jerry-core/ecma/base/ecma-helpers-values-collection.c @@ -25,60 +25,26 @@ * @{ */ +/** + * The type of ecma error and ecma collection chunk must be the same. + */ +JERRY_STATIC_ASSERT (ECMA_TYPE_ERROR == ECMA_TYPE_COLLECTION_CHUNK, + ecma_type_error_must_be_the_same_as_ecma_type_collection_chunk); + /** * Allocate a collection of ecma values. * * @return pointer to the collection's header */ ecma_collection_header_t * -ecma_new_values_collection (const ecma_value_t values_buffer[], /**< ecma values */ - ecma_length_t values_number, /**< number of ecma values */ - bool do_ref_if_object) /**< if the value is object value, - increase reference counter of the object */ +ecma_new_values_collection (void) { - JERRY_ASSERT (values_buffer != NULL || values_number == 0); - - const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t); - - ecma_collection_header_t *header_p = ecma_alloc_collection_header (); - - header_p->unit_number = values_number; - - jmem_cpointer_t *next_chunk_cp_p = &header_p->first_chunk_cp; - ecma_collection_chunk_t *last_chunk_p = NULL; - ecma_value_t *cur_value_buf_iter_p = NULL; - ecma_value_t *cur_value_buf_end_p = NULL; - - for (ecma_length_t value_index = 0; - value_index < values_number; - value_index++) - { - if (cur_value_buf_iter_p == cur_value_buf_end_p) - { - ecma_collection_chunk_t *chunk_p = ecma_alloc_collection_chunk (); - ECMA_SET_POINTER (*next_chunk_cp_p, chunk_p); - next_chunk_cp_p = &chunk_p->next_chunk_cp; - - cur_value_buf_iter_p = (ecma_value_t *) chunk_p->data; - cur_value_buf_end_p = cur_value_buf_iter_p + values_in_chunk; - - last_chunk_p = chunk_p; - } - - JERRY_ASSERT (cur_value_buf_iter_p + 1 <= cur_value_buf_end_p); + ecma_collection_header_t *header_p; + header_p = (ecma_collection_header_t *) jmem_pools_alloc (sizeof (ecma_collection_header_t)); - if (do_ref_if_object) - { - *cur_value_buf_iter_p++ = ecma_copy_value (values_buffer[value_index]); - } - else - { - *cur_value_buf_iter_p++ = ecma_copy_value_if_not_object (values_buffer[value_index]); - } - } - - *next_chunk_cp_p = ECMA_NULL_POINTER; - ECMA_SET_POINTER (header_p->last_chunk_cp, last_chunk_p); + header_p->item_count = 0; + header_p->first_chunk_cp = ECMA_NULL_POINTER; + header_p->last_chunk_cp = ECMA_NULL_POINTER; return header_p; } /* ecma_new_values_collection */ @@ -88,49 +54,44 @@ ecma_new_values_collection (const ecma_value_t values_buffer[], /**< ecma values */ void ecma_free_values_collection (ecma_collection_header_t *header_p, /**< collection's header */ - bool do_deref_if_object) /**< if the value is object value, - decrement reference counter of the object */ + uint32_t flags) /**< combination of ecma_collection_flag_t flags */ { - JERRY_ASSERT (header_p != NULL); - - const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t); - ecma_collection_chunk_t *chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t, header_p->first_chunk_cp); - ecma_length_t value_index = 0; - while (chunk_p != NULL) + jmem_heap_free_block (header_p, sizeof (ecma_collection_header_t)); + + if (chunk_p == NULL) { - JERRY_ASSERT (value_index < header_p->unit_number); + return; + } - ecma_value_t *cur_value_buf_iter_p = (ecma_value_t *) chunk_p->data; - ecma_value_t *cur_value_buf_end_p = cur_value_buf_iter_p + values_in_chunk; + do + { + ecma_value_t *item_p = chunk_p->items; - while (cur_value_buf_iter_p != cur_value_buf_end_p - && value_index < header_p->unit_number) - { - JERRY_ASSERT (cur_value_buf_iter_p < cur_value_buf_end_p); + JERRY_ASSERT (!ecma_is_value_collection_chunk (*item_p)); - if (do_deref_if_object) - { - ecma_free_value (*cur_value_buf_iter_p); - } - else + do + { + if (!(flags & ECMA_COLLECTION_NO_COPY) + && (!ecma_is_value_object (*item_p) + || !(flags & ECMA_COLLECTION_NO_REF_OBJECTS))) { - ecma_free_value_if_not_object (*cur_value_buf_iter_p); + ecma_free_value (*item_p); } - cur_value_buf_iter_p++; - value_index++; + item_p++; } + while (!ecma_is_value_collection_chunk (*item_p)); + + ecma_collection_chunk_t *next_chunk_p = ecma_get_collection_chunk_from_value (*item_p); + + jmem_heap_free_block (chunk_p, sizeof (ecma_collection_chunk_t)); - ecma_collection_chunk_t *next_chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t, - chunk_p->next_chunk_cp); - ecma_dealloc_collection_chunk (chunk_p); chunk_p = next_chunk_p; } - - ecma_dealloc_collection_header (header_p); + while (chunk_p != NULL); } /* ecma_free_values_collection */ /** @@ -138,234 +99,99 @@ ecma_free_values_collection (ecma_collection_header_t *header_p, /**< collection */ void ecma_append_to_values_collection (ecma_collection_header_t *header_p, /**< collection's header */ - ecma_value_t v, /**< ecma value to append */ - bool do_ref_if_object) /**< if the value is object value, - increase reference counter of the object */ + ecma_value_t value, /**< ecma value to append */ + uint32_t flags) /**< combination of ecma_collection_flag_t flags */ { - const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t); - - size_t values_number = header_p->unit_number; - size_t pos_of_new_value_in_chunk = values_number % values_in_chunk; - - values_number++; + ecma_length_t item_index; + ecma_collection_chunk_t *chunk_p; - if ((ecma_length_t) values_number == values_number) + if (unlikely (header_p->item_count == 0)) { - header_p->unit_number = (ecma_length_t) values_number; + item_index = 0; + chunk_p = (ecma_collection_chunk_t *) jmem_heap_alloc_block (sizeof (ecma_collection_chunk_t)); + + ECMA_SET_POINTER (header_p->first_chunk_cp, chunk_p); + header_p->last_chunk_cp = header_p->first_chunk_cp; } else { - jerry_fatal (ERR_OUT_OF_MEMORY); - } + item_index = header_p->item_count % ECMA_COLLECTION_CHUNK_ITEMS; - ecma_collection_chunk_t *chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t, - header_p->last_chunk_cp); + chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, + header_p->last_chunk_cp); - if (pos_of_new_value_in_chunk == 0) - { - /* all chunks are currently filled with values */ + if (unlikely (item_index == 0)) + { + JERRY_ASSERT (ecma_is_value_collection_chunk (chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS]) + && ecma_get_collection_chunk_from_value (chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS]) == NULL); - chunk_p = ecma_alloc_collection_chunk (); - chunk_p->next_chunk_cp = ECMA_NULL_POINTER; + ecma_collection_chunk_t *next_chunk_p; + next_chunk_p = (ecma_collection_chunk_t *) jmem_heap_alloc_block (sizeof (ecma_collection_chunk_t)); - if (header_p->last_chunk_cp == ECMA_NULL_POINTER) - { - JERRY_ASSERT (header_p->first_chunk_cp == ECMA_NULL_POINTER); + chunk_p->items[ECMA_COLLECTION_CHUNK_ITEMS] = ecma_make_collection_chunk_value (next_chunk_p); + ECMA_SET_POINTER (header_p->last_chunk_cp, next_chunk_p); - ECMA_SET_NON_NULL_POINTER (header_p->first_chunk_cp, chunk_p); + chunk_p = next_chunk_p; } else { - ecma_collection_chunk_t *last_chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, - header_p->last_chunk_cp); - - JERRY_ASSERT (last_chunk_p->next_chunk_cp == ECMA_NULL_POINTER); - - ECMA_SET_NON_NULL_POINTER (last_chunk_p->next_chunk_cp, chunk_p); + JERRY_ASSERT (ecma_is_value_collection_chunk (chunk_p->items[item_index]) + && ecma_get_collection_chunk_from_value (chunk_p->items[item_index]) == NULL); } - - ECMA_SET_NON_NULL_POINTER (header_p->last_chunk_cp, chunk_p); } - else - { - /* last chunk can be appended with the new value */ - JERRY_ASSERT (chunk_p != NULL); - } - - ecma_value_t *values_p = (ecma_value_t *) chunk_p->data; - - JERRY_ASSERT ((uint8_t *) (values_p + pos_of_new_value_in_chunk + 1) <= (uint8_t *) (chunk_p + 1)); - if (do_ref_if_object) + if (!(flags & ECMA_COLLECTION_NO_COPY) + && (!ecma_is_value_object (value) + || !(flags & ECMA_COLLECTION_NO_REF_OBJECTS))) { - values_p[pos_of_new_value_in_chunk] = ecma_copy_value (v); + value = ecma_copy_value (value); } - else - { - values_p[pos_of_new_value_in_chunk] = ecma_copy_value_if_not_object (v); - } -} /* ecma_append_to_values_collection */ -/** - * Remove last element of the collection - * - * Warning: - * the function invalidates all iterators that are configured to access the passed collection - */ -void -ecma_remove_last_value_from_values_collection (ecma_collection_header_t *header_p) /**< collection's header */ -{ - JERRY_ASSERT (header_p != NULL && header_p->unit_number > 0); - - const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t); - size_t values_number = header_p->unit_number; - size_t pos_of_value_to_remove_in_chunk = (values_number - 1u) % values_in_chunk; - - ecma_collection_chunk_t *last_chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, - header_p->last_chunk_cp); - - ecma_value_t *values_p = (ecma_value_t *) last_chunk_p->data; - JERRY_ASSERT ((uint8_t *) (values_p + pos_of_value_to_remove_in_chunk + 1) <= (uint8_t *) (last_chunk_p + 1)); - - ecma_value_t value_to_remove = values_p[pos_of_value_to_remove_in_chunk]; - - ecma_free_value (value_to_remove); - - header_p->unit_number--; - - if (pos_of_value_to_remove_in_chunk == 0) - { - ecma_collection_chunk_t *chunk_to_remove_p = last_chunk_p; - - /* free last chunk */ - if (header_p->first_chunk_cp == header_p->last_chunk_cp) - { - header_p->first_chunk_cp = ECMA_NULL_POINTER; - header_p->last_chunk_cp = ECMA_NULL_POINTER; - } - else - { - ecma_collection_chunk_t *chunk_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, - header_p->first_chunk_cp); - - while (chunk_iter_p->next_chunk_cp != header_p->last_chunk_cp) - { - chunk_iter_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, - chunk_iter_p->next_chunk_cp); - } - - ecma_collection_chunk_t *new_last_chunk_p = chunk_iter_p; - - JERRY_ASSERT (ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, - new_last_chunk_p->next_chunk_cp) == chunk_to_remove_p); - - ECMA_SET_NON_NULL_POINTER (header_p->last_chunk_cp, new_last_chunk_p); - new_last_chunk_p->next_chunk_cp = ECMA_NULL_POINTER; - } - - ecma_dealloc_collection_chunk (chunk_to_remove_p); - } -} /* ecma_remove_last_value_from_values_collection */ + chunk_p->items[item_index] = value; + chunk_p->items[item_index + 1] = ecma_make_collection_chunk_value (NULL); + header_p->item_count++; +} /* ecma_append_to_values_collection */ /** - * Allocate a collection of ecma-strings. + * Initialize new collection iterator for the collection * - * @return pointer to the collection's header + * @return pointer to the first item */ -ecma_collection_header_t * -ecma_new_strings_collection (ecma_string_t *string_ptrs_buffer[], /**< pointers to ecma-strings */ - ecma_length_t strings_number) /**< number of ecma-strings */ +ecma_value_t * +ecma_collection_iterator_init (ecma_collection_header_t *header_p) /**< header of collection */ { - JERRY_ASSERT (string_ptrs_buffer != NULL || strings_number == 0); - - ecma_collection_header_t *new_collection_p; - - new_collection_p = ecma_new_values_collection (NULL, 0, false); - - for (ecma_length_t string_index = 0; - string_index < strings_number; - string_index++) + if (unlikely (!header_p || header_p->item_count == 0)) { - ecma_append_to_values_collection (new_collection_p, - ecma_make_string_value (string_ptrs_buffer[string_index]), - false); + return NULL; } - return new_collection_p; -} /* ecma_new_strings_collection */ + ecma_collection_chunk_t *chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, + header_p->first_chunk_cp); -/** - * Initialize new collection iterator for the collection - */ -void -ecma_collection_iterator_init (ecma_collection_iterator_t *iterator_p, /**< context of iterator */ - ecma_collection_header_t *collection_p) /**< header of collection */ -{ - iterator_p->header_p = collection_p; - iterator_p->next_chunk_cp = (collection_p != NULL ? collection_p->first_chunk_cp : JMEM_CP_NULL); - iterator_p->current_index = 0; - iterator_p->current_value_p = NULL; - iterator_p->current_chunk_end_p = NULL; + return chunk_p->items; } /* ecma_collection_iterator_init */ /** * Move collection iterator to next element if there is any. * - * @return true - if iterator moved, - * false - otherwise (current element is last element in the collection) + * @return pointer to the next item */ -bool -ecma_collection_iterator_next (ecma_collection_iterator_t *iterator_p) /**< context of iterator */ +ecma_value_t * +ecma_collection_iterator_next (ecma_value_t *ecma_value_p) /**< current value */ { - if (iterator_p->header_p == NULL - || unlikely (iterator_p->header_p->unit_number == 0) - || unlikely (iterator_p->header_p->first_chunk_cp == JMEM_CP_NULL)) - { - return false; - } + JERRY_ASSERT (ecma_value_p != NULL); - const size_t values_in_chunk = JERRY_SIZE_OF_STRUCT_MEMBER (ecma_collection_chunk_t, data) / sizeof (ecma_value_t); + ecma_value_p++; - if (iterator_p->current_value_p == NULL) + if (unlikely (ecma_is_value_collection_chunk (*ecma_value_p))) { - JERRY_ASSERT (iterator_p->current_index == 0); - - ecma_collection_chunk_t *first_chunk_p = ECMA_GET_NON_NULL_POINTER (ecma_collection_chunk_t, - iterator_p->header_p->first_chunk_cp); + ecma_value_p = ecma_get_collection_chunk_from_value (*ecma_value_p)->items; - iterator_p->next_chunk_cp = first_chunk_p->next_chunk_cp; - iterator_p->current_value_p = (ecma_value_t *) &first_chunk_p->data; - iterator_p->current_chunk_end_p = (iterator_p->current_value_p + values_in_chunk); - } - else - { - if (iterator_p->current_index + 1 == iterator_p->header_p->unit_number) - { - return false; - } - - JERRY_ASSERT (iterator_p->current_index + 1 < iterator_p->header_p->unit_number); - - iterator_p->current_index++; - iterator_p->current_value_p++; - } - - if (iterator_p->current_value_p == iterator_p->current_chunk_end_p) - { - ecma_collection_chunk_t *next_chunk_p = ECMA_GET_POINTER (ecma_collection_chunk_t, - iterator_p->next_chunk_cp); - JERRY_ASSERT (next_chunk_p != NULL); - - iterator_p->next_chunk_cp = next_chunk_p->next_chunk_cp; - iterator_p->current_value_p = (ecma_value_t *) &next_chunk_p->data; - iterator_p->current_chunk_end_p = iterator_p->current_value_p + values_in_chunk; - } - else - { - JERRY_ASSERT (iterator_p->current_value_p < iterator_p->current_chunk_end_p); + JERRY_ASSERT (ecma_value_p == NULL || !ecma_is_value_collection_chunk (*ecma_value_p)); + return ecma_value_p; } - return true; + return ecma_value_p; } /* ecma_collection_iterator_next */ /** diff --git a/deps/jerry/jerry-core/ecma/base/ecma-helpers.c b/deps/jerry/jerry-core/ecma/base/ecma-helpers.c index ee71105..3272f94 100644 --- a/deps/jerry/jerry-core/ecma/base/ecma-helpers.c +++ b/deps/jerry/jerry-core/ecma/base/ecma-helpers.c @@ -19,6 +19,7 @@ #include "ecma-helpers.h" #include "ecma-lcache.h" #include "ecma-property-hashmap.h" +#include "jcontext.h" #include "jrt-bit-fields.h" #include "byte-code.h" #include "re-compiler.h" @@ -26,7 +27,6 @@ #ifdef JERRY_DEBUGGER #include "debugger.h" -#include "jcontext.h" #endif /* JERRY_DEBUGGER */ /** \addtogroup ecma ECMA @@ -36,48 +36,33 @@ * @{ */ -/** - * The ecma property types must be lower than the container mask. - */ JERRY_STATIC_ASSERT (ECMA_PROPERTY_TYPE_MASK >= ECMA_PROPERTY_TYPE__MAX, ecma_property_types_must_be_lower_than_the_container_mask); -/** - * The ecma object types must be lower than the container mask. - */ JERRY_STATIC_ASSERT (ECMA_OBJECT_TYPE_MASK >= ECMA_OBJECT_TYPE__MAX - 1, ecma_object_types_must_be_lower_than_the_container_mask); -/** - * The ecma lexical environment types must be lower than the container mask. - */ JERRY_STATIC_ASSERT (ECMA_OBJECT_TYPE_MASK >= ECMA_LEXICAL_ENVIRONMENT_TYPE__MAX, ecma_lexical_environment_types_must_be_lower_than_the_container_mask); -/** - * The ecma built in flag must follow the object type. - */ JERRY_STATIC_ASSERT (ECMA_OBJECT_TYPE_MASK + 1 == ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV, ecma_built_in_flag_must_follow_the_object_type); -/** - * The ecma extensible flag must follow the gc visited flag. - */ JERRY_STATIC_ASSERT (ECMA_OBJECT_FLAG_EXTENSIBLE == (ECMA_OBJECT_FLAG_BUILT_IN_OR_LEXICAL_ENV << 1), ecma_extensible_flag_must_follow_the_built_in_flag); -/** - * The ecma object ref one must follow the extensible flag. - */ JERRY_STATIC_ASSERT (ECMA_OBJECT_REF_ONE == (ECMA_OBJECT_FLAG_EXTENSIBLE << 1), ecma_object_ref_one_must_follow_the_extensible_flag); -/** - * The ecma object max ref does not fill the remaining bits. - */ JERRY_STATIC_ASSERT ((ECMA_OBJECT_MAX_REF | (ECMA_OBJECT_REF_ONE - 1)) == UINT16_MAX, ecma_object_max_ref_does_not_fill_the_remaining_bits); +JERRY_STATIC_ASSERT (ECMA_PROPERTY_TYPE_DELETED == (ECMA_DIRECT_STRING_MAGIC << ECMA_PROPERTY_NAME_TYPE_SHIFT), + ecma_property_type_deleted_must_have_magic_string_name_type); + +JERRY_STATIC_ASSERT (ECMA_PROPERTY_DELETED_NAME >= LIT_MAGIC_STRING__COUNT, + ecma_property_deleted_name_must_not_be_valid_maigc_string_id); + /** * Create an object with specified prototype object * (or NULL prototype if there is not prototype for the object) @@ -486,7 +471,7 @@ ecma_create_property (ecma_object_t *object_p, /**< the object */ /* Just copy the previous value (no need to decompress, compress). */ first_property_pair_p->header.next_property_cp = *property_list_head_p; first_property_pair_p->header.types[0] = ECMA_PROPERTY_TYPE_DELETED; - first_property_pair_p->names_cp[0] = ECMA_NULL_POINTER; + first_property_pair_p->names_cp[0] = ECMA_PROPERTY_DELETED_NAME; if (name_p == NULL) { @@ -628,47 +613,85 @@ ecma_find_named_property (ecma_object_t *obj_p, /**< object to find property in } #endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */ - property_p = NULL; - jmem_cpointer_t property_name_cp = ECMA_NULL_POINTER; + JERRY_ASSERT (ECMA_PROPERTY_PAIR_ITEM_COUNT == 2); uint32_t steps = 0; + jmem_cpointer_t property_name_cp = ECMA_NULL_POINTER; - while (prop_iter_p != NULL) + if (ECMA_IS_DIRECT_STRING (name_p)) { - JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); - - ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; + ecma_property_t prop_name_type = (ecma_property_t) ECMA_GET_DIRECT_STRING_TYPE (name_p); + property_name_cp = (jmem_cpointer_t) ECMA_GET_DIRECT_STRING_VALUE (name_p); - JERRY_ASSERT (ECMA_PROPERTY_PAIR_ITEM_COUNT == 2); + JERRY_ASSERT (prop_name_type > 0); - if (ECMA_PROPERTY_IS_NAMED_PROPERTY (prop_iter_p->types[0])) + while (prop_iter_p != NULL) { - if (ecma_string_compare_to_property_name (prop_iter_p->types[0], - prop_pair_p->names_cp[0], - name_p)) + JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); + + ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; + + if (prop_pair_p->names_cp[0] == property_name_cp + && ECMA_PROPERTY_GET_NAME_TYPE (prop_iter_p->types[0]) == prop_name_type) { - property_name_cp = prop_pair_p->names_cp[0]; + JERRY_ASSERT (ECMA_PROPERTY_IS_NAMED_PROPERTY (prop_iter_p->types[0])); + property_p = prop_iter_p->types + 0; break; } - } - if (ECMA_PROPERTY_IS_NAMED_PROPERTY (prop_iter_p->types[1])) - { - if (ecma_string_compare_to_property_name (prop_iter_p->types[1], - prop_pair_p->names_cp[1], - name_p)) + if (prop_pair_p->names_cp[1] == property_name_cp + && ECMA_PROPERTY_GET_NAME_TYPE (prop_iter_p->types[1]) == prop_name_type) { - property_name_cp = prop_pair_p->names_cp[1]; + JERRY_ASSERT (ECMA_PROPERTY_IS_NAMED_PROPERTY (prop_iter_p->types[1])); + property_p = prop_iter_p->types + 1; break; } + + steps++; + + prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, + prop_iter_p->next_property_cp); } + } + else + { + while (prop_iter_p != NULL) + { + JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p)); - steps++; + ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; - prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, - prop_iter_p->next_property_cp); + if (ECMA_PROPERTY_GET_NAME_TYPE (prop_iter_p->types[0]) == ECMA_DIRECT_STRING_PTR) + { + property_name_cp = prop_pair_p->names_cp[0]; + ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, property_name_cp); + + if (ecma_compare_ecma_non_direct_strings (name_p, prop_name_p)) + { + property_p = prop_iter_p->types + 0; + break; + } + } + + if (ECMA_PROPERTY_GET_NAME_TYPE (prop_iter_p->types[1]) == ECMA_DIRECT_STRING_PTR) + { + property_name_cp = prop_pair_p->names_cp[1]; + ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, property_name_cp); + + if (ecma_compare_ecma_non_direct_strings (name_p, prop_name_p)) + { + property_p = prop_iter_p->types + 1; + break; + } + } + + steps++; + + prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t, + prop_iter_p->next_property_cp); + } } if (steps >= (ECMA_PROPERTY_HASMAP_MINIMUM_SIZE / 2)) @@ -723,7 +746,7 @@ ecma_free_property (ecma_object_t *object_p, /**< object the property belongs to { case ECMA_PROPERTY_TYPE_NAMEDDATA: { - if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_STRING_CONTAINER_MAGIC_STRING) + if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC) { if (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_HANDLE || name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER) @@ -758,13 +781,11 @@ ecma_free_property (ecma_object_t *object_p, /**< object the property belongs to ecma_lcache_invalidate (object_p, name_cp, property_p); } - if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_PROPERTY_NAME_TYPE_STRING) + if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_PTR) { ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, name_cp); ecma_deref_ecma_string (prop_name_p); } - - *property_p = ECMA_PROPERTY_TYPE_DELETED; } /* ecma_free_property */ /** @@ -809,6 +830,8 @@ ecma_delete_property (ecma_object_t *object_p, /**< object */ } ecma_free_property (object_p, prop_pair_p->names_cp[i], cur_prop_p->types + i); + cur_prop_p->types[i] = ECMA_PROPERTY_TYPE_DELETED; + prop_pair_p->names_cp[i] = ECMA_PROPERTY_DELETED_NAME; JERRY_ASSERT (ECMA_PROPERTY_PAIR_ITEM_COUNT == 2); @@ -949,8 +972,8 @@ ecma_delete_array_properties (ecma_object_t *object_p, /**< object */ } ecma_free_property (object_p, prop_pair_p->names_cp[i], current_prop_p->types + i); - - JERRY_ASSERT (current_prop_p->types[i] == ECMA_PROPERTY_TYPE_DELETED); + current_prop_p->types[i] = ECMA_PROPERTY_TYPE_DELETED; + prop_pair_p->names_cp[i] = ECMA_PROPERTY_DELETED_NAME; } } } @@ -1335,15 +1358,28 @@ JERRY_STATIC_ASSERT (sizeof (ecma_error_reference_t) == 8, * @return error reference value */ ecma_value_t -ecma_create_error_reference (ecma_value_t value) /**< referenced value */ +ecma_create_error_reference (ecma_value_t value, /**< referenced value */ + bool is_exception) /**< error reference is an exception */ { ecma_error_reference_t *error_ref_p = (ecma_error_reference_t *) jmem_pools_alloc (sizeof (ecma_error_reference_t)); - error_ref_p->refs = 1; + error_ref_p->refs_and_flags = ECMA_ERROR_REF_ONE | (is_exception ? 0 : ECMA_ERROR_REF_ABORT); error_ref_p->value = value; return ecma_make_error_reference_value (error_ref_p); } /* ecma_create_error_reference */ +/** + * Create an error reference from the currently thrown error value. + * + * @return error reference value + */ +ecma_value_t +ecma_create_error_reference_from_context (void) +{ + return ecma_create_error_reference (JERRY_CONTEXT (error_value), + (JERRY_CONTEXT (status_flags) & ECMA_STATUS_EXCEPTION) != 0); +} /* ecma_create_error_reference_from_context */ + /** * Create an error reference from a given object. * @@ -1355,7 +1391,7 @@ ecma_create_error_reference (ecma_value_t value) /**< referenced value */ inline ecma_value_t __attr_always_inline___ ecma_create_error_object_reference (ecma_object_t *object_p) /**< referenced object */ { - return ecma_create_error_reference (ecma_make_object_value (object_p)); + return ecma_create_error_reference (ecma_make_object_value (object_p), true); } /* ecma_create_error_object_reference */ /** @@ -1364,9 +1400,9 @@ ecma_create_error_object_reference (ecma_object_t *object_p) /**< referenced obj void ecma_ref_error_reference (ecma_error_reference_t *error_ref_p) /**< error reference */ { - if (likely (error_ref_p->refs < UINT32_MAX)) + if (likely (error_ref_p->refs_and_flags < ECMA_ERROR_MAX_REF)) { - error_ref_p->refs++; + error_ref_p->refs_and_flags += ECMA_ERROR_REF_ONE; } else { @@ -1380,11 +1416,11 @@ ecma_ref_error_reference (ecma_error_reference_t *error_ref_p) /**< error refere void ecma_deref_error_reference (ecma_error_reference_t *error_ref_p) /**< error reference */ { - JERRY_ASSERT (error_ref_p->refs > 0); + JERRY_ASSERT (error_ref_p->refs_and_flags >= ECMA_ERROR_REF_ONE); - error_ref_p->refs--; + error_ref_p->refs_and_flags -= ECMA_ERROR_REF_ONE; - if (error_ref_p->refs == 0) + if (error_ref_p->refs_and_flags < ECMA_ERROR_REF_ONE) { ecma_free_value (error_ref_p->value); jmem_pools_free (error_ref_p, sizeof (ecma_error_reference_t)); @@ -1397,15 +1433,28 @@ ecma_deref_error_reference (ecma_error_reference_t *error_ref_p) /**< error refe * @return value referenced by the error */ ecma_value_t -ecma_clear_error_reference (ecma_value_t value) +ecma_clear_error_reference (ecma_value_t value, /**< error reference */ + bool set_abort_flag) /**< set abort flag */ { ecma_error_reference_t *error_ref_p = ecma_get_error_reference_from_value (value); - JERRY_ASSERT (error_ref_p->refs > 0); + if (set_abort_flag) + { + if (error_ref_p->refs_and_flags & ECMA_ERROR_REF_ABORT) + { + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; + } + else + { + JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + } + } + + JERRY_ASSERT (error_ref_p->refs_and_flags >= ECMA_ERROR_REF_ONE); - if (error_ref_p->refs > 1) + if (error_ref_p->refs_and_flags >= 2 * ECMA_ERROR_REF_ONE) { - error_ref_p->refs--; + error_ref_p->refs_and_flags -= ECMA_ERROR_REF_ONE; return ecma_copy_value (error_ref_p->value); } @@ -1438,6 +1487,7 @@ void ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */ { JERRY_ASSERT (bytecode_p->refs > 0); + JERRY_ASSERT (!(bytecode_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)); bytecode_p->refs--; @@ -1449,34 +1499,33 @@ ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */ if (bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) { - jmem_cpointer_t *literal_start_p = NULL; + ecma_value_t *literal_start_p = NULL; uint32_t literal_end; uint32_t const_literal_end; if (bytecode_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { - uint8_t *byte_p = (uint8_t *) bytecode_p; - literal_start_p = (jmem_cpointer_t *) (byte_p + sizeof (cbc_uint16_arguments_t)); - cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_p; literal_end = args_p->literal_end; const_literal_end = args_p->const_literal_end; + + literal_start_p = (ecma_value_t *) ((uint8_t *) bytecode_p + sizeof (cbc_uint16_arguments_t)); + literal_start_p -= args_p->register_end; } else { - uint8_t *byte_p = (uint8_t *) bytecode_p; - literal_start_p = (jmem_cpointer_t *) (byte_p + sizeof (cbc_uint8_arguments_t)); - cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_p; literal_end = args_p->literal_end; const_literal_end = args_p->const_literal_end; + + literal_start_p = (ecma_value_t *) ((uint8_t *) bytecode_p + sizeof (cbc_uint8_arguments_t)); + literal_start_p -= args_p->register_end; } for (uint32_t i = const_literal_end; i < literal_end; i++) { - jmem_cpointer_t bytecode_cpointer = literal_start_p[i]; - ecma_compiled_code_t *bytecode_literal_p = ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, - bytecode_cpointer); + ecma_compiled_code_t *bytecode_literal_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, + literal_start_p[i]); /* Self references are ignored. */ if (bytecode_literal_p != bytecode_p) @@ -1528,7 +1577,7 @@ ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */ #ifndef CONFIG_DISABLE_REGEXP_BUILTIN re_compiled_code_t *re_bytecode_p = (re_compiled_code_t *) bytecode_p; - ecma_deref_ecma_string (ECMA_GET_NON_NULL_POINTER (ecma_string_t, re_bytecode_p->pattern_cp)); + ecma_deref_ecma_string (ecma_get_string_from_value (re_bytecode_p->pattern)); #endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */ } diff --git a/deps/jerry/jerry-core/ecma/base/ecma-helpers.h b/deps/jerry/jerry-core/ecma/base/ecma-helpers.h index f155955..765b72c 100644 --- a/deps/jerry/jerry-core/ecma/base/ecma-helpers.h +++ b/deps/jerry/jerry-core/ecma/base/ecma-helpers.h @@ -50,6 +50,13 @@ */ #define ECMA_SET_POINTER(field, non_compressed_pointer) JMEM_CP_SET_POINTER (field, non_compressed_pointer) +typedef enum +{ + ECMA_STRING_FLAG_EMPTY = 0, + ECMA_STRING_FLAG_IS_ASCII, + ECMA_STRING_FLAG_MUST_BE_FREED +} ecma_string_flag_t; + /** * Convert ecma-string's contents to a cesu-8 string and put it into a buffer. */ @@ -57,58 +64,73 @@ utf8_ptr, /**< [out] output buffer pointer */ \ utf8_str_size) /**< [out] output buffer size */ \ lit_utf8_size_t utf8_str_size; \ - bool utf8_ptr ## must_be_freed; \ - const lit_utf8_byte_t *utf8_ptr = ecma_string_raw_chars (ecma_str_ptr, &utf8_str_size, &utf8_ptr ## must_be_freed); \ - utf8_ptr ## must_be_freed = false; /* it was used as 'is_ascii' in 'ecma_string_raw_chars', so we must reset it */ \ - \ - if (utf8_ptr == NULL) \ + uint8_t utf8_ptr ## flags = ECMA_STRING_FLAG_EMPTY; \ + const lit_utf8_byte_t *utf8_ptr = ecma_string_get_chars (ecma_str_ptr, &utf8_str_size, &utf8_ptr ## flags); + +/** + * Free the cesu-8 string buffer allocated by 'ECMA_STRING_TO_UTF8_STRING' + */ +#define ECMA_FINALIZE_UTF8_STRING(utf8_ptr, /**< pointer to character buffer */ \ + utf8_str_size) /**< buffer size */ \ + if (utf8_ptr ## flags & ECMA_STRING_FLAG_MUST_BE_FREED) \ { \ - utf8_ptr = (const lit_utf8_byte_t *) jmem_heap_alloc_block (utf8_str_size); \ - ecma_string_to_utf8_bytes (ecma_str_ptr, (lit_utf8_byte_t *) utf8_ptr, utf8_str_size); \ - utf8_ptr ## must_be_freed = true; \ + JERRY_ASSERT (utf8_ptr != NULL); \ + jmem_heap_free_block ((void *) utf8_ptr, utf8_str_size); \ } #ifdef ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY /** - * Set an internal property value of pointer + * Set an internal property value from pointer. */ #define ECMA_SET_INTERNAL_VALUE_POINTER(field, pointer) \ (field) = ((ecma_value_t) pointer) /** - * Get an internal property value of pointer + * Set an internal property value from pointer. Pointer can be NULL. + */ +#define ECMA_SET_INTERNAL_VALUE_ANY_POINTER(field, pointer) \ + (field) = ((ecma_value_t) pointer) + +/** + * Convert an internal property value to pointer. */ #define ECMA_GET_INTERNAL_VALUE_POINTER(type, field) \ ((type *) field) +/** + * Convert an internal property value to pointer. Result can be NULL. + */ +#define ECMA_GET_INTERNAL_VALUE_ANY_POINTER(type, field) \ + ((type *) field) + #else /* !ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ /** - * Set an internal property value of non-null pointer so that it will correspond - * to specified non_compressed_pointer. + * Set an internal property value from pointer. */ -#define ECMA_SET_INTERNAL_VALUE_POINTER(field, non_compressed_pointer) \ - ECMA_SET_NON_NULL_POINTER (field, non_compressed_pointer) +#define ECMA_SET_INTERNAL_VALUE_POINTER(field, pointer) \ + ECMA_SET_NON_NULL_POINTER (field, pointer) /** - * Get an internal property value of pointer from specified compressed pointer. + * Set an internal property value from pointer. Pointer can be NULL. */ -#define ECMA_GET_INTERNAL_VALUE_POINTER(type, field) \ - ECMA_GET_POINTER (type, field) +#define ECMA_SET_INTERNAL_VALUE_ANY_POINTER(field, pointer) \ + ECMA_SET_POINTER (field, pointer) -#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ +/** + * Convert an internal property value to pointer. + */ +#define ECMA_GET_INTERNAL_VALUE_POINTER(type, field) \ + ECMA_GET_NON_NULL_POINTER (type, field) /** - * Free the cesu-8 string buffer allocated by 'ECMA_STRING_TO_UTF8_STRING' + * Convert an internal property value to pointer. Result can be NULL. */ -#define ECMA_FINALIZE_UTF8_STRING(utf8_ptr, /**< pointer to character buffer */ \ - utf8_str_size) /**< buffer size */ \ - if (utf8_ptr ## must_be_freed) \ - { \ - JERRY_ASSERT (utf8_ptr != NULL); \ - jmem_heap_free_block ((void *) utf8_ptr, utf8_str_size); \ - } +#define ECMA_GET_INTERNAL_VALUE_ANY_POINTER(type, field) \ + ECMA_GET_POINTER (type, field) + +#endif /* ECMA_VALUE_CAN_STORE_UINTPTR_VALUE_DIRECTLY */ /** * Convert boolean to bitfield value. @@ -132,8 +154,10 @@ bool ecma_are_values_integer_numbers (ecma_value_t first_value, ecma_value_t sec bool ecma_is_value_float_number (ecma_value_t value) __attr_const___; bool ecma_is_value_number (ecma_value_t value) __attr_const___; bool ecma_is_value_string (ecma_value_t value) __attr_const___; +bool ecma_is_value_direct_string (ecma_value_t value) __attr_const___; bool ecma_is_value_object (ecma_value_t value) __attr_const___; bool ecma_is_value_error_reference (ecma_value_t value) __attr_const___; +bool ecma_is_value_collection_chunk (ecma_value_t value) __attr_const___; void ecma_check_value_type_is_spec_defined (ecma_value_t value); @@ -144,14 +168,17 @@ ecma_value_t ecma_make_number_value (ecma_number_t ecma_number); ecma_value_t ecma_make_int32_value (int32_t int32_number); ecma_value_t ecma_make_uint32_value (uint32_t uint32_number); ecma_value_t ecma_make_string_value (const ecma_string_t *ecma_string_p) __attr_pure___; +ecma_value_t ecma_make_magic_string_value (lit_magic_string_id_t id) __attr_pure___; ecma_value_t ecma_make_object_value (const ecma_object_t *object_p) __attr_pure___; ecma_value_t ecma_make_error_reference_value (const ecma_error_reference_t *error_ref_p) __attr_pure___; +ecma_value_t ecma_make_collection_chunk_value (const ecma_collection_chunk_t *collection_chunk_p) __attr_pure___; ecma_integer_value_t ecma_get_integer_from_value (ecma_value_t value) __attr_const___; ecma_number_t ecma_get_float_from_value (ecma_value_t value) __attr_pure___; ecma_number_t ecma_get_number_from_value (ecma_value_t value) __attr_pure___; ecma_string_t *ecma_get_string_from_value (ecma_value_t value) __attr_pure___; ecma_object_t *ecma_get_object_from_value (ecma_value_t value) __attr_pure___; ecma_error_reference_t *ecma_get_error_reference_from_value (ecma_value_t value) __attr_pure___; +ecma_collection_chunk_t *ecma_get_collection_chunk_from_value (ecma_value_t value) __attr_pure___; ecma_value_t ecma_invert_boolean_value (ecma_value_t value) __attr_const___; ecma_value_t ecma_copy_value (ecma_value_t value); ecma_value_t ecma_fast_copy_value (ecma_value_t value); @@ -162,6 +189,7 @@ void ecma_value_assign_number (ecma_value_t *value_p, ecma_number_t ecma_number) void ecma_free_value (ecma_value_t value); void ecma_fast_free_value (ecma_value_t value); void ecma_free_value_if_not_object (ecma_value_t value); +lit_magic_string_id_t ecma_get_typeof_lit_id (ecma_value_t value); /* ecma-helpers-string.c */ ecma_string_t *ecma_new_ecma_string_from_utf8 (const lit_utf8_byte_t *string_p, lit_utf8_size_t string_size); @@ -169,10 +197,10 @@ ecma_string_t *ecma_new_ecma_string_from_utf8_converted_to_cesu8 (const lit_utf8 lit_utf8_size_t string_size); ecma_string_t *ecma_new_ecma_string_from_code_unit (ecma_char_t code_unit); ecma_string_t *ecma_new_ecma_string_from_uint32 (uint32_t uint32_number); +ecma_string_t *ecma_get_ecma_string_from_uint32 (uint32_t uint32_number); ecma_string_t *ecma_new_ecma_string_from_number (ecma_number_t num); -ecma_string_t *ecma_new_ecma_string_from_magic_string_id (lit_magic_string_id_t id); +ecma_string_t *ecma_get_magic_string (lit_magic_string_id_t id); ecma_string_t *ecma_new_ecma_string_from_magic_string_ex_id (lit_magic_string_ex_id_t id); -ecma_string_t *ecma_new_ecma_length_string (void); ecma_string_t *ecma_append_chars_to_string (ecma_string_t *string1_p, const lit_utf8_byte_t *cesu8_string2_p, lit_utf8_size_t cesu8_string2_size, @@ -206,9 +234,7 @@ ecma_substring_copy_to_utf8_buffer (const ecma_string_t *string_desc_p, lit_utf8_size_t buffer_size); void ecma_string_to_utf8_bytes (const ecma_string_t *string_desc_p, lit_utf8_byte_t *buffer_p, lit_utf8_size_t buffer_size); -const lit_utf8_byte_t *ecma_string_raw_chars (const ecma_string_t *string_p, lit_utf8_size_t *size_p, bool *is_ascii_p); -void ecma_init_ecma_string_from_uint32 (ecma_string_t *string_desc_p, uint32_t uint32_number); -void ecma_init_ecma_magic_string (ecma_string_t *string_desc_p, lit_magic_string_id_t id); +const lit_utf8_byte_t *ecma_string_get_chars (const ecma_string_t *string_p, lit_utf8_size_t *size_p, uint8_t *flags_p); bool ecma_compare_ecma_string_to_magic_id (const ecma_string_t *string_p, lit_magic_string_id_t id); bool ecma_string_is_empty (const ecma_string_t *string_p); bool ecma_string_is_length (const ecma_string_t *string_p); @@ -221,6 +247,7 @@ bool ecma_string_compare_to_property_name (ecma_property_t property, jmem_cpoint const ecma_string_t *string_p); bool ecma_compare_ecma_strings (const ecma_string_t *string1_p, const ecma_string_t *string2_p); +bool ecma_compare_ecma_non_direct_strings (const ecma_string_t *string1_p, const ecma_string_t *string2_p); bool ecma_compare_ecma_strings_relational (const ecma_string_t *string1_p, const ecma_string_t *string2_p); ecma_length_t ecma_string_get_length (const ecma_string_t *string_p); ecma_length_t ecma_string_get_utf8_length (const ecma_string_t *string_p); @@ -228,8 +255,6 @@ lit_utf8_size_t ecma_string_get_size (const ecma_string_t *string_p); lit_utf8_size_t ecma_string_get_utf8_size (const ecma_string_t *string_p); ecma_char_t ecma_string_get_char_at_pos (const ecma_string_t *string_p, ecma_length_t index); -ecma_string_t *ecma_get_magic_string (lit_magic_string_id_t id); -ecma_string_t *ecma_get_magic_string_ex (lit_magic_string_ex_id_t id); lit_magic_string_id_t ecma_get_string_magic (const ecma_string_t *string_p); lit_string_hash_t ecma_string_hash (const ecma_string_t *string_p); @@ -260,31 +285,14 @@ lit_utf8_size_t ecma_number_to_binary_floating_point_number (ecma_number_t num, int32_t *out_decimal_exp_p); /* ecma-helpers-values-collection.c */ -ecma_collection_header_t *ecma_new_values_collection (const ecma_value_t values_buffer[], ecma_length_t values_number, - bool do_ref_if_object); -void ecma_free_values_collection (ecma_collection_header_t *header_p, bool do_deref_if_object); -void ecma_append_to_values_collection (ecma_collection_header_t *header_p, ecma_value_t v, bool do_ref_if_object); -void ecma_remove_last_value_from_values_collection (ecma_collection_header_t *header_p); -ecma_collection_header_t *ecma_new_strings_collection (ecma_string_t *string_ptrs_buffer[], - ecma_length_t strings_number); +ecma_collection_header_t *ecma_new_values_collection (void); +void ecma_free_values_collection (ecma_collection_header_t *header_p, uint32_t flags); +void ecma_append_to_values_collection (ecma_collection_header_t *header_p, ecma_value_t v, uint32_t flags); -/** - * Context of ecma values' collection iterator - */ -typedef struct -{ - ecma_collection_header_t *header_p; /**< collection header */ - jmem_cpointer_t next_chunk_cp; /**< compressed pointer to next chunk */ - ecma_length_t current_index; /**< index of current element */ - const ecma_value_t *current_value_p; /**< pointer to current element */ - const ecma_value_t *current_chunk_beg_p; /**< pointer to beginning of current chunk's data */ - const ecma_value_t *current_chunk_end_p; /**< pointer to place right after the end of current chunk's data */ -} ecma_collection_iterator_t; - -void -ecma_collection_iterator_init (ecma_collection_iterator_t *iterator_p, ecma_collection_header_t *collection_p); -bool -ecma_collection_iterator_next (ecma_collection_iterator_t *iterator_p); +ecma_value_t * +ecma_collection_iterator_init (ecma_collection_header_t *header_p); +ecma_value_t * +ecma_collection_iterator_next (ecma_value_t *iterator_p); /* ecma-helpers.c */ ecma_object_t *ecma_create_object (ecma_object_t *prototype_object_p, size_t ext_object_size, ecma_object_type_t type); @@ -343,11 +351,12 @@ void ecma_set_property_lcached (ecma_property_t *property_p, bool is_lcached); ecma_property_descriptor_t ecma_make_empty_property_descriptor (void); void ecma_free_property_descriptor (ecma_property_descriptor_t *prop_desc_p); -ecma_value_t ecma_create_error_reference (ecma_value_t value); +ecma_value_t ecma_create_error_reference (ecma_value_t value, bool is_exception); +ecma_value_t ecma_create_error_reference_from_context (void); ecma_value_t ecma_create_error_object_reference (ecma_object_t *object_p); void ecma_ref_error_reference (ecma_error_reference_t *error_ref_p); void ecma_deref_error_reference (ecma_error_reference_t *error_ref_p); -ecma_value_t ecma_clear_error_reference (ecma_value_t value); +ecma_value_t ecma_clear_error_reference (ecma_value_t value, bool set_abort_flag); void ecma_bytecode_ref (ecma_compiled_code_t *bytecode_p); void ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p); diff --git a/deps/jerry/jerry-core/ecma/base/ecma-init-finalize.c b/deps/jerry/jerry-core/ecma/base/ecma-init-finalize.c index 95b08d4..d9bf0be 100644 --- a/deps/jerry/jerry-core/ecma/base/ecma-init-finalize.c +++ b/deps/jerry/jerry-core/ecma/base/ecma-init-finalize.c @@ -43,7 +43,7 @@ ecma_init (void) #ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) = ECMA_PROP_HASHMAP_ALLOC_ON; - JERRY_CONTEXT (ecma_prop_hashmap_alloc_last_is_hs_gc) = false; + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_HIGH_SEV_GC; #endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */ #ifndef CONFIG_DISABLE_ES2015_PROMISE_BUILTIN diff --git a/deps/jerry/jerry-core/ecma/base/ecma-lcache.c b/deps/jerry/jerry-core/ecma/base/ecma-lcache.c index 6982883..572a12c 100644 --- a/deps/jerry/jerry-core/ecma/base/ecma-lcache.c +++ b/deps/jerry/jerry-core/ecma/base/ecma-lcache.c @@ -134,52 +134,7 @@ ecma_lcache_insert (ecma_object_t *object_p, /**< object */ #ifndef CONFIG_ECMA_LCACHE_DISABLE -/** - * Converts a string into a property name - * - * @return the compressed pointer part of the name - */ -static inline jmem_cpointer_t __attr_always_inline___ -ecma_string_to_lcache_property_name (const ecma_string_t *prop_name_p, /**< property name */ - ecma_property_t *name_type_p) /**< [out] property name type */ -{ - ecma_string_container_t container = ECMA_STRING_GET_CONTAINER (prop_name_p); - - switch (container) - { - case ECMA_STRING_CONTAINER_UINT32_IN_DESC: - case ECMA_STRING_CONTAINER_MAGIC_STRING: - case ECMA_STRING_CONTAINER_MAGIC_STRING_EX: - { -#ifdef JERRY_CPOINTER_32_BIT - - *name_type_p = (ecma_property_t) container; - return (jmem_cpointer_t) prop_name_p->u.uint32_number; - -#else /* !JERRY_CPOINTER_32_BIT */ - - if (prop_name_p->u.uint32_number < (UINT16_MAX + 1)) - { - *name_type_p = (ecma_property_t) container; - return (jmem_cpointer_t) prop_name_p->u.uint32_number; - } - -#endif /* JERRY_CPOINTER_32_BIT */ - - break; - } - default: - { - break; - } - } - *name_type_p = ECMA_PROPERTY_NAME_TYPE_STRING; - - jmem_cpointer_t prop_name_cp; - ECMA_SET_NON_NULL_POINTER (prop_name_cp, prop_name_p); - return prop_name_cp; -} /* ecma_string_to_lcache_property_name */ #endif /* !CONFIG_ECMA_LCACHE_DISABLE */ @@ -200,13 +155,36 @@ ecma_lcache_lookup (ecma_object_t *object_p, /**< object */ jmem_cpointer_t object_cp; ECMA_SET_NON_NULL_POINTER (object_cp, object_p); - size_t row_index = ecma_lcache_row_index (object_cp, ecma_string_hash (prop_name_p)); + ecma_property_t prop_name_type; + jmem_cpointer_t prop_name_cp; + lit_string_hash_t name_hash; + + if (ECMA_IS_DIRECT_STRING (prop_name_p)) + { + prop_name_type = (ecma_property_t) ECMA_GET_DIRECT_STRING_TYPE (prop_name_p); + + uintptr_t value = ECMA_GET_DIRECT_STRING_VALUE (prop_name_p); + prop_name_cp = (jmem_cpointer_t) value; + name_hash = (lit_string_hash_t) value; + + if (prop_name_type == ECMA_DIRECT_STRING_MAGIC_EX) + { + name_hash = (lit_string_hash_t) (name_hash + LIT_MAGIC_STRING__COUNT); + } + } + else + { + prop_name_type = ECMA_DIRECT_STRING_PTR; + + ECMA_SET_NON_NULL_POINTER (prop_name_cp, prop_name_p); + name_hash = prop_name_p->hash; + } + + size_t row_index = ecma_lcache_row_index (object_cp, name_hash); + ecma_lcache_hash_entry_t *entry_p = JERRY_HASH_TABLE_CONTEXT (table) [row_index]; ecma_lcache_hash_entry_t *entry_end_p = entry_p + ECMA_LCACHE_HASH_ROW_LENGTH; - ecma_property_t prop_name_type; - jmem_cpointer_t prop_name_cp = ecma_string_to_lcache_property_name (prop_name_p, &prop_name_type); - while (entry_p < entry_end_p) { if (entry_p->object_cp == object_cp diff --git a/deps/jerry/jerry-core/ecma/base/ecma-literal-storage.c b/deps/jerry/jerry-core/ecma/base/ecma-literal-storage.c index e1627f0..b93bd77 100644 --- a/deps/jerry/jerry-core/ecma/base/ecma-literal-storage.c +++ b/deps/jerry/jerry-core/ecma/base/ecma-literal-storage.c @@ -66,12 +66,17 @@ ecma_finalize_lit_storage (void) * * @return ecma_string_t compressed pointer */ -jmem_cpointer_t +ecma_value_t ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, /**< string to be searched */ lit_utf8_size_t size) /**< size of the string */ { ecma_string_t *string_p = ecma_new_ecma_string_from_utf8 (chars_p, size); + if (ECMA_IS_DIRECT_STRING (string_p)) + { + return ecma_make_string_value (string_p); + } + ecma_lit_storage_item_t *string_list_p = JERRY_CONTEXT (string_list_first_p); jmem_cpointer_t *empty_cpointer_p = NULL; @@ -95,7 +100,7 @@ ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, /**< string { /* Return with string if found in the list. */ ecma_deref_ecma_string (string_p); - return string_list_p->values[i]; + return ecma_make_string_value (value_p); } } } @@ -109,7 +114,7 @@ ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, /**< string if (empty_cpointer_p != NULL) { *empty_cpointer_p = result; - return result; + return ecma_make_string_value (string_p); } ecma_lit_storage_item_t *new_item_p; @@ -124,7 +129,7 @@ ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, /**< string JMEM_CP_SET_POINTER (new_item_p->next_cp, JERRY_CONTEXT (string_list_first_p)); JERRY_CONTEXT (string_list_first_p) = new_item_p; - return result; + return ecma_make_string_value (string_p); } /* ecma_find_or_create_literal_string */ /** @@ -132,11 +137,18 @@ ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, /**< string * * @return ecma_string_t compressed pointer */ -jmem_cpointer_t +ecma_value_t ecma_find_or_create_literal_number (ecma_number_t number_arg) /**< number to be searched */ { ecma_value_t num = ecma_make_number_value (number_arg); + if (ecma_is_value_integer_number (num)) + { + return num; + } + + JERRY_ASSERT (ecma_is_value_float_number (num)); + ecma_lit_storage_item_t *number_list_p = JERRY_CONTEXT (number_list_first_p); jmem_cpointer_t *empty_cpointer_p = NULL; @@ -157,22 +169,12 @@ ecma_find_or_create_literal_number (ecma_number_t number_arg) /**< number to be number_list_p->values[i]); JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (value_p) == ECMA_STRING_LITERAL_NUMBER); + JERRY_ASSERT (ecma_is_value_float_number (value_p->u.lit_number)); - if (ecma_is_value_integer_number (num)) - { - if (value_p->u.lit_number == num) - { - return number_list_p->values[i]; - } - } - else + if (ecma_get_float_from_value (value_p->u.lit_number) == number_arg) { - if (ecma_is_value_float_number (value_p->u.lit_number) - && ecma_get_float_from_value (value_p->u.lit_number) == ecma_get_float_from_value (num)) - { - ecma_free_value (num); - return number_list_p->values[i]; - } + ecma_free_value (num); + return value_p->u.lit_number; } } } @@ -190,7 +192,7 @@ ecma_find_or_create_literal_number (ecma_number_t number_arg) /**< number to be if (empty_cpointer_p != NULL) { *empty_cpointer_p = result; - return result; + return num; } ecma_lit_storage_item_t *new_item_p; @@ -205,175 +207,256 @@ ecma_find_or_create_literal_number (ecma_number_t number_arg) /**< number to be JMEM_CP_SET_POINTER (new_item_p->next_cp, JERRY_CONTEXT (number_list_first_p)); JERRY_CONTEXT (number_list_first_p) = new_item_p; - return result; + return num; } /* ecma_find_or_create_literal_number */ /** * Log2 of snapshot literal alignment. */ -#define JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG 2 +#define JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG 1 /** * Snapshot literal alignment. */ #define JERRY_SNAPSHOT_LITERAL_ALIGNMENT (1u << JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG) +/** + * Literal offset shift. + */ +#define JERRY_SNAPSHOT_LITERAL_SHIFT (ECMA_VALUE_SHIFT + 1) + +/** + * Literal value is number. + */ +#define JERRY_SNAPSHOT_LITERAL_IS_NUMBER (1u << ECMA_VALUE_SHIFT) + #ifdef JERRY_ENABLE_SNAPSHOT_SAVE /** - * Save literals to specified snapshot buffer. - * - * @return true - if save was performed successfully (i.e. buffer size is sufficient), - * false - otherwise + * Append the value at the end of the appropriate list if it is not present there. */ -bool -ecma_save_literals_for_snapshot (uint32_t *buffer_p, /**< [out] output snapshot buffer */ - size_t buffer_size, /**< size of the buffer */ - size_t *in_out_buffer_offset_p, /**< [in,out] write position in the buffer */ - lit_mem_to_snapshot_id_map_entry_t **out_map_p, /**< [out] map from literal identifiers - * to the literal offsets - * in snapshot */ - uint32_t *out_map_len_p) /**< [out] number of literals */ +void ecma_save_literals_append_value (ecma_value_t value, /**< value to be appended */ + ecma_collection_header_t *lit_pool_p) /**< list of known values */ { - /* Count literals and literal space. */ - uint32_t lit_table_size = sizeof (uint32_t); - uint32_t total_count = 0; + /* Unlike direct numbers, direct strings are converted to character literals. */ + if (!ecma_is_value_string (value) && !ecma_is_value_float_number (value)) + { + return; + } - ecma_lit_storage_item_t *string_list_p = JERRY_CONTEXT (string_list_first_p); + ecma_value_t *iterator_p = ecma_collection_iterator_init (lit_pool_p); - while (string_list_p != NULL) + while (iterator_p != NULL) { - for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++) + /* Strings / numbers are direct strings or stored in the literal storage. + * Therefore direct comparison is enough to find the same strings / numbers. */ + if (*iterator_p == value) { - if (string_list_p->values[i] != JMEM_CP_NULL) - { - ecma_string_t *string_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, - string_list_p->values[i]); - - lit_table_size += (uint32_t) JERRY_ALIGNUP (sizeof (uint16_t) + ecma_string_get_size (string_p), - JERRY_SNAPSHOT_LITERAL_ALIGNMENT); - total_count++; - } + return; } - string_list_p = JMEM_CP_GET_POINTER (ecma_lit_storage_item_t, string_list_p->next_cp); + iterator_p = ecma_collection_iterator_next (iterator_p); } - uint32_t number_offset = lit_table_size; + ecma_append_to_values_collection (lit_pool_p, value, ECMA_COLLECTION_NO_COPY); +} /* ecma_save_literals_append_value */ - ecma_lit_storage_item_t *number_list_p = JERRY_CONTEXT (number_list_first_p); +/** + * Add names from a byte-code data to a list. + */ +void +ecma_save_literals_add_compiled_code (const ecma_compiled_code_t *compiled_code_p, /**< byte-code data */ + ecma_collection_header_t *lit_pool_p) /**< list of known values */ +{ + ecma_value_t *literal_p; + uint32_t argument_end = 0; + uint32_t register_end; + uint32_t const_literal_end; + uint32_t literal_end; - while (number_list_p != NULL) + JERRY_ASSERT (compiled_code_p->status_flags & CBC_CODE_FLAGS_FUNCTION); + + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { - for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++) + cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) compiled_code_p; + uint8_t *byte_p = (uint8_t *) compiled_code_p; + + literal_p = (ecma_value_t *) (byte_p + sizeof (cbc_uint16_arguments_t)); + register_end = args_p->register_end; + const_literal_end = args_p->const_literal_end - register_end; + literal_end = args_p->literal_end - register_end; + + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED) { - if (number_list_p->values[i] != JMEM_CP_NULL) - { - lit_table_size += (uint32_t) sizeof (ecma_number_t); - total_count++; - } + argument_end = args_p->argument_end; } + } + else + { + cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) compiled_code_p; + uint8_t *byte_p = (uint8_t *) compiled_code_p; - number_list_p = JMEM_CP_GET_POINTER (ecma_lit_storage_item_t, number_list_p->next_cp); + literal_p = (ecma_value_t *) (byte_p + sizeof (cbc_uint8_arguments_t)); + register_end = args_p->register_end; + const_literal_end = args_p->const_literal_end - register_end; + literal_end = args_p->literal_end - register_end; + + if (compiled_code_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED) + { + argument_end = args_p->argument_end; + } } - /* Check whether enough space is available. */ - if (*in_out_buffer_offset_p + lit_table_size > buffer_size) + for (uint32_t i = 0; i < argument_end; i++) { - return false; + ecma_save_literals_append_value (literal_p[i], lit_pool_p); } - /* Check whether the maximum literal table size is reached. */ - if ((lit_table_size >> JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG) > UINT16_MAX) + for (uint32_t i = 0; i < const_literal_end; i++) { - return false; + ecma_save_literals_append_value (literal_p[i], lit_pool_p); } - lit_mem_to_snapshot_id_map_entry_t *map_p; + for (uint32_t i = const_literal_end; i < literal_end; i++) + { + ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, + literal_p[i]); - map_p = jmem_heap_alloc_block (total_count * sizeof (lit_mem_to_snapshot_id_map_entry_t)); + if ((bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) + && bytecode_p != compiled_code_p) + { + ecma_save_literals_add_compiled_code (bytecode_p, lit_pool_p); + } + } - /* Set return values (no error is possible from here). */ - JERRY_ASSERT ((*in_out_buffer_offset_p % sizeof (uint32_t)) == 0); - buffer_p += *in_out_buffer_offset_p / sizeof (uint32_t); - *in_out_buffer_offset_p += lit_table_size; - *out_map_p = map_p; - *out_map_len_p = total_count; + if (argument_end != 0) + { + uint8_t *byte_p = (uint8_t *) compiled_code_p; + byte_p += ((size_t) compiled_code_p->size) << JMEM_ALIGNMENT_LOG; + literal_p = ((ecma_value_t *) byte_p) - argument_end; - /* Write data into the buffer. */ + for (uint32_t i = 0; i < argument_end; i++) + { + ecma_save_literals_append_value (literal_p[i], lit_pool_p); + } + } +} /* ecma_save_literals_add_compiled_code */ - /* The zero value is reserved for NULL (no literal) - * constant so the first literal must have offset one. */ - uint32_t literal_offset = JERRY_SNAPSHOT_LITERAL_ALIGNMENT; +/** + * Save literals to specified snapshot buffer. + * + * Note: + * Frees lit_pool_p regardless of success. + * + * @return true - if save was performed successfully (i.e. buffer size is sufficient), + * false - otherwise + */ +bool +ecma_save_literals_for_snapshot (ecma_collection_header_t *lit_pool_p, /**< list of known values */ + uint32_t *buffer_p, /**< [out] output snapshot buffer */ + size_t buffer_size, /**< size of the buffer */ + size_t *in_out_buffer_offset_p, /**< [in,out] write position in the buffer */ + lit_mem_to_snapshot_id_map_entry_t **out_map_p, /**< [out] map from literal identifiers + * to the literal offsets + * in snapshot */ + uint32_t *out_map_len_p) /**< [out] number of literals */ +{ + if (lit_pool_p->item_count == 0) + { + *out_map_p = NULL; + *out_map_len_p = 0; + } - *buffer_p++ = number_offset; + uint32_t lit_table_size = 0; + size_t max_lit_table_size = buffer_size - *in_out_buffer_offset_p; - string_list_p = JERRY_CONTEXT (string_list_first_p); + if (max_lit_table_size > (UINT32_MAX >> JERRY_SNAPSHOT_LITERAL_SHIFT)) + { + max_lit_table_size = (UINT32_MAX >> JERRY_SNAPSHOT_LITERAL_SHIFT); + } - uint16_t *destination_p = (uint16_t *) buffer_p; + ecma_value_t *iterator_p = ecma_collection_iterator_init (lit_pool_p); - while (string_list_p != NULL) + /* Compute the size of the literal pool. */ + while (iterator_p != NULL) { - for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++) + if (ecma_is_value_float_number (*iterator_p)) { - if (string_list_p->values[i] != JMEM_CP_NULL) - { - map_p->literal_id = string_list_p->values[i]; - map_p->literal_offset = (jmem_cpointer_t) (literal_offset >> JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG); - map_p++; + lit_table_size += (uint32_t) sizeof (ecma_number_t); + } + else + { + ecma_string_t *string_p = ecma_get_string_from_value (*iterator_p); - ecma_string_t *string_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, - string_list_p->values[i]); + lit_table_size += (uint32_t) JERRY_ALIGNUP (sizeof (uint16_t) + ecma_string_get_size (string_p), + JERRY_SNAPSHOT_LITERAL_ALIGNMENT); + } + + /* Check whether enough space is available and the maximum size is not reached. */ + if (lit_table_size > max_lit_table_size) + { + ecma_free_values_collection (lit_pool_p, ECMA_COLLECTION_NO_COPY); + return false; + } - ecma_length_t length = ecma_string_get_size (string_p); + iterator_p = ecma_collection_iterator_next (iterator_p); + } - *destination_p = (uint16_t) length; - ecma_string_to_utf8_bytes (string_p, ((lit_utf8_byte_t *) destination_p) + sizeof (uint16_t), length); + lit_mem_to_snapshot_id_map_entry_t *map_p; + ecma_length_t total_count = lit_pool_p->item_count; - length = JERRY_ALIGNUP (sizeof (uint16_t) + length, - JERRY_SNAPSHOT_LITERAL_ALIGNMENT); + map_p = jmem_heap_alloc_block (total_count * sizeof (lit_mem_to_snapshot_id_map_entry_t)); - JERRY_ASSERT ((length % sizeof (uint16_t)) == 0); - destination_p += length / sizeof (uint16_t); - literal_offset += length; - } - } + /* Set return values (no error is possible from here). */ + JERRY_ASSERT ((*in_out_buffer_offset_p % sizeof (uint32_t)) == 0); - string_list_p = JMEM_CP_GET_POINTER (ecma_lit_storage_item_t, string_list_p->next_cp); - } + uint8_t *destination_p = (uint8_t *) (buffer_p + (*in_out_buffer_offset_p / sizeof (uint32_t))); + uint32_t literal_offset = 0; - number_list_p = JERRY_CONTEXT (number_list_first_p); + *in_out_buffer_offset_p += lit_table_size; + *out_map_p = map_p; + *out_map_len_p = total_count; - while (number_list_p != NULL) + iterator_p = ecma_collection_iterator_init (lit_pool_p); + + /* Generate literal pool data. */ + while (iterator_p != NULL) { - for (int i = 0; i < ECMA_LIT_STORAGE_VALUE_COUNT; i++) + map_p->literal_id = *iterator_p; + map_p->literal_offset = (literal_offset << JERRY_SNAPSHOT_LITERAL_SHIFT) | ECMA_TYPE_SNAPSHOT_OFFSET; + + ecma_length_t length; + + if (ecma_is_value_float_number (*iterator_p)) { - if (number_list_p->values[i] != JMEM_CP_NULL) - { - map_p->literal_id = number_list_p->values[i]; - map_p->literal_offset = (jmem_cpointer_t) (literal_offset >> JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG); - map_p++; + map_p->literal_offset |= JERRY_SNAPSHOT_LITERAL_IS_NUMBER; - ecma_string_t *value_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, - number_list_p->values[i]); + ecma_number_t num = ecma_get_float_from_value (*iterator_p); + memcpy (destination_p, &num, sizeof (ecma_number_t)); - JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (value_p) == ECMA_STRING_LITERAL_NUMBER); + length = JERRY_ALIGNUP (sizeof (ecma_number_t), JERRY_SNAPSHOT_LITERAL_ALIGNMENT); + } + else + { + ecma_string_t *string_p = ecma_get_string_from_value (*iterator_p); + length = ecma_string_get_size (string_p); - ecma_number_t num = ecma_get_number_from_value (value_p->u.lit_number); - memcpy (destination_p, &num, sizeof (ecma_number_t)); + *(uint16_t *) destination_p = (uint16_t) length; - ecma_length_t length = JERRY_ALIGNUP (sizeof (ecma_number_t), - JERRY_SNAPSHOT_LITERAL_ALIGNMENT); + ecma_string_to_utf8_bytes (string_p, destination_p + sizeof (uint16_t), length); - JERRY_ASSERT ((length % sizeof (uint16_t)) == 0); - destination_p += length / sizeof (uint16_t); - literal_offset += length; - } + length = JERRY_ALIGNUP (sizeof (uint16_t) + length, JERRY_SNAPSHOT_LITERAL_ALIGNMENT); } - number_list_p = JMEM_CP_GET_POINTER (ecma_lit_storage_item_t, number_list_p->next_cp); + JERRY_ASSERT ((length % sizeof (uint16_t)) == 0); + destination_p += length; + literal_offset += length; + + iterator_p = ecma_collection_iterator_next (iterator_p); + map_p++; } + ecma_free_values_collection (lit_pool_p, ECMA_COLLECTION_NO_COPY); return true; } /* ecma_save_literals_for_snapshot */ @@ -381,38 +464,20 @@ ecma_save_literals_for_snapshot (uint32_t *buffer_p, /**< [out] output snapshot #if defined JERRY_ENABLE_SNAPSHOT_EXEC || defined JERRY_ENABLE_SNAPSHOT_SAVE -/** - * Computes the base pointer of the literals and starting offset of numbers. - * - * @return the base pointer of the literals - */ -const uint8_t * -ecma_snapshot_get_literals_base (uint32_t *buffer_p, /**< literal buffer start */ - const uint8_t **number_base_p) /**< [out] literal number start */ -{ - *number_base_p = ((uint8_t *) buffer_p) + buffer_p[0]; - - return ((uint8_t *) (buffer_p + 1)) - JERRY_SNAPSHOT_LITERAL_ALIGNMENT; -} /* ecma_snapshot_get_literals_base */ - /** * Get the compressed pointer of a given literal. * * @return literal compressed pointer */ -jmem_cpointer_t +ecma_value_t ecma_snapshot_get_literal (const uint8_t *literal_base_p, /**< literal start */ - const uint8_t *number_base_p, /**< literal number start */ - jmem_cpointer_t offset) + ecma_value_t literal_value) /**< string / number offset */ { - if (offset == 0) - { - return ECMA_NULL_POINTER; - } + JERRY_ASSERT ((literal_value & ECMA_VALUE_TYPE_MASK) == ECMA_TYPE_SNAPSHOT_OFFSET); - const uint8_t *literal_p = literal_base_p + (((size_t) offset) << JERRY_SNAPSHOT_LITERAL_ALIGNMENT_LOG); + const uint8_t *literal_p = literal_base_p + (literal_value >> JERRY_SNAPSHOT_LITERAL_SHIFT); - if (literal_p >= number_base_p) + if (literal_value & JERRY_SNAPSHOT_LITERAL_IS_NUMBER) { ecma_number_t num; memcpy (&num, literal_p, sizeof (ecma_number_t)); diff --git a/deps/jerry/jerry-core/ecma/base/ecma-literal-storage.h b/deps/jerry/jerry-core/ecma/base/ecma-literal-storage.h index ec64691..814da60 100644 --- a/deps/jerry/jerry-core/ecma/base/ecma-literal-storage.h +++ b/deps/jerry/jerry-core/ecma/base/ecma-literal-storage.h @@ -27,32 +27,34 @@ * @{ */ +#ifdef JERRY_ENABLE_SNAPSHOT_SAVE /** * Snapshot literal - offset map */ typedef struct { - jmem_cpointer_t literal_id; /**< literal id */ - jmem_cpointer_t literal_offset; /**< literal offset */ + ecma_value_t literal_id; /**< literal id */ + ecma_value_t literal_offset; /**< literal offset */ } lit_mem_to_snapshot_id_map_entry_t; +#endif /* JERRY_ENABLE_SNAPSHOT_SAVE */ void ecma_finalize_lit_storage (void); -jmem_cpointer_t ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, lit_utf8_size_t size); -jmem_cpointer_t ecma_find_or_create_literal_number (ecma_number_t number_arg); +ecma_value_t ecma_find_or_create_literal_string (const lit_utf8_byte_t *chars_p, lit_utf8_size_t size); +ecma_value_t ecma_find_or_create_literal_number (ecma_number_t number_arg); #ifdef JERRY_ENABLE_SNAPSHOT_SAVE -bool -ecma_save_literals_for_snapshot (uint32_t *buffer_p, size_t buffer_size, size_t *in_out_buffer_offset_p, - lit_mem_to_snapshot_id_map_entry_t **out_map_p, uint32_t *out_map_len_p); +void ecma_save_literals_append_value (ecma_value_t value, ecma_collection_header_t *lit_pool_p); +void ecma_save_literals_add_compiled_code (const ecma_compiled_code_t *compiled_code_p, + ecma_collection_header_t *lit_pool_p); +bool ecma_save_literals_for_snapshot (ecma_collection_header_t *lit_pool_p, uint32_t *buffer_p, size_t buffer_size, + size_t *in_out_buffer_offset_p, lit_mem_to_snapshot_id_map_entry_t **out_map_p, + uint32_t *out_map_len_p); #endif /* JERRY_ENABLE_SNAPSHOT_SAVE */ #if defined JERRY_ENABLE_SNAPSHOT_EXEC || defined JERRY_ENABLE_SNAPSHOT_SAVE -const uint8_t * -ecma_snapshot_get_literals_base (uint32_t *buffer_p, const uint8_t **number_base_p); -jmem_cpointer_t -ecma_snapshot_get_literal (const uint8_t *literal_base_p, const uint8_t *number_base_p, - jmem_cpointer_t offset); +ecma_value_t +ecma_snapshot_get_literal (const uint8_t *literal_base_p, ecma_value_t literal_value); #endif /* JERRY_ENABLE_SNAPSHOT_EXEC || JERRY_ENABLE_SNAPSHOT_SAVE */ /** diff --git a/deps/jerry/jerry-core/ecma/base/ecma-property-hashmap.c b/deps/jerry/jerry-core/ecma/base/ecma-property-hashmap.c index d9c0047..aaff483 100644 --- a/deps/jerry/jerry-core/ecma/base/ecma-property-hashmap.c +++ b/deps/jerry/jerry-core/ecma/base/ecma-property-hashmap.c @@ -134,7 +134,7 @@ ecma_property_hashmap_create (ecma_object_t *object_p) /**< object */ memset (hashmap_p, 0, total_size); hashmap_p->header.types[0] = ECMA_PROPERTY_TYPE_HASHMAP; - hashmap_p->header.types[1] = ECMA_PROPERTY_TYPE_DELETED; + hashmap_p->header.types[1] = 0; hashmap_p->header.next_property_cp = object_p->property_list_or_bound_object_cp; hashmap_p->max_property_count = max_property_count; hashmap_p->null_count = max_property_count - named_property_count; @@ -146,17 +146,10 @@ ecma_property_hashmap_create (ecma_object_t *object_p) /**< object */ uint8_t shift_counter = 0; - if (max_property_count <= LIT_STRING_HASH_LIMIT) + while (max_property_count > LIT_STRING_HASH_LIMIT) { - hashmap_p->header.types[1] = 0; - } - else - { - while (max_property_count > LIT_STRING_HASH_LIMIT) - { - shift_counter++; - max_property_count >>= 1; - } + shift_counter++; + max_property_count >>= 1; } hashmap_p->header.types[1] = shift_counter; @@ -275,7 +268,7 @@ ecma_property_hashmap_insert (ecma_object_t *object_p, /**< object */ JERRY_ASSERT (property_index < ECMA_PROPERTY_PAIR_ITEM_COUNT); - uint32_t entry_index = name_p->hash; + uint32_t entry_index = ecma_string_hash (name_p); uint32_t step = ecma_property_hashmap_steps[entry_index & (ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS - 1)]; uint32_t mask = hashmap_p->max_property_count - 1; @@ -471,7 +464,7 @@ ecma_property_hashmap_find (ecma_property_hashmap_t *hashmap_p, /**< hashmap */ } #endif /* !JERRY_NDEBUG */ - uint32_t entry_index = name_p->hash; + uint32_t entry_index = ecma_string_hash (name_p); uint32_t step = ecma_property_hashmap_steps[entry_index & (ECMA_PROPERTY_HASHMAP_NUMBER_OF_STEPS - 1)]; uint32_t mask = hashmap_p->max_property_count - 1; jmem_cpointer_t *pair_list_p = (jmem_cpointer_t *) (hashmap_p + 1); @@ -492,6 +485,64 @@ ecma_property_hashmap_find (ecma_property_hashmap_t *hashmap_p, /**< hashmap */ uint32_t start_entry_index = entry_index; #endif /* !JERRY_NDEBUG */ + if (ECMA_IS_DIRECT_STRING (name_p)) + { + ecma_property_t prop_name_type = (ecma_property_t) ECMA_GET_DIRECT_STRING_TYPE (name_p); + jmem_cpointer_t property_name_cp = (jmem_cpointer_t) ECMA_GET_DIRECT_STRING_VALUE (name_p); + + JERRY_ASSERT (prop_name_type > 0); + + while (true) + { + if (pair_list_p[entry_index] != ECMA_NULL_POINTER) + { + size_t offset = 0; + if (ECMA_PROPERTY_HASHMAP_GET_BIT (bits_p, entry_index)) + { + offset = 1; + } + + ecma_property_pair_t *property_pair_p = ECMA_GET_NON_NULL_POINTER (ecma_property_pair_t, + pair_list_p[entry_index]); + + ecma_property_t *property_p = property_pair_p->header.types + offset; + + JERRY_ASSERT (ECMA_PROPERTY_IS_NAMED_PROPERTY (*property_p)); + + if (property_pair_p->names_cp[offset] == property_name_cp + && ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == prop_name_type) + { +#ifndef JERRY_NDEBUG + JERRY_ASSERT (property_found); +#endif /* !JERRY_NDEBUG */ + + *property_real_name_cp = property_name_cp; + return property_p; + } + } + else + { + if (!ECMA_PROPERTY_HASHMAP_GET_BIT (bits_p, entry_index)) + { +#ifndef JERRY_NDEBUG + JERRY_ASSERT (!property_found); +#endif /* !JERRY_NDEBUG */ + + return NULL; + } + /* Otherwise it is a deleted entry. */ + } + + entry_index = (entry_index + step) & mask; + +#ifndef JERRY_NDEBUG + JERRY_ASSERT (entry_index != start_entry_index); +#endif /* !JERRY_NDEBUG */ + } + + JERRY_UNREACHABLE (); + } + while (true) { if (pair_list_p[entry_index] != ECMA_NULL_POINTER) @@ -509,15 +560,19 @@ ecma_property_hashmap_find (ecma_property_hashmap_t *hashmap_p, /**< hashmap */ JERRY_ASSERT (ECMA_PROPERTY_IS_NAMED_PROPERTY (*property_p)); - if (ecma_string_compare_to_property_name (*property_p, - property_pair_p->names_cp[offset], - name_p)) + if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_PTR) { + ecma_string_t *prop_name_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, property_pair_p->names_cp[offset]); + + if (ecma_compare_ecma_non_direct_strings (prop_name_p, name_p)) + { #ifndef JERRY_NDEBUG - JERRY_ASSERT (property_found); + JERRY_ASSERT (property_found); #endif /* !JERRY_NDEBUG */ - *property_real_name_cp = property_pair_p->names_cp[offset]; - return property_p; + + *property_real_name_cp = property_pair_p->names_cp[offset]; + return property_p; + } } } else @@ -527,6 +582,7 @@ ecma_property_hashmap_find (ecma_property_hashmap_t *hashmap_p, /**< hashmap */ #ifndef JERRY_NDEBUG JERRY_ASSERT (!property_found); #endif /* !JERRY_NDEBUG */ + return NULL; } /* Otherwise it is a deleted entry. */ diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c index 6f7d794..8318005 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-array-prototype.c @@ -59,17 +59,14 @@ ecma_builtin_array_prototype_helper_set_length (ecma_object_t *object, /**< obje ecma_number_t length) /**< new length */ { ecma_value_t ret_value; - ecma_string_t *magic_string_length_p = ecma_new_ecma_length_string (); ecma_value_t length_value = ecma_make_number_value (length); ret_value = ecma_op_object_put (object, - magic_string_length_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH), length_value, true), ecma_free_value (length_value); - ecma_deref_ecma_string (magic_string_length_p); - return ret_value; } /* ecma_builtin_array_prototype_helper_set_length */ @@ -155,8 +152,7 @@ ecma_builtin_array_prototype_object_to_locale_string (const ecma_value_t this_ar /* 5. */ if (length == 0) { - ecma_string_t *empty_string_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); - ret_value = ecma_make_string_value (empty_string_p); + ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); } else { @@ -282,13 +278,10 @@ ecma_op_array_get_separator_string (ecma_value_t separator) /**< possible separa { if (ecma_is_value_undefined (separator)) { - ecma_string_t *comma_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_COMMA_CHAR); - return ecma_make_string_value (comma_string_p); - } - else - { - return ecma_op_to_string (separator); + return ecma_make_magic_string_value (LIT_MAGIC_STRING_COMMA_CHAR); } + + return ecma_op_to_string (separator); } /* ecma_op_array_get_separator_string */ /** @@ -314,8 +307,7 @@ ecma_op_array_get_to_string_at_index (ecma_object_t *obj_p, /**< this object */ if (ecma_is_value_undefined (index_value) || ecma_is_value_null (index_value)) { - ecma_string_t *empty_string_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); - ret_value = ecma_make_string_value (empty_string_p); + ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); } else { @@ -371,8 +363,7 @@ ecma_builtin_array_prototype_join (const ecma_value_t this_arg, /**< this argume if (length == 0) { /* 6. */ - ecma_string_t *empty_string_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); - ret_value = ecma_make_string_value (empty_string_p); + ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); } else { @@ -709,10 +700,10 @@ ecma_builtin_array_prototype_object_shift (ecma_value_t this_arg) /**< this argu } else { - ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (0); - /* 5. */ - ECMA_TRY_CATCH (first_value, ecma_op_object_get (obj_p, index_str_p), ret_value); + ECMA_TRY_CATCH (first_value, + ecma_op_object_get (obj_p, ecma_get_ecma_string_from_uint32 (0)), + ret_value); /* 6. and 7. */ for (uint32_t k = 1; k < len && ecma_is_value_empty (ret_value); k++) @@ -766,7 +757,6 @@ ecma_builtin_array_prototype_object_shift (ecma_value_t this_arg) /**< this argu } ECMA_FINALIZE (first_value); - ecma_deref_ecma_string (index_str_p); } ECMA_OP_TO_NUMBER_FINALIZE (len_number); @@ -1180,14 +1170,13 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum uint32_t defined_prop_count = 0; uint32_t copied_num = 0; - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, array_index_props_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (array_index_props_p); /* Count properties with name that is array index less than len */ - while (ecma_collection_iterator_next (&iter) - && ecma_is_value_empty (ret_value)) + while (ecma_value_p != NULL && ecma_is_value_empty (ret_value)) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); uint32_t index = ecma_string_get_array_index (property_name_p); JERRY_ASSERT (index != ECMA_STRING_NOT_ARRAY_INDEX); @@ -1200,13 +1189,13 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum JMEM_DEFINE_LOCAL_ARRAY (values_buffer, defined_prop_count, ecma_value_t); - ecma_collection_iterator_init (&iter, array_index_props_p); + ecma_value_p = ecma_collection_iterator_init (array_index_props_p); /* Copy unsorted array into a native c array. */ - while (ecma_collection_iterator_next (&iter) - && ecma_is_value_empty (ret_value)) + while (ecma_value_p != NULL && ecma_is_value_empty (ret_value)) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); uint32_t index = ecma_string_get_array_index (property_name_p); JERRY_ASSERT (index != ECMA_STRING_NOT_ARRAY_INDEX); @@ -1260,12 +1249,12 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum /* Undefined properties should be in the back of the array. */ - ecma_collection_iterator_init (&iter, array_index_props_p); + ecma_value_p = ecma_collection_iterator_init (array_index_props_p); - while (ecma_collection_iterator_next (&iter) - && ecma_is_value_empty (ret_value)) + while (ecma_value_p != NULL && ecma_is_value_empty (ret_value)) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); uint32_t index = ecma_string_get_array_index (property_name_p); JERRY_ASSERT (index != ECMA_STRING_NOT_ARRAY_INDEX); @@ -1277,7 +1266,7 @@ ecma_builtin_array_prototype_object_sort (ecma_value_t this_arg, /**< this argum } } - ecma_free_values_collection (array_index_props_p, true); + ecma_free_values_collection (array_index_props_p, 0); if (ecma_is_value_empty (ret_value)) { @@ -1902,19 +1891,33 @@ ecma_builtin_array_prototype_object_last_index_of (ecma_value_t this_arg, /**< t } /* ecma_builtin_array_prototype_object_last_index_of */ /** - * The Array.prototype object's 'every' routine - * - * See also: - * ECMA-262 v5, 15.4.4.16 + * Type of array routine. + */ +typedef enum +{ + ARRAY_ROUTINE_EVERY, /**< Array.every: ECMA-262 v5, 15.4.4.16 */ + ARRAY_ROUTINE_SOME, /**< Array.some: ECMA-262 v5, 15.4.4.17 */ + ARRAY_ROUTINE_FOREACH, /**< Array.forEach: ECMA-262 v5, 15.4.4.18 */ + ARRAY_ROUTINE__COUNT /**< count of the modes */ +} array_routine_mode; + +/** + * Applies the provided function to each element of the array as long as + * the return value stays empty. The common function for 'every', 'some' + * and 'forEach' of the Array prototype. * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_array_prototype_object_every (ecma_value_t this_arg, /**< this argument */ - ecma_value_t arg1, /**< callbackfn */ - ecma_value_t arg2) /**< thisArg */ +ecma_builtin_array_apply (ecma_value_t this_arg, /**< this argument */ + ecma_value_t arg1, /**< callbackfn */ + ecma_value_t arg2, /**< thisArg */ + array_routine_mode mode) /**< array routine mode */ + { + JERRY_ASSERT (mode < ARRAY_ROUTINE__COUNT); + ecma_value_t ret_value = ECMA_VALUE_EMPTY; /* 1. */ @@ -1969,10 +1972,14 @@ ecma_builtin_array_prototype_object_every (ecma_value_t this_arg, /**< this argu ECMA_TRY_CATCH (call_value, ecma_op_function_call (func_object_p, arg2, call_args, 3), ret_value); /* 7.c.iii */ - if (!ecma_op_to_boolean (call_value)) + if (mode == ARRAY_ROUTINE_EVERY && !ecma_op_to_boolean (call_value)) { ret_value = ECMA_VALUE_FALSE; } + else if (mode == ARRAY_ROUTINE_SOME && ecma_op_to_boolean (call_value)) + { + ret_value = ECMA_VALUE_TRUE; + } ECMA_FINALIZE (call_value); } @@ -1984,10 +1991,21 @@ ecma_builtin_array_prototype_object_every (ecma_value_t this_arg, /**< this argu ecma_free_value (to_object_comp); + /* 8. */ if (ecma_is_value_empty (ret_value)) { - /* 8. */ - ret_value = ECMA_VALUE_TRUE; + if (mode == ARRAY_ROUTINE_EVERY) + { + ret_value = ECMA_VALUE_TRUE; + } + else if (mode == ARRAY_ROUTINE_SOME) + { + ret_value = ECMA_VALUE_FALSE; + } + else + { + ret_value = ECMA_VALUE_UNDEFINED; + } } } @@ -1996,6 +2014,23 @@ ecma_builtin_array_prototype_object_every (ecma_value_t this_arg, /**< this argu ECMA_FINALIZE (obj_this); return ret_value; +} /* ecma_builtin_array_apply */ + +/** + * The Array.prototype object's 'every' routine + * + * See also: + * ECMA-262 v5, 15.4.4.16 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_array_prototype_object_every (ecma_value_t this_arg, /**< this argument */ + ecma_value_t arg1, /**< callbackfn */ + ecma_value_t arg2) /**< thisArg */ +{ + return ecma_builtin_array_apply (this_arg, arg1, arg2, ARRAY_ROUTINE_EVERY); } /* ecma_builtin_array_prototype_object_every */ /** @@ -2012,88 +2047,7 @@ ecma_builtin_array_prototype_object_some (ecma_value_t this_arg, /**< this argum ecma_value_t arg1, /**< callbackfn */ ecma_value_t arg2) /**< thisArg */ { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - - /* 1. */ - ECMA_TRY_CATCH (obj_this, - ecma_op_to_object (this_arg), - ret_value); - - ecma_object_t *obj_p = ecma_get_object_from_value (obj_this); - - /* 2. */ - ECMA_TRY_CATCH (len_value, - ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_LENGTH), - ret_value); - - ECMA_OP_TO_NUMBER_TRY_CATCH (len_number, len_value, ret_value); - - /* 3. */ - uint32_t len = ecma_number_to_uint32 (len_number); - - /* 4. */ - if (!ecma_op_is_callable (arg1)) - { - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Callback function is not callable.")); - } - else - { - ecma_value_t current_index; - ecma_object_t *func_object_p; - - /* We already checked that arg1 is callable, so it will always coerce to an object. */ - ecma_value_t to_object_comp = ecma_op_to_object (arg1); - JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (to_object_comp)); - - func_object_p = ecma_get_object_from_value (to_object_comp); - - /* 7. */ - for (uint32_t index = 0; index < len && ecma_is_value_empty (ret_value); index++) - { - /* 7.a */ - ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index); - - /* 7.c */ - ECMA_TRY_CATCH (get_value, ecma_op_object_find (obj_p, index_str_p), ret_value); - - if (ecma_is_value_found (get_value)) - { - /* 7.c.i */ - current_index = ecma_make_uint32_value (index); - - ecma_value_t call_args[] = { get_value, current_index, obj_this }; - - /* 7.c.ii */ - ECMA_TRY_CATCH (call_value, ecma_op_function_call (func_object_p, arg2, call_args, 3), ret_value); - - /* 7.c.iii */ - if (ecma_op_to_boolean (call_value)) - { - ret_value = ECMA_VALUE_TRUE; - } - - ECMA_FINALIZE (call_value); - } - - ECMA_FINALIZE (get_value); - - ecma_deref_ecma_string (index_str_p); - } - - ecma_free_value (to_object_comp); - - if (ecma_is_value_empty (ret_value)) - { - /* 8. */ - ret_value = ECMA_VALUE_FALSE; - } - } - - ECMA_OP_TO_NUMBER_FINALIZE (len_number); - ECMA_FINALIZE (len_value); - ECMA_FINALIZE (obj_this); - - return ret_value; + return ecma_builtin_array_apply (this_arg, arg1, arg2, ARRAY_ROUTINE_SOME); } /* ecma_builtin_array_prototype_object_some */ /** @@ -2110,80 +2064,7 @@ ecma_builtin_array_prototype_object_for_each (ecma_value_t this_arg, /**< this a ecma_value_t arg1, /**< callbackfn */ ecma_value_t arg2) /**< thisArg */ { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - /* 1. */ - ECMA_TRY_CATCH (obj_this, - ecma_op_to_object (this_arg), - ret_value); - - ecma_object_t *obj_p = ecma_get_object_from_value (obj_this); - - /* 2. */ - ECMA_TRY_CATCH (len_value, - ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_LENGTH), - ret_value); - - ECMA_OP_TO_NUMBER_TRY_CATCH (len_number, len_value, ret_value); - - /* 3. */ - uint32_t len = ecma_number_to_uint32 (len_number); - - /* 4. */ - if (!ecma_op_is_callable (arg1)) - { - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Callback function is not callable.")); - } - else - { - ecma_value_t current_index; - ecma_object_t *func_object_p; - - /* We already checked that arg1 is callable, so it will always coerce to an object. */ - ecma_value_t to_object_comp = ecma_op_to_object (arg1); - JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (to_object_comp)); - - func_object_p = ecma_get_object_from_value (to_object_comp); - - /* Iterate over array and call callbackfn on every element */ - for (uint32_t index = 0; index < len && ecma_is_value_empty (ret_value); index++) - { - /* 7.a */ - ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index); - - /* 7.b */ - ECMA_TRY_CATCH (current_value, ecma_op_object_find (obj_p, index_str_p), ret_value); - - if (ecma_is_value_found (current_value)) - { - /* 7.c.i */ - current_index = ecma_make_uint32_value (index); - - /* 7.c.ii */ - ecma_value_t call_args[] = {current_value, current_index, obj_this}; - ECMA_TRY_CATCH (call_value, ecma_op_function_call (func_object_p, arg2, call_args, 3), ret_value); - - ECMA_FINALIZE (call_value); - } - - ECMA_FINALIZE (current_value); - - ecma_deref_ecma_string (index_str_p); - } - - if (ecma_is_value_empty (ret_value)) - { - /* 8. */ - ret_value = ECMA_VALUE_UNDEFINED; - } - - ecma_free_value (to_object_comp); - } - - ECMA_OP_TO_NUMBER_FINALIZE (len_number); - ECMA_FINALIZE (len_value); - ECMA_FINALIZE (obj_this); - - return ret_value; + return ecma_builtin_array_apply (this_arg, arg1, arg2, ARRAY_ROUTINE_FOREACH); } /* ecma_builtin_array_prototype_object_for_each */ /** @@ -2415,18 +2296,20 @@ ecma_builtin_array_prototype_object_filter (ecma_value_t this_arg, /**< this arg } /* ecma_builtin_array_prototype_object_filter */ /** - * The Array.prototype object's 'reduce' routine + * Reduces the Array starting from left or right * * See also: - * ECMA-262 v5, 15.4.4.21 + * Array.prototype.reduce + * Array.prototype.reduceRight * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t -ecma_builtin_array_prototype_object_reduce (ecma_value_t this_arg, /**< this argument */ - const ecma_value_t args[], /**< arguments list */ - ecma_length_t args_number) /**< number of arguments */ +ecma_builtin_array_reduce_from (ecma_value_t this_arg, /**< this argument */ + const ecma_value_t args[], /**< arguments list */ + ecma_length_t args_number, /**< number of arguments */ + bool start_from_left) /**< whether the reduce starts from left or right */ { ecma_value_t ret_value = ECMA_VALUE_EMPTY; ecma_value_t callbackfn = (args_number > 0) ? args[0] : ECMA_VALUE_UNDEFINED; @@ -2460,7 +2343,6 @@ ecma_builtin_array_prototype_object_reduce (ecma_value_t this_arg, /**< this arg JERRY_ASSERT (ecma_is_value_object (callbackfn)); func_object_p = ecma_get_object_from_value (callbackfn); - ecma_value_t accumulator = ECMA_VALUE_UNDEFINED; /* 5. */ if (len_number == ECMA_NUMBER_ZERO && ecma_is_value_undefined (initial_value)) @@ -2469,8 +2351,11 @@ ecma_builtin_array_prototype_object_reduce (ecma_value_t this_arg, /**< this arg } else { + ecma_value_t accumulator = ECMA_VALUE_UNDEFINED; + /* 6. */ uint32_t index = 0; + const uint32_t last_index = len - 1; /* 7.a */ if (args_number > 1) @@ -2486,7 +2371,8 @@ ecma_builtin_array_prototype_object_reduce (ecma_value_t this_arg, /**< this arg while (!k_present && index < len && ecma_is_value_empty (ret_value)) { /* 8.b.i */ - ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index); + ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (start_from_left ? index + : last_index - index); k_present = true; /* 8.b.ii-iii */ @@ -2520,8 +2406,10 @@ ecma_builtin_array_prototype_object_reduce (ecma_value_t this_arg, /**< this arg for (; index < len && ecma_is_value_empty (ret_value); index++) { + const uint32_t corrected_index = start_from_left ? index : last_index - index; + /* 9.a */ - ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index); + ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (corrected_index); /* 9.b */ ECMA_TRY_CATCH (current_value, ecma_op_object_find (obj_p, index_str_p), ret_value); @@ -2529,7 +2417,7 @@ ecma_builtin_array_prototype_object_reduce (ecma_value_t this_arg, /**< this arg if (ecma_is_value_found (current_value)) { /* 9.c.i, 9.c.ii */ - current_index = ecma_make_uint32_value (index); + current_index = ecma_make_uint32_value (corrected_index); ecma_value_t call_args[] = {accumulator, current_value, current_index, obj_this}; ECMA_TRY_CATCH (call_value, @@ -2548,6 +2436,7 @@ ecma_builtin_array_prototype_object_reduce (ecma_value_t this_arg, /**< this arg ECMA_FINALIZE (current_value); ecma_deref_ecma_string (index_str_p); + /* 9.d in for loop */ } @@ -2555,9 +2444,9 @@ ecma_builtin_array_prototype_object_reduce (ecma_value_t this_arg, /**< this arg { ret_value = ecma_copy_value (accumulator); } - } - ecma_free_value (accumulator); + ecma_free_value (accumulator); + } } ECMA_OP_TO_NUMBER_FINALIZE (len_number); @@ -2565,6 +2454,23 @@ ecma_builtin_array_prototype_object_reduce (ecma_value_t this_arg, /**< this arg ECMA_FINALIZE (obj_this); return ret_value; +} /* ecma_builtin_array_reduce_from */ + +/** + * The Array.prototype object's 'reduce' routine + * + * See also: + * ECMA-262 v5, 15.4.4.21 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_array_prototype_object_reduce (ecma_value_t this_arg, /**< this argument */ + const ecma_value_t args[], /**< arguments list */ + ecma_length_t args_number) /**< number of arguments */ +{ + return ecma_builtin_array_reduce_from (this_arg, args, args_number, true); } /* ecma_builtin_array_prototype_object_reduce */ /** @@ -2581,144 +2487,7 @@ ecma_builtin_array_prototype_object_reduce_right (ecma_value_t this_arg, /**< th const ecma_value_t args[], /**< arguments list */ ecma_length_t args_number) /**< number of arguments */ { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - ecma_value_t callbackfn = (args_number > 0) ? args[0] : ECMA_VALUE_UNDEFINED; - ecma_value_t initial_value = (args_number > 1) ? args[1] : ECMA_VALUE_UNDEFINED; - - /* 1. */ - ECMA_TRY_CATCH (obj_this, - ecma_op_to_object (this_arg), - ret_value); - - ecma_object_t *obj_p = ecma_get_object_from_value (obj_this); - - /* 2. */ - ECMA_TRY_CATCH (len_value, - ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_LENGTH), - ret_value); - - ECMA_OP_TO_NUMBER_TRY_CATCH (len_number, len_value, ret_value); - - /* 3. */ - uint32_t len = ecma_number_to_uint32 (len_number); - - /* 4. */ - if (!ecma_op_is_callable (callbackfn)) - { - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Callback function is not callable.")); - } - else - { - ecma_object_t *func_object_p; - - JERRY_ASSERT (ecma_is_value_object (callbackfn)); - func_object_p = ecma_get_object_from_value (callbackfn); - - /* 5. */ - if (len_number == ECMA_NUMBER_ZERO && ecma_is_value_undefined (initial_value)) - { - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Initial value cannot be undefined.")); - } - else - { - ecma_value_t accumulator = ECMA_VALUE_UNDEFINED; - - /* 6. */ - int64_t index = (int64_t) len - 1; - - /* 7.a */ - if (args_number > 1) - { - accumulator = ecma_copy_value (initial_value); - } - else - { - /* 8.a */ - bool k_present = false; - - /* 8.b */ - while (!k_present && index >= 0 && ecma_is_value_empty (ret_value)) - { - /* 8.b.i */ - ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 ((uint32_t) index); - k_present = true; - - /* 8.b.ii-iii */ - ECMA_TRY_CATCH (current_value, ecma_op_object_find (obj_p, index_str_p), ret_value); - - if (ecma_is_value_found (current_value)) - { - accumulator = ecma_copy_value (current_value); - } - else - { - k_present = false; - } - - ECMA_FINALIZE (current_value); - - /* 8.b.iv */ - index--; - - ecma_deref_ecma_string (index_str_p); - } - - /* 8.c */ - if (!k_present) - { - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Missing array element.")); - } - } - /* 9. */ - ecma_value_t current_index; - - for (; index >= 0 && ecma_is_value_empty (ret_value); index--) - { - /* 9.a */ - ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 ((uint32_t) index); - - /* 9.b */ - ECMA_TRY_CATCH (current_value, ecma_op_object_find (obj_p, index_str_p), ret_value); - - if (ecma_is_value_found (current_value)) - { - /* 9.c.i, 9.c.ii */ - current_index = ecma_make_uint32_value ((uint32_t) index); - ecma_value_t call_args[] = {accumulator, current_value, current_index, obj_this}; - - ECMA_TRY_CATCH (call_value, - ecma_op_function_call (func_object_p, - ECMA_VALUE_UNDEFINED, - call_args, - 4), - ret_value); - - ecma_free_value (accumulator); - accumulator = ecma_copy_value (call_value); - - ECMA_FINALIZE (call_value); - } - - ECMA_FINALIZE (current_value); - - ecma_deref_ecma_string (index_str_p); - /* 9.d in for loop */ - } - - if (ecma_is_value_empty (ret_value)) - { - ret_value = ecma_copy_value (accumulator); - } - - ecma_free_value (accumulator); - } - } - - ECMA_OP_TO_NUMBER_FINALIZE (len_number); - ECMA_FINALIZE (len_value); - ECMA_FINALIZE (obj_this); - - return ret_value; + return ecma_builtin_array_reduce_from (this_arg, args, args_number, false); } /* ecma_builtin_array_prototype_object_reduce_right */ /** diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.c index 4195ed0..285db44 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-arraybuffer-prototype.c @@ -121,6 +121,11 @@ ecma_builtin_arraybuffer_prototype_object_slice (ecma_value_t this_arg, /**< thi ECMA_OP_TO_NUMBER_FINALIZE (start_num); + if (ret_value != ECMA_VALUE_EMPTY) + { + return ret_value; + } + JERRY_ASSERT (start <= len && end <= len); ecma_length_t new_len = (end >= start) ? (end - start) : 0; ecma_object_t *new_arraybuffer_p = ecma_arraybuffer_new_object (new_len); diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-boolean-prototype.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-boolean-prototype.c index c1d5ca9..78d3169 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-boolean-prototype.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-boolean-prototype.c @@ -62,21 +62,17 @@ ecma_builtin_boolean_prototype_object_to_string (ecma_value_t this_arg) /**< thi ecma_builtin_boolean_prototype_object_value_of (this_arg), ret_value); - ecma_string_t *ret_str_p; - if (ecma_is_value_true (value_of_ret)) { - ret_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_TRUE); + ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING_TRUE); } else { JERRY_ASSERT (ecma_is_value_boolean (value_of_ret)); - ret_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_FALSE); + ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING_FALSE); } - ret_value = ecma_make_string_value (ret_str_p); - ECMA_FINALIZE (value_of_ret); return ret_value; diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.c index c14761b..a427b2f 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-date-prototype.c @@ -192,8 +192,7 @@ ecma_builtin_date_prototype_dispatch_get (uint16_t builtin_routine_id, /**< buil { if (ecma_number_is_nan (date_num)) { - ecma_string_t *nan_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NAN); - return ecma_make_string_value (nan_str_p); + return ecma_make_magic_string_value (LIT_MAGIC_STRING_NAN); } switch (builtin_routine_id) @@ -624,8 +623,7 @@ ecma_builtin_date_prototype_dispatch_routine (uint16_t builtin_routine_id, /**< if (ecma_number_is_nan (*prim_value_p)) { - ecma_string_t *magic_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_INVALID_DATE_UL); - return ecma_make_string_value (magic_str_p); + return ecma_make_magic_string_value (LIT_MAGIC_STRING_INVALID_DATE_UL); } switch (builtin_routine_id) diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-date.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-date.c index 78603dc..440b5ce 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-date.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-date.c @@ -22,6 +22,7 @@ #include "ecma-helpers.h" #include "ecma-try-catch-macro.h" #include "lit-char-helpers.h" +#include "math.h" #ifndef CONFIG_DISABLE_DATE_BUILTIN @@ -437,7 +438,7 @@ static ecma_value_t ecma_builtin_date_now (ecma_value_t this_arg) /**< this argument */ { JERRY_UNUSED (this_arg); - return ecma_make_number_value (DOUBLE_TO_ECMA_NUMBER_T (jerry_port_get_current_time ())); + return ecma_make_number_value (floor (DOUBLE_TO_ECMA_NUMBER_T (jerry_port_get_current_time ()))); } /* ecma_builtin_date_now */ /** diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-error-prototype.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-error-prototype.c index d7f1177..f1f900b 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-error-prototype.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-error-prototype.c @@ -74,9 +74,7 @@ ecma_builtin_error_prototype_object_to_string (ecma_value_t this_arg) /**< this if (ecma_is_value_undefined (name_get_ret_value)) { - ecma_string_t *error_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ERROR_UL); - - name_to_str_completion = ecma_make_string_value (error_magic_string_p); + name_to_str_completion = ecma_make_magic_string_value (LIT_MAGIC_STRING_ERROR_UL); } else { @@ -97,9 +95,7 @@ ecma_builtin_error_prototype_object_to_string (ecma_value_t this_arg) /**< this if (ecma_is_value_undefined (msg_get_ret_value)) { - ecma_string_t *empty_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); - - msg_to_str_completion = ecma_make_string_value (empty_magic_string_p); + msg_to_str_completion = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); } else { diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c index 0f78cc6..78e9a48 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-function-prototype.c @@ -43,6 +43,11 @@ * @{ */ +/** + * Maximum number of arguments for an apply function. + */ +#define ECMA_FUNCTION_APPLY_ARGUMENT_COUNT_LIMIT 65535 + /** * The Function.prototype object's 'toString' routine * @@ -63,8 +68,7 @@ ecma_builtin_function_prototype_object_to_string (ecma_value_t this_arg) /**< th } else { - ecma_string_t *function_to_string_p = ecma_get_magic_string (LIT_MAGIC_STRING__FUNCTION_TO_STRING); - ret_value = ecma_make_string_value (function_to_string_p); + ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__FUNCTION_TO_STRING); } return ret_value; } /* ecma_builtin_function_prototype_object_to_string */ @@ -111,57 +115,68 @@ ecma_builtin_function_prototype_object_apply (ecma_value_t this_arg, /**< this a ecma_object_t *obj_p = ecma_get_object_from_value (arg2); /* 4. */ - ECMA_TRY_CATCH (length_value, - ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_LENGTH), - ret_value); - - ECMA_OP_TO_NUMBER_TRY_CATCH (length_number, - length_value, - ret_value); - - /* 5. */ - const uint32_t length = ecma_number_to_uint32 (length_number); - - /* 6. */ - JMEM_DEFINE_LOCAL_ARRAY (arguments_list_p, length, ecma_value_t); - uint32_t last_index = 0; - - /* 7. */ - for (uint32_t index = 0; - index < length && ecma_is_value_empty (ret_value); - index++) + ecma_value_t length_value = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_LENGTH); + if (ECMA_IS_VALUE_ERROR (length_value)) { - ecma_string_t *curr_idx_str_p = ecma_new_ecma_string_from_uint32 (index); + return length_value; + } - ECMA_TRY_CATCH (get_value, - ecma_op_object_get (obj_p, curr_idx_str_p), - ret_value); + ecma_number_t length_number; + ecma_value_t get_result = ecma_get_number (length_value, &length_number); - arguments_list_p[index] = ecma_copy_value (get_value); - last_index = index + 1; + ecma_free_value (length_value); - ECMA_FINALIZE (get_value); - ecma_deref_ecma_string (curr_idx_str_p); + if (ECMA_IS_VALUE_ERROR (get_result)) + { + return get_result; } + JERRY_ASSERT (ecma_is_value_empty (get_result)); + + /* 5. */ + const uint32_t length = ecma_number_to_uint32 (length_number); - if (ecma_is_value_empty (ret_value)) + if (length >= ECMA_FUNCTION_APPLY_ARGUMENT_COUNT_LIMIT) { - JERRY_ASSERT (last_index == length); - ret_value = ecma_op_function_call (func_obj_p, - arg1, - arguments_list_p, - length); + ret_value = ecma_raise_range_error (ECMA_ERR_MSG ("Too many arguments declared for Function.apply().")); } - - for (uint32_t index = 0; index < last_index; index++) + else { - ecma_free_value (arguments_list_p[index]); + /* 6. */ + JMEM_DEFINE_LOCAL_ARRAY (arguments_list_p, length, ecma_value_t); + uint32_t index = 0; + + /* 7. */ + for (index = 0; index < length; index++) + { + ecma_string_t *curr_idx_str_p = ecma_new_ecma_string_from_uint32 (index); + ecma_value_t get_value = ecma_op_object_get (obj_p, curr_idx_str_p); + ecma_deref_ecma_string (curr_idx_str_p); + + if (ECMA_IS_VALUE_ERROR (get_value)) + { + ret_value = get_value; + break; + } + + arguments_list_p[index] = get_value; + } + + if (ecma_is_value_empty (ret_value)) + { + JERRY_ASSERT (index == length); + ret_value = ecma_op_function_call (func_obj_p, + arg1, + arguments_list_p, + length); + } + + for (uint32_t remove_index = 0; remove_index < index; remove_index++) + { + ecma_free_value (arguments_list_p[remove_index]); + } + + JMEM_FINALIZE_LOCAL_ARRAY (arguments_list_p); } - - JMEM_FINALIZE_LOCAL_ARRAY (arguments_list_p); - - ECMA_OP_TO_NUMBER_FINALIZE (length_number); - ECMA_FINALIZE (length_value); } } } diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-function.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-function.c index b8de78e..eed3378 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-function.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-function.c @@ -21,8 +21,12 @@ #include "ecma-function-object.h" #include "ecma-lex-env.h" #include "ecma-try-catch-macro.h" -#include "lit-magic-strings.h" #include "js-parser.h" +#include "lit-magic-strings.h" + +#ifdef JERRY_ENABLE_LINE_INFO +#include "jcontext.h" +#endif /* JERRY_ENABLE_LINE_INFO */ #define ECMA_BUILTINS_INTERNAL #include "ecma-builtins-internal.h" @@ -72,7 +76,7 @@ ecma_builtin_function_helper_get_function_arguments (const ecma_value_t *argumen if (arguments_list_len <= 1) { - return ecma_make_string_value (ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY)); + return ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); } ecma_value_t final_str = ecma_op_to_string (arguments_list_p[0]); @@ -146,7 +150,7 @@ ecma_builtin_function_dispatch_construct (const ecma_value_t *arguments_list_p, else { /* Very unlikely code path, not optimized. */ - function_body_value = ecma_make_string_value (ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY)); + function_body_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); } ecma_string_t *arguments_str_p = ecma_get_string_from_value (arguments_value); @@ -155,6 +159,10 @@ ecma_builtin_function_dispatch_construct (const ecma_value_t *arguments_list_p, ECMA_STRING_TO_UTF8_STRING (arguments_str_p, arguments_buffer_p, arguments_buffer_size); ECMA_STRING_TO_UTF8_STRING (function_body_str_p, function_body_buffer_p, function_body_buffer_size); +#ifdef JERRY_ENABLE_LINE_INFO + JERRY_CONTEXT (resource_name) = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); +#endif /* JERRY_ENABLE_LINE_INFO */ + ecma_compiled_code_t *bytecode_data_p = NULL; ecma_value_t ret_value = parser_parse_script (arguments_buffer_p, diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-json.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-json.c index f954446..d964e4d 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-json.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-helpers-json.c @@ -18,6 +18,8 @@ #include "ecma-builtin-helpers.h" #include "lit-char-helpers.h" +#ifndef CONFIG_DISABLE_JSON_BUILTIN + /** \addtogroup ecma ECMA * @{ * @@ -26,38 +28,31 @@ */ /** - * Check the object value existance in the collection. + * Check whether the object is pushed onto the occurence stack * * Used by: * - ecma_builtin_json_object step 1 * - ecma_builtin_json_array step 1 * - * @return true, if the object is already in the collection. + * @return true - if the object is pushed onto the occurence stack + * false - otherwise */ bool -ecma_has_object_value_in_collection (ecma_collection_header_t *collection_p, /**< collection */ - ecma_value_t object_value) /**< object value */ +ecma_json_has_object_in_stack (ecma_json_occurence_stack_item_t *stack_p, /**< stack */ + ecma_object_t *object_p) /**< object */ { - JERRY_ASSERT (ecma_is_value_object (object_value)); - - ecma_object_t *obj_p = ecma_get_object_from_value (object_value); - - ecma_collection_iterator_t iterator; - ecma_collection_iterator_init (&iterator, collection_p); - - while (ecma_collection_iterator_next (&iterator)) + while (stack_p != NULL) { - ecma_value_t value = *iterator.current_value_p; - ecma_object_t *current_p = ecma_get_object_from_value (value); - - if (current_p == obj_p) + if (stack_p->object_p == object_p) { return true; } + + stack_p = stack_p->next_p; } return false; -} /* ecma_has_object_value_in_collection */ +} /* ecma_json_has_object_in_stack */ /** * Check the string value existance in the collection. @@ -75,18 +70,18 @@ ecma_has_string_value_in_collection (ecma_collection_header_t *collection_p, /** ecma_string_t *string_p = ecma_get_string_from_value (string_value); - ecma_collection_iterator_t iterator; - ecma_collection_iterator_init (&iterator, collection_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (collection_p); - while (ecma_collection_iterator_next (&iterator)) + while (ecma_value_p != NULL) { - ecma_value_t value = *iterator.current_value_p; - ecma_string_t *current_p = ecma_get_string_from_value (value); + ecma_string_t *current_p = ecma_get_string_from_value (*ecma_value_p); if (ecma_compare_ecma_strings (current_p, string_p)) { return true; } + + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); } return false; @@ -111,15 +106,14 @@ ecma_builtin_helper_json_create_separated_properties (ecma_collection_header_t * { ecma_string_t *properties_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); - ecma_collection_iterator_t iterator; - ecma_collection_iterator_init (&iterator, partial_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (partial_p); bool first = true; - while (ecma_collection_iterator_next (&iterator)) + while (ecma_value_p != NULL) { - ecma_value_t name_value = *iterator.current_value_p; - ecma_string_t *current_p = ecma_get_string_from_value (name_value); + ecma_string_t *current_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); if (likely (!first)) { @@ -215,7 +209,6 @@ ecma_builtin_helper_json_create_non_formatted_json (lit_utf8_byte_t left_bracket /* 10.a.i */ properties_str_p = ecma_builtin_helper_json_create_separated_properties (partial_p, comma_str_p); - ecma_deref_ecma_string (comma_str_p); /* 10.a.ii */ ecma_string_t *result_str_p = ecma_new_ecma_string_from_code_unit (left_bracket); @@ -230,6 +223,8 @@ ecma_builtin_helper_json_create_non_formatted_json (lit_utf8_byte_t left_bracket return ecma_make_string_value (result_str_p); } /* ecma_builtin_helper_json_create_non_formatted_json */ +#endif /* !CONFIG_DISABLE_JSON_BUILTIN */ + /** * @} * @} diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c index a1bcca1..b14588a 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.c @@ -131,8 +131,7 @@ ecma_builtin_helper_get_to_locale_string_at_index (ecma_object_t *obj_p, /**< th if (ecma_is_value_undefined (index_value) || ecma_is_value_null (index_value)) { - ecma_string_t *return_string_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); - ret_value = ecma_make_string_value (return_string_p); + ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); } else { @@ -203,16 +202,15 @@ ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /**< object */ only_enumerable_properties, false); - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, props_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); ecma_value_t completion = ecma_builtin_helper_def_prop (new_array_p, index_string_p, - *iter.current_value_p, + *ecma_value_p, true, /* Writable */ true, /* Enumerable */ true, /* Configurable */ @@ -222,10 +220,12 @@ ecma_builtin_helper_object_get_properties (ecma_object_t *obj_p, /**< object */ ecma_deref_ecma_string (index_string_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); + index++; } - ecma_free_values_collection (props_p, true); + ecma_free_values_collection (props_p, 0); return new_array; } /* ecma_builtin_helper_object_get_properties */ diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h index a86d476..1e14a86 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-helpers.h @@ -122,6 +122,15 @@ ecma_value_t ecma_date_value_to_time_string (ecma_number_t datetime_number); /* ecma-builtin-helper-json.c */ +/** + * Occurence stack item of JSON.stringify() + */ +typedef struct struct_ecma_json_occurence_stack_item_t +{ + struct struct_ecma_json_occurence_stack_item_t *next_p; /**< next stack item */ + ecma_object_t *object_p; /**< current object */ +} ecma_json_occurence_stack_item_t; + /** * Context for JSON.stringify() */ @@ -131,7 +140,7 @@ typedef struct ecma_collection_header_t *property_list_p; /** Collection for traversing objects. */ - ecma_collection_header_t *occurence_stack_p; + ecma_json_occurence_stack_item_t *occurence_stack_last_p; /** The actual indentation text. */ ecma_string_t *indent_str_p; @@ -143,7 +152,10 @@ typedef struct ecma_object_t *replacer_function_p; } ecma_json_stringify_context_t; -bool ecma_has_object_value_in_collection (ecma_collection_header_t *collection_p, ecma_value_t object_value); +ecma_value_t ecma_builtin_json_parse_buffer (const lit_utf8_byte_t * str_start_p, + lit_utf8_size_t string_size); +ecma_value_t ecma_builtin_json_string_from_object (const ecma_value_t arg1); +bool ecma_json_has_object_in_stack (ecma_json_occurence_stack_item_t *stack_p, ecma_object_t *object_p); bool ecma_has_string_value_in_collection (ecma_collection_header_t *collection_p, ecma_value_t string_value); ecma_string_t * diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-json.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-json.c index eafe6fe..d1cd028 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-json.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-json.c @@ -40,6 +40,11 @@ #define BUILTIN_UNDERSCORED_ID json #include "ecma-builtin-internal-routines-template.inc.h" +/** + * The number of expected hexidecimal characters in a hex escape sequence + */ +#define ECMA_JSON_HEX_ESCAPE_SEQUENCE_LENGTH (4) + /** \addtogroup ecma ECMA * @{ * @@ -161,6 +166,12 @@ ecma_builtin_json_parse_string (ecma_json_token_t *token_p) /**< token argument current_p++; has_escape_sequence = true; + /* If there is an escape sequence but there's no escapable character just return */ + if (current_p >= end_p) + { + return; + } + switch (*current_p) { case LIT_CHAR_DOUBLE_QUOTE: @@ -176,14 +187,18 @@ ecma_builtin_json_parse_string (ecma_json_token_t *token_p) /**< token argument } case LIT_CHAR_LOWERCASE_U: { - ecma_char_t code_unit; + if ((end_p - current_p <= ECMA_JSON_HEX_ESCAPE_SEQUENCE_LENGTH)) + { + return; + } - if (!(lit_read_code_unit_from_hex (current_p + 1, 4, &code_unit))) + ecma_char_t code_unit; + if (!(lit_read_code_unit_from_hex (current_p + 1, ECMA_JSON_HEX_ESCAPE_SEQUENCE_LENGTH, &code_unit))) { return; } - current_p += 5; + current_p += ECMA_JSON_HEX_ESCAPE_SEQUENCE_LENGTH + 1; lit_utf8_byte_t char_buffer[LIT_UTF8_MAX_BYTES_IN_CODE_UNIT]; buffer_size += lit_code_unit_to_utf8 (code_unit, char_buffer); @@ -253,9 +268,9 @@ ecma_builtin_json_parse_string (ecma_json_token_t *token_p) /**< token argument { ecma_char_t code_unit; - lit_read_code_unit_from_hex (current_p + 1, 4, &code_unit); + lit_read_code_unit_from_hex (current_p + 1, ECMA_JSON_HEX_ESCAPE_SEQUENCE_LENGTH, &code_unit); - current_p += 5; + current_p += ECMA_JSON_HEX_ESCAPE_SEQUENCE_LENGTH + 1; write_p += lit_code_unit_to_utf8 (code_unit, write_p); continue; } @@ -728,13 +743,12 @@ ecma_builtin_json_walk (ecma_object_t *reviver_p, /**< reviver function */ ecma_collection_header_t *props_p = ecma_op_object_get_property_names (object_p, false, true, false); - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, props_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p); - while (ecma_collection_iterator_next (&iter) - && ecma_is_value_empty (ret_value)) + while (ecma_value_p != NULL && ecma_is_value_empty (ret_value)) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); ECMA_TRY_CATCH (value_walk, ecma_builtin_json_walk (reviver_p, @@ -763,7 +777,7 @@ ecma_builtin_json_walk (ecma_object_t *reviver_p, /**< reviver function */ ECMA_FINALIZE (value_walk); } - ecma_free_values_collection (props_p, true); + ecma_free_values_collection (props_p, 0); } if (ecma_is_value_empty (ret_value)) @@ -791,6 +805,35 @@ ecma_builtin_json_walk (ecma_object_t *reviver_p, /**< reviver function */ return ret_value; } /* ecma_builtin_json_walk */ +/** + * Function to set a string token from the given arguments, fills its fields and advances the string pointer. + * + * @return ecma_value_t containing an object or an error massage + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_builtin_json_parse_buffer (const lit_utf8_byte_t * str_start_p, /**< String to parse */ + lit_utf8_size_t string_size) /**< size of the string */ +{ + ecma_json_token_t token; + token.current_p = str_start_p; + token.end_p = str_start_p + string_size; + + ecma_value_t final_result = ecma_builtin_json_parse_value (&token); + + if (!ecma_is_value_undefined (final_result)) + { + ecma_builtin_json_parse_next_token (&token, false); + + if (token.type != end_token) + { + ecma_free_value (final_result); + final_result = ECMA_VALUE_UNDEFINED; + } + } + return final_result; +} /*ecma_builtin_json_parse_buffer*/ + /** * The JSON object's 'parse' routine * @@ -816,22 +859,7 @@ ecma_builtin_json_parse (ecma_value_t this_arg, /**< 'this' argument */ ECMA_STRING_TO_UTF8_STRING (string_p, str_start_p, string_size); - ecma_json_token_t token; - token.current_p = str_start_p; - token.end_p = str_start_p + string_size; - - ecma_value_t final_result = ecma_builtin_json_parse_value (&token); - - if (!ecma_is_value_undefined (final_result)) - { - ecma_builtin_json_parse_next_token (&token, false); - - if (token.type != end_token) - { - ecma_free_value (final_result); - final_result = ECMA_VALUE_UNDEFINED; - } - } + ecma_value_t final_result = ecma_builtin_json_parse_buffer (str_start_p, string_size); if (ecma_is_value_undefined (final_result)) { @@ -842,11 +870,10 @@ ecma_builtin_json_parse (ecma_value_t this_arg, /**< 'this' argument */ if (ecma_op_is_callable (arg2)) { ecma_object_t *object_p = ecma_op_create_object_object_noarg (); - ecma_string_t *name_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); ecma_property_value_t *prop_value_p; prop_value_p = ecma_create_named_data_property (object_p, - name_p, + ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY), ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, NULL); @@ -855,9 +882,8 @@ ecma_builtin_json_parse (ecma_value_t this_arg, /**< 'this' argument */ ret_value = ecma_builtin_json_walk (ecma_get_object_from_value (arg2), object_p, - name_p); + ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY)); ecma_deref_object (object_p); - ecma_deref_ecma_string (name_p); } else { @@ -880,6 +906,61 @@ ecma_builtin_json_object (ecma_object_t *obj_p, ecma_json_stringify_context_t *c static ecma_value_t ecma_builtin_json_array (ecma_object_t *obj_p, ecma_json_stringify_context_t *context_p); +/** + * Helper function to stringify an object in JSON format representing an ecma_value. + * + * @return ecma_value_t string created from an abject formating by a given context + * Returned value must be freed with ecma_free_value. + * + */ +static ecma_value_t ecma_builtin_json_str_helper (const ecma_value_t arg1, /**< object argument */ + ecma_json_stringify_context_t context) /**< context argument */ +{ + ecma_value_t ret_value = ECMA_VALUE_EMPTY; + ecma_object_t *obj_wrapper_p = ecma_op_create_object_object_noarg (); + ecma_string_t *empty_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); + ecma_value_t put_comp_val = ecma_op_object_put (obj_wrapper_p, + empty_str_p, + arg1, + false); + JERRY_ASSERT (ecma_is_value_true (put_comp_val)); + ecma_free_value (put_comp_val); + ECMA_TRY_CATCH (str_val, + ecma_builtin_json_str (empty_str_p, obj_wrapper_p, &context), + ret_value); + ret_value = ecma_copy_value (str_val); + ECMA_FINALIZE (str_val); + ecma_free_value (put_comp_val); + ecma_deref_ecma_string (empty_str_p); + ecma_deref_object (obj_wrapper_p); + + return ret_value; +} /* ecma_builtin_json_str_helper */ + +/** + * Function to create a json formated string from an object + * + * @return ecma_value_t containing a json string + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_builtin_json_string_from_object (const ecma_value_t arg1) /**< object argument */ +{ + ecma_json_stringify_context_t context; + context.occurence_stack_last_p = NULL; + context.indent_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); + context.property_list_p = ecma_new_values_collection (); + context.replacer_function_p = NULL; + context.gap_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); + + ecma_value_t ret_value = ecma_builtin_json_str_helper (arg1, context); + + ecma_deref_ecma_string (context.gap_str_p); + ecma_deref_ecma_string (context.indent_str_p); + ecma_free_values_collection (context.property_list_p, 0); + return ret_value; +} /*ecma_builtin_json_string_from_object*/ + /** * The JSON object's 'stringify' routine * @@ -901,13 +982,13 @@ ecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */ ecma_json_stringify_context_t context; /* 1. */ - context.occurence_stack_p = ecma_new_values_collection (NULL, 0, false); + context.occurence_stack_last_p = NULL; /* 2. */ context.indent_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); /* 3. */ - context.property_list_p = ecma_new_values_collection (NULL, 0, false); + context.property_list_p = ecma_new_values_collection (); context.replacer_function_p = NULL; @@ -987,7 +1068,7 @@ ecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */ { if (!ecma_has_string_value_in_collection (context.property_list_p, item)) { - ecma_append_to_values_collection (context.property_list_p, item, true); + ecma_append_to_values_collection (context.property_list_p, item, 0); ecma_deref_ecma_string (ecma_get_string_from_value (item)); } else @@ -1107,29 +1188,7 @@ ecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */ if (ecma_is_value_empty (ret_value)) { /* 9. */ - ecma_object_t *obj_wrapper_p = ecma_op_create_object_object_noarg (); - ecma_string_t *empty_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); - - /* 10. */ - ecma_value_t put_comp_val = ecma_op_object_put (obj_wrapper_p, - empty_str_p, - arg1, - false); - - JERRY_ASSERT (ecma_is_value_true (put_comp_val)); - ecma_free_value (put_comp_val); - - /* 11. */ - ECMA_TRY_CATCH (str_val, - ecma_builtin_json_str (empty_str_p, obj_wrapper_p, &context), - ret_value); - - ret_value = ecma_copy_value (str_val); - - ECMA_FINALIZE (str_val); - - ecma_deref_object (obj_wrapper_p); - ecma_deref_ecma_string (empty_str_p); + ret_value = ecma_builtin_json_str_helper (arg1, context); } ecma_deref_ecma_string (context.gap_str_p); @@ -1137,8 +1196,7 @@ ecma_builtin_json_stringify (ecma_value_t this_arg, /**< 'this' argument */ ecma_deref_ecma_string (context.indent_str_p); - ecma_free_values_collection (context.property_list_p, true); - ecma_free_values_collection (context.occurence_stack_p, true); + ecma_free_values_collection (context.property_list_p, 0); return ret_value; } /* ecma_builtin_json_stringify */ @@ -1400,8 +1458,7 @@ ecma_builtin_json_str (ecma_string_t *key_p, /**< property key*/ else { /* 9.b */ - ecma_string_t *null_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NULL); - ret_value = ecma_make_string_value (null_str_p); + ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING_NULL); } } /* 10. */ @@ -1459,10 +1516,8 @@ static ecma_value_t ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ ecma_json_stringify_context_t *context_p) /**< context*/ { - ecma_value_t obj_value = ecma_make_object_value (obj_p); - /* 1. */ - if (ecma_has_object_value_in_collection (context_p->occurence_stack_p, obj_value)) + if (ecma_json_has_object_in_stack (context_p->occurence_stack_last_p, obj_p)) { return ecma_raise_type_error (ECMA_ERR_MSG ("The structure is cyclical.")); } @@ -1470,7 +1525,10 @@ ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ ecma_value_t ret_value = ECMA_VALUE_EMPTY; /* 2. */ - ecma_append_to_values_collection (context_p->occurence_stack_p, obj_value, true); + ecma_json_occurence_stack_item_t stack_item; + stack_item.next_p = context_p->occurence_stack_last_p; + stack_item.object_p = obj_p; + context_p->occurence_stack_last_p = &stack_item; /* 3. */ ecma_string_t *stepback_p = context_p->indent_str_p; @@ -1482,23 +1540,22 @@ ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ ecma_collection_header_t *property_keys_p; /* 5. */ - if (context_p->property_list_p->unit_number > 0) + if (context_p->property_list_p->item_count > 0) { property_keys_p = context_p->property_list_p; } /* 6. */ else { - property_keys_p = ecma_new_values_collection (NULL, 0, true); + property_keys_p = ecma_new_values_collection (); ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, true, false); - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, props_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); ecma_property_t property = ecma_op_object_get_own_property (obj_p, property_name_p, @@ -1507,26 +1564,28 @@ ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ JERRY_ASSERT (ecma_is_property_enumerable (property)); - if (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_NAMEDDATA) + if (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_NAMEDDATA + || ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_VIRTUAL) { - ecma_append_to_values_collection (property_keys_p, *iter.current_value_p, true); + ecma_append_to_values_collection (property_keys_p, *ecma_value_p, 0); } + + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); } - ecma_free_values_collection (props_p, true); + ecma_free_values_collection (props_p, 0); } /* 7. */ - ecma_collection_header_t *partial_p = ecma_new_values_collection (NULL, 0, true); + ecma_collection_header_t *partial_p = ecma_new_values_collection (); /* 8. */ - ecma_collection_iterator_t iterator; - ecma_collection_iterator_init (&iterator, property_keys_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (property_keys_p); - while (ecma_collection_iterator_next (&iterator) && ecma_is_value_empty (ret_value)) + while (ecma_value_p != NULL && ecma_is_value_empty (ret_value)) { - ecma_value_t value = *iterator.current_value_p; - ecma_string_t *key_p = ecma_get_string_from_value (value); + ecma_string_t *key_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); /* 8.a */ ECMA_TRY_CATCH (str_val, @@ -1558,27 +1617,27 @@ ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ /* 8.b.v */ ecma_value_t member_value = ecma_make_string_value (member_str_p); - ecma_append_to_values_collection (partial_p, member_value, true); + ecma_append_to_values_collection (partial_p, member_value, 0); ecma_deref_ecma_string (member_str_p); } ECMA_FINALIZE (str_val); } - if (context_p->property_list_p->unit_number == 0) + if (context_p->property_list_p->item_count == 0) { - ecma_free_values_collection (property_keys_p, true); + ecma_free_values_collection (property_keys_p, 0); } if (!ecma_is_value_empty (ret_value)) { - ecma_free_values_collection (partial_p, true); + ecma_free_values_collection (partial_p, 0); ecma_deref_ecma_string (stepback_p); return ret_value; } /* 9. */ - if (partial_p->unit_number == 0) + if (partial_p->item_count == 0) { lit_utf8_byte_t chars[2] = { LIT_CHAR_LEFT_BRACE, LIT_CHAR_RIGHT_BRACE }; @@ -1606,10 +1665,10 @@ ecma_builtin_json_object (ecma_object_t *obj_p, /**< the object*/ } } - ecma_free_values_collection (partial_p, true); + ecma_free_values_collection (partial_p, 0); /* 11. */ - ecma_remove_last_value_from_values_collection (context_p->occurence_stack_p); + context_p->occurence_stack_last_p = stack_item.next_p; /* 12. */ ecma_deref_ecma_string (context_p->indent_str_p); @@ -1632,10 +1691,8 @@ static ecma_value_t ecma_builtin_json_array (ecma_object_t *obj_p, /**< the array object*/ ecma_json_stringify_context_t *context_p) /**< context*/ { - ecma_value_t obj_value = ecma_make_object_value (obj_p); - /* 1. */ - if (ecma_has_object_value_in_collection (context_p->occurence_stack_p, obj_value)) + if (ecma_json_has_object_in_stack (context_p->occurence_stack_last_p, obj_p)) { return ecma_raise_type_error (ECMA_ERR_MSG ("The structure is cyclical.")); } @@ -1643,7 +1700,10 @@ ecma_builtin_json_array (ecma_object_t *obj_p, /**< the array object*/ ecma_value_t ret_value = ECMA_VALUE_EMPTY; /* 2. */ - ecma_append_to_values_collection (context_p->occurence_stack_p, obj_value, true); + ecma_json_occurence_stack_item_t stack_item; + stack_item.next_p = context_p->occurence_stack_last_p; + stack_item.object_p = obj_p; + context_p->occurence_stack_last_p = &stack_item; /* 3. */ ecma_string_t *stepback_p = context_p->indent_str_p; @@ -1653,7 +1713,7 @@ ecma_builtin_json_array (ecma_object_t *obj_p, /**< the array object*/ context_p->indent_str_p = ecma_concat_ecma_strings (stepback_p, context_p->gap_str_p); /* 5. */ - ecma_collection_header_t *partial_p = ecma_new_values_collection (NULL, 0, true); + ecma_collection_header_t *partial_p = ecma_new_values_collection (); /* 6. */ ECMA_TRY_CATCH (array_length, @@ -1680,14 +1740,12 @@ ecma_builtin_json_array (ecma_object_t *obj_p, /**< the array object*/ /* 8.b */ if (ecma_is_value_undefined (str_val)) { - ecma_string_t *null_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NULL); - ecma_append_to_values_collection (partial_p, ecma_make_string_value (null_str_p), true); - ecma_deref_ecma_string (null_str_p); + ecma_append_to_values_collection (partial_p, ecma_make_magic_string_value (LIT_MAGIC_STRING_NULL), 0); } /* 8.c */ else { - ecma_append_to_values_collection (partial_p, str_val, true); + ecma_append_to_values_collection (partial_p, str_val, 0); } ECMA_FINALIZE (str_val); @@ -1697,7 +1755,7 @@ ecma_builtin_json_array (ecma_object_t *obj_p, /**< the array object*/ if (ecma_is_value_empty (ret_value)) { /* 9. */ - if (partial_p->unit_number == 0) + if (partial_p->item_count == 0) { lit_utf8_byte_t chars[2] = { LIT_CHAR_LEFT_SQUARE, LIT_CHAR_RIGHT_SQUARE }; @@ -1729,10 +1787,10 @@ ecma_builtin_json_array (ecma_object_t *obj_p, /**< the array object*/ ECMA_OP_TO_NUMBER_FINALIZE (array_length_num); ECMA_FINALIZE (array_length); - ecma_free_values_collection (partial_p, true); + ecma_free_values_collection (partial_p, 0); /* 11. */ - ecma_remove_last_value_from_values_collection (context_p->occurence_stack_p); + context_p->occurence_stack_last_p = stack_item.next_p; /* 12. */ ecma_deref_ecma_string (context_p->indent_str_p); diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-number-prototype.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-number-prototype.c index caaf195..d8c6a75 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-number-prototype.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-number-prototype.c @@ -590,8 +590,7 @@ ecma_builtin_number_prototype_object_to_fixed (ecma_value_t this_arg, /**< this /* 4. */ if (ecma_number_is_nan (this_num)) { - ecma_string_t *nan_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NAN); - ret_value = ecma_make_string_value (nan_str_p); + ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING_NAN); } else { @@ -609,7 +608,7 @@ ecma_builtin_number_prototype_object_to_fixed (ecma_value_t this_arg, /**< this lit_magic_string_id_t id = (is_negative ? LIT_MAGIC_STRING_NEGATIVE_INFINITY_UL : LIT_MAGIC_STRING_INFINITY_UL); - ret_value = ecma_make_string_value (ecma_get_magic_string (id)); + ret_value = ecma_make_magic_string_value (id); } else { @@ -721,8 +720,7 @@ ecma_builtin_number_prototype_object_to_exponential (ecma_value_t this_arg, /**< /* 3. */ if (ecma_number_is_nan (this_num)) { - ecma_string_t *nan_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NAN); - ret_value = ecma_make_string_value (nan_str_p); + ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING_NAN); } else { @@ -740,7 +738,7 @@ ecma_builtin_number_prototype_object_to_exponential (ecma_value_t this_arg, /**< lit_magic_string_id_t id = (is_negative ? LIT_MAGIC_STRING_NEGATIVE_INFINITY_UL : LIT_MAGIC_STRING_INFINITY_UL); - ret_value = ecma_make_string_value (ecma_get_magic_string (id)); + ret_value = ecma_make_magic_string_value (id); } else { @@ -858,8 +856,7 @@ ecma_builtin_number_prototype_object_to_precision (ecma_value_t this_arg, /**< t /* 4. */ if (ecma_number_is_nan (this_num)) { - ecma_string_t *nan_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NAN); - ret_value = ecma_make_string_value (nan_str_p); + ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING_NAN); } else { @@ -877,7 +874,7 @@ ecma_builtin_number_prototype_object_to_precision (ecma_value_t this_arg, /**< t lit_magic_string_id_t id = (is_negative ? LIT_MAGIC_STRING_NEGATIVE_INFINITY_UL : LIT_MAGIC_STRING_INFINITY_UL); - ret_value = ecma_make_string_value (ecma_get_magic_string (id)); + ret_value = ecma_make_magic_string_value (id); } /* 8. */ else if (arg_num < 1.0 || arg_num >= 22.0) diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-object.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-object.c index 8b57e4d..f74f20e 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-object.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-object.c @@ -14,7 +14,6 @@ */ #include "ecma-alloc.h" -#include "ecma-array-object.h" #include "ecma-builtin-helpers.h" #include "ecma-builtins.h" #include "ecma-conversion.h" @@ -109,28 +108,41 @@ ecma_builtin_object_object_get_prototype_of (ecma_value_t this_arg, /**< 'this' { JERRY_UNUSED (this_arg); ecma_value_t ret_value = ECMA_VALUE_EMPTY; + bool was_object = ecma_is_value_object (arg); /* 1. */ - if (!ecma_is_value_object (arg)) + if (!was_object) { - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an object.")); +#ifndef CONFIG_DISABLE_ES2015_BUILTIN + arg = ecma_op_to_object (arg); + if (ECMA_IS_VALUE_ERROR (arg)) + { + return arg; + } +#else /* CONFIG_DISABLE_ES2015_BUILTIN */ + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument is not an object.")); +#endif /* !CONFIG_DISABLE_ES2015_BUILTIN */ + } + /* 2. */ + ecma_object_t *obj_p = ecma_get_object_from_value (arg); + ecma_object_t *prototype_p = ecma_get_object_prototype (obj_p); + + if (prototype_p) + { + ret_value = ecma_make_object_value (prototype_p); + ecma_ref_object (prototype_p); } else { - /* 2. */ - ecma_object_t *obj_p = ecma_get_object_from_value (arg); - ecma_object_t *prototype_p = ecma_get_object_prototype (obj_p); + ret_value = ECMA_VALUE_NULL; + } - if (prototype_p) - { - ret_value = ecma_make_object_value (prototype_p); - ecma_ref_object (prototype_p); - } - else - { - ret_value = ECMA_VALUE_NULL; - } +#ifndef CONFIG_DISABLE_ES2015_BUILTIN + if (!was_object) + { + ecma_free_value (arg); } +#endif /* !CONFIG_DISABLE_ES2015_BUILTIN */ return ret_value; } /* ecma_builtin_object_object_get_prototype_of */ @@ -315,13 +327,12 @@ ecma_builtin_object_object_seal (ecma_value_t this_arg, /**< 'this' argument */ ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, props_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p); - while (ecma_collection_iterator_next (&iter) - && ecma_is_value_empty (ret_value)) + while (ecma_value_p != NULL && ecma_is_value_empty (ret_value)) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); /* 2.a */ ecma_property_descriptor_t prop_desc; @@ -346,7 +357,7 @@ ecma_builtin_object_object_seal (ecma_value_t this_arg, /**< 'this' argument */ ecma_free_property_descriptor (&prop_desc); } - ecma_free_values_collection (props_p, true); + ecma_free_values_collection (props_p, 0); if (ecma_is_value_empty (ret_value)) { @@ -389,14 +400,12 @@ ecma_builtin_object_object_freeze (ecma_value_t this_arg, /**< 'this' argument * ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p); - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, props_p); - - while (ecma_collection_iterator_next (&iter) - && ecma_is_value_empty (ret_value)) + while (ecma_value_p != NULL && ecma_is_value_empty (ret_value)) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); /* 2.a */ ecma_property_descriptor_t prop_desc; @@ -427,7 +436,7 @@ ecma_builtin_object_object_freeze (ecma_value_t this_arg, /**< 'this' argument * ecma_free_property_descriptor (&prop_desc); } - ecma_free_values_collection (props_p, true); + ecma_free_values_collection (props_p, 0); if (ecma_is_value_empty (ret_value)) { @@ -513,12 +522,12 @@ ecma_builtin_object_object_is_sealed (ecma_value_t this_arg, /**< 'this' argumen /* 2. */ ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, props_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); /* 2.a */ ecma_property_t property = ecma_op_object_get_own_property (obj_p, @@ -534,7 +543,7 @@ ecma_builtin_object_object_is_sealed (ecma_value_t this_arg, /**< 'this' argumen } } - ecma_free_values_collection (props_p, true); + ecma_free_values_collection (props_p, 0); } /* 4. */ @@ -583,12 +592,12 @@ ecma_builtin_object_object_is_frozen (ecma_value_t this_arg, /**< 'this' argumen /* 2. */ ecma_collection_header_t *props_p = ecma_op_object_get_property_names (obj_p, false, false, false); - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, props_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (props_p); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_string_t *property_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *property_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); /* 2.a */ ecma_property_t property = ecma_op_object_get_own_property (obj_p, @@ -612,7 +621,7 @@ ecma_builtin_object_object_is_frozen (ecma_value_t this_arg, /**< 'this' argumen } } - ecma_free_values_collection (props_p, true); + ecma_free_values_collection (props_p, 0); } /* 4 */ @@ -829,22 +838,20 @@ ecma_builtin_object_object_define_properties (ecma_value_t this_arg, /**< 'this' ecma_object_t *props_p = ecma_get_object_from_value (props); /* 3. */ ecma_collection_header_t *prop_names_p = ecma_op_object_get_property_names (props_p, false, true, false); - uint32_t property_number = prop_names_p->unit_number; + uint32_t property_number = prop_names_p->item_count; - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, prop_names_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (prop_names_p); /* 4. */ JMEM_DEFINE_LOCAL_ARRAY (property_descriptors, property_number, ecma_property_descriptor_t); uint32_t property_descriptor_number = 0; - while (ecma_collection_iterator_next (&iter) - && ecma_is_value_empty (ret_value)) + while (ecma_value_p != NULL && ecma_is_value_empty (ret_value)) { /* 5.a */ ECMA_TRY_CATCH (desc_obj, - ecma_op_object_get (props_p, ecma_get_string_from_value (*iter.current_value_p)), + ecma_op_object_get (props_p, ecma_get_string_from_value (*ecma_value_p)), ret_value); /* 5.b */ @@ -857,25 +864,27 @@ ecma_builtin_object_object_define_properties (ecma_value_t this_arg, /**< 'this' ECMA_FINALIZE (conv_result); ECMA_FINALIZE (desc_obj); + + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); } /* 6. */ - ecma_collection_iterator_init (&iter, prop_names_p); + ecma_value_p = ecma_collection_iterator_init (prop_names_p); + for (uint32_t index = 0; index < property_number && ecma_is_value_empty (ret_value); index++) { - bool is_next = ecma_collection_iterator_next (&iter); - JERRY_ASSERT (is_next); - ECMA_TRY_CATCH (define_own_prop_ret, ecma_op_object_define_own_property (obj_p, - ecma_get_string_from_value (*iter.current_value_p), + ecma_get_string_from_value (*ecma_value_p), &property_descriptors[index], true), ret_value); ECMA_FINALIZE (define_own_prop_ret); + + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); } /* Clean up. */ @@ -888,7 +897,7 @@ ecma_builtin_object_object_define_properties (ecma_value_t this_arg, /**< 'this' JMEM_FINALIZE_LOCAL_ARRAY (property_descriptors); - ecma_free_values_collection (prop_names_p, true); + ecma_free_values_collection (prop_names_p, 0); /* 7. */ if (ecma_is_value_empty (ret_value)) diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c index 1c7e3e5..274ded3 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c @@ -79,19 +79,18 @@ ecma_builtin_promise_reject_or_resolve (ecma_value_t this_arg, /**< "this" argum return capability; } - ecma_string_t *str; + ecma_string_t *property_str_p; if (is_resolve) { - str = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); + property_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); } else { - str = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); + property_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); } - ecma_value_t func = ecma_op_object_get (ecma_get_object_from_value (capability), str); - ecma_deref_ecma_string (str); + ecma_value_t func = ecma_op_object_get (ecma_get_object_from_value (capability), property_str_p); ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (func), ECMA_VALUE_UNDEFINED, @@ -107,9 +106,8 @@ ecma_builtin_promise_reject_or_resolve (ecma_value_t this_arg, /**< "this" argum ecma_free_value (call_ret); - ecma_string_t *str_promise = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); - ecma_value_t promise_new = ecma_op_object_get (ecma_get_object_from_value (capability), str_promise); - ecma_deref_ecma_string (str_promise); + ecma_string_t *promise_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); + ecma_value_t promise_new = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p); ecma_free_value (capability); return promise_new; @@ -128,9 +126,8 @@ inline static ecma_value_t ecma_builtin_promise_reject_abrupt (ecma_value_t capability) /**< reject description */ { ecma_value_t reason = JERRY_CONTEXT (error_value); - ecma_string_t *str_reject = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); - ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), str_reject); - ecma_deref_ecma_string (str_reject); + ecma_string_t *reject_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); + ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), reject_str_p); ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (reject), ECMA_VALUE_UNDEFINED, @@ -145,9 +142,8 @@ ecma_builtin_promise_reject_abrupt (ecma_value_t capability) /**< reject descrip ecma_free_value (call_ret); - ecma_string_t *str_promise = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); - ecma_value_t promise_new = ecma_op_object_get (ecma_get_object_from_value (capability), str_promise); - ecma_deref_ecma_string (str_promise); + ecma_string_t *promise_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); + ecma_value_t promise_new = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p); return promise_new; } /* ecma_builtin_promise_reject_abrupt */ @@ -210,28 +206,28 @@ ecma_builtin_promise_do_race (ecma_value_t array, /**< the array for race */ ecma_length_t len = (ecma_length_t) ecma_get_integer_from_value (len_value); ecma_fast_free_value (len_value); - ecma_string_t *str_promise = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); - ecma_string_t *str_resolve = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); - ecma_string_t *str_reject = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); + ecma_string_t *promise_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); + ecma_string_t *resolve_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); + ecma_string_t *reject_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), - str_resolve); + resolve_str_p); ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), - str_reject); + reject_str_p); for (ecma_length_t index = 0; index <= len; index++) { /* b-d. */ if (index == len) { - ret = ecma_op_object_get (ecma_get_object_from_value (capability), str_promise); + ret = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p); break; } /* e. */ - ecma_string_t *str_index = ecma_new_ecma_string_from_uint32 (index); - ecma_value_t array_item = ecma_op_object_get (array_p, str_index); - ecma_deref_ecma_string (str_index); + ecma_string_t *index_to_str_p = ecma_new_ecma_string_from_uint32 (index); + ecma_value_t array_item = ecma_op_object_get (array_p, index_to_str_p); + ecma_deref_ecma_string (index_to_str_p); /* h. */ ecma_value_t next_promise = ecma_builtin_promise_resolve (ctor, array_item); @@ -260,9 +256,6 @@ ecma_builtin_promise_do_race (ecma_value_t array, /**< the array for race */ ecma_free_value (reject); ecma_free_value (resolve); - ecma_deref_ecma_string (str_promise); - ecma_deref_ecma_string (str_resolve); - ecma_deref_ecma_string (str_reject); JERRY_ASSERT (!ecma_is_value_empty (ret)); @@ -323,8 +316,8 @@ ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function ecma_value_t ret = ECMA_VALUE_UNDEFINED; /* 1. */ ecma_object_t *function_p = ecma_get_object_from_value (function); - ecma_string_t *str_already_called = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_ALREADY_CALLED); - ecma_value_t already_called = ecma_op_object_get (function_p, str_already_called); + ecma_string_t *already_called_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_ALREADY_CALLED); + ecma_value_t already_called = ecma_op_object_get (function_p, already_called_str_p); JERRY_ASSERT (ecma_is_value_boolean (already_called)); @@ -332,46 +325,43 @@ ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function if (ecma_is_value_true (already_called)) { ecma_fast_free_value (already_called); - ecma_deref_ecma_string (str_already_called); - return ret; } /* 3. */ ecma_op_object_put (function_p, - str_already_called, + already_called_str_p, ecma_make_boolean_value (true), false); - ecma_string_t *str_index = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_INDEX); - ecma_string_t *str_value = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_VALUE); - ecma_string_t *str_capability = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); - ecma_string_t *str_remaining = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REMAINING_ELEMENT); + ecma_string_t *str_index_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_INDEX); + ecma_string_t *str_value_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_VALUE); + ecma_string_t *str_capability_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); + ecma_string_t *str_remaining_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REMAINING_ELEMENT); /* 4-7. */ - ecma_value_t index_val = ecma_op_object_get (function_p, str_index); - ecma_value_t value_array = ecma_op_object_get (function_p, str_value); - ecma_value_t capability = ecma_op_object_get (function_p, str_capability); - ecma_value_t remaining = ecma_op_object_get (function_p, str_remaining); + ecma_value_t index_val = ecma_op_object_get (function_p, str_index_p); + ecma_value_t value_array = ecma_op_object_get (function_p, str_value_p); + ecma_value_t capability = ecma_op_object_get (function_p, str_capability_p); + ecma_value_t remaining = ecma_op_object_get (function_p, str_remaining_p); JERRY_ASSERT (ecma_is_value_integer_number (index_val)); /* 8. */ - ecma_string_t *index_str = ecma_new_ecma_string_from_uint32 ((uint32_t) ecma_get_integer_from_value (index_val)); + ecma_string_t *index_to_str_p = ecma_new_ecma_string_from_uint32 ((uint32_t) ecma_get_integer_from_value (index_val)); ecma_op_object_put (ecma_get_object_from_value (value_array), - index_str, + index_to_str_p, argv[0], false); - ecma_deref_ecma_string (index_str); + ecma_deref_ecma_string (index_to_str_p); /* 9-10. */ if (ecma_builtin_promise_remaining_inc_or_dec (remaining, false) == 0) { - ecma_string_t *str_resolve = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); - ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), - str_resolve); - ecma_deref_ecma_string (str_resolve); + ecma_string_t *resolve_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); + ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), resolve_str_p); + ret = ecma_op_function_call (ecma_get_object_from_value (resolve), ECMA_VALUE_UNDEFINED, &value_array, @@ -384,11 +374,6 @@ ecma_builtin_promise_all_handler (const ecma_value_t function, /**< the function ecma_free_value (value_array); ecma_fast_free_value (index_val); ecma_fast_free_value (already_called); - ecma_deref_ecma_string (str_already_called); - ecma_deref_ecma_string (str_index); - ecma_deref_ecma_string (str_value); - ecma_deref_ecma_string (str_capability); - ecma_deref_ecma_string (str_remaining); return ret; } /* ecma_builtin_promise_all_handler */ @@ -419,21 +404,21 @@ ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */ ecma_length_t len = (ecma_length_t) ecma_get_integer_from_value (len_value); ecma_fast_free_value (len_value); - ecma_string_t *str_promise = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); - ecma_string_t *str_resolve = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); - ecma_string_t *str_reject = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); - ecma_string_t *str_already_called = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_ALREADY_CALLED); - ecma_string_t *str_index = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_INDEX); - ecma_string_t *str_value = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_VALUE); - ecma_string_t *str_capability = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); - ecma_string_t *str_remaining = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REMAINING_ELEMENT); + ecma_string_t *promise_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); + ecma_string_t *resolve_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); + ecma_string_t *reject_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); + ecma_string_t *already_called_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_ALREADY_CALLED); + ecma_string_t *index_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_INDEX); + ecma_string_t *value_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_VALUE); + ecma_string_t *capability_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); + ecma_string_t *remaining_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REMAINING_ELEMENT); ecma_value_t undefined_val = ECMA_VALUE_UNDEFINED; /* String '1' indicates [[Resolve]] and '2' indicates [[Reject]]. */ ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), - str_resolve); + resolve_str_p); ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), - str_reject); + reject_str_p); /* 3. */ ecma_value_t result_array_length_val = ecma_make_uint32_value (0); ecma_value_t value_array = ecma_op_create_array_object (&result_array_length_val, 1, true); @@ -467,18 +452,18 @@ ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */ } /* iv. */ - ret = ecma_op_object_get (ecma_get_object_from_value (capability), str_promise); + ret = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p); break; } /* e. h. */ - ecma_string_t *index_str = ecma_new_ecma_string_from_uint32 (index); - ecma_value_t array_item = ecma_op_object_get (array_p, index_str); + ecma_string_t *index_to_str_p = ecma_new_ecma_string_from_uint32 (index); + ecma_value_t array_item = ecma_op_object_get (array_p, index_to_str_p); ecma_op_object_put (ecma_get_object_from_value (value_array), - index_str, + index_to_str_p, undefined_val, false); - ecma_deref_ecma_string (index_str); + ecma_deref_ecma_string (index_to_str_p); /* i. */ ecma_value_t next_promise = ecma_builtin_promise_resolve (ctor, array_item); ecma_free_value (array_item); @@ -495,27 +480,27 @@ ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */ res_ele_p = ecma_op_create_external_function_object (ecma_builtin_promise_all_handler); /* l. */ ecma_op_object_put (res_ele_p, - str_already_called, + already_called_str_p, ecma_make_boolean_value (false), false); /* m. */ ecma_op_object_put (res_ele_p, - str_index, + index_str_p, ecma_make_uint32_value (index), false); /* n. */ ecma_op_object_put (res_ele_p, - str_value, + value_str_p, value_array, false); /* o. */ ecma_op_object_put (res_ele_p, - str_capability, + capability_str_p, capability, false); /* p. */ ecma_op_object_put (res_ele_p, - str_remaining, + remaining_str_p, remaining, false); @@ -543,14 +528,6 @@ ecma_builtin_promise_do_all (ecma_value_t array, /**< the array for all */ ecma_free_value (resolve); ecma_free_value (remaining); ecma_free_value (value_array); - ecma_deref_ecma_string (str_already_called); - ecma_deref_ecma_string (str_index); - ecma_deref_ecma_string (str_value); - ecma_deref_ecma_string (str_capability); - ecma_deref_ecma_string (str_remaining); - ecma_deref_ecma_string (str_resolve); - ecma_deref_ecma_string (str_reject); - ecma_deref_ecma_string (str_promise); JERRY_ASSERT (!ecma_is_value_empty (ret)); diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c index 2afa155..7946f54 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.c @@ -89,13 +89,11 @@ ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument /* Get source. */ ecma_string_t *magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE); ecma_value_t source_value = ecma_op_object_get_own_data_prop (target_p, magic_string_p); - ecma_deref_ecma_string (magic_string_p); ecma_string_t *pattern_string_p = ecma_get_string_from_value (source_value); /* Get flags. */ magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL); ecma_value_t global_value = ecma_op_object_get_own_data_prop (target_p, magic_string_p); - ecma_deref_ecma_string (magic_string_p); JERRY_ASSERT (ecma_is_value_boolean (global_value)); @@ -106,7 +104,6 @@ ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL); ecma_value_t ignore_case_value = ecma_op_object_get_own_data_prop (target_p, magic_string_p); - ecma_deref_ecma_string (magic_string_p); JERRY_ASSERT (ecma_is_value_boolean (ignore_case_value)); @@ -117,7 +114,6 @@ ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE); ecma_value_t multiline_value = ecma_op_object_get_own_data_prop (target_p, magic_string_p); - ecma_deref_ecma_string (magic_string_p); JERRY_ASSERT (ecma_is_value_boolean (multiline_value)); @@ -141,7 +137,7 @@ ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument ecma_deref_ecma_string (pattern_string_p); - re_compiled_code_t *old_bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, *bc_prop_p); + re_compiled_code_t *old_bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, *bc_prop_p); if (old_bc_p != NULL) { @@ -213,7 +209,7 @@ ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument re_compile_bytecode (&new_bc_p, pattern_string_p, flags), ret_value); - re_compiled_code_t *old_bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, *bc_prop_p); + re_compiled_code_t *old_bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, *bc_prop_p); if (old_bc_p != NULL) { @@ -275,20 +271,16 @@ ecma_builtin_regexp_prototype_exec (ecma_value_t this_arg, /**< this argument */ ecma_object_t *obj_p = ecma_get_object_from_value (obj_this); ecma_value_t *bytecode_prop_p = &(((ecma_extended_object_t *) obj_p)->u.class_prop.u.value); - void *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (void, *bytecode_prop_p); + void *bytecode_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (void, *bytecode_prop_p); if (bytecode_p == NULL) { /* Missing bytecode means empty RegExp: '/(?:)/', so always return empty string. */ - ecma_string_t *capture_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); - ecma_value_t arguments_list[1]; - arguments_list[0] = ecma_make_string_value (capture_str_p); + arguments_list[0] = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); ret_value = ecma_op_create_array_object (arguments_list, 1, false); - ecma_deref_ecma_string (capture_str_p); - re_set_result_array_properties (ecma_get_object_from_value (ret_value), ecma_get_string_from_value (input_str_value), 1, @@ -364,7 +356,6 @@ ecma_builtin_regexp_prototype_to_string (ecma_value_t this_arg) /**< this argume /* Get RegExp source from the source property */ ecma_string_t *magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE); ecma_value_t source_value = ecma_op_object_get_own_data_prop (obj_p, magic_string_p); - ecma_deref_ecma_string (magic_string_p); ecma_string_t *output_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_SLASH_CHAR); ecma_string_t *source_str_p = ecma_get_string_from_value (source_value); @@ -379,7 +370,6 @@ ecma_builtin_regexp_prototype_to_string (ecma_value_t this_arg) /**< this argume /* Check the global flag */ magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL); ecma_value_t global_value = ecma_op_object_get_own_data_prop (obj_p, magic_string_p); - ecma_deref_ecma_string (magic_string_p); JERRY_ASSERT (ecma_is_value_boolean (global_value)); @@ -391,7 +381,6 @@ ecma_builtin_regexp_prototype_to_string (ecma_value_t this_arg) /**< this argume /* Check the ignoreCase flag */ magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL); ecma_value_t ignore_case_value = ecma_op_object_get_own_data_prop (obj_p, magic_string_p); - ecma_deref_ecma_string (magic_string_p); JERRY_ASSERT (ecma_is_value_boolean (ignore_case_value)); @@ -403,7 +392,6 @@ ecma_builtin_regexp_prototype_to_string (ecma_value_t this_arg) /**< this argume /* Check the multiline flag */ magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE); ecma_value_t multiline_value = ecma_op_object_get_own_data_prop (obj_p, magic_string_p); - ecma_deref_ecma_string (magic_string_p); JERRY_ASSERT (ecma_is_value_boolean (multiline_value)); diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c index b1bfa81..1cd05a6 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-string-prototype.c @@ -139,7 +139,7 @@ ecma_builtin_string_prototype_object_char_at (ecma_value_t this_arg, /**< this a /* 5 */ if (index_num < 0 || index_num >= len || !len) { - ret_value = ecma_make_string_value (ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY)); + ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); } else { @@ -446,13 +446,11 @@ ecma_builtin_string_prototype_object_match (ecma_value_t this_arg, /**< this arg else { /* 8.a. */ - ecma_string_t *index_zero_string_p = ecma_new_ecma_string_from_uint32 (0); - - ecma_string_t *last_index_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); + ecma_string_t *index_zero_string_p = ecma_get_ecma_string_from_uint32 (0); ECMA_TRY_CATCH (put_value, ecma_op_object_put (regexp_obj_p, - last_index_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), ecma_make_integer_value (0), true), ret_value); @@ -503,7 +501,7 @@ ecma_builtin_string_prototype_object_match (ecma_value_t this_arg, /**< this arg /* 8.f.iii.2.a. */ ECMA_TRY_CATCH (index_put_value, ecma_op_object_put (regexp_obj_p, - last_index_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), ecma_make_number_value (this_index + 1), true), ret_value); @@ -575,9 +573,6 @@ ecma_builtin_string_prototype_object_match (ecma_value_t this_arg, /**< this arg ECMA_FINALIZE (new_array_value); ECMA_FINALIZE (put_value); - - ecma_deref_ecma_string (last_index_string_p); - ecma_deref_ecma_string (index_zero_string_p); } ECMA_FINALIZE (global_value); @@ -671,14 +666,12 @@ ecma_builtin_string_prototype_object_replace_match (ecma_builtin_replace_search_ JERRY_ASSERT (ecma_is_value_object (match_value)); ecma_object_t *match_object_p = ecma_get_object_from_value (match_value); - ecma_string_t *zero_string_p = ecma_new_ecma_string_from_uint32 (0); - ECMA_TRY_CATCH (index_value, ecma_op_object_get_by_magic_id (match_object_p, LIT_MAGIC_STRING_INDEX), ret_value); ECMA_TRY_CATCH (result_string_value, - ecma_op_object_get (match_object_p, zero_string_p), + ecma_op_object_get (match_object_p, ecma_get_ecma_string_from_uint32 (0)), ret_value); /* We directly call the built-in exec, so @@ -701,8 +694,6 @@ ecma_builtin_string_prototype_object_replace_match (ecma_builtin_replace_search_ ECMA_FINALIZE (result_string_value); ECMA_FINALIZE (index_value); - - ecma_deref_ecma_string (zero_string_p); } else { @@ -1082,18 +1073,16 @@ ecma_builtin_string_prototype_object_replace_loop (ecma_builtin_replace_search_c } else { - ecma_string_t *last_index_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); ecma_object_t *regexp_obj_p = ecma_get_object_from_value (context_p->regexp_or_search_string); ECMA_TRY_CATCH (put_value, ecma_op_object_put (regexp_obj_p, - last_index_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), ecma_make_uint32_value (context_p->match_end + 1), true), ret_value); ECMA_FINALIZE (put_value); - ecma_deref_ecma_string (last_index_string_p); } } } @@ -1244,17 +1233,14 @@ ecma_builtin_string_prototype_object_replace (ecma_value_t this_arg, /**< this a if (context.is_global) { - ecma_string_t *last_index_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); - ECMA_TRY_CATCH (put_value, ecma_op_object_put (regexp_obj_p, - last_index_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), ecma_make_integer_value (0), true), ret_value); ECMA_FINALIZE (put_value); - ecma_deref_ecma_string (last_index_string_p); } if (ecma_is_value_empty (ret_value)) @@ -1554,9 +1540,10 @@ ecma_builtin_string_prototype_object_split (ecma_value_t this_arg, /**< this arg { #ifndef CONFIG_DISABLE_REGEXP_BUILTIN ecma_value_t regexp_value = ecma_copy_value_if_not_object (separator); - ecma_string_t *substr_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); ecma_value_t match_result; - match_result = ecma_regexp_exec_helper (regexp_value, ecma_make_string_value (substr_str_p), true); + match_result = ecma_regexp_exec_helper (regexp_value, + ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY), + true); should_return = !ecma_is_value_null (match_result); if (ECMA_IS_VALUE_ERROR (match_result)) @@ -1564,7 +1551,6 @@ ecma_builtin_string_prototype_object_split (ecma_value_t this_arg, /**< this arg match_result = JERRY_CONTEXT (error_value); } - ecma_deref_ecma_string (substr_str_p); ecma_free_value (match_result); #else return ecma_raise_type_error (ECMA_ERR_MSG ("REGEXP separator is disabled in split method.")); @@ -1663,11 +1649,10 @@ ecma_builtin_string_prototype_object_split (ecma_value_t this_arg, /**< this arg else { ecma_object_t *match_obj_p = ecma_get_object_from_value (match_result); - ecma_string_t *zero_str_p = ecma_new_ecma_string_from_uint32 (0); + ecma_string_t *zero_str_p = ecma_get_ecma_string_from_uint32 (0); ecma_string_t *magic_index_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_INDEX); ecma_property_value_t *index_prop_value_p; - if (separator_is_regexp) { index_prop_value_p = ecma_get_named_data_property (match_obj_p, magic_index_str_p); @@ -1691,26 +1676,21 @@ ecma_builtin_string_prototype_object_split (ecma_value_t this_arg, /**< this arg magic_index_str_p, ECMA_PROPERTY_FLAG_WRITABLE, NULL); + ecma_named_data_property_assign_value (match_obj_p, index_prop_value_p, ecma_make_uint32_value (curr_pos)); - } - ecma_deref_ecma_string (magic_index_str_p); - ecma_value_t match_comp_value = ecma_op_object_get (match_obj_p, zero_str_p); JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (match_comp_value)); ecma_string_t *match_str_p = ecma_get_string_from_value (match_comp_value); ecma_length_t match_str_length = ecma_string_get_length (match_str_p); - ecma_string_t *magic_empty_str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING__EMPTY); - separator_is_empty = ecma_compare_ecma_strings (magic_empty_str_p, match_str_p); + separator_is_empty = ecma_string_is_empty (match_str_p); - ecma_deref_ecma_string (magic_empty_str_p); ecma_free_value (match_comp_value); - ecma_deref_ecma_string (zero_str_p); ecma_number_t index_num = ecma_get_number_from_value (index_prop_value_p->value); JERRY_ASSERT (index_num >= 0); diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-string.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-string.c index 0648256..af99107 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-string.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtin-string.c @@ -59,47 +59,45 @@ ecma_builtin_string_object_from_char_code (ecma_value_t this_arg, /**< 'this' ar ecma_length_t args_number) /**< number of arguments */ { JERRY_UNUSED (this_arg); - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - ecma_string_t *ret_string_p = NULL; if (args_number == 0) { - ret_string_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); + return ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); } - else - { - lit_utf8_size_t utf8_buf_size = args_number * LIT_CESU8_MAX_BYTES_IN_CODE_UNIT; - JMEM_DEFINE_LOCAL_ARRAY (utf8_buf_p, - utf8_buf_size, - lit_utf8_byte_t); + ecma_value_t ret_value = ECMA_VALUE_EMPTY; + ecma_string_t *ret_string_p = NULL; + lit_utf8_size_t utf8_buf_size = args_number * LIT_CESU8_MAX_BYTES_IN_CODE_UNIT; - lit_utf8_size_t utf8_buf_used = 0; + JMEM_DEFINE_LOCAL_ARRAY (utf8_buf_p, + utf8_buf_size, + lit_utf8_byte_t); - for (ecma_length_t arg_index = 0; - arg_index < args_number && ecma_is_value_empty (ret_value); - arg_index++) - { - ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, args[arg_index], ret_value); + lit_utf8_size_t utf8_buf_used = 0; - uint32_t uint32_char_code = ecma_number_to_uint32 (arg_num); - ecma_char_t code_unit = (uint16_t) uint32_char_code; + for (ecma_length_t arg_index = 0; + arg_index < args_number && ecma_is_value_empty (ret_value); + arg_index++) + { + ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, args[arg_index], ret_value); - JERRY_ASSERT (utf8_buf_used <= utf8_buf_size - LIT_UTF8_MAX_BYTES_IN_CODE_UNIT); - utf8_buf_used += lit_code_unit_to_utf8 (code_unit, utf8_buf_p + utf8_buf_used); - JERRY_ASSERT (utf8_buf_used <= utf8_buf_size); + uint32_t uint32_char_code = ecma_number_to_uint32 (arg_num); + ecma_char_t code_unit = (uint16_t) uint32_char_code; - ECMA_OP_TO_NUMBER_FINALIZE (arg_num); - } + JERRY_ASSERT (utf8_buf_used <= utf8_buf_size - LIT_UTF8_MAX_BYTES_IN_CODE_UNIT); + utf8_buf_used += lit_code_unit_to_utf8 (code_unit, utf8_buf_p + utf8_buf_used); + JERRY_ASSERT (utf8_buf_used <= utf8_buf_size); - if (ecma_is_value_empty (ret_value)) - { - ret_string_p = ecma_new_ecma_string_from_utf8 (utf8_buf_p, utf8_buf_used); - } + ECMA_OP_TO_NUMBER_FINALIZE (arg_num); + } - JMEM_FINALIZE_LOCAL_ARRAY (utf8_buf_p); + if (ecma_is_value_empty (ret_value)) + { + ret_string_p = ecma_new_ecma_string_from_utf8 (utf8_buf_p, utf8_buf_used); } + JMEM_FINALIZE_LOCAL_ARRAY (utf8_buf_p); + if (ecma_is_value_empty (ret_value)) { ret_value = ecma_make_string_value (ret_string_p); @@ -123,10 +121,7 @@ ecma_builtin_string_dispatch_call (const ecma_value_t *arguments_list_p, /**< ar if (arguments_list_len == 0) { - ecma_string_t *str_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING__EMPTY); - ecma_value_t str_value = ecma_make_string_value (str_p); - - ret_value = str_value; + ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); } else { diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtins-internal.h b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtins-internal.h index 4ccec71..98dca30 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtins-internal.h +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtins-internal.h @@ -69,12 +69,11 @@ typedef struct uint16_t value; /**< value of the property */ } ecma_builtin_property_descriptor_t; -#define BUILTIN(builtin_id, \ - object_type, \ - object_prototype_builtin_id, \ - is_extensible, \ - is_static, \ - lowercase_name) \ +#define BUILTIN_ROUTINE(builtin_id, \ + object_type, \ + object_prototype_builtin_id, \ + is_extensible, \ + lowercase_name) \ extern const ecma_builtin_property_descriptor_t \ ecma_builtin_ ## lowercase_name ## _property_descriptor_list[]; \ ecma_value_t \ @@ -84,10 +83,25 @@ ecma_value_t \ ecma_builtin_ ## lowercase_name ## _dispatch_construct (const ecma_value_t *, \ ecma_length_t); \ ecma_value_t \ +ecma_builtin_ ## lowercase_name ## _dispatch_routine (uint16_t builtin_routine_id, \ + ecma_value_t this_arg_value, \ + const ecma_value_t [], \ + ecma_length_t); +#define BUILTIN(builtin_id, \ + object_type, \ + object_prototype_builtin_id, \ + is_extensible, \ + lowercase_name) \ +extern const ecma_builtin_property_descriptor_t \ +ecma_builtin_ ## lowercase_name ## _property_descriptor_list[]; \ +ecma_value_t \ ecma_builtin_ ## lowercase_name ## _dispatch_routine (uint16_t builtin_routine_id, \ ecma_value_t this_arg_value, \ const ecma_value_t [], \ ecma_length_t); #include "ecma-builtins.inc.h" +#undef BUILTIN_ROUTINE +#undef BUILTIN + #endif /* !ECMA_BUILTINS_INTERNAL_H */ diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtins.c b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtins.c index c4a1e18..c4ae866 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtins.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtins.c @@ -39,19 +39,90 @@ static void ecma_instantiate_builtin (ecma_builtin_id_t id); */ typedef const ecma_builtin_property_descriptor_t *ecma_builtin_property_list_reference_t; +typedef ecma_value_t (*ecma_builtin_dispatch_routine_t)(uint16_t builtin_routine_id, + ecma_value_t this_arg, + const ecma_value_t arguments_list[], + ecma_length_t arguments_number); +typedef ecma_value_t (*ecma_builtin_dispatch_call_t)(const ecma_value_t arguments_list[], + ecma_length_t arguments_number); + +static const ecma_builtin_dispatch_routine_t ecma_builtin_routines[] = +{ + #define BUILTIN(a, b, c, d, e) + #define BUILTIN_ROUTINE(builtin_id, \ + object_type, \ + object_prototype_builtin_id, \ + is_extensible, \ + lowercase_name) \ + ecma_builtin_ ## lowercase_name ## _dispatch_routine, + #include "ecma-builtins.inc.h" + #undef BUILTIN + #undef BUILTIN_ROUTINE + #define BUILTIN_ROUTINE(a, b, c, d, e) + #define BUILTIN(builtin_id, \ + object_type, \ + object_prototype_builtin_id, \ + is_extensible, \ + lowercase_name) \ + ecma_builtin_ ## lowercase_name ## _dispatch_routine, + #include "ecma-builtins.inc.h" + #undef BUILTIN + #undef BUILTIN_ROUTINE +}; + +static const ecma_builtin_dispatch_call_t ecma_builtin_call_functions[] = +{ + #define BUILTIN(a, b, c, d, e) + #define BUILTIN_ROUTINE(builtin_id, \ + object_type, \ + object_prototype_builtin_id, \ + is_extensible, \ + lowercase_name) \ + ecma_builtin_ ## lowercase_name ## _dispatch_call, + #include "ecma-builtins.inc.h" + #undef BUILTIN_ROUTINE + #undef BUILTIN +}; + +static const ecma_builtin_dispatch_call_t ecma_builtin_construct_functions[] = +{ + #define BUILTIN(a, b, c, d, e) + #define BUILTIN_ROUTINE(builtin_id, \ + object_type, \ + object_prototype_builtin_id, \ + is_extensible, \ + lowercase_name) \ + ecma_builtin_ ## lowercase_name ## _dispatch_construct, + #include "ecma-builtins.inc.h" + #undef BUILTIN_ROUTINE + #undef BUILTIN +}; + /** * Property descriptor lists for all built-ins. */ static const ecma_builtin_property_list_reference_t ecma_builtin_property_list_references[] = { +#define BUILTIN(a, b, c, d, e) +#define BUILTIN_ROUTINE(builtin_id, \ + object_type, \ + object_prototype_builtin_id, \ + is_extensible, \ + lowercase_name) \ + ecma_builtin_ ## lowercase_name ## _property_descriptor_list, +#include "ecma-builtins.inc.h" +#undef BUILTIN +#undef BUILTIN_ROUTINE +#define BUILTIN_ROUTINE(a, b, c, d, e) #define BUILTIN(builtin_id, \ object_type, \ object_prototype_builtin_id, \ is_extensible, \ - is_static, \ lowercase_name) \ ecma_builtin_ ## lowercase_name ## _property_descriptor_list, #include "ecma-builtins.inc.h" +#undef BUILTIN_ROUTINE +#undef BUILTIN }; /** @@ -162,7 +233,7 @@ ecma_builtin_init_object (ecma_builtin_id_t obj_builtin_id, /**< built-in ID */ ecma_object_t *obj_p = ecma_create_object (prototype_obj_p, ext_object_size, obj_type); - if (!is_extensible) + if (unlikely (!is_extensible)) { ecma_set_object_extensible (obj_p, false); } @@ -224,8 +295,7 @@ ecma_builtin_init_object (ecma_builtin_id_t obj_builtin_id, /**< built-in ID */ ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p; ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_STRING_UL; - ecma_string_t *prim_prop_str_value_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); - ext_object_p->u.class_prop.u.value = ecma_make_string_value (prim_prop_str_value_p); + ext_object_p->u.class_prop.u.value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); break; } #endif /* !CONFIG_DISABLE_STRING_BUILTIN */ @@ -290,6 +360,39 @@ ecma_builtin_init_object (ecma_builtin_id_t obj_builtin_id, /**< built-in ID */ return obj_p; } /* ecma_builtin_init_object */ +/** + * Helper function for 'ecma_instantiate_builtin' + */ +static void +ecma_instantiate_builtin_helper (ecma_builtin_id_t builtin_id, /**< built-in id */ + ecma_object_type_t object_type, /**< object type */ + ecma_builtin_id_t object_prototype_builtin_id, /**< built-in id of prototype */ + bool is_extensible) /**< value of object's [[Extensible]] property */ +{ + JERRY_ASSERT (JERRY_CONTEXT (ecma_builtin_objects)[builtin_id] == NULL); + + ecma_object_t *prototype_obj_p; + if (object_prototype_builtin_id == ECMA_BUILTIN_ID__COUNT) + { + prototype_obj_p = NULL; + } + else + { + if (JERRY_CONTEXT (ecma_builtin_objects)[object_prototype_builtin_id] == NULL) + { + ecma_instantiate_builtin (object_prototype_builtin_id); + } + prototype_obj_p = JERRY_CONTEXT (ecma_builtin_objects)[object_prototype_builtin_id]; + JERRY_ASSERT (prototype_obj_p != NULL); + } + + ecma_object_t *builtin_obj_p = ecma_builtin_init_object (builtin_id, + prototype_obj_p, + object_type, + is_extensible); + JERRY_CONTEXT (ecma_builtin_objects)[builtin_id] = builtin_obj_p; +} /* ecma_instantiate_builtin_helper */ + /** * Instantiate specified ECMA built-in object */ @@ -302,37 +405,19 @@ ecma_instantiate_builtin (ecma_builtin_id_t id) /**< built-in id */ object_type, \ object_prototype_builtin_id, \ is_extensible, \ - is_static, \ lowercase_name) \ case builtin_id: \ { \ - JERRY_ASSERT (JERRY_CONTEXT (ecma_builtin_objects)[builtin_id] == NULL); \ - \ - ecma_object_t *prototype_obj_p; \ - if (object_prototype_builtin_id == ECMA_BUILTIN_ID__COUNT) \ - { \ - prototype_obj_p = NULL; \ - } \ - else \ - { \ - if (JERRY_CONTEXT (ecma_builtin_objects)[object_prototype_builtin_id] == NULL) \ - { \ - ecma_instantiate_builtin (object_prototype_builtin_id); \ - } \ - prototype_obj_p = JERRY_CONTEXT (ecma_builtin_objects)[object_prototype_builtin_id]; \ - JERRY_ASSERT (prototype_obj_p != NULL); \ - } \ - \ - ecma_object_t *builtin_obj_p = ecma_builtin_init_object (builtin_id, \ - prototype_obj_p, \ - object_type, \ - is_extensible); \ - JERRY_CONTEXT (ecma_builtin_objects)[builtin_id] = builtin_obj_p; \ - \ + ecma_instantiate_builtin_helper (builtin_id, \ + object_type, \ + object_prototype_builtin_id, \ + is_extensible); \ break; \ } +#define BUILTIN_ROUTINE(a, b, c, d, e) BUILTIN(a, b, c, d, e) #include "ecma-builtins.inc.h" - +#undef BUILTIN +#undef BUILTIN_ROUTINE default: { JERRY_ASSERT (id < ECMA_BUILTIN_ID__COUNT); @@ -611,7 +696,7 @@ ecma_builtin_try_to_instantiate_property (ecma_object_t *object_p, /**< object * } case ECMA_BUILTIN_PROPERTY_STRING: { - value = ecma_make_string_value (ecma_get_magic_string (curr_property_p->value)); + value = ecma_make_magic_string_value (curr_property_p->value); break; } case ECMA_BUILTIN_PROPERTY_OBJECT: @@ -718,9 +803,9 @@ ecma_builtin_list_lazy_property_names (ecma_object_t *object_p, /**< a built-in ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; /* 'length' property is non-enumerable (ECMA-262 v5, 15) */ - ecma_string_t *name_p = ecma_new_ecma_length_string (); - ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); - ecma_deref_ecma_string (name_p); + ecma_append_to_values_collection (for_non_enumerable_p, + ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH), + 0); } else { @@ -764,8 +849,8 @@ ecma_builtin_list_lazy_property_names (ecma_object_t *object_p, /**< a built-in if (!(*bitset_p & bit_for_index) || ecma_op_object_has_own_property (object_p, name_p)) { ecma_append_to_values_collection (for_non_enumerable_p, - ecma_make_string_value (name_p), - true); + ecma_make_magic_string_value (curr_property_p->magic_string_id), + 0); } ecma_deref_ecma_string (name_p); @@ -788,38 +873,14 @@ ecma_builtin_dispatch_routine (ecma_builtin_id_t builtin_object_id, /**< built-i * of the built-in object's * routine property */ ecma_value_t this_arg_value, /**< 'this' argument value */ - const ecma_value_t arguments_list[], /**< list of arguments passed to routine */ - ecma_length_t arguments_number) /**< length of arguments' list */ + const ecma_value_t *arguments_list_p, /**< list of arguments passed to routine */ + ecma_length_t arguments_list_len) /**< length of arguments' list */ { - switch (builtin_object_id) - { -#define BUILTIN(builtin_id, \ - object_type, \ - object_prototype_builtin_id, \ - is_extensible, \ - is_static, \ - lowercase_name) \ - case builtin_id: \ - { \ - return ecma_builtin_ ## lowercase_name ## _dispatch_routine (builtin_routine_id, \ - this_arg_value, \ - arguments_list, \ - arguments_number); \ - } -#include "ecma-builtins.inc.h" - - case ECMA_BUILTIN_ID__COUNT: - { - JERRY_UNREACHABLE (); - } - - default: - { - JERRY_UNREACHABLE (); /* The built-in is not implemented. */ - } - } - - JERRY_UNREACHABLE (); + JERRY_ASSERT (builtin_object_id < ECMA_BUILTIN_ID__COUNT); + return ecma_builtin_routines[builtin_object_id] (builtin_routine_id, + this_arg_value, + arguments_list_p, + arguments_list_len); } /* ecma_builtin_dispatch_routine */ /** @@ -849,35 +910,9 @@ ecma_builtin_dispatch_call (ecma_object_t *obj_p, /**< built-in object */ } else { - switch ((ecma_builtin_id_t) ext_obj_p->u.built_in.id) - { -#define BUILTIN(builtin_id, \ - object_type, \ - object_prototype_builtin_id, \ - is_extensible, \ - is_static, \ - lowercase_name) \ - case builtin_id: \ - { \ - if (object_type == ECMA_OBJECT_TYPE_FUNCTION) \ - { \ - ret_value = ecma_builtin_ ## lowercase_name ## _dispatch_call (arguments_list_p, \ - arguments_list_len); \ - } \ - break; \ - } -#include "ecma-builtins.inc.h" - - case ECMA_BUILTIN_ID__COUNT: - { - JERRY_UNREACHABLE (); - } - - default: - { - JERRY_UNREACHABLE (); /* The built-in is not implemented. */ - } - } + ecma_builtin_id_t builtin_object_id = ext_obj_p->u.built_in.id; + JERRY_ASSERT (builtin_object_id < sizeof (ecma_builtin_call_functions) / sizeof (ecma_builtin_dispatch_call_t)); + return ecma_builtin_call_functions[builtin_object_id] (arguments_list_p, arguments_list_len); } JERRY_ASSERT (!ecma_is_value_empty (ret_value)); @@ -898,43 +933,10 @@ ecma_builtin_dispatch_construct (ecma_object_t *obj_p, /**< built-in object */ JERRY_ASSERT (ecma_get_object_type (obj_p) == ECMA_OBJECT_TYPE_FUNCTION); JERRY_ASSERT (ecma_get_object_is_builtin (obj_p)); - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) obj_p; - - switch (ext_obj_p->u.built_in.id) - { -#define BUILTIN(builtin_id, \ - object_type, \ - object_prototype_builtin_id, \ - is_extensible, \ - is_static, \ - lowercase_name) \ - case builtin_id: \ - { \ - if (object_type == ECMA_OBJECT_TYPE_FUNCTION) \ - { \ - ret_value = ecma_builtin_ ## lowercase_name ## _dispatch_construct (arguments_list_p, \ - arguments_list_len); \ - } \ - break; \ - } -#include "ecma-builtins.inc.h" - - case ECMA_BUILTIN_ID__COUNT: - { - JERRY_UNREACHABLE (); - } - - default: - { - JERRY_UNREACHABLE (); /* The built-in is not implemented. */ - } - } - - JERRY_ASSERT (!ecma_is_value_empty (ret_value)); - - return ret_value; + ecma_builtin_id_t builtin_object_id = ext_obj_p->u.built_in.id; + JERRY_ASSERT (builtin_object_id < sizeof (ecma_builtin_construct_functions) / sizeof (ecma_builtin_dispatch_call_t)); + return ecma_builtin_construct_functions[builtin_object_id] (arguments_list_p, arguments_list_len); } /* ecma_builtin_dispatch_construct */ /** diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtins.h b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtins.h index 2468018..11ac1dc 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtins.h +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtins.h @@ -23,14 +23,26 @@ */ typedef enum { +#define BUILTIN(a, b, c, d, e) +#define BUILTIN_ROUTINE(builtin_id, \ + object_type, \ + object_prototype_builtin_id, \ + is_extensible, \ + lowercase_name) \ + builtin_id, +#include "ecma-builtins.inc.h" +#undef BUILTIN +#undef BUILTIN_ROUTINE +#define BUILTIN_ROUTINE(a, b, c, d, e) #define BUILTIN(builtin_id, \ object_type, \ object_prototype_builtin_id, \ is_extensible, \ - is_static, \ lowercase_name) \ builtin_id, #include "ecma-builtins.inc.h" +#undef BUILTIN +#undef BUILTIN_ROUTINE ECMA_BUILTIN_ID__COUNT /**< number of built-in objects */ } ecma_builtin_id_t; diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h index fdc68eb..d557f57 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h +++ b/deps/jerry/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h @@ -21,16 +21,14 @@ BUILTIN (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID__COUNT /* no prototype */, true, - true, object_prototype) /* The Object object (15.2.1) */ -BUILTIN (ECMA_BUILTIN_ID_OBJECT, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - object) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_OBJECT, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + object) #ifndef CONFIG_DISABLE_ARRAY_BUILTIN /* The Array.prototype object (15.4.4) */ @@ -38,16 +36,14 @@ BUILTIN (ECMA_BUILTIN_ID_ARRAY_PROTOTYPE, ECMA_OBJECT_TYPE_ARRAY, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, true, - true, array_prototype) /* The Array object (15.4.1) */ -BUILTIN (ECMA_BUILTIN_ID_ARRAY, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - array) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_ARRAY, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + array) #endif /* !CONFIG_DISABLE_ARRAY_BUILTIN*/ #ifndef CONFIG_DISABLE_STRING_BUILTIN @@ -56,16 +52,14 @@ BUILTIN (ECMA_BUILTIN_ID_STRING_PROTOTYPE, ECMA_OBJECT_TYPE_CLASS, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, true, - true, string_prototype) /* The String object (15.5.1) */ -BUILTIN (ECMA_BUILTIN_ID_STRING, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - string) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_STRING, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + string) #endif /* !CONFIG_DISABLE_STRING_BUILTIN */ #ifndef CONFIG_DISABLE_BOOLEAN_BUILTIN @@ -74,16 +68,14 @@ BUILTIN (ECMA_BUILTIN_ID_BOOLEAN_PROTOTYPE, ECMA_OBJECT_TYPE_CLASS, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, true, - true, boolean_prototype) /* The Boolean object (15.6.1) */ -BUILTIN (ECMA_BUILTIN_ID_BOOLEAN, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - boolean) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_BOOLEAN, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + boolean) #endif /* !CONFIG_DISABLE_BOOLEAN_BUILTIN */ #ifndef CONFIG_DISABLE_NUMBER_BUILTIN @@ -92,33 +84,29 @@ BUILTIN (ECMA_BUILTIN_ID_NUMBER_PROTOTYPE, ECMA_OBJECT_TYPE_CLASS, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, true, - true, number_prototype) /* The Number object (15.7.1) */ -BUILTIN (ECMA_BUILTIN_ID_NUMBER, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - number) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_NUMBER, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + number) #endif /* !CONFIG_DISABLE_NUMBER_BUILTIN */ /* The Function.prototype object (15.3.4) */ -BUILTIN (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, - true, - true, - function_prototype) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + function_prototype) /* The Function object (15.3.1) */ -BUILTIN (ECMA_BUILTIN_ID_FUNCTION, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - function) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_FUNCTION, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + function) #ifndef CONFIG_DISABLE_MATH_BUILTIN /* The Math object (15.8) */ @@ -126,7 +114,6 @@ BUILTIN (ECMA_BUILTIN_ID_MATH, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, true, - true, math) #endif /* !CONFIG_DISABLE_MATH_BUILTIN */ @@ -136,7 +123,6 @@ BUILTIN (ECMA_BUILTIN_ID_JSON, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, true, - true, json) #endif /* !CONFIG_DISABLE_JSON_BUILTIN */ @@ -146,16 +132,14 @@ BUILTIN (ECMA_BUILTIN_ID_DATE_PROTOTYPE, ECMA_OBJECT_TYPE_CLASS, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, true, - true, date_prototype) /* The Date object (15.9.3) */ -BUILTIN (ECMA_BUILTIN_ID_DATE, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - date) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_DATE, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + date) #endif /* !CONFIG_DISABLE_DATE_BUILTIN */ #ifndef CONFIG_DISABLE_REGEXP_BUILTIN @@ -164,32 +148,28 @@ BUILTIN (ECMA_BUILTIN_ID_REGEXP_PROTOTYPE, ECMA_OBJECT_TYPE_CLASS, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, true, - true, regexp_prototype) /* The RegExp object (15.10) */ -BUILTIN (ECMA_BUILTIN_ID_REGEXP, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - regexp) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_REGEXP, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + regexp) #endif /* !CONFIG_DISABLE_REGEXP_BUILTIN */ /* The Error object (15.11.1) */ -BUILTIN (ECMA_BUILTIN_ID_ERROR, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - error) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_ERROR, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + error) /* The Error.prototype object (15.11.4) */ BUILTIN (ECMA_BUILTIN_ID_ERROR_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, true, - true, error_prototype) #ifndef CONFIG_DISABLE_ERROR_BUILTINS @@ -198,105 +178,92 @@ BUILTIN (ECMA_BUILTIN_ID_EVAL_ERROR_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_ERROR_PROTOTYPE, true, - true, eval_error_prototype) /* The EvalError object (15.11.6.1) */ -BUILTIN (ECMA_BUILTIN_ID_EVAL_ERROR, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - eval_error) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_EVAL_ERROR, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + eval_error) /* The RangeError.prototype object (15.11.6.2) */ BUILTIN (ECMA_BUILTIN_ID_RANGE_ERROR_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_ERROR_PROTOTYPE, true, - true, range_error_prototype) /* The RangeError object (15.11.6.2) */ -BUILTIN (ECMA_BUILTIN_ID_RANGE_ERROR, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - range_error) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_RANGE_ERROR, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + range_error) /* The ReferenceError.prototype object (15.11.6.3) */ BUILTIN (ECMA_BUILTIN_ID_REFERENCE_ERROR_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_ERROR_PROTOTYPE, true, - true, reference_error_prototype) /* The ReferenceError object (15.11.6.3) */ -BUILTIN (ECMA_BUILTIN_ID_REFERENCE_ERROR, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - reference_error) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_REFERENCE_ERROR, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + reference_error) /* The SyntaxError.prototype object (15.11.6.4) */ BUILTIN (ECMA_BUILTIN_ID_SYNTAX_ERROR_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_ERROR_PROTOTYPE, true, - true, syntax_error_prototype) /* The SyntaxError object (15.11.6.4) */ -BUILTIN (ECMA_BUILTIN_ID_SYNTAX_ERROR, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - syntax_error) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_SYNTAX_ERROR, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + syntax_error) /* The TypeError.prototype object (15.11.6.5) */ BUILTIN (ECMA_BUILTIN_ID_TYPE_ERROR_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_ERROR_PROTOTYPE, true, - true, type_error_prototype) /* The TypeError object (15.11.6.5) */ -BUILTIN (ECMA_BUILTIN_ID_TYPE_ERROR, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - type_error) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_TYPE_ERROR, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + type_error) /* The URIError.prototype object (15.11.6.6) */ BUILTIN (ECMA_BUILTIN_ID_URI_ERROR_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_ERROR_PROTOTYPE, true, - true, uri_error_prototype) /* The URIError object (15.11.6.6) */ -BUILTIN (ECMA_BUILTIN_ID_URI_ERROR, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - uri_error) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_URI_ERROR, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + uri_error) #endif /* !CONFIG_DISABLE_ERROR_BUILTINS */ /**< The [[ThrowTypeError]] object (13.2.3) */ -BUILTIN (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - false, - true, - type_error_thrower) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_TYPE_ERROR_THROWER, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + false, + type_error_thrower) #ifndef CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN @@ -305,160 +272,138 @@ BUILTIN (ECMA_BUILTIN_ID_ARRAYBUFFER_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, true, - true, arraybuffer_prototype) /* The ArrayBuffer object (ES2015 24.1.2) */ -BUILTIN (ECMA_BUILTIN_ID_ARRAYBUFFER, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - arraybuffer) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_ARRAYBUFFER, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + arraybuffer) /* The %TypedArrayPrototype% object (ES2015 24.2.3) */ BUILTIN (ECMA_BUILTIN_ID_TYPEDARRAY_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, true, - true, typedarray_prototype) /* The %TypedArray% intrinsic object (ES2015 22.2.1) */ -BUILTIN (ECMA_BUILTIN_ID_TYPEDARRAY, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - typedarray) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_TYPEDARRAY, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + typedarray) BUILTIN (ECMA_BUILTIN_ID_INT8ARRAY_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_TYPEDARRAY_PROTOTYPE, true, - true, int8array_prototype) -BUILTIN (ECMA_BUILTIN_ID_INT8ARRAY, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_TYPEDARRAY, - true, - true, - int8array) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_INT8ARRAY, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_TYPEDARRAY, + true, + int8array) BUILTIN (ECMA_BUILTIN_ID_UINT8ARRAY_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_TYPEDARRAY_PROTOTYPE, true, - true, uint8array_prototype) -BUILTIN (ECMA_BUILTIN_ID_UINT8ARRAY, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_TYPEDARRAY, - true, - true, - uint8array) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_UINT8ARRAY, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_TYPEDARRAY, + true, + uint8array) BUILTIN (ECMA_BUILTIN_ID_INT16ARRAY_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_TYPEDARRAY_PROTOTYPE, true, - true, int16array_prototype) -BUILTIN (ECMA_BUILTIN_ID_INT16ARRAY, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_TYPEDARRAY, - true, - true, - int16array) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_INT16ARRAY, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_TYPEDARRAY, + true, + int16array) BUILTIN (ECMA_BUILTIN_ID_UINT16ARRAY_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_TYPEDARRAY_PROTOTYPE, true, - true, uint16array_prototype) -BUILTIN (ECMA_BUILTIN_ID_UINT16ARRAY, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_TYPEDARRAY, - true, - true, - uint16array) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_UINT16ARRAY, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_TYPEDARRAY, + true, + uint16array) BUILTIN (ECMA_BUILTIN_ID_INT32ARRAY_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_TYPEDARRAY_PROTOTYPE, true, - true, int32array_prototype) -BUILTIN (ECMA_BUILTIN_ID_INT32ARRAY, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_TYPEDARRAY, - true, - true, - int32array) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_INT32ARRAY, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_TYPEDARRAY, + true, + int32array) BUILTIN (ECMA_BUILTIN_ID_UINT32ARRAY_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_TYPEDARRAY_PROTOTYPE, true, - true, uint32array_prototype) -BUILTIN (ECMA_BUILTIN_ID_UINT32ARRAY, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_TYPEDARRAY, - true, - true, - uint32array) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_UINT32ARRAY, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_TYPEDARRAY, + true, + uint32array) BUILTIN (ECMA_BUILTIN_ID_FLOAT32ARRAY_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_TYPEDARRAY_PROTOTYPE, true, - true, float32array_prototype) -BUILTIN (ECMA_BUILTIN_ID_FLOAT32ARRAY, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_TYPEDARRAY, - true, - true, - float32array) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_FLOAT32ARRAY, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_TYPEDARRAY, + true, + float32array) #if CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 BUILTIN (ECMA_BUILTIN_ID_FLOAT64ARRAY_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_TYPEDARRAY_PROTOTYPE, true, - true, float64array_prototype) -BUILTIN (ECMA_BUILTIN_ID_FLOAT64ARRAY, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_TYPEDARRAY, - true, - true, - float64array) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_FLOAT64ARRAY, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_TYPEDARRAY, + true, + float64array) #endif /* CONFIG_ECMA_NUMBER_TYPE == CONFIG_ECMA_NUMBER_FLOAT64 */ BUILTIN (ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_TYPEDARRAY_PROTOTYPE, true, - true, uint8clampedarray_prototype) -BUILTIN (ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_TYPEDARRAY, - true, - true, - uint8clampedarray) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_UINT8CLAMPEDARRAY, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_TYPEDARRAY, + true, + uint8clampedarray) #endif /* !CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN */ @@ -468,15 +413,13 @@ BUILTIN (ECMA_BUILTIN_ID_PROMISE_PROTOTYPE, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, true, - true, promise_prototype) -BUILTIN (ECMA_BUILTIN_ID_PROMISE, - ECMA_OBJECT_TYPE_FUNCTION, - ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, - true, - true, - promise) +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_PROMISE, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + promise) #endif /* !CONFIG_DISABLE_ES2015_PROMISE_BUILTIN */ @@ -485,7 +428,6 @@ BUILTIN (ECMA_BUILTIN_ID_GLOBAL, ECMA_OBJECT_TYPE_GENERAL, ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, /* Implementation-dependent */ true, - true, global) #undef BUILTIN diff --git a/deps/jerry/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c b/deps/jerry/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c index b633503..6b09a71 100644 --- a/deps/jerry/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c +++ b/deps/jerry/jerry-core/ecma/builtin-objects/typedarray/ecma-builtin-typedarray-prototype.c @@ -736,11 +736,10 @@ ecma_builtin_typedarray_prototype_set (ecma_value_t this_arg, /**< this argument while (k < source_length_uint32 && ecma_is_value_empty (ret_val)) { - ecma_string_t k_str; - ecma_init_ecma_string_from_uint32 (&k_str, k); + ecma_string_t *k_str_p = ecma_new_ecma_string_from_uint32 (k); ECMA_TRY_CATCH (elem, - ecma_op_object_get (source_obj_p, &k_str), + ecma_op_object_get (source_obj_p, k_str_p), ret_val); ECMA_OP_TO_NUMBER_TRY_CATCH (elem_num, elem, ret_val); @@ -750,6 +749,8 @@ ecma_builtin_typedarray_prototype_set (ecma_value_t this_arg, /**< this argument ECMA_OP_TO_NUMBER_FINALIZE (elem_num); ECMA_FINALIZE (elem); + ecma_deref_ecma_string (k_str_p); + k++; target_byte_index += element_size; } diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-array-object.c b/deps/jerry/jerry-core/ecma/operations/ecma-array-object.c index 298bfec..6fe9222 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-array-object.c +++ b/deps/jerry/jerry-core/ecma/operations/ecma-array-object.c @@ -353,9 +353,9 @@ ecma_op_array_list_lazy_property_names (ecma_object_t *obj_p, /**< a String obje ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; - ecma_string_t *length_str_p = ecma_new_ecma_length_string (); - ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (length_str_p), true); - ecma_deref_ecma_string (length_str_p); + ecma_append_to_values_collection (for_non_enumerable_p, + ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH), + 0); } /* ecma_op_array_list_lazy_property_names */ /** diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-arraybuffer-object.c b/deps/jerry/jerry-core/ecma/operations/ecma-arraybuffer-object.c index b5e68c7..1840791 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-arraybuffer-object.c +++ b/deps/jerry/jerry-core/ecma/operations/ecma-arraybuffer-object.c @@ -51,6 +51,7 @@ ecma_arraybuffer_new_object (ecma_length_t length) /**< length of the arraybuffe ECMA_OBJECT_TYPE_CLASS); ecma_deref_object (prototype_obj_p); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + ext_object_p->u.class_prop.extra_info = ECMA_ARRAYBUFFER_INTERNAL_MEMORY; ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_ARRAY_BUFFER_UL; ext_object_p->u.class_prop.u.length = length; @@ -60,6 +61,38 @@ ecma_arraybuffer_new_object (ecma_length_t length) /**< length of the arraybuffe return object_p; } /* ecma_arraybuffer_new_object */ +/** + * Helper function: create arraybuffer object with external buffer backing. + * + * The struct of external arraybuffer object: + * ecma_object_t + * extend_part + * arraybuffer external info part + * + * @return ecma_object_t *, pointer to the created ArrayBuffer object + */ +ecma_object_t * +ecma_arraybuffer_new_object_external (ecma_length_t length, /**< length of the buffer_p to use */ + void *buffer_p, /**< pointer for ArrayBuffer's buffer backing */ + ecma_object_native_free_callback_t free_cb) /**< buffer free callback */ +{ + ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAYBUFFER_PROTOTYPE); + ecma_object_t *object_p = ecma_create_object (prototype_obj_p, + sizeof (ecma_arraybuffer_external_info), + ECMA_OBJECT_TYPE_CLASS); + ecma_deref_object (prototype_obj_p); + ecma_arraybuffer_external_info *array_object_p = (ecma_arraybuffer_external_info *) object_p; + array_object_p->extended_object.u.class_prop.extra_info = ECMA_ARRAYBUFFER_EXTERNAL_MEMORY; + array_object_p->extended_object.u.class_prop.class_id = LIT_MAGIC_STRING_ARRAY_BUFFER_UL; + array_object_p->extended_object.u.class_prop.u.length = length; + + array_object_p->buffer_p = buffer_p; + array_object_p->free_cb = free_cb; + + return object_p; +} /* ecma_arraybuffer_new_object_external */ + + /** * ArrayBuffer object creation operation. * @@ -158,7 +191,16 @@ ecma_arraybuffer_get_buffer (ecma_object_t *object_p) /**< pointer to the ArrayB JERRY_ASSERT (ecma_object_class_is (object_p, LIT_MAGIC_STRING_ARRAY_BUFFER_UL)); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; - return (lit_utf8_byte_t *) (ext_object_p + 1); + + if (ECMA_ARRAYBUFFER_HAS_EXTERNAL_MEMORY (ext_object_p)) + { + ecma_arraybuffer_external_info *array_p = (ecma_arraybuffer_external_info *) ext_object_p; + return (lit_utf8_byte_t *) array_p->buffer_p; + } + else + { + return (lit_utf8_byte_t *) (ext_object_p + 1); + } } /* ecma_arraybuffer_get_buffer */ /** diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-arraybuffer-object.h b/deps/jerry/jerry-core/ecma/operations/ecma-arraybuffer-object.h index f363f4c..0fe3f5c 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-arraybuffer-object.h +++ b/deps/jerry/jerry-core/ecma/operations/ecma-arraybuffer-object.h @@ -34,6 +34,10 @@ ecma_op_create_arraybuffer_object (const ecma_value_t *, ecma_length_t); */ ecma_object_t * ecma_arraybuffer_new_object (ecma_length_t lengh); +ecma_object_t * +ecma_arraybuffer_new_object_external (ecma_length_t length, + void *buffer_p, + ecma_object_native_free_callback_t free_cb); lit_utf8_byte_t * ecma_arraybuffer_get_buffer (ecma_object_t *obj_p) __attr_pure___; ecma_length_t diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-conversion.c b/deps/jerry/jerry-core/ecma/operations/ecma-conversion.c index 4314623..e1fe516 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-conversion.c +++ b/deps/jerry/jerry-core/ecma/operations/ecma-conversion.c @@ -247,58 +247,116 @@ ecma_op_to_number (ecma_value_t value) /**< ecma value */ { return value; } - else if (ecma_is_value_float_number (value)) + + if (ecma_is_value_float_number (value)) { return ecma_copy_value (value); } - else if (ecma_is_value_string (value)) + + if (ecma_is_value_string (value)) { ecma_string_t *str_p = ecma_get_string_from_value (value); return ecma_make_number_value (ecma_string_to_number (str_p)); } - else if (ecma_is_value_object (value)) + + if (ecma_is_value_object (value)) { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; + ecma_value_t primitive_value = ecma_op_to_primitive (value, ECMA_PREFERRED_TYPE_NUMBER); - ECMA_TRY_CATCH (primitive_value, - ecma_op_to_primitive (value, ECMA_PREFERRED_TYPE_NUMBER), - ret_value); + if (ECMA_IS_VALUE_ERROR (primitive_value)) + { + return primitive_value; + } - ret_value = ecma_op_to_number (primitive_value); + ecma_value_t ret_value = ecma_op_to_number (primitive_value); + ecma_fast_free_value (primitive_value); + return ret_value; + } - ECMA_FINALIZE (primitive_value); + if (ecma_is_value_undefined (value)) + { + return ecma_make_nan_value (); + } - return ret_value; + ecma_integer_value_t num = 0; + + if (ecma_is_value_null (value)) + { + num = 0; } else { - int16_t num = 0; + JERRY_ASSERT (ecma_is_value_boolean (value)); - if (ecma_is_value_undefined (value)) - { - return ecma_make_nan_value (); - } - else if (ecma_is_value_null (value)) + num = ecma_is_value_true (value) ? 1 : 0; + } + + return ecma_make_integer_value (num); +} /* ecma_op_to_number */ + +/** + * Helper to get the number contained in an ecma value. + * + * See also: + * ECMA-262 v5, 9.3 + * + * @return ECMA_VALUE_EMPTY if successful + * conversion error otherwise + * Returned value must be freed with ecma_free_value + */ +ecma_value_t +ecma_get_number (ecma_value_t value, ecma_number_t *number_p) +{ + if (ecma_is_value_integer_number (value)) + { + *number_p = ecma_get_integer_from_value (value); + return ECMA_VALUE_EMPTY; + } + + if (ecma_is_value_float_number (value)) + { + *number_p = ecma_get_float_from_value (value); + return ECMA_VALUE_EMPTY; + } + + if (ecma_is_value_string (value)) + { + ecma_string_t *str_p = ecma_get_string_from_value (value); + *number_p = ecma_string_to_number (str_p); + return ECMA_VALUE_EMPTY; + } + + if (ecma_is_value_object (value)) + { + ecma_value_t primitive_value = ecma_op_to_primitive (value, ECMA_PREFERRED_TYPE_NUMBER); + + if (ECMA_IS_VALUE_ERROR (primitive_value)) { - num = 0; + return primitive_value; } - else - { - JERRY_ASSERT (ecma_is_value_boolean (value)); - if (ecma_is_value_true (value)) - { - num = 1; - } - else - { - num = 0; - } - } + ecma_value_t ret_value = ecma_get_number (primitive_value, number_p); + ecma_fast_free_value (primitive_value); + return ret_value; + } - return ecma_make_integer_value (num); + if (ecma_is_value_undefined (value)) + { + *number_p = ecma_number_make_nan (); + return ECMA_VALUE_EMPTY; } -} /* ecma_op_to_number */ + + if (ecma_is_value_null (value)) + { + *number_p = 0; + return ECMA_VALUE_EMPTY; + } + + JERRY_ASSERT (ecma_is_value_boolean (value)); + + *number_p = ecma_is_value_true (value) ? 1 : 0; + return ECMA_VALUE_EMPTY; +} /* ecma_get_number */ /** * ToString operation. @@ -461,24 +519,20 @@ ecma_op_from_property_descriptor (const ecma_property_descriptor_t *src_prop_des /* a. */ prop_desc.value = src_prop_desc_p->value; - ecma_string_t *value_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_VALUE); completion = ecma_op_object_define_own_property (obj_p, - value_magic_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_VALUE), &prop_desc, false); - ecma_deref_ecma_string (value_magic_string_p); JERRY_ASSERT (ecma_is_value_true (completion)); /* b. */ const bool is_writable = (src_prop_desc_p->is_writable); prop_desc.value = ecma_make_boolean_value (is_writable); - ecma_string_t *writable_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_WRITABLE); completion = ecma_op_object_define_own_property (obj_p, - writable_magic_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_WRITABLE), &prop_desc, false); - ecma_deref_ecma_string (writable_magic_string_p); JERRY_ASSERT (ecma_is_value_true (completion)); } else @@ -497,12 +551,10 @@ ecma_op_from_property_descriptor (const ecma_property_descriptor_t *src_prop_des prop_desc.value = ecma_make_object_value (src_prop_desc_p->get_p); } - ecma_string_t *get_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GET); completion = ecma_op_object_define_own_property (obj_p, - get_magic_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_GET), &prop_desc, false); - ecma_deref_ecma_string (get_magic_string_p); JERRY_ASSERT (ecma_is_value_true (completion)); /* b. */ @@ -515,35 +567,29 @@ ecma_op_from_property_descriptor (const ecma_property_descriptor_t *src_prop_des prop_desc.value = ecma_make_object_value (src_prop_desc_p->set_p); } - ecma_string_t *set_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SET); completion = ecma_op_object_define_own_property (obj_p, - set_magic_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_SET), &prop_desc, false); - ecma_deref_ecma_string (set_magic_string_p); JERRY_ASSERT (ecma_is_value_true (completion)); } const bool is_enumerable = src_prop_desc_p->is_enumerable; prop_desc.value = ecma_make_boolean_value (is_enumerable); - ecma_string_t *enumerable_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ENUMERABLE); completion = ecma_op_object_define_own_property (obj_p, - enumerable_magic_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_ENUMERABLE), &prop_desc, false); - ecma_deref_ecma_string (enumerable_magic_string_p); JERRY_ASSERT (ecma_is_value_true (completion)); const bool is_configurable = src_prop_desc_p->is_configurable; prop_desc.value = ecma_make_boolean_value (is_configurable); - ecma_string_t *configurable_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_CONFIGURABLE); completion = ecma_op_object_define_own_property (obj_p, - configurable_magic_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_CONFIGURABLE), &prop_desc, false); - ecma_deref_ecma_string (configurable_magic_string_p); JERRY_ASSERT (ecma_is_value_true (completion)); return obj_p; @@ -579,10 +625,8 @@ ecma_op_to_property_descriptor (ecma_value_t obj_value, /**< object value */ ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); /* 3. */ - ecma_string_t *enumerable_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_ENUMERABLE); - ECMA_TRY_CATCH (enumerable_prop_value, - ecma_op_object_find (obj_p, enumerable_magic_string_p), + ecma_op_object_find (obj_p, ecma_get_magic_string (LIT_MAGIC_STRING_ENUMERABLE)), ret_value); if (ecma_is_value_found (enumerable_prop_value)) @@ -593,17 +637,13 @@ ecma_op_to_property_descriptor (ecma_value_t obj_value, /**< object value */ ECMA_FINALIZE (enumerable_prop_value); - ecma_deref_ecma_string (enumerable_magic_string_p); - if (!ECMA_IS_VALUE_ERROR (ret_value)) { JERRY_ASSERT (ecma_is_value_empty (ret_value)); /* 4. */ - ecma_string_t *configurable_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_CONFIGURABLE); - ECMA_TRY_CATCH (configurable_prop_value, - ecma_op_object_find (obj_p, configurable_magic_string_p), + ecma_op_object_find (obj_p, ecma_get_magic_string (LIT_MAGIC_STRING_CONFIGURABLE)), ret_value); if (ecma_is_value_found (configurable_prop_value)) @@ -613,8 +653,6 @@ ecma_op_to_property_descriptor (ecma_value_t obj_value, /**< object value */ } ECMA_FINALIZE (configurable_prop_value); - - ecma_deref_ecma_string (configurable_magic_string_p); } if (!ECMA_IS_VALUE_ERROR (ret_value)) @@ -622,10 +660,8 @@ ecma_op_to_property_descriptor (ecma_value_t obj_value, /**< object value */ JERRY_ASSERT (ecma_is_value_empty (ret_value)); /* 5. */ - ecma_string_t *value_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_VALUE); - ECMA_TRY_CATCH (value_prop_value, - ecma_op_object_find (obj_p, value_magic_string_p), + ecma_op_object_find (obj_p, ecma_get_magic_string (LIT_MAGIC_STRING_VALUE)), ret_value); if (ecma_is_value_found (value_prop_value)) @@ -635,8 +671,6 @@ ecma_op_to_property_descriptor (ecma_value_t obj_value, /**< object value */ } ECMA_FINALIZE (value_prop_value); - - ecma_deref_ecma_string (value_magic_string_p); } if (!ECMA_IS_VALUE_ERROR (ret_value)) @@ -644,10 +678,8 @@ ecma_op_to_property_descriptor (ecma_value_t obj_value, /**< object value */ JERRY_ASSERT (ecma_is_value_empty (ret_value)); /* 6. */ - ecma_string_t *writable_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_WRITABLE); - ECMA_TRY_CATCH (writable_prop_value, - ecma_op_object_find (obj_p, writable_magic_string_p), + ecma_op_object_find (obj_p, ecma_get_magic_string (LIT_MAGIC_STRING_WRITABLE)), ret_value); if (ecma_is_value_found (writable_prop_value)) @@ -657,8 +689,6 @@ ecma_op_to_property_descriptor (ecma_value_t obj_value, /**< object value */ } ECMA_FINALIZE (writable_prop_value); - - ecma_deref_ecma_string (writable_magic_string_p); } if (!ECMA_IS_VALUE_ERROR (ret_value)) @@ -666,10 +696,8 @@ ecma_op_to_property_descriptor (ecma_value_t obj_value, /**< object value */ JERRY_ASSERT (ecma_is_value_empty (ret_value)); /* 7. */ - ecma_string_t *get_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GET); - ECMA_TRY_CATCH (get_prop_value, - ecma_op_object_find (obj_p, get_magic_string_p), + ecma_op_object_find (obj_p, ecma_get_magic_string (LIT_MAGIC_STRING_GET)), ret_value); if (ecma_is_value_found (get_prop_value)) @@ -700,8 +728,6 @@ ecma_op_to_property_descriptor (ecma_value_t obj_value, /**< object value */ } ECMA_FINALIZE (get_prop_value); - - ecma_deref_ecma_string (get_magic_string_p); } if (!ECMA_IS_VALUE_ERROR (ret_value)) @@ -709,10 +735,8 @@ ecma_op_to_property_descriptor (ecma_value_t obj_value, /**< object value */ JERRY_ASSERT (ecma_is_value_empty (ret_value)); /* 8. */ - ecma_string_t *set_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SET); - ECMA_TRY_CATCH (set_prop_value, - ecma_op_object_find (obj_p, set_magic_string_p), + ecma_op_object_find (obj_p, ecma_get_magic_string (LIT_MAGIC_STRING_SET)), ret_value); if (ecma_is_value_found (set_prop_value)) @@ -743,8 +767,6 @@ ecma_op_to_property_descriptor (ecma_value_t obj_value, /**< object value */ } ECMA_FINALIZE (set_prop_value); - - ecma_deref_ecma_string (set_magic_string_p); } if (!ECMA_IS_VALUE_ERROR (ret_value)) diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-conversion.h b/deps/jerry/jerry-core/ecma/operations/ecma-conversion.h index 056b255..ce00ffe 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-conversion.h +++ b/deps/jerry/jerry-core/ecma/operations/ecma-conversion.h @@ -42,6 +42,7 @@ bool ecma_op_same_value (ecma_value_t x, ecma_value_t y); ecma_value_t ecma_op_to_primitive (ecma_value_t value, ecma_preferred_type_hint_t preferred_type); bool ecma_op_to_boolean (ecma_value_t value); ecma_value_t ecma_op_to_number (ecma_value_t value); +ecma_value_t ecma_get_number (ecma_value_t value, ecma_number_t *number_p); ecma_value_t ecma_op_to_string (ecma_value_t value); ecma_value_t ecma_op_to_object (ecma_value_t value); diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-eval.c b/deps/jerry/jerry-core/ecma/operations/ecma-eval.c index 4e4a34b..994d398 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-eval.c +++ b/deps/jerry/jerry-core/ecma/operations/ecma-eval.c @@ -23,6 +23,10 @@ #include "js-parser.h" #include "vm.h" +#ifdef JERRY_ENABLE_LINE_INFO +#include "jcontext.h" +#endif /* JERRY_ENABLE_LINE_INFO */ + /** \addtogroup ecma ECMA * @{ * @@ -88,6 +92,10 @@ ecma_op_eval_chars_buffer (const lit_utf8_byte_t *code_p, /**< code characters b bool is_strict_call = (is_direct && is_called_from_strict_mode_code); +#ifdef JERRY_ENABLE_LINE_INFO + JERRY_CONTEXT (resource_name) = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); +#endif /* JERRY_ENABLE_LINE_INFO */ + ecma_value_t parse_status = parser_parse_script (NULL, 0, code_p, diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-exceptions.c b/deps/jerry/jerry-core/ecma/operations/ecma-exceptions.c index aecd9af..f3e782b 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-exceptions.c +++ b/deps/jerry/jerry-core/ecma/operations/ecma-exceptions.c @@ -24,16 +24,46 @@ #include "jcontext.h" #include "jrt.h" +#ifdef JERRY_ENABLE_LINE_INFO +#include "vm.h" +#endif /* JERRY_ENABLE_LINE_INFO */ + /** \addtogroup ecma ECMA * @{ * * \addtogroup exceptions Exceptions * @{ */ +typedef struct +{ + ecma_standard_error_t error_type; + ecma_builtin_id_t error_prototype_id; +} ecma_error_mapping_t; + +const ecma_error_mapping_t ecma_error_mappings[] = +{ +#define ERROR_ELEMENT(TYPE, ID) { TYPE, ID } + ERROR_ELEMENT (ECMA_ERROR_COMMON, ECMA_BUILTIN_ID_ERROR_PROTOTYPE), + +#ifndef CONFIG_DISABLE_ERROR_BUILTINS + ERROR_ELEMENT (ECMA_ERROR_EVAL, ECMA_BUILTIN_ID_EVAL_ERROR_PROTOTYPE), + ERROR_ELEMENT (ECMA_ERROR_RANGE, ECMA_BUILTIN_ID_RANGE_ERROR_PROTOTYPE), + ERROR_ELEMENT (ECMA_ERROR_REFERENCE, ECMA_BUILTIN_ID_REFERENCE_ERROR_PROTOTYPE), + ERROR_ELEMENT (ECMA_ERROR_TYPE, ECMA_BUILTIN_ID_TYPE_ERROR_PROTOTYPE), + ERROR_ELEMENT (ECMA_ERROR_URI, ECMA_BUILTIN_ID_URI_ERROR_PROTOTYPE), + ERROR_ELEMENT (ECMA_ERROR_SYNTAX, ECMA_BUILTIN_ID_SYNTAX_ERROR_PROTOTYPE), +#endif /* !CONFIG_DISABLE_ERROR_BUILTINS */ + +#undef ERROR_ELEMENT +}; /** * Standard ecma-error object constructor. * + * Note: + * calling with ECMA_ERROR_NONE does not make sense thus it will + * cause a fault in the system. + * * @return pointer to ecma-object representing specified error * with reference counter set to one. */ @@ -86,6 +116,12 @@ ecma_new_standard_error (ecma_standard_error_t error_type) /**< native error typ prototype_id = ECMA_BUILTIN_ID_SYNTAX_ERROR_PROTOTYPE; break; } + + case ECMA_ERROR_NONE: + { + JERRY_UNREACHABLE (); + break; + } } #else JERRY_UNUSED (error_type); @@ -102,9 +138,53 @@ ecma_new_standard_error (ecma_standard_error_t error_type) /**< native error typ ((ecma_extended_object_t *) new_error_obj_p)->u.class_prop.class_id = LIT_MAGIC_STRING_ERROR_UL; +#ifdef JERRY_ENABLE_LINE_INFO + /* The "stack" identifier is not a magic string. */ + const char *stack_id_p = "stack"; + + ecma_string_t *stack_str_p = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *) stack_id_p, 5); + + ecma_property_value_t *prop_value_p = ecma_create_named_data_property (new_error_obj_p, + stack_str_p, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE, + NULL); + ecma_deref_ecma_string (stack_str_p); + + ecma_value_t backtrace_value = vm_get_backtrace (0); + + prop_value_p->value = backtrace_value; + ecma_deref_object (ecma_get_object_from_value (backtrace_value)); +#endif /* JERRY_ENABLE_LINE_INFO */ + return new_error_obj_p; } /* ecma_new_standard_error */ +/** + * Return the error type for an Error object. + * + * @return one of the ecma_standard_error_t value + * if it is not an Error object then ECMA_ERROR_NONE will be returned + */ +ecma_standard_error_t +ecma_get_error_type (ecma_object_t *error_object) /**< possible error object */ +{ + ecma_object_t *prototype_p = ecma_get_object_prototype (error_object); + if (prototype_p != NULL) + { + uint8_t builtin_id = ecma_get_object_builtin_id (prototype_p); + + for (uint8_t idx = 0; idx < sizeof (ecma_error_mappings) / sizeof (ecma_error_mappings[0]); idx++) + { + if (ecma_error_mappings[idx].error_prototype_id == builtin_id) + { + return ecma_error_mappings[idx].error_type; + } + } + } + + return ECMA_ERROR_NONE; +} /* ecma_get_error_type */ + /** * Standard ecma-error object constructor. * @@ -117,14 +197,11 @@ ecma_new_standard_error_with_message (ecma_standard_error_t error_type, /**< nat { ecma_object_t *new_error_obj_p = ecma_new_standard_error (error_type); - ecma_string_t *message_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE); - ecma_property_value_t *prop_value_p; prop_value_p = ecma_create_named_data_property (new_error_obj_p, - message_magic_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_MESSAGE), ECMA_PROPERTY_CONFIGURABLE_WRITABLE, NULL); - ecma_deref_ecma_string (message_magic_string_p); ecma_ref_ecma_string (message_string_p); prop_value_p->value = ecma_make_string_value (message_string_p); @@ -157,6 +234,7 @@ ecma_raise_standard_error (ecma_standard_error_t error_type, /**< error type */ } JERRY_CONTEXT (error_value) = ecma_make_object_value (error_obj_p); + JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; return ECMA_VALUE_ERROR; } /* ecma_raise_standard_error */ @@ -203,6 +281,7 @@ ecma_raise_standard_error_with_format (ecma_standard_error_t error_type, /**< er /* Convert an argument to string without side effects. */ ecma_string_t *arg_string_p; const ecma_value_t arg_val = va_arg (args, ecma_value_t); + if (unlikely (ecma_is_value_object (arg_val))) { ecma_object_t *arg_object_p = ecma_get_object_from_value (arg_val); @@ -243,6 +322,7 @@ ecma_raise_standard_error_with_format (ecma_standard_error_t error_type, /**< er ecma_deref_ecma_string (error_msg_p); JERRY_CONTEXT (error_value) = ecma_make_object_value (error_obj_p); + JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; return ECMA_VALUE_ERROR; } /* ecma_raise_standard_error_with_format */ diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-exceptions.h b/deps/jerry/jerry-core/ecma/operations/ecma-exceptions.h index 7decda2..c11c53a 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-exceptions.h +++ b/deps/jerry/jerry-core/ecma/operations/ecma-exceptions.h @@ -39,6 +39,8 @@ */ typedef enum { + ECMA_ERROR_NONE, /**< Not an Error */ + ECMA_ERROR_COMMON, /**< Error */ ECMA_ERROR_EVAL, /**< EvalError */ ECMA_ERROR_RANGE, /**< RangeError */ @@ -48,6 +50,7 @@ typedef enum ECMA_ERROR_URI /**< URIError */ } ecma_standard_error_t; +ecma_standard_error_t ecma_get_error_type (ecma_object_t *error_object); ecma_object_t *ecma_new_standard_error (ecma_standard_error_t error_type); ecma_object_t *ecma_new_standard_error_with_message (ecma_standard_error_t error_type, ecma_string_t *message_string_p); ecma_value_t ecma_raise_standard_error (ecma_standard_error_t error_type, const lit_utf8_byte_t *msg_p); diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-function-object.c b/deps/jerry/jerry-core/ecma/operations/ecma-function-object.c index 407ba48..30e4758 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-function-object.c +++ b/deps/jerry/jerry-core/ecma/operations/ecma-function-object.c @@ -124,8 +124,17 @@ ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */ /* 1., 4., 13. */ ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); + size_t function_object_size = sizeof (ecma_extended_object_t); + +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION) + { + function_object_size = sizeof (ecma_static_function_t); + } +#endif + ecma_object_t *func_p = ecma_create_object (prototype_obj_p, - sizeof (ecma_extended_object_t), + function_object_size, ECMA_OBJECT_TYPE_FUNCTION); ecma_deref_object (prototype_obj_p); @@ -150,8 +159,22 @@ ecma_op_create_function_object (ecma_object_t *scope_p, /**< function's scope */ ECMA_SET_INTERNAL_VALUE_POINTER (ext_func_p->u.function.scope_cp, scope_p); /* 10., 11., 12. */ + +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) + { + ECMA_SET_INTERNAL_VALUE_POINTER (ext_func_p->u.function.bytecode_cp, bytecode_data_p); + ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p); + } + else + { + ext_func_p->u.function.bytecode_cp = ECMA_NULL_POINTER; + ((ecma_static_function_t *) func_p)->bytecode_p = bytecode_data_p; + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ ECMA_SET_INTERNAL_VALUE_POINTER (ext_func_p->u.function.bytecode_cp, bytecode_data_p); ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p); +#endif /* 14., 15., 16., 17., 18. */ /* @@ -179,8 +202,17 @@ ecma_op_create_arrow_function_object (ecma_object_t *scope_p, /**< function's sc { ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); + size_t arrow_function_object_size = sizeof (ecma_arrow_function_t); + +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION) + { + arrow_function_object_size = sizeof (ecma_static_arrow_function_t); + } +#endif + ecma_object_t *func_p = ecma_create_object (prototype_obj_p, - sizeof (ecma_arrow_function_t), + arrow_function_object_size, ECMA_OBJECT_TYPE_ARROW_FUNCTION); ecma_deref_object (prototype_obj_p); @@ -190,8 +222,21 @@ ecma_op_create_arrow_function_object (ecma_object_t *scope_p, /**< function's sc ECMA_SET_NON_NULL_POINTER (arrow_func_p->scope_cp, scope_p); +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) + { + ECMA_SET_NON_NULL_POINTER (arrow_func_p->bytecode_cp, bytecode_data_p); + ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p); + } + else + { + arrow_func_p->bytecode_cp = ECMA_NULL_POINTER; + ((ecma_static_arrow_function_t *) func_p)->bytecode_p = bytecode_data_p; + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ ECMA_SET_NON_NULL_POINTER (arrow_func_p->bytecode_cp, bytecode_data_p); ecma_bytecode_ref ((ecma_compiled_code_t *) bytecode_data_p); +#endif arrow_func_p->this_binding = ecma_copy_value_if_not_object (this_binding); return func_p; @@ -232,6 +277,58 @@ ecma_op_create_external_function_object (ecma_external_handler_t handler_cb) /** return function_obj_p; } /* ecma_op_create_external_function_object */ +/** + * Get compiled code of a function object. + * + * @return compiled code + */ +inline const ecma_compiled_code_t * __attr_always_inline___ +ecma_op_function_get_compiled_code (ecma_extended_object_t *function_p) /**< function pointer */ +{ +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (function_p->u.function.bytecode_cp != ECMA_NULL_POINTER) + { + return ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, + function_p->u.function.bytecode_cp); + } + else + { + return ((ecma_static_function_t *) function_p)->bytecode_p; + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ + return ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, + function_p->u.function.bytecode_cp); +#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ +} /* ecma_op_function_get_compiled_code */ + +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION + +/** + * Get compiled code of an arrow function object. + * + * @return compiled code + */ +inline const ecma_compiled_code_t * __attr_always_inline___ +ecma_op_arrow_function_get_compiled_code (ecma_arrow_function_t *arrow_function_p) /**< arrow function pointer */ +{ +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (arrow_function_p->bytecode_cp != ECMA_NULL_POINTER) + { + return ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, + arrow_function_p->bytecode_cp); + } + else + { + return ((ecma_static_arrow_function_t *) arrow_function_p)->bytecode_p; + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ + return ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, + arrow_function_p->bytecode_cp); +#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ +} /* ecma_op_arrow_function_get_compiled_code */ + +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ + /** * [[Call]] implementation for Function objects, * created through 13.2 (ECMA_OBJECT_TYPE_FUNCTION) @@ -357,9 +454,7 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ bool is_strict; bool is_no_lex_env; - const ecma_compiled_code_t *bytecode_data_p; - bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp); + const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) ? true : false; is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) ? true : false; @@ -428,9 +523,7 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ bool is_no_lex_env; - const ecma_compiled_code_t *bytecode_data_p; - bytecode_data_p = ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, - arrow_func_p->bytecode_cp); + const ecma_compiled_code_t *bytecode_data_p = ecma_op_arrow_function_get_compiled_code (arrow_func_p); is_no_lex_env = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED) ? true : false; @@ -470,14 +563,20 @@ ecma_op_function_call (ecma_object_t *func_obj_p, /**< Function object */ if (unlikely (ecma_is_value_error_reference (ret_value))) { - JERRY_CONTEXT (error_value) = ecma_clear_error_reference (ret_value); + JERRY_CONTEXT (error_value) = ecma_clear_error_reference (ret_value, true); ret_value = ECMA_VALUE_ERROR; } + else + { +#ifdef JERRY_DEBUGGER + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN); +#endif /* JERRY_DEBUGGER */ + } } else { JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_BOUND_FUNCTION); - JERRY_CONTEXT (is_direct_eval_form_call) = false; + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL; /* 2-3. */ ecma_extended_object_t *ext_function_p = (ecma_extended_object_t *) func_obj_p; @@ -749,12 +848,11 @@ ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< ecma_object_t *proto_object_p = ecma_op_create_object_object_noarg (); /* 17. */ - ecma_string_t magic_string_constructor; - ecma_init_ecma_magic_string (&magic_string_constructor, LIT_MAGIC_STRING_CONSTRUCTOR); + ecma_string_t *magic_string_constructor_p = ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR); ecma_property_value_t *constructor_prop_value_p; constructor_prop_value_p = ecma_create_named_data_property (proto_object_p, - &magic_string_constructor, + magic_string_constructor_p, ECMA_PROPERTY_CONFIGURABLE_WRITABLE, NULL); @@ -783,15 +881,13 @@ ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, /**< if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_ARROW_FUNCTION) { ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; - bytecode_data_p = ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, - arrow_func_p->bytecode_cp); + bytecode_data_p = ecma_op_arrow_function_get_compiled_code (arrow_func_p); } else { #endif /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp); + bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); #ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION } #endif /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ @@ -953,32 +1049,29 @@ ecma_op_function_list_lazy_property_names (ecma_object_t *object_p, /**< functio ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; /* 'length' property is non-enumerable (ECMA-262 v5, 13.2.5) */ - ecma_string_t *name_p = ecma_new_ecma_length_string (); - ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); - ecma_deref_ecma_string (name_p); + ecma_append_to_values_collection (for_non_enumerable_p, + ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH), + 0); /* 'prototype' property is non-enumerable (ECMA-262 v5, 13.2.18) */ - name_p = ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE); - ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); - ecma_deref_ecma_string (name_p); - - ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; + ecma_append_to_values_collection (for_non_enumerable_p, + ecma_make_magic_string_value (LIT_MAGIC_STRING_PROTOTYPE), + 0); const ecma_compiled_code_t *bytecode_data_p; - bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp); + bytecode_data_p = ecma_op_function_get_compiled_code ((ecma_extended_object_t *) object_p); if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) { /* 'caller' property is non-enumerable (ECMA-262 v5, 13.2.5) */ - name_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER); - ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); - ecma_deref_ecma_string (name_p); + ecma_append_to_values_collection (for_non_enumerable_p, + ecma_make_magic_string_value (LIT_MAGIC_STRING_CALLER), + 0); /* 'arguments' property is non-enumerable (ECMA-262 v5, 13.2.5) */ - name_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS); - ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); - ecma_deref_ecma_string (name_p); + ecma_append_to_values_collection (for_non_enumerable_p, + ecma_make_magic_string_value (LIT_MAGIC_STRING_ARGUMENTS), + 0); } } /* ecma_op_function_list_lazy_property_names */ @@ -1008,9 +1101,9 @@ ecma_op_external_function_list_lazy_property_names (bool separate_enumerable, /* ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; /* 'prototype' property is non-enumerable (ECMA-262 v5, 13.2.18) */ - ecma_string_t *name_p = ecma_get_magic_string (LIT_MAGIC_STRING_PROTOTYPE); - ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); - ecma_deref_ecma_string (name_p); + ecma_append_to_values_collection (for_non_enumerable_p, + ecma_make_magic_string_value (LIT_MAGIC_STRING_PROTOTYPE), + 0); } /* ecma_op_external_function_list_lazy_property_names */ /** @@ -1040,19 +1133,19 @@ ecma_op_bound_function_list_lazy_property_names (bool separate_enumerable, /**< ecma_collection_header_t *for_non_enumerable_p = separate_enumerable ? non_enum_collection_p : main_collection_p; /* 'length' property is non-enumerable (ECMA-262 v5, 13.2.5) */ - ecma_string_t *name_p = ecma_new_ecma_length_string (); - ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); - ecma_deref_ecma_string (name_p); + ecma_append_to_values_collection (for_non_enumerable_p, + ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH), + 0); /* 'caller' property is non-enumerable (ECMA-262 v5, 13.2.5) */ - name_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER); - ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); - ecma_deref_ecma_string (name_p); + ecma_append_to_values_collection (for_non_enumerable_p, + ecma_make_magic_string_value (LIT_MAGIC_STRING_CALLER), + 0); /* 'arguments' property is non-enumerable (ECMA-262 v5, 13.2.5) */ - name_p = ecma_get_magic_string (LIT_MAGIC_STRING_ARGUMENTS); - ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (name_p), true); - ecma_deref_ecma_string (name_p); + ecma_append_to_values_collection (for_non_enumerable_p, + ecma_make_magic_string_value (LIT_MAGIC_STRING_ARGUMENTS), + 0); } /* ecma_op_bound_function_list_lazy_property_names */ /** diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-function-object.h b/deps/jerry/jerry-core/ecma/operations/ecma-function-object.h index 3a92c09..a047b6a 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-function-object.h +++ b/deps/jerry/jerry-core/ecma/operations/ecma-function-object.h @@ -43,6 +43,17 @@ ecma_op_create_arrow_function_object (ecma_object_t *scope_p, const ecma_compile ecma_object_t * ecma_op_create_external_function_object (ecma_external_handler_t handler_cb); +const ecma_compiled_code_t * +ecma_op_function_get_compiled_code (ecma_extended_object_t *function_p); + +#ifndef CONFIG_DISABLE_ES2015_ARROW_FUNCTION +const ecma_compiled_code_t * +ecma_op_arrow_function_get_compiled_code (ecma_arrow_function_t *arrow_function_p); +#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ + +ecma_value_t +ecma_op_function_has_instance (ecma_object_t *func_obj_p, ecma_value_t value); + ecma_value_t ecma_op_function_call (ecma_object_t *func_obj_p, ecma_value_t this_arg_value, const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len); @@ -51,9 +62,6 @@ ecma_value_t ecma_op_function_construct (ecma_object_t *func_obj_p, const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len); -ecma_value_t -ecma_op_function_has_instance (ecma_object_t *func_obj_p, ecma_value_t value); - ecma_property_t * ecma_op_function_try_to_lazy_instantiate_property (ecma_object_t *object_p, ecma_string_t *property_name_p); diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-get-put-value.c b/deps/jerry/jerry-core/ecma/operations/ecma-get-put-value.c index c9bf7b2..7d5873a 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-get-put-value.c +++ b/deps/jerry/jerry-core/ecma/operations/ecma-get-put-value.c @@ -98,15 +98,14 @@ ecma_op_get_value_object_base (ecma_value_t base_value, /**< base value */ || ecma_is_value_number (base_value) || ecma_is_value_string (base_value)); - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - - ECMA_TRY_CATCH (object_base, ecma_op_to_object (base_value), ret_value); + ecma_value_t object_base = ecma_op_to_object (base_value); + JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (object_base)); ecma_object_t *object_p = ecma_get_object_from_value (object_base); JERRY_ASSERT (object_p != NULL && !ecma_is_lexical_environment (object_p)); - ret_value = ECMA_VALUE_UNDEFINED; + ecma_value_t ret_value = ECMA_VALUE_UNDEFINED; /* Circular reference is possible in JavaScript and testing it is complicated. */ int max_depth = ECMA_PROPERTY_SEARCH_DEPTH_LIMIT; @@ -130,7 +129,7 @@ ecma_op_get_value_object_base (ecma_value_t base_value, /**< base value */ } while (object_p != NULL); - ECMA_FINALIZE (object_base); + ecma_free_value (object_base); return ret_value; } /* ecma_op_get_value_object_base */ diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-jobqueue.c b/deps/jerry/jerry-core/ecma/operations/ecma-jobqueue.c index f6c20be..59b5c8a 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-jobqueue.c +++ b/deps/jerry/jerry-core/ecma/operations/ecma-jobqueue.c @@ -145,15 +145,15 @@ ecma_process_promise_reaction_job (void *obj_p) /**< the job to be operated */ ecma_job_promise_reaction_t *job_p = (ecma_job_promise_reaction_t *) obj_p; ecma_object_t *reaction_p = ecma_get_object_from_value (job_p->reaction); - ecma_string_t *str_capability = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); - ecma_string_t *str_handler = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_HANDLER); - ecma_string_t *str_resolve = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); - ecma_string_t *str_reject = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); + ecma_string_t *capability_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); + ecma_string_t *handler_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_HANDLER); + ecma_string_t *resolve_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); + ecma_string_t *reject_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); /* 2. */ - ecma_value_t capability = ecma_op_object_get (reaction_p, str_capability); + ecma_value_t capability = ecma_op_object_get (reaction_p, capability_str_p); /* 3. */ - ecma_value_t handler = ecma_op_object_get (reaction_p, str_handler); + ecma_value_t handler = ecma_op_object_get (reaction_p, handler_str_p); JERRY_ASSERT (ecma_is_value_boolean (handler) || ecma_op_is_callable (handler)); @@ -183,7 +183,7 @@ ecma_process_promise_reaction_job (void *obj_p) /**< the job to be operated */ } /* 7. */ - ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), str_reject); + ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), reject_str_p); JERRY_ASSERT (ecma_op_is_callable (reject)); @@ -196,7 +196,7 @@ ecma_process_promise_reaction_job (void *obj_p) /**< the job to be operated */ else { /* 8. */ - ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), str_resolve); + ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), resolve_str_p); JERRY_ASSERT (ecma_op_is_callable (resolve)); @@ -210,10 +210,6 @@ ecma_process_promise_reaction_job (void *obj_p) /**< the job to be operated */ ecma_free_value (handler_result); ecma_free_value (handler); ecma_free_value (capability); - ecma_deref_ecma_string (str_capability); - ecma_deref_ecma_string (str_handler); - ecma_deref_ecma_string (str_resolve); - ecma_deref_ecma_string (str_reject); ecma_free_promise_reaction_job (job_p); return status; @@ -233,15 +229,16 @@ ecma_process_promise_resolve_thenable_job (void *obj_p) /**< the job to be opera ecma_job_promise_resolve_thenable_t *job_p = (ecma_job_promise_resolve_thenable_t *) obj_p; ecma_object_t *promise_p = ecma_get_object_from_value (job_p->promise); ecma_promise_resolving_functions_t *funcs = ecma_promise_create_resolving_functions (promise_p); - ecma_string_t str_resolve, str_reject; - ecma_init_ecma_magic_string (&str_resolve, LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION); - ecma_init_ecma_magic_string (&str_reject, LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION); + + ecma_string_t *str_resolve_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION); + ecma_string_t *str_reject_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION); + ecma_op_object_put (promise_p, - &str_resolve, + str_resolve_p, funcs->resolve, false); ecma_op_object_put (promise_p, - &str_reject, + str_reject_p, funcs->reject, false); @@ -349,6 +346,23 @@ ecma_process_all_enqueued_jobs (void) return ret; } /* ecma_process_all_enqueued_jobs */ +/** + * Release enqueued Promise jobs. + */ +void +ecma_free_all_enqueued_jobs (void) +{ + while (JERRY_CONTEXT (job_queue_head_p) != NULL) + { + ecma_job_queueitem_t *item_p = JERRY_CONTEXT (job_queue_head_p); + JERRY_CONTEXT (job_queue_head_p) = item_p->next_p; + void *job_p = item_p->job_p; + jmem_heap_free_block (item_p, sizeof (ecma_job_queueitem_t)); + + ecma_free_promise_reaction_job (job_p); + } +} /* ecma_free_all_enqueued_jobs */ + /** * @} * @} diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-jobqueue.h b/deps/jerry/jerry-core/ecma/operations/ecma-jobqueue.h index 76dcb4b..378a957 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-jobqueue.h +++ b/deps/jerry/jerry-core/ecma/operations/ecma-jobqueue.h @@ -44,6 +44,7 @@ void ecma_job_queue_init (void); void ecma_enqueue_promise_reaction_job (ecma_value_t reaction, ecma_value_t argument); void ecma_enqueue_promise_resolve_thenable_job (ecma_value_t promise, ecma_value_t thenable, ecma_value_t then); +void ecma_free_all_enqueued_jobs (void); ecma_value_t ecma_process_all_enqueued_jobs (void); diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-objects-arguments.c b/deps/jerry/jerry-core/ecma/operations/ecma-objects-arguments.c index d55fbf5..0318626 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-objects-arguments.c +++ b/deps/jerry/jerry-core/ecma/operations/ecma-objects-arguments.c @@ -51,23 +51,18 @@ ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function bool is_strict = (bytecode_data_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0; ecma_length_t formal_params_number; - jmem_cpointer_t *literal_p; if (bytecode_data_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_data_p; - uint8_t *byte_p = (uint8_t *) bytecode_data_p; formal_params_number = args_p->argument_end; - literal_p = (jmem_cpointer_t *) (byte_p + sizeof (cbc_uint16_arguments_t)); } else { cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_data_p; - uint8_t *byte_p = (uint8_t *) bytecode_data_p; formal_params_number = args_p->argument_end; - literal_p = (jmem_cpointer_t *) (byte_p + sizeof (cbc_uint8_arguments_t)); } ecma_object_t *prototype_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE); @@ -76,7 +71,7 @@ ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function if (!is_strict && arguments_number > 0 && formal_params_number > 0) { - size_t formal_params_size = formal_params_number * sizeof (jmem_cpointer_t); + size_t formal_params_size = formal_params_number * sizeof (ecma_value_t); obj_p = ecma_create_object (prototype_p, sizeof (ecma_extended_object_t) + formal_params_size, @@ -90,15 +85,19 @@ ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function ext_object_p->u.pseudo_array.u1.length = (uint16_t) formal_params_number; - jmem_cpointer_t *arg_Literal_p = (jmem_cpointer_t *) (ext_object_p + 1); + ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1); - memcpy (arg_Literal_p, literal_p, formal_params_size); + uint8_t *byte_p = (uint8_t *) bytecode_data_p; + byte_p += ((size_t) bytecode_data_p->size) << JMEM_ALIGNMENT_LOG; + byte_p -= formal_params_size; + + memcpy (arg_Literal_p, byte_p, formal_params_size); for (ecma_length_t i = 0; i < formal_params_number; i++) { - if (arg_Literal_p[i] != JMEM_CP_NULL) + if (arg_Literal_p[i] != ECMA_VALUE_EMPTY) { - ecma_string_t *name_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, arg_Literal_p[i]); + ecma_string_t *name_p = ecma_get_string_from_value (arg_Literal_p[i]); ecma_ref_ecma_string (name_p); } } @@ -116,49 +115,41 @@ ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function ecma_property_value_t *prop_value_p; /* 11.a, 11.b */ - for (ecma_length_t indx = 0; - indx < arguments_number; - indx++) + for (ecma_length_t index = 0; + index < arguments_number; + index++) { - ecma_string_t *indx_string_p = ecma_new_ecma_string_from_uint32 (indx); + ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index); prop_value_p = ecma_create_named_data_property (obj_p, - indx_string_p, + index_string_p, ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, NULL); - prop_value_p->value = ecma_copy_value_if_not_object (arguments_list_p[indx]); + prop_value_p->value = ecma_copy_value_if_not_object (arguments_list_p[index]); - ecma_deref_ecma_string (indx_string_p); + ecma_deref_ecma_string (index_string_p); } /* 7. */ - ecma_string_t *length_magic_string_p = ecma_new_ecma_length_string (); - prop_value_p = ecma_create_named_data_property (obj_p, - length_magic_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH), ECMA_PROPERTY_CONFIGURABLE_WRITABLE, NULL); prop_value_p->value = ecma_make_uint32_value (arguments_number); - ecma_deref_ecma_string (length_magic_string_p); - ecma_property_descriptor_t prop_desc = ecma_make_empty_property_descriptor (); /* 13. */ if (!is_strict) { - ecma_string_t *callee_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLEE); - prop_value_p = ecma_create_named_data_property (obj_p, - callee_magic_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_CALLEE), ECMA_PROPERTY_CONFIGURABLE_WRITABLE, NULL); prop_value_p->value = ecma_make_object_value (func_obj_p); - - ecma_deref_ecma_string (callee_magic_string_p); } else { @@ -180,23 +171,18 @@ ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function prop_desc.is_configurable = false; } - ecma_string_t *callee_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLEE); - ecma_value_t completion = ecma_op_object_define_own_property (obj_p, - callee_magic_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_CALLEE), &prop_desc, false); JERRY_ASSERT (ecma_is_value_true (completion)); - ecma_deref_ecma_string (callee_magic_string_p); - ecma_string_t *caller_magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_CALLER); completion = ecma_op_object_define_own_property (obj_p, - caller_magic_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_CALLER), &prop_desc, false); JERRY_ASSERT (ecma_is_value_true (completion)); - ecma_deref_ecma_string (caller_magic_string_p); ecma_deref_object (thrower_p); } @@ -224,7 +210,6 @@ ecma_op_create_arguments_object (ecma_object_t *func_obj_p, /**< callee function JERRY_ASSERT (ecma_is_value_empty (completion)); } - ecma_deref_ecma_string (arguments_string_p); ecma_deref_object (obj_p); } /* ecma_op_create_arguments_object */ @@ -270,20 +255,20 @@ ecma_op_arguments_object_define_own_property (ecma_object_t *object_p, /**< the return ret_value; } - jmem_cpointer_t *arg_Literal_p = (jmem_cpointer_t *) (ext_object_p + 1); + ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1); - if (arg_Literal_p[index] == JMEM_CP_NULL) + if (arg_Literal_p[index] == ECMA_VALUE_EMPTY) { return ret_value; } - ecma_string_t *name_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, arg_Literal_p[index]); + ecma_string_t *name_p = ecma_get_string_from_value (arg_Literal_p[index]); if (property_desc_p->is_get_defined || property_desc_p->is_set_defined) { ecma_deref_ecma_string (name_p); - arg_Literal_p[index] = JMEM_CP_NULL; + arg_Literal_p[index] = ECMA_VALUE_EMPTY; } else { @@ -305,7 +290,7 @@ ecma_op_arguments_object_define_own_property (ecma_object_t *object_p, /**< the && !property_desc_p->is_writable) { ecma_deref_ecma_string (name_p); - arg_Literal_p[index] = JMEM_CP_NULL; + arg_Literal_p[index] = ECMA_VALUE_EMPTY; } } @@ -347,13 +332,13 @@ ecma_op_arguments_object_delete (ecma_object_t *object_p, /**< the object */ if (index < ext_object_p->u.pseudo_array.u1.length) { - jmem_cpointer_t *arg_Literal_p = (jmem_cpointer_t *) (ext_object_p + 1); + ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1); - if (arg_Literal_p[index] != JMEM_CP_NULL) + if (arg_Literal_p[index] != ECMA_VALUE_EMPTY) { - ecma_string_t *name_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, arg_Literal_p[index]); + ecma_string_t *name_p = ecma_get_string_from_value (arg_Literal_p[index]); ecma_deref_ecma_string (name_p); - arg_Literal_p[index] = JMEM_CP_NULL; + arg_Literal_p[index] = ECMA_VALUE_EMPTY; } } } diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-objects.c b/deps/jerry/jerry-core/ecma/operations/ecma-objects.c index d3cff50..d535d4b 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-objects.c +++ b/deps/jerry/jerry-core/ecma/operations/ecma-objects.c @@ -142,9 +142,11 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ /* ES2015 9.4.5.1 */ if (ecma_is_typedarray (ecma_make_object_value (object_p))) { - if (ECMA_STRING_GET_CONTAINER (property_name_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC) + uint32_t array_index = ecma_string_get_array_index (property_name_p); + + if (array_index != ECMA_STRING_NOT_ARRAY_INDEX) { - ecma_value_t value = ecma_op_typedarray_get_index_prop (object_p, property_name_p->u.uint32_number); + ecma_value_t value = ecma_op_typedarray_get_index_prop (object_p, array_index); if (!ecma_is_value_undefined (value)) { @@ -206,19 +208,16 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ if (type != ECMA_OBJECT_TYPE_ARROW_FUNCTION) { ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp); + bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); } else { ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; - bytecode_data_p = ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, - arrow_func_p->bytecode_cp); + bytecode_data_p = ecma_op_arrow_function_get_compiled_code (arrow_func_p); } #else /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp); + bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); #endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ uint32_t len; @@ -269,12 +268,11 @@ ecma_op_object_get_own_property (ecma_object_t *object_p, /**< the object */ { if (index < ext_object_p->u.pseudo_array.u1.length) { - jmem_cpointer_t *arg_Literal_p = (jmem_cpointer_t *) (ext_object_p + 1); + ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1); - if (arg_Literal_p[index] != JMEM_CP_NULL) + if (arg_Literal_p[index] != ECMA_VALUE_EMPTY) { - ecma_string_t *arg_name_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, - arg_Literal_p[index]); + ecma_string_t *arg_name_p = ecma_get_string_from_value (arg_Literal_p[index]); ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, ext_object_p->u.pseudo_array.u2.lex_env_cp); @@ -462,12 +460,11 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */ { if (index < ext_object_p->u.pseudo_array.u1.length) { - jmem_cpointer_t *arg_Literal_p = (jmem_cpointer_t *) (ext_object_p + 1); + ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1); - if (arg_Literal_p[index] != JMEM_CP_NULL) + if (arg_Literal_p[index] != ECMA_VALUE_EMPTY) { - ecma_string_t *arg_name_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, - arg_Literal_p[index]); + ecma_string_t *arg_name_p = ecma_get_string_from_value (arg_Literal_p[index]); ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, ext_object_p->u.pseudo_array.u2.lex_env_cp); @@ -484,9 +481,11 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */ /* ES2015 9.4.5.4 */ if (ecma_is_typedarray (ecma_make_object_value (object_p))) { - if (ECMA_STRING_GET_CONTAINER (property_name_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC) + uint32_t array_index = ecma_string_get_array_index (property_name_p); + + if (array_index != ECMA_STRING_NOT_ARRAY_INDEX) { - return ecma_op_typedarray_get_index_prop (object_p, property_name_p->u.uint32_number); + return ecma_op_typedarray_get_index_prop (object_p, array_index); } ecma_number_t num = ecma_string_to_number (property_name_p); @@ -530,19 +529,16 @@ ecma_op_object_find_own (ecma_value_t base_value, /**< base value */ if (type != ECMA_OBJECT_TYPE_ARROW_FUNCTION) { ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp); + bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); } else { ecma_arrow_function_t *arrow_func_p = (ecma_arrow_function_t *) object_p; - bytecode_data_p = ECMA_GET_NON_NULL_POINTER (const ecma_compiled_code_t, - arrow_func_p->bytecode_cp); + bytecode_data_p = ecma_op_arrow_function_get_compiled_code (arrow_func_p); } #else /* CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ ecma_extended_object_t *ext_func_p = (ecma_extended_object_t *) object_p; - bytecode_data_p = ECMA_GET_INTERNAL_VALUE_POINTER (const ecma_compiled_code_t, - ext_func_p->u.function.bytecode_cp); + bytecode_data_p = ecma_op_function_get_compiled_code (ext_func_p); #endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ uint32_t len; @@ -722,36 +718,11 @@ ecma_op_object_get (ecma_object_t *object_p, /**< the object */ * @return ecma value * Returned value must be freed with ecma_free_value */ -ecma_value_t +inline ecma_value_t __attr_always_inline___ ecma_op_object_get_by_magic_id (ecma_object_t *object_p, /**< the object */ lit_magic_string_id_t property_id) /**< property magic string id */ { - /* Circular reference is possible in JavaScript and testing it is complicated. */ - int max_depth = ECMA_PROPERTY_SEARCH_DEPTH_LIMIT; - - ecma_string_t property_name; - ecma_init_ecma_magic_string (&property_name, property_id); - - ecma_value_t base_value = ecma_make_object_value (object_p); - do - { - ecma_value_t value = ecma_op_object_find_own (base_value, object_p, &property_name); - - if (ecma_is_value_found (value)) - { - return value; - } - - if (--max_depth == 0) - { - break; - } - - object_p = ecma_get_object_prototype (object_p); - } - while (object_p != NULL); - - return ECMA_VALUE_UNDEFINED; + return ecma_op_object_get (object_p, ecma_get_magic_string (property_id)); } /* ecma_op_object_get_by_magic_id */ /** @@ -814,12 +785,11 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ { if (index < ext_object_p->u.pseudo_array.u1.length) { - jmem_cpointer_t *arg_Literal_p = (jmem_cpointer_t *) (ext_object_p + 1); + ecma_value_t *arg_Literal_p = (ecma_value_t *) (ext_object_p + 1); - if (arg_Literal_p[index] != JMEM_CP_NULL) + if (arg_Literal_p[index] != ECMA_VALUE_EMPTY) { - ecma_string_t *arg_name_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, - arg_Literal_p[index]); + ecma_string_t *arg_name_p = ecma_get_string_from_value (arg_Literal_p[index]); ecma_object_t *lex_env_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_object_t, ext_object_p->u.pseudo_array.u2.lex_env_cp); @@ -837,9 +807,11 @@ ecma_op_object_put (ecma_object_t *object_p, /**< the object */ /* ES2015 9.4.5.5 */ if (ecma_is_typedarray (ecma_make_object_value (object_p))) { - if (ECMA_STRING_GET_CONTAINER (property_name_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC) + uint32_t array_index = ecma_string_get_array_index (property_name_p); + + if (array_index != ECMA_STRING_NOT_ARRAY_INDEX) { - bool set_status = ecma_op_typedarray_set_index_prop (object_p, property_name_p->u.uint32_number, value); + bool set_status = ecma_op_typedarray_set_index_prop (object_p, array_index, value); if (set_status) { @@ -1179,10 +1151,12 @@ ecma_op_object_define_own_property (ecma_object_t *obj_p, /**< the object */ /* ES2015 9.4.5.3 */ if (ecma_is_typedarray (ecma_make_object_value (obj_p))) { - if (ECMA_STRING_GET_CONTAINER (property_name_p) == ECMA_STRING_CONTAINER_UINT32_IN_DESC) + uint32_t array_index = ecma_string_get_array_index (property_name_p); + + if (array_index != ECMA_STRING_NOT_ARRAY_INDEX) { bool define_status = ecma_op_typedarray_define_index_prop (obj_p, - property_name_p->u.uint32_number, + array_index, property_desc_p); if (define_status) @@ -1381,8 +1355,8 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ JERRY_ASSERT (obj_p != NULL && !ecma_is_lexical_environment (obj_p)); - ecma_collection_header_t *ret_p = ecma_new_strings_collection (NULL, 0); - ecma_collection_header_t *skipped_non_enumerable_p = ecma_new_strings_collection (NULL, 0); + ecma_collection_header_t *ret_p = ecma_new_values_collection (); + ecma_collection_header_t *skipped_non_enumerable_p = ecma_new_values_collection (); const ecma_object_type_t type = ecma_get_object_type (obj_p); const bool obj_is_builtin = ecma_get_object_is_builtin (obj_p); @@ -1400,7 +1374,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ ecma_length_t string_named_properties_count = 0; ecma_length_t array_index_named_properties_count = 0; - ecma_collection_header_t *prop_names_p = ecma_new_strings_collection (NULL, 0); + ecma_collection_header_t *prop_names_p = ecma_new_values_collection (); if (obj_is_builtin) { @@ -1482,17 +1456,17 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ } } - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, prop_names_p); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (prop_names_p); uint32_t own_names_hashes_bitmap[ECMA_OBJECT_HASH_BITMAP_SIZE / bitmap_row_size]; memset (own_names_hashes_bitmap, 0, sizeof (own_names_hashes_bitmap)); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_string_t *name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); - uint8_t hash = (uint8_t) name_p->hash; + uint8_t hash = (uint8_t) ecma_string_hash (name_p); uint32_t bitmap_row = (uint32_t) (hash / bitmap_row_size); uint32_t bitmap_column = (uint32_t) (hash % bitmap_row_size); @@ -1523,7 +1497,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ { ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) prop_iter_p; - if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_STRING_CONTAINER_MAGIC_STRING + if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC && prop_pair_p->names_cp[i] >= LIT_NON_INTERNAL_MAGIC_STRING__COUNT) { /* Internal properties are never enumerated. */ @@ -1535,7 +1509,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ if (!(is_enumerable_only && !ecma_is_property_enumerable (*property_p))) { - uint8_t hash = (uint8_t) name_p->hash; + uint8_t hash = (uint8_t) ecma_string_hash (name_p); uint32_t bitmap_row = (uint32_t) (hash / bitmap_row_size); uint32_t bitmap_column = (uint32_t) (hash % bitmap_row_size); @@ -1543,13 +1517,14 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ if ((own_names_hashes_bitmap[bitmap_row] & (1u << bitmap_column)) != 0) { - ecma_collection_iterator_init (&iter, prop_names_p); + ecma_value_p = ecma_collection_iterator_init (prop_names_p); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_string_t *name2_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *current_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); - if (ecma_compare_ecma_strings (name_p, name2_p)) + if (ecma_compare_ecma_strings (name_p, current_name_p)) { is_add = false; break; @@ -1563,7 +1538,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ ecma_append_to_values_collection (prop_names_p, ecma_make_string_value (name_p), - true); + 0); } } else @@ -1572,7 +1547,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ ecma_append_to_values_collection (skipped_non_enumerable_p, ecma_make_string_value (name_p), - true); + 0); } ecma_deref_ecma_string (name_p); @@ -1583,10 +1558,12 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ prop_iter_p->next_property_cp); } - ecma_collection_iterator_init (&iter, prop_names_p); - while (ecma_collection_iterator_next (&iter)) + ecma_value_p = ecma_collection_iterator_init (prop_names_p); + + while (ecma_value_p != NULL) { - ecma_string_t *name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); uint32_t index = ecma_string_get_array_index (name_p); @@ -1610,10 +1587,12 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ uint32_t name_pos = array_index_named_properties_count + string_named_properties_count; uint32_t array_index_name_pos = 0; - ecma_collection_iterator_init (&iter, prop_names_p); - while (ecma_collection_iterator_next (&iter)) + ecma_value_p = ecma_collection_iterator_init (prop_names_p); + + while (ecma_value_p != NULL) { - ecma_string_t *name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); uint32_t index = ecma_string_get_array_index (name_p); @@ -1674,7 +1653,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ JMEM_FINALIZE_LOCAL_ARRAY (array_index_names_p); - ecma_free_values_collection (prop_names_p, true); + ecma_free_values_collection (prop_names_p, 0); /* Third pass: * embedding own property names of current object of prototype chain to aggregate property names collection */ @@ -1686,7 +1665,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ ecma_string_t *name_p = names_p[i]; - uint8_t hash = (uint8_t) name_p->hash; + uint8_t hash = (uint8_t) ecma_string_hash (name_p); uint32_t bitmap_row = (uint32_t) (hash / bitmap_row_size); uint32_t bitmap_column = (uint32_t) (hash % bitmap_row_size); @@ -1698,13 +1677,14 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ else { /* Name with same hash has already occured. */ - ecma_collection_iterator_init (&iter, ret_p); + ecma_value_p = ecma_collection_iterator_init (ret_p); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_string_t *iter_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *current_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); - if (ecma_compare_ecma_strings (name_p, iter_name_p)) + if (ecma_compare_ecma_strings (name_p, current_name_p)) { is_append = false; break; @@ -1714,12 +1694,14 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ if (is_append) { - ecma_collection_iterator_init (&iter, skipped_non_enumerable_p); - while (ecma_collection_iterator_next (&iter)) + ecma_value_p = ecma_collection_iterator_init (skipped_non_enumerable_p); + + while (ecma_value_p != NULL) { - ecma_string_t *iter_name_p = ecma_get_string_from_value (*iter.current_value_p); + ecma_string_t *current_name_p = ecma_get_string_from_value (*ecma_value_p); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); - if (ecma_compare_ecma_strings (name_p, iter_name_p)) + if (ecma_compare_ecma_strings (name_p, current_name_p)) { is_append = false; break; @@ -1731,7 +1713,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ { JERRY_ASSERT ((names_hashes_bitmap[bitmap_row] & (1u << bitmap_column)) != 0); - ecma_append_to_values_collection (ret_p, ecma_make_string_value (names_p[i]), true); + ecma_append_to_values_collection (ret_p, ecma_make_string_value (names_p[i]), 0); } ecma_deref_ecma_string (name_p); @@ -1740,7 +1722,7 @@ ecma_op_object_get_property_names (ecma_object_t *obj_p, /**< object */ JMEM_FINALIZE_LOCAL_ARRAY (names_p); } - ecma_free_values_collection (skipped_non_enumerable_p, true); + ecma_free_values_collection (skipped_non_enumerable_p, 0); return ret_p; } /* ecma_op_object_get_property_names */ diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-promise-object.c b/deps/jerry/jerry-core/ecma/operations/ecma-promise-object.c index 04b325c..f6415d5 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-promise-object.c +++ b/deps/jerry/jerry-core/ecma/operations/ecma-promise-object.c @@ -148,15 +148,15 @@ static void ecma_promise_trigger_reactions (ecma_collection_header_t *reactions, /**< lists of reactions */ ecma_value_t value) /**< value for resolve or reject */ { - ecma_collection_iterator_t iter; - ecma_collection_iterator_init (&iter, reactions); + ecma_value_t *ecma_value_p = ecma_collection_iterator_init (reactions); - while (ecma_collection_iterator_next (&iter)) + while (ecma_value_p != NULL) { - ecma_enqueue_promise_reaction_job (*iter.current_value_p, value); + ecma_enqueue_promise_reaction_job (*ecma_value_p, value); + ecma_value_p = ecma_collection_iterator_next (ecma_value_p); } - ecma_free_values_collection (reactions, false); + ecma_free_values_collection (reactions, ECMA_COLLECTION_NO_REF_OBJECTS); } /* ecma_promise_trigger_reactions */ /** @@ -175,11 +175,17 @@ ecma_reject_promise (ecma_value_t promise, /**< promise */ ecma_promise_set_state (obj_p, ECMA_PROMISE_STATE_REJECTED); ecma_promise_set_result (obj_p, ecma_copy_value_if_not_object (reason)); ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p; - ecma_promise_trigger_reactions (promise_p->reject_reactions, reason); - promise_p->reject_reactions = ecma_new_values_collection (NULL, 0, false); - /* Free all fullfill_reactions. */ - ecma_free_values_collection (promise_p->fulfill_reactions, false); - promise_p->fulfill_reactions = ecma_new_values_collection (NULL, 0, false); + + /* GC can be triggered by ecma_new_values_collection so freeing the collection + first and creating a new one might cause a heap after use event. */ + ecma_collection_header_t *reject_reactions = promise_p->reject_reactions; + ecma_collection_header_t *fulfill_reactions = promise_p->fulfill_reactions; + promise_p->reject_reactions = ecma_new_values_collection (); + promise_p->fulfill_reactions = ecma_new_values_collection (); + + /* Fulfill reactions will never be triggered. */ + ecma_free_values_collection (fulfill_reactions, ECMA_COLLECTION_NO_REF_OBJECTS); + ecma_promise_trigger_reactions (reject_reactions, reason); } /* ecma_reject_promise */ /** @@ -198,11 +204,17 @@ ecma_fulfill_promise (ecma_value_t promise, /**< promise */ ecma_promise_set_state (obj_p, ECMA_PROMISE_STATE_FULFILLED); ecma_promise_set_result (obj_p, ecma_copy_value_if_not_object (value)); ecma_promise_object_t *promise_p = (ecma_promise_object_t *) obj_p; - ecma_promise_trigger_reactions (promise_p->fulfill_reactions, value); - promise_p->fulfill_reactions = ecma_new_values_collection (NULL, 0, false); - /* Free all reject_reactions. */ - ecma_free_values_collection (promise_p->reject_reactions, false); - promise_p->reject_reactions = ecma_new_values_collection (NULL, 0, false); + + /* GC can be triggered by ecma_new_values_collection so freeing the collection + first and creating a new one might cause a heap after use event. */ + ecma_collection_header_t *reject_reactions = promise_p->reject_reactions; + ecma_collection_header_t *fulfill_reactions = promise_p->fulfill_reactions; + promise_p->reject_reactions = ecma_new_values_collection (); + promise_p->fulfill_reactions = ecma_new_values_collection (); + + /* Reject reactions will never be triggered. */ + ecma_free_values_collection (reject_reactions, ECMA_COLLECTION_NO_REF_OBJECTS); + ecma_promise_trigger_reactions (fulfill_reactions, value); } /* ecma_fulfill_promise */ /** @@ -220,17 +232,16 @@ ecma_promise_reject_handler (const ecma_value_t function, /**< the function itse { JERRY_UNUSED (this); - ecma_string_t str_promise; - ecma_string_t str_already_resolved; - ecma_init_ecma_magic_string (&str_promise, LIT_INTERNAL_MAGIC_STRING_PROMISE); - ecma_init_ecma_magic_string (&str_already_resolved, LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); + ecma_string_t *str_promise_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE); + ecma_string_t *str_already_resolved_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); + ecma_object_t *function_p = ecma_get_object_from_value (function); /* 2. */ - ecma_value_t promise = ecma_op_object_get (function_p, &str_promise); + ecma_value_t promise = ecma_op_object_get (function_p, str_promise_p); /* 1. */ JERRY_ASSERT (ecma_is_promise (ecma_get_object_from_value (promise))); /* 3. */ - ecma_value_t already_resolved = ecma_op_object_get (function_p, &str_already_resolved); + ecma_value_t already_resolved = ecma_op_object_get (function_p, str_already_resolved_p); /* 4. */ if (ecma_get_already_resolved_bool_value (already_resolved)) @@ -266,17 +277,16 @@ ecma_promise_resolve_handler (const ecma_value_t function, /**< the function its { JERRY_UNUSED (this); - ecma_string_t str_promise; - ecma_string_t str_already_resolved; - ecma_init_ecma_magic_string (&str_promise, LIT_INTERNAL_MAGIC_STRING_PROMISE); - ecma_init_ecma_magic_string (&str_already_resolved, LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); + ecma_string_t *str_promise_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE); + ecma_string_t *str_already_resolved_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); + ecma_object_t *function_p = ecma_get_object_from_value (function); /* 2. */ - ecma_value_t promise = ecma_op_object_get (function_p, &str_promise); + ecma_value_t promise = ecma_op_object_get (function_p, str_promise_p); /* 1. */ JERRY_ASSERT (ecma_is_promise (ecma_get_object_from_value (promise))); /* 3. */ - ecma_value_t already_resolved = ecma_op_object_get (function_p, &str_already_resolved); + ecma_value_t already_resolved = ecma_op_object_get (function_p, str_already_resolved_p); /* 4. */ if (ecma_get_already_resolved_bool_value (already_resolved)) @@ -352,55 +362,46 @@ ecma_call_builtin_executor (ecma_object_t *executor_p, /**< the executor object ecma_value_t resolve_func, /**< the resolve function */ ecma_value_t reject_func) /**< the reject function */ { - ecma_string_t *str_capability = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); - ecma_string_t *str_resolve = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); - ecma_string_t *str_reject = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); + ecma_string_t *capability_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); + ecma_string_t *resolve_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); + ecma_string_t *reject_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); /* 2. */ - ecma_value_t capability = ecma_op_object_get (executor_p, str_capability); + ecma_value_t capability = ecma_op_object_get (executor_p, capability_str_p); /* 3. */ - ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), str_resolve); + ecma_value_t resolve = ecma_op_object_get (ecma_get_object_from_value (capability), resolve_str_p); if (resolve != ECMA_VALUE_UNDEFINED) { ecma_free_value (resolve); ecma_free_value (capability); - ecma_deref_ecma_string (str_capability); - ecma_deref_ecma_string (str_resolve); - ecma_deref_ecma_string (str_reject); return ecma_raise_type_error (ECMA_ERR_MSG ("'resolve' function should be undefined.")); } /* 4. */ - ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), str_reject); + ecma_value_t reject = ecma_op_object_get (ecma_get_object_from_value (capability), reject_str_p); if (reject != ECMA_VALUE_UNDEFINED) { ecma_free_value (reject); ecma_free_value (capability); - ecma_deref_ecma_string (str_capability); - ecma_deref_ecma_string (str_resolve); - ecma_deref_ecma_string (str_reject); return ecma_raise_type_error (ECMA_ERR_MSG ("'reject' function should be undefined.")); } /* 5. */ ecma_op_object_put (ecma_get_object_from_value (capability), - str_resolve, + resolve_str_p, resolve_func, false); /* 6. */ ecma_op_object_put (ecma_get_object_from_value (capability), - str_reject, + reject_str_p, reject_func, false); ecma_free_value (capability); - ecma_deref_ecma_string (str_capability); - ecma_deref_ecma_string (str_resolve); - ecma_deref_ecma_string (str_reject); return ECMA_VALUE_UNDEFINED; } /* ecma_call_builtin_executor */ @@ -418,22 +419,21 @@ ecma_promise_create_resolving_functions (ecma_object_t *object_p) /**< the promi /* 1. */ ecma_value_t already_resolved = ecma_op_create_boolean_object (ecma_make_boolean_value (false)); - ecma_string_t str_promise; - ecma_string_t str_already_resolved; - ecma_init_ecma_magic_string (&str_promise, LIT_INTERNAL_MAGIC_STRING_PROMISE); - ecma_init_ecma_magic_string (&str_already_resolved, LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); + ecma_string_t *str_promise_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE); + ecma_string_t *str_already_resolved_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ALREADY_RESOLVED); + /* 2. */ ecma_object_t *resolve_p; resolve_p = ecma_op_create_external_function_object (ecma_promise_resolve_handler); /* 3. */ ecma_op_object_put (resolve_p, - &str_promise, + str_promise_p, ecma_make_object_value (object_p), false); /* 4. */ ecma_op_object_put (resolve_p, - &str_already_resolved, + str_already_resolved_p, already_resolved, false); /* 5. */ @@ -441,12 +441,12 @@ ecma_promise_create_resolving_functions (ecma_object_t *object_p) /**< the promi reject_p = ecma_op_create_external_function_object (ecma_promise_reject_handler); /* 6. */ ecma_op_object_put (reject_p, - &str_promise, + str_promise_p, ecma_make_object_value (object_p), false); /* 7. */ ecma_op_object_put (reject_p, - &str_already_resolved, + str_already_resolved_p, already_resolved, false); @@ -499,20 +499,20 @@ ecma_op_create_promise_object (ecma_value_t executor, /**< the executor function /* 5 */ ecma_promise_set_state (object_p, ECMA_PROMISE_STATE_PENDING); /* 6-7. */ - promise_object_p->fulfill_reactions = ecma_new_values_collection (NULL, 0, false); - promise_object_p->reject_reactions = ecma_new_values_collection (NULL, 0, false); + promise_object_p->fulfill_reactions = ecma_new_values_collection (); + promise_object_p->reject_reactions = ecma_new_values_collection (); /* 8. */ ecma_promise_resolving_functions_t *funcs = ecma_promise_create_resolving_functions (object_p); - ecma_string_t str_resolve, str_reject; - ecma_init_ecma_magic_string (&str_resolve, LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION); - ecma_init_ecma_magic_string (&str_reject, LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION); + ecma_string_t *str_resolve_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_RESOLVE_FUNCTION); + ecma_string_t *str_reject_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_REJECT_FUNCTION); + ecma_op_object_put (object_p, - &str_resolve, + str_resolve_p, funcs->resolve, false); ecma_op_object_put (object_p, - &str_reject, + str_reject_p, funcs->reject, false); @@ -584,15 +584,16 @@ ecma_promise_new_capability (void) { /* 3. */ ecma_object_t *capability_p = ecma_op_create_object_object_noarg (); - ecma_string_t *str_capability = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); - ecma_string_t *str_promise = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); + + ecma_string_t *capability_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); + ecma_string_t *promise_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); /* 4. */ ecma_object_t *executor_p; executor_p = ecma_op_create_object_object_noarg (); ecma_value_t executor = ecma_make_object_value (executor_p); /* 5. */ ecma_op_object_put (executor_p, - str_capability, + capability_str_p, ecma_make_object_value (capability_p), false); @@ -601,13 +602,12 @@ ecma_promise_new_capability (void) /* 10. */ ecma_op_object_put (capability_p, - str_promise, + promise_str_p, promise, false); ecma_deref_object (executor_p); - ecma_deref_ecma_string (str_promise); - ecma_deref_ecma_string (str_capability); + /* 7. */ if (ECMA_IS_VALUE_ERROR (promise)) { @@ -618,9 +618,8 @@ ecma_promise_new_capability (void) ecma_free_value (promise); /* 8. */ - ecma_string_t *str_resolve = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); - ecma_value_t resolve = ecma_op_object_get (capability_p, str_resolve); - ecma_deref_ecma_string (str_resolve); + ecma_string_t *resolve_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_RESOLVE); + ecma_value_t resolve = ecma_op_object_get (capability_p, resolve_str_p); if (!ecma_op_is_callable (resolve)) { @@ -631,9 +630,8 @@ ecma_promise_new_capability (void) ecma_free_value (resolve); /* 9. */ - ecma_string_t *str_reject = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); - ecma_value_t reject = ecma_op_object_get (capability_p, str_reject); - ecma_deref_ecma_string (str_reject); + ecma_string_t *reject_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_REJECT); + ecma_value_t reject = ecma_op_object_get (capability_p, reject_str_p); if (!ecma_op_is_callable (reject)) { @@ -662,9 +660,9 @@ ecma_promise_do_then (ecma_value_t promise, /**< the promise which call 'then' * ecma_value_t on_rejected, /**< on_rejected function */ ecma_value_t result_capability) /**< promise capability */ { - ecma_string_t *str_capability = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); - ecma_string_t *str_handler = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_HANDLER); - ecma_string_t *str_promise = ecma_new_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); + ecma_string_t *capability_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_CAPABILITY); + ecma_string_t *handler_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_HANDLER); + ecma_string_t *promise_str_p = ecma_get_ecma_string_from_uint32 (ECMA_PROMISE_PROPERTY_PROMISE); /* 3. boolean true indicates "indentity" */ if (!ecma_op_is_callable (on_fulfilled)) @@ -682,20 +680,20 @@ ecma_promise_do_then (ecma_value_t promise, /**< the promise which call 'then' * ecma_object_t *fulfill_reaction_p = ecma_op_create_object_object_noarg (); ecma_object_t *reject_reaction_p = ecma_op_create_object_object_noarg (); ecma_op_object_put (fulfill_reaction_p, - str_capability, + capability_str_p, result_capability, false); ecma_op_object_put (fulfill_reaction_p, - str_handler, + handler_str_p, on_fulfilled, false); ecma_op_object_put (reject_reaction_p, - str_capability, + capability_str_p, result_capability, false); ecma_op_object_put (reject_reaction_p, - str_handler, + handler_str_p, on_rejected, false); @@ -707,11 +705,11 @@ ecma_promise_do_then (ecma_value_t promise, /**< the promise which call 'then' * /* 7. */ ecma_append_to_values_collection (promise_p->fulfill_reactions, ecma_make_object_value (fulfill_reaction_p), - false); + ECMA_COLLECTION_NO_REF_OBJECTS); ecma_append_to_values_collection (promise_p->reject_reactions, ecma_make_object_value (reject_reaction_p), - false); + ECMA_COLLECTION_NO_REF_OBJECTS); } else if (ecma_promise_get_state (obj_p) == ECMA_PROMISE_STATE_FULFILLED) { @@ -729,13 +727,10 @@ ecma_promise_do_then (ecma_value_t promise, /**< the promise which call 'then' * } /* 10. */ - ecma_value_t ret = ecma_op_object_get (ecma_get_object_from_value (result_capability), str_promise); + ecma_value_t ret = ecma_op_object_get (ecma_get_object_from_value (result_capability), promise_str_p); ecma_deref_object (fulfill_reaction_p); ecma_deref_object (reject_reaction_p); - ecma_deref_ecma_string (str_capability); - ecma_deref_ecma_string (str_handler); - ecma_deref_ecma_string (str_promise); return ret; } /* ecma_promise_do_then */ diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-regexp-object.c b/deps/jerry/jerry-core/ecma/operations/ecma-regexp-object.c index 22c5b1d..6ab0909 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-regexp-object.c +++ b/deps/jerry/jerry-core/ecma/operations/ecma-regexp-object.c @@ -164,47 +164,35 @@ re_initialize_props (ecma_object_t *re_obj_p, /**< RegExp object */ ecma_string_t *source_p, /**< source string */ uint16_t flags) /**< flags */ { - /* Set source property. ECMA-262 v5, 15.10.7.1 */ - ecma_string_t *magic_string_p; - - magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE); + /* Set source property. ECMA-262 v5, 15.10.7.1 */ re_set_data_property (re_obj_p, - magic_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE), ECMA_PROPERTY_FIXED, ecma_make_string_value (source_p)); - ecma_deref_ecma_string (magic_string_p); /* Set global property. ECMA-262 v5, 15.10.7.2 */ - magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL); re_set_data_property (re_obj_p, - magic_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL), ECMA_PROPERTY_FIXED, ecma_make_boolean_value (flags & RE_FLAG_GLOBAL)); - ecma_deref_ecma_string (magic_string_p); /* Set ignoreCase property. ECMA-262 v5, 15.10.7.3 */ - magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL); re_set_data_property (re_obj_p, - magic_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL), ECMA_PROPERTY_FIXED, ecma_make_boolean_value (flags & RE_FLAG_IGNORE_CASE)); - ecma_deref_ecma_string (magic_string_p); /* Set multiline property. ECMA-262 v5, 15.10.7.4 */ - magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE); re_set_data_property (re_obj_p, - magic_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE), ECMA_PROPERTY_FIXED, ecma_make_boolean_value (flags & RE_FLAG_MULTILINE)); - ecma_deref_ecma_string (magic_string_p); /* Set lastIndex property. ECMA-262 v5, 15.10.7.5 */ - magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); re_set_data_property (re_obj_p, - magic_string_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), ECMA_PROPERTY_FLAG_WRITABLE, ecma_make_integer_value (0)); - ecma_deref_ecma_string (magic_string_p); } /* re_initialize_props */ /** @@ -239,7 +227,7 @@ ecma_op_create_regexp_object_from_bytecode (re_compiled_code_t *bytecode_p) /**< /* Initialize RegExp object properties */ re_initialize_props (object_p, - ECMA_GET_NON_NULL_POINTER (ecma_string_t, bytecode_p->pattern_cp), + ecma_get_string_from_value (bytecode_p->pattern), bytecode_p->header.status_flags); return ecma_make_object_value (object_p); @@ -1172,33 +1160,24 @@ re_set_result_array_properties (ecma_object_t *array_obj_p, /**< result array */ int32_t index) /**< index of matching */ { /* Set index property of the result array */ - ecma_string_t *result_prop_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_INDEX); - { - ecma_builtin_helper_def_prop (array_obj_p, - result_prop_str_p, - ecma_make_int32_value (index), - true, /* Writable */ - true, /* Enumerable */ - true, /* Configurable */ - true); /* Failure handling */ - } - ecma_deref_ecma_string (result_prop_str_p); + ecma_builtin_helper_def_prop (array_obj_p, + ecma_get_magic_string (LIT_MAGIC_STRING_INDEX), + ecma_make_int32_value (index), + true, /* Writable */ + true, /* Enumerable */ + true, /* Configurable */ + true); /* Failure handling */ /* Set input property of the result array */ - result_prop_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_INPUT); - ecma_builtin_helper_def_prop (array_obj_p, - result_prop_str_p, + ecma_get_magic_string (LIT_MAGIC_STRING_INPUT), ecma_make_string_value (input_str_p), true, /* Writable */ true, /* Enumerable */ true, /* Configurable */ true); /* Failure handling */ - ecma_deref_ecma_string (result_prop_str_p); - /* Set length property of the result array */ - result_prop_str_p = ecma_new_ecma_length_string (); { ecma_property_descriptor_t array_item_prop_desc = ecma_make_empty_property_descriptor (); array_item_prop_desc.is_value_defined = true; @@ -1206,11 +1185,10 @@ re_set_result_array_properties (ecma_object_t *array_obj_p, /**< result array */ array_item_prop_desc.value = ecma_make_uint32_value (num_of_elements); ecma_op_object_define_own_property (array_obj_p, - result_prop_str_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LENGTH), &array_item_prop_desc, true); } - ecma_deref_ecma_string (result_prop_str_p); } /* re_set_result_array_properties */ /** @@ -1241,8 +1219,8 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */ JERRY_ASSERT (ecma_object_class_is (regexp_object_p, LIT_MAGIC_STRING_REGEXP_UL)); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) regexp_object_p; - re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t, - ext_object_p->u.class_prop.u.value); + re_compiled_code_t *bc_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (re_compiled_code_t, + ext_object_p->u.class_prop.u.value); if (bc_p == NULL) { @@ -1321,8 +1299,6 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */ ECMA_OP_TO_NUMBER_FINALIZE (lastindex_num); ecma_fast_free_value (lastindex_value); - - ecma_deref_ecma_string (magic_str_p); } /* 2. Try to match */ @@ -1335,9 +1311,10 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */ { if (re_ctx.flags & RE_FLAG_GLOBAL) { - ecma_string_t *magic_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); - ecma_op_object_put (regexp_object_p, magic_str_p, ecma_make_integer_value (0), true); - ecma_deref_ecma_string (magic_str_p); + ecma_op_object_put (regexp_object_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), + ecma_make_integer_value (0), + true); } is_match = false; @@ -1369,7 +1346,6 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */ if (input_curr_p && (re_ctx.flags & RE_FLAG_GLOBAL)) { - ecma_string_t *magic_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); ecma_number_t lastindex_num; if (sub_str_p != NULL @@ -1383,8 +1359,10 @@ ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */ lastindex_num = ECMA_NUMBER_ZERO; } - ecma_op_object_put (regexp_object_p, magic_str_p, ecma_make_number_value (lastindex_num), true); - ecma_deref_ecma_string (magic_str_p); + ecma_op_object_put (regexp_object_p, + ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL), + ecma_make_number_value (lastindex_num), + true); } /* 3. Fill the result array or return with 'undefiend' */ diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-string-object.c b/deps/jerry/jerry-core/ecma/operations/ecma-string-object.c index 207a370..a4a18df 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-string-object.c +++ b/deps/jerry/jerry-core/ecma/operations/ecma-string-object.c @@ -46,27 +46,18 @@ ecma_op_create_string_object (const ecma_value_t *arguments_list_p, /**< list of JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); - ecma_string_t *prim_prop_str_value_p; + ecma_value_t prim_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY); - if (arguments_list_len == 0) + if (arguments_list_len > 0) { - prim_prop_str_value_p = ecma_new_ecma_string_from_magic_string_id (LIT_MAGIC_STRING__EMPTY); - } - else - { - ecma_value_t to_str_arg_value = ecma_op_to_string (arguments_list_p[0]); + prim_value = ecma_op_to_string (arguments_list_p[0]); - if (ECMA_IS_VALUE_ERROR (to_str_arg_value)) + if (ECMA_IS_VALUE_ERROR (prim_value)) { - return to_str_arg_value; + return prim_value; } - else - { - JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (to_str_arg_value)); - JERRY_ASSERT (ecma_is_value_string (to_str_arg_value)); - prim_prop_str_value_p = ecma_get_string_from_value (to_str_arg_value); - } + JERRY_ASSERT (ecma_is_value_string (prim_value)); } #ifndef CONFIG_DISABLE_STRING_BUILTIN @@ -83,7 +74,7 @@ ecma_op_create_string_object (const ecma_value_t *arguments_list_p, /**< list of ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_STRING_UL; - ext_object_p->u.class_prop.u.value = ecma_make_string_value (prim_prop_str_value_p); + ext_object_p->u.class_prop.u.value = prim_value; return ecma_make_object_value (object_p); } /* ecma_op_create_string_object */ @@ -126,14 +117,14 @@ ecma_op_string_list_lazy_property_names (ecma_object_t *obj_p, /**< a String obj ecma_string_t *name_p = ecma_new_ecma_string_from_uint32 (i); /* the properties are enumerable (ECMA-262 v5, 15.5.5.2.9) */ - ecma_append_to_values_collection (for_enumerable_p, ecma_make_string_value (name_p), true); + ecma_append_to_values_collection (for_enumerable_p, ecma_make_string_value (name_p), 0); ecma_deref_ecma_string (name_p); } - ecma_string_t *length_str_p = ecma_new_ecma_length_string (); - ecma_append_to_values_collection (for_non_enumerable_p, ecma_make_string_value (length_str_p), true); - ecma_deref_ecma_string (length_str_p); + ecma_append_to_values_collection (for_non_enumerable_p, + ecma_make_magic_string_value (LIT_MAGIC_STRING_LENGTH), + 0); } /* ecma_op_string_list_lazy_property_names */ /** diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-try-catch-macro.h b/deps/jerry/jerry-core/ecma/operations/ecma-try-catch-macro.h index 69fec7e..b97f1e9 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-try-catch-macro.h +++ b/deps/jerry/jerry-core/ecma/operations/ecma-try-catch-macro.h @@ -66,23 +66,10 @@ */ #define ECMA_OP_TO_NUMBER_TRY_CATCH(num_var, value, return_value) \ JERRY_ASSERT (return_value == ECMA_VALUE_EMPTY); \ - ecma_number_t num_var = ecma_number_make_nan (); \ - if (ecma_is_value_number (value)) \ - { \ - num_var = ecma_get_number_from_value (value); \ - } \ - else \ - { \ - ECMA_TRY_CATCH (to_number_value, \ - ecma_op_to_number (value), \ - return_value); \ - \ - num_var = ecma_get_number_from_value (to_number_value); \ - \ - ECMA_FINALIZE (to_number_value); \ - } \ + ecma_number_t num_var; \ + return_value = ecma_get_number (value, &num_var); \ \ - if (ecma_is_value_empty (return_value)) \ + if (likely (ecma_is_value_empty (return_value))) \ { /** @@ -92,10 +79,6 @@ * Each ECMA_OP_TO_NUMBER_TRY_CATCH should be followed by ECMA_OP_TO_NUMBER_FINALIZE * with same argument as corresponding ECMA_OP_TO_NUMBER_TRY_CATCH's first argument. */ -#define ECMA_OP_TO_NUMBER_FINALIZE(num_var) } \ - else \ - { \ - JERRY_ASSERT (ecma_number_is_nan (num_var)); \ - } +#define ECMA_OP_TO_NUMBER_FINALIZE(num_var) } #endif /* !ECMA_TRY_CATCH_MACRO_H */ diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-typedarray-object.c b/deps/jerry/jerry-core/ecma/operations/ecma-typedarray-object.c index 29ca06c..0dce329 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-typedarray-object.c +++ b/deps/jerry/jerry-core/ecma/operations/ecma-typedarray-object.c @@ -226,7 +226,7 @@ ecma_set_typedarray_element (lit_utf8_byte_t *dst_p, /**< the location in the in * @return ecma value of the new typedarray object * Returned value must be freed with ecma_free_value */ -static ecma_value_t +ecma_value_t ecma_typedarray_create_object_with_length (ecma_length_t array_length, /**< length of the typedarray */ ecma_object_t *proto_p, /**< prototype object */ uint8_t element_size_shift, /**< the size shift of the element length */ @@ -777,7 +777,7 @@ ecma_op_typedarray_list_lazy_property_names (ecma_object_t *obj_p, /**< a TypedA { ecma_string_t *name_p = ecma_new_ecma_string_from_uint32 (i); - ecma_append_to_values_collection (main_collection_p, ecma_make_string_value (name_p), true); + ecma_append_to_values_collection (main_collection_p, ecma_make_string_value (name_p), 0); ecma_deref_ecma_string (name_p); } diff --git a/deps/jerry/jerry-core/ecma/operations/ecma-typedarray-object.h b/deps/jerry/jerry-core/ecma/operations/ecma-typedarray-object.h index 078b5f9..68e75df 100644 --- a/deps/jerry/jerry-core/ecma/operations/ecma-typedarray-object.h +++ b/deps/jerry/jerry-core/ecma/operations/ecma-typedarray-object.h @@ -57,6 +57,10 @@ bool ecma_op_typedarray_define_index_prop (ecma_object_t *obj_p, bool ecma_op_typedarray_set_index_prop (ecma_object_t *obj_p, uint32_t index, ecma_value_t value); ecma_value_t ecma_op_create_typedarray_with_type_and_length (ecma_object_t *obj_p, ecma_length_t array_length); +ecma_value_t ecma_typedarray_create_object_with_length (ecma_length_t array_length, + ecma_object_t *proto_p, + uint8_t element_size_shift, + lit_magic_string_id_t class_id); /** * @} diff --git a/deps/jerry/jerry-core/include/jerryscript-core.h b/deps/jerry/jerry-core/include/jerryscript-core.h index 57abeb4..bba7861 100644 --- a/deps/jerry/jerry-core/include/jerryscript-core.h +++ b/deps/jerry/jerry-core/include/jerryscript-core.h @@ -64,6 +64,8 @@ typedef enum */ typedef enum { + JERRY_ERROR_NONE = 0, /**< No Error */ + JERRY_ERROR_COMMON, /**< Error */ JERRY_ERROR_EVAL, /**< EvalError */ JERRY_ERROR_RANGE, /**< RangeError */ @@ -88,9 +90,24 @@ typedef enum JERRY_FEATURE_SNAPSHOT_EXEC, /**< executing snapshot files */ JERRY_FEATURE_DEBUGGER, /**< debugging */ JERRY_FEATURE_VM_EXEC_STOP, /**< stopping ECMAScript execution */ + JERRY_FEATURE_JSON, /**< JSON support */ + JERRY_FEATURE_PROMISE, /**< promise support */ + JERRY_FEATURE_TYPEDARRAY, /**< Typedarray support */ + JERRY_FEATURE_DATE, /**< Date support */ + JERRY_FEATURE_REGEXP, /**< Regexp support */ + JERRY_FEATURE_LINE_INFO, /**< line info available */ JERRY_FEATURE__COUNT /**< number of features. NOTE: must be at the end of the list */ } jerry_feature_t; +/** + * Option flags for jerry_parse and jerry_parse_function functions. + */ +typedef enum +{ + JERRY_PARSE_NO_OPTS = 0, /**< no options passed */ + JERRY_PARSE_STRICT_MODE = (1 << 0), /**< enable strict mode */ +} jerry_parse_opts_t; + /** * Character type of JerryScript. */ @@ -208,15 +225,62 @@ typedef jerry_value_t (*jerry_vm_exec_stop_callback_t) (void *user_p); typedef bool (*jerry_object_property_foreach_t) (const jerry_value_t property_name, const jerry_value_t property_value, void *user_data_p); +/** + * Function type applied for each object in the engine. + */ +typedef bool (*jerry_objects_foreach_t) (const jerry_value_t object, + void *user_data_p); + +/** + * Function type applied for each matching object in the engine. + */ +typedef bool (*jerry_objects_foreach_by_native_info_t) (const jerry_value_t object, + void *object_data_p, + void *user_data_p); /** * User context item manager */ typedef struct { - void (*init_cb) (void *); /**< callback responsible for initializing a context item, or NULL to zero out the memory */ - void (*deinit_cb) (void *); /**< callback responsible for deinitializing a context item */ - size_t bytes_needed; /**< number of bytes to allocate for this manager */ + /** + * Callback responsible for initializing a context item, or NULL to zero out the memory. This is called lazily, the + * first time jerry_get_context_data () is called with this manager. + * + * @param [in] data The buffer that JerryScript allocated for the manager. The buffer is zeroed out. The size is + * determined by the bytes_needed field. The buffer is kept alive until jerry_cleanup () is called. + */ + void (*init_cb) (void *data); + + /** + * Callback responsible for deinitializing a context item, or NULL. This is called as part of jerry_cleanup (), + * right *before* the VM has been cleaned up. This is a good place to release strong references to jerry_value_t's + * that the manager may be holding. + * Note: because the VM has not been fully cleaned up yet, jerry_object_native_info_t free_cb's can still get called + * *after* all deinit_cb's have been run. See finalize_cb for a callback that is guaranteed to run *after* all + * free_cb's have been run. + * + * @param [in] data The buffer that JerryScript allocated for the manager. + */ + void (*deinit_cb) (void *data); + + /** + * Callback responsible for finalizing a context item, or NULL. This is called as part of jerry_cleanup (), + * right *after* the VM has been cleaned up and destroyed and jerry_... APIs cannot be called any more. At this point, + * all values in the VM have been cleaned up. This is a good place to clean up native state that can only be cleaned + * up at the very end when there are no more VM values around that may need to access that state. + * + * @param [in] data The buffer that JerryScript allocated for the manager. After returning from this callback, + * the data pointer may no longer be used. + */ + void (*finalize_cb) (void *data); + + /** + * Number of bytes to allocate for this manager. This is the size of the buffer that JerryScript will allocate on + * behalf of the manager. The pointer to this buffer is passed into init_cb, deinit_cb and finalize_cb. It is also + * returned from the jerry_get_context_data () API. + */ + size_t bytes_needed; } jerry_context_data_manager_t; /** @@ -254,12 +318,11 @@ bool jerry_get_memory_stats (jerry_heap_stats_t *out_stats_p); * Parser and executor functions. */ bool jerry_run_simple (const jerry_char_t *script_source_p, size_t script_source_size, jerry_init_flag_t flags); -jerry_value_t jerry_parse (const jerry_char_t *source_p, size_t source_size, bool is_strict); -jerry_value_t jerry_parse_named_resource (const jerry_char_t *resource_name_p, size_t resource_name_length, - const jerry_char_t *source_p, size_t source_size, bool is_strict); +jerry_value_t jerry_parse (const jerry_char_t *resource_name_p, size_t resource_name_length, + const jerry_char_t *source_p, size_t source_size, uint32_t parse_opts); jerry_value_t jerry_parse_function (const jerry_char_t *resource_name_p, size_t resource_name_length, const jerry_char_t *arg_list_p, size_t arg_list_size, - const jerry_char_t *source_p, size_t source_size, bool is_strict); + const jerry_char_t *source_p, size_t source_size, uint32_t parse_opts); jerry_value_t jerry_run (const jerry_value_t func_val); jerry_value_t jerry_eval (const jerry_char_t *source_p, size_t source_size, bool is_strict); @@ -284,6 +347,23 @@ bool jerry_value_is_promise (const jerry_value_t value); bool jerry_value_is_string (const jerry_value_t value); bool jerry_value_is_undefined (const jerry_value_t value); +/** + * JerryScript API value type information. + */ +typedef enum +{ + JERRY_TYPE_NONE = 0u, /**< no type information */ + JERRY_TYPE_UNDEFINED, /**< undefined type */ + JERRY_TYPE_NULL, /**< null type */ + JERRY_TYPE_BOOLEAN, /**< boolean type */ + JERRY_TYPE_NUMBER, /**< number type */ + JERRY_TYPE_STRING, /**< string type */ + JERRY_TYPE_OBJECT, /**< object type */ + JERRY_TYPE_FUNCTION, /**< function type */ +} jerry_type_t; + +jerry_type_t jerry_value_get_type (const jerry_value_t value); + /** * Checker function of whether the specified compile feature is enabled. */ @@ -293,10 +373,17 @@ bool jerry_is_feature_enabled (const jerry_feature_t feature); * Error flag manipulation functions. */ bool jerry_value_has_error_flag (const jerry_value_t value); +bool jerry_value_has_abort_flag (const jerry_value_t value); void jerry_value_clear_error_flag (jerry_value_t *value_p); void jerry_value_set_error_flag (jerry_value_t *value_p); +void jerry_value_set_abort_flag (jerry_value_t *value_p); jerry_value_t jerry_get_value_without_error_flag (jerry_value_t value); +/** + * Error object function(s). + */ +jerry_error_t jerry_get_error_type (const jerry_value_t value); + /** * Getter functions of 'jerry_value_t'. */ @@ -379,7 +466,7 @@ bool jerry_delete_property (const jerry_value_t obj_val, const jerry_value_t pro bool jerry_delete_property_by_index (const jerry_value_t obj_val, uint32_t index); jerry_value_t jerry_get_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val); -jerry_value_t jerry_get_property_by_index (const jerry_value_t obj_val, uint32_t index); +jerry_value_t jerry_get_property_by_index (const jerry_value_t obj_val, uint32_t index); jerry_value_t jerry_set_property (const jerry_value_t obj_val, const jerry_value_t prop_name_val, const jerry_value_t value_to_set); jerry_value_t jerry_set_property_by_index (const jerry_value_t obj_val, uint32_t index, @@ -413,6 +500,11 @@ void jerry_set_object_native_handle (const jerry_value_t obj_val, uintptr_t hand bool jerry_get_object_native_pointer (const jerry_value_t obj_val, void **out_native_pointer_p, const jerry_object_native_info_t **out_pointer_info_p); +bool jerry_objects_foreach (jerry_objects_foreach_t foreach_p, + void *user_data); +bool jerry_objects_foreach_by_native_info (const jerry_object_native_info_t *native_info_p, + jerry_objects_foreach_by_native_info_t foreach_p, + void *user_data_p); void jerry_set_object_native_pointer (const jerry_value_t obj_val, void *native_pointer_p, const jerry_object_native_info_t *native_info_p); @@ -440,6 +532,65 @@ jerry_instance_t *jerry_create_instance (uint32_t heap_size, jerry_instance_allo * Miscellaneous functions. */ void jerry_set_vm_exec_stop_callback (jerry_vm_exec_stop_callback_t stop_cb, void *user_p, uint32_t frequency); +jerry_value_t jerry_get_backtrace (uint32_t max_depth); + +/** + * Array buffer components. + */ +bool jerry_value_is_arraybuffer (const jerry_value_t value); +jerry_value_t jerry_create_arraybuffer (const jerry_length_t size); +jerry_value_t jerry_create_arraybuffer_external (const jerry_length_t size, + uint8_t *buffer_p, + jerry_object_native_free_callback_t free_cb); +jerry_length_t jerry_arraybuffer_write (const jerry_value_t value, + jerry_length_t offset, + const uint8_t *buf_p, + jerry_length_t buf_size); +jerry_length_t jerry_arraybuffer_read (const jerry_value_t value, + jerry_length_t offset, + uint8_t *buf_p, + jerry_length_t buf_size); +jerry_length_t jerry_get_arraybuffer_byte_length (const jerry_value_t value); +uint8_t *jerry_get_arraybuffer_pointer (const jerry_value_t value); + + +/** + * TypedArray functions. + */ + +/** + * TypedArray types. + */ +typedef enum +{ + JERRY_TYPEDARRAY_INVALID = 0, + JERRY_TYPEDARRAY_UINT8, + JERRY_TYPEDARRAY_UINT8CLAMPED, + JERRY_TYPEDARRAY_INT8, + JERRY_TYPEDARRAY_UINT16, + JERRY_TYPEDARRAY_INT16, + JERRY_TYPEDARRAY_UINT32, + JERRY_TYPEDARRAY_INT32, + JERRY_TYPEDARRAY_FLOAT32, + JERRY_TYPEDARRAY_FLOAT64, +} jerry_typedarray_type_t; + + +bool jerry_value_is_typedarray (jerry_value_t value); +jerry_value_t jerry_create_typedarray (jerry_typedarray_type_t type_name, jerry_length_t length); +jerry_value_t jerry_create_typedarray_for_arraybuffer_sz (jerry_typedarray_type_t type_name, + const jerry_value_t arraybuffer, + jerry_length_t byte_offset, + jerry_length_t length); +jerry_value_t jerry_create_typedarray_for_arraybuffer (jerry_typedarray_type_t type_name, + const jerry_value_t arraybuffer); +jerry_typedarray_type_t jerry_get_typedarray_type (jerry_value_t value); +jerry_length_t jerry_get_typedarray_length (jerry_value_t value); +jerry_value_t jerry_get_typedarray_buffer (jerry_value_t value, + jerry_length_t *byte_offset, + jerry_length_t *byte_length); +jerry_value_t jerry_json_parse (const jerry_char_t *string_p, jerry_size_t string_size); +jerry_value_t jerry_json_stringfy (const jerry_value_t object_to_stringify); /** * @} diff --git a/deps/jerry/jerry-core/include/jerryscript-port.h b/deps/jerry/jerry-core/include/jerryscript-port.h index f15db6d..95a9763 100644 --- a/deps/jerry/jerry-core/include/jerryscript-port.h +++ b/deps/jerry/jerry-core/include/jerryscript-port.h @@ -138,6 +138,13 @@ double jerry_port_get_current_time (void); */ struct jerry_instance_t *jerry_port_get_current_instance (void); +/** + * Makes the process sleep for a given time. + */ +#ifdef JERRY_DEBUGGER +void jerry_port_sleep (uint32_t sleep_time); +#endif /* JERRY_DEBUGGER */ + /** * @} */ diff --git a/deps/jerry/jerry-core/include/jerryscript-snapshot.h b/deps/jerry/jerry-core/include/jerryscript-snapshot.h index e8c6691..8da3f48 100644 --- a/deps/jerry/jerry-core/include/jerryscript-snapshot.h +++ b/deps/jerry/jerry-core/include/jerryscript-snapshot.h @@ -27,26 +27,46 @@ extern "C" * @{ */ +/** + * Flags for jerry_generate_snapshot and jerry_generate_function_snapshot. + */ +typedef enum +{ + JERRY_SNAPSHOT_SAVE_STATIC = (1u << 0), /**< static snapshot */ + JERRY_SNAPSHOT_SAVE_STRICT = (1u << 1), /**< strict mode code */ +} jerry_generate_snapshot_opts_t; + +/** + * Flags for jerry_exec_snapshot_at and jerry_load_function_snapshot_at. + */ +typedef enum +{ + JERRY_SNAPSHOT_EXEC_COPY_DATA = (1u << 0), /**< copy snashot data */ + JERRY_SNAPSHOT_EXEC_ALLOW_STATIC = (1u << 1), /**< static snapshots allowed */ +} jerry_exec_snapshot_opts_t; + /** * Snapshot functions. */ -size_t jerry_parse_and_save_snapshot (const jerry_char_t *source_p, size_t source_size, bool is_for_global, - bool is_strict, uint32_t *buffer_p, size_t buffer_size); -jerry_value_t jerry_exec_snapshot (const uint32_t *snapshot_p, size_t snapshot_size, bool copy_bytecode); -jerry_value_t jerry_exec_snapshot_at (const uint32_t *snapshot_p, size_t snapshot_size, - size_t func_index, bool copy_bytecode); +jerry_value_t jerry_generate_snapshot (const jerry_char_t *resource_name_p, size_t resource_name_length, + const jerry_char_t *source_p, size_t source_size, + uint32_t generate_snapshot_opts, uint32_t *buffer_p, size_t buffer_size); +jerry_value_t jerry_generate_function_snapshot (const jerry_char_t *resource_name_p, size_t resource_name_length, + const jerry_char_t *source_p, size_t source_size, + const jerry_char_t *args_p, size_t args_size, + uint32_t generate_snapshot_opts, uint32_t *buffer_p, + size_t buffer_size); + +jerry_value_t jerry_exec_snapshot (const uint32_t *snapshot_p, size_t snapshot_size, + size_t func_index, uint32_t exec_snapshot_opts); +jerry_value_t jerry_load_function_snapshot (const uint32_t *function_snapshot_p, + const size_t function_snapshot_size, + size_t func_index, uint32_t exec_snapshot_opts); + size_t jerry_merge_snapshots (const uint32_t **inp_buffers_p, size_t *inp_buffer_sizes_p, size_t number_of_snapshots, uint32_t *out_buffer_p, size_t out_buffer_size, const char **error_p); size_t jerry_parse_and_save_literals (const jerry_char_t *source_p, size_t source_size, bool is_strict, uint32_t *buffer_p, size_t buffer_size, bool is_c_format); - -size_t jerry_parse_and_save_function_snapshot (const jerry_char_t *source_p, size_t source_size, - const jerry_char_t *args_p, size_t args_size, - bool is_strict, uint32_t *buffer_p, size_t buffer_size); -jerry_value_t jerry_load_function_snapshot_at (const uint32_t *function_snapshot_p, - const size_t function_snapshot_size, - size_t func_index, - bool copy_bytecode); /** * @} */ diff --git a/deps/jerry/jerry-core/jcontext/jcontext.h b/deps/jerry/jerry-core/jcontext/jcontext.h index 72e58a1..917c5e9 100644 --- a/deps/jerry/jerry-core/jcontext/jcontext.h +++ b/deps/jerry/jerry-core/jcontext/jcontext.h @@ -84,13 +84,11 @@ typedef struct ecma_value_t error_value; /**< currently thrown error value */ uint32_t lit_magic_string_ex_count; /**< external magic strings count */ uint32_t jerry_init_flags; /**< run-time configuration flags */ - uint8_t is_direct_eval_form_call; /**< direct call from eval */ - uint8_t jerry_api_available; /**< API availability flag */ + uint32_t status_flags; /**< run-time flags */ #ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE uint8_t ecma_prop_hashmap_alloc_state; /**< property hashmap allocation state: 0-4, * if !0 property hashmap allocation is disabled */ - bool ecma_prop_hashmap_alloc_last_is_hs_gc; /**< true, if and only if the last gc action was a high severity gc */ #endif /* !CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE */ #ifndef CONFIG_DISABLE_REGEXP_BUILTIN @@ -113,16 +111,23 @@ typedef struct #ifdef JERRY_DEBUGGER uint8_t debugger_send_buffer[JERRY_DEBUGGER_MAX_BUFFER_SIZE]; /**< buffer for sending messages */ uint8_t debugger_receive_buffer[JERRY_DEBUGGER_MAX_BUFFER_SIZE]; /**< buffer for receiving messages */ + uint8_t *debugger_send_buffer_payload_p; /**< start where the outgoing message can be written */ vm_frame_ctx_t *debugger_stop_context; /**< stop only if the current context is equal to this context */ jmem_cpointer_t debugger_byte_code_free_head; /**< head of byte code free linked list */ jmem_cpointer_t debugger_byte_code_free_tail; /**< tail of byte code free linked list */ - uint8_t debugger_flags; /**< debugger flags */ - uint8_t debugger_message_delay; /**< call receive message when reaches zero */ + uint32_t debugger_flags; /**< debugger flags */ uint16_t debugger_receive_buffer_offset; /**< receive buffer offset */ - int debugger_connection; /**< holds the file descriptor of the socket communication */ uint16_t debugger_port; /**< debugger socket communication port */ + uint8_t debugger_message_delay; /**< call receive message when reaches zero */ + uint8_t debugger_max_send_size; /**< maximum amount of data that can be written */ + uint8_t debugger_max_receive_size; /**< maximum amount of data that can be received */ + int debugger_connection; /**< holds the file descriptor of the socket communication */ #endif /* JERRY_DEBUGGER */ +#ifdef JERRY_ENABLE_LINE_INFO + ecma_value_t resource_name; /**< resource name (usually a file name) */ +#endif /* JERRY_ENABLE_LINE_INFO */ + #ifdef JMEM_STATS jmem_heap_stats_t jmem_heap_stats; /**< heap's memory usage statistics */ #endif /* JMEM_STATS */ diff --git a/deps/jerry/jerry-core/jrt/jrt.h b/deps/jerry/jerry-core/jrt/jrt.h index b947fc5..46ab6b2 100644 --- a/deps/jerry/jerry-core/jrt/jrt.h +++ b/deps/jerry/jerry-core/jrt/jrt.h @@ -16,8 +16,11 @@ #ifndef JRT_H #define JRT_H +#if !defined (_XOPEN_SOURCE) || _XOPEN_SOURCE < 500 +#undef _XOPEN_SOURCE /* Required macro for sleep functions (nanosleep or usleep) */ #define _XOPEN_SOURCE 500 +#endif #include #include diff --git a/deps/jerry/jerry-core/lit/lit-char-helpers.c b/deps/jerry/jerry-core/lit/lit-char-helpers.c index 1089923..cb790fc 100644 --- a/deps/jerry/jerry-core/lit/lit-char-helpers.c +++ b/deps/jerry/jerry-core/lit/lit-char-helpers.c @@ -387,7 +387,6 @@ lit_char_to_utf8_bytes (uint8_t *dst_p, /**< destination buffer */ return 2; } - JERRY_ASSERT (!(chr & ~LIT_UTF8_3_BYTE_CODE_POINT_MAX)); /* zzzzyyyy yyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx */ *(dst_p++) = (uint8_t) (LIT_UTF8_3_BYTE_MARKER | ((chr >> 12) & LIT_UTF8_LAST_4_BITS_MASK)); *(dst_p++) = (uint8_t) (LIT_UTF8_EXTRA_BYTE_MARKER | ((chr >> 6) & LIT_UTF8_LAST_6_BITS_MASK)); @@ -416,7 +415,6 @@ lit_char_get_utf8_length (ecma_char_t chr) /**< EcmaScript character */ } /* zzzzyyyy yyxxxxxx */ - JERRY_ASSERT (!(chr & ~LIT_UTF8_3_BYTE_CODE_POINT_MAX)); return 3; } /* lit_char_get_utf8_length */ diff --git a/deps/jerry/jerry-core/parser/js/byte-code.h b/deps/jerry/jerry-core/parser/js/byte-code.h index 511fb60..a8db088 100644 --- a/deps/jerry/jerry-core/parser/js/byte-code.h +++ b/deps/jerry/jerry-core/parser/js/byte-code.h @@ -200,7 +200,7 @@ /* Stack consumption of opcodes with context. */ /* PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION must be <= 4 */ -#define PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION 3 +#define PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION 4 /* PARSER_WITH_CONTEXT_STACK_ALLOCATION must be <= 4 */ #define PARSER_WITH_CONTEXT_STACK_ALLOCATION 2 /* PARSER_TRY_CONTEXT_STACK_ALLOCATION must be <= 3 */ @@ -539,6 +539,10 @@ /* Basic opcodes. */ \ CBC_OPCODE (CBC_EXT_DEBUGGER, CBC_NO_FLAG, 0, \ VM_OC_NONE) \ + CBC_OPCODE (CBC_EXT_RESOURCE_NAME, CBC_NO_FLAG, 0, \ + VM_OC_RESOURCE_NAME) \ + CBC_OPCODE (CBC_EXT_LINE, CBC_NO_FLAG, 0, \ + VM_OC_LINE) \ \ /* Binary compound assignment opcodes with pushing the result. */ \ CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_ADD, \ @@ -637,9 +641,7 @@ typedef struct uint16_t ident_end; /**< end position of the identifier group */ uint16_t const_literal_end; /**< end position of the const literal group */ uint16_t literal_end; /**< end position of the literal group */ -#ifdef JERRY_CPOINTER_32_BIT uint16_t padding; /**< an unused value */ -#endif } cbc_uint16_arguments_t; /** @@ -652,9 +654,11 @@ typedef enum CBC_CODE_FLAGS_UINT16_ARGUMENTS = (1u << 2), /**< compiled code data is cbc_uint16_arguments_t */ CBC_CODE_FLAGS_STRICT_MODE = (1u << 3), /**< strict mode is enabled */ CBC_CODE_FLAGS_ARGUMENTS_NEEDED = (1u << 4), /**< arguments object must be constructed */ - CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED = (1u << 5), /**< no need to create a lexical environment */ - CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 6), /**< this function should be ignored by debugger */ + CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED = (1u << 5), /**< non-strict arguments object must be constructed */ + CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED = (1u << 6), /**< no need to create a lexical environment */ CBC_CODE_FLAGS_ARROW_FUNCTION = (1u << 7), /**< this function is an arrow function */ + CBC_CODE_FLAGS_STATIC_FUNCTION = (1u << 8), /**< this function is a static snapshot function */ + CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 9), /**< this function should be ignored by debugger */ } cbc_code_flags; #define CBC_OPCODE(arg1, arg2, arg3, arg4) arg1, diff --git a/deps/jerry/jerry-core/parser/js/common.c b/deps/jerry/jerry-core/parser/js/common.c index 9c31333..52e68a4 100644 --- a/deps/jerry/jerry-core/parser/js/common.c +++ b/deps/jerry/jerry-core/parser/js/common.c @@ -107,12 +107,8 @@ util_print_literal (lexer_literal_t *literal_p) /**< literal */ } else if (literal_p->type == LEXER_NUMBER_LITERAL) { - ecma_string_t *value_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, literal_p->u.value); - - JERRY_ASSERT (ECMA_STRING_GET_CONTAINER (value_p) == ECMA_STRING_LITERAL_NUMBER); - JERRY_DEBUG_MSG ("number("); - util_print_number (ecma_get_number_from_value (value_p->u.lit_number)); + util_print_number (ecma_get_number_from_value (literal_p->u.value)); } else if (literal_p->type == LEXER_REGEXP_LITERAL) { diff --git a/deps/jerry/jerry-core/parser/js/common.h b/deps/jerry/jerry-core/parser/js/common.h index 6829d0a..1e88a94 100644 --- a/deps/jerry/jerry-core/parser/js/common.h +++ b/deps/jerry/jerry-core/parser/js/common.h @@ -74,6 +74,15 @@ typedef enum /* Initialize this variable after the byte code is freed. */ #define LEXER_FLAG_LATE_INIT 0x80 +/** + * Type of property length. + */ +#ifdef JERRY_CPOINTER_32_BIT +typedef uint32_t prop_length_t; +#else /* !JERRY_CPOINTER_32_BIT */ +typedef uint16_t prop_length_t; +#endif /* JERRY_CPOINTER_32_BIT */ + /** * Literal data. */ @@ -81,7 +90,7 @@ typedef struct { union { - jmem_cpointer_t value; /**< literal value (not processed by the parser) */ + ecma_value_t value; /**< literal value (not processed by the parser) */ const uint8_t *char_p; /**< character value */ ecma_compiled_code_t *bytecode_p; /**< compiled function or regexp pointer */ uint32_t source_data; /**< encoded source literal */ @@ -93,7 +102,7 @@ typedef struct union #endif /* PARSER_DUMP_BYTE_CODE */ { - uint16_t length; /**< length of ident / string literal */ + prop_length_t length; /**< length of ident / string literal */ uint16_t index; /**< real index during post processing */ } prop; diff --git a/deps/jerry/jerry-core/parser/js/js-lexer.c b/deps/jerry/jerry-core/parser/js/js-lexer.c index e271fd3..a25498a 100644 --- a/deps/jerry/jerry-core/parser/js/js-lexer.c +++ b/deps/jerry/jerry-core/parser/js/js-lexer.c @@ -544,7 +544,7 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */ { /* Fill literal data. */ context_p->token.lit_location.char_p = ident_start_p; - context_p->token.lit_location.length = (uint16_t) length; + context_p->token.lit_location.length = (prop_length_t) length; } context_p->source_p = source_p; @@ -815,7 +815,7 @@ lexer_parse_string (parser_context_t *context_p) /**< context */ /* Fill literal data. */ context_p->token.lit_location.char_p = string_start_p; - context_p->token.lit_location.length = (uint16_t) length; + context_p->token.lit_location.length = (prop_length_t) length; context_p->token.lit_location.type = LEXER_STRING_LITERAL; context_p->token.lit_location.has_escape = has_escape; @@ -966,7 +966,7 @@ lexer_parse_number (parser_context_t *context_p) /**< context */ parser_raise_error (context_p, PARSER_ERR_NUMBER_TOO_LONG); } - context_p->token.lit_location.length = (uint16_t) length; + context_p->token.lit_location.length = (prop_length_t) length; PARSER_PLUS_EQUAL_LC (context_p->column, length); context_p->source_p = source_p; } /* lexer_parse_number */ @@ -1374,7 +1374,7 @@ lexer_process_char_literal (parser_context_t *context_p, /**< context */ } literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool); - literal_p->prop.length = (uint16_t) length; + literal_p->prop.length = (prop_length_t) length; literal_p->type = literal_type; literal_p->status_flags = has_escape ? 0 : LEXER_FLAG_SOURCE_PTR; @@ -1718,7 +1718,7 @@ lexer_construct_number_object (parser_context_t *context_p, /**< context */ lexer_literal_t *literal_p; ecma_number_t num; uint32_t literal_index = 0; - uint16_t length = context_p->token.lit_location.length; + prop_length_t length = context_p->token.lit_location.length; if (context_p->token.extra_value != LEXER_NUMBER_OCTAL) { @@ -1759,13 +1759,13 @@ lexer_construct_number_object (parser_context_t *context_p, /**< context */ num = -num; } - jmem_cpointer_t lit_cp = ecma_find_or_create_literal_number (num); + ecma_value_t lit_value = ecma_find_or_create_literal_number (num); parser_list_iterator_init (&context_p->literal_pool, &literal_iterator); while ((literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator)) != NULL) { if (literal_p->type == LEXER_NUMBER_LITERAL - && literal_p->u.value == lit_cp) + && literal_p->u.value == lit_value) { context_p->lit_object.literal_p = literal_p; context_p->lit_object.index = (uint16_t) literal_index; @@ -1790,7 +1790,7 @@ lexer_construct_number_object (parser_context_t *context_p, /**< context */ context_p->literal_count++; - literal_p->u.value = lit_cp; + literal_p->u.value = lit_value; literal_p->type = LEXER_NUMBER_LITERAL; context_p->lit_object.literal_p = literal_p; @@ -2007,7 +2007,7 @@ lexer_construct_regexp_object (parser_context_t *context_p, /**< context */ } literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool); - literal_p->prop.length = (uint16_t) length; + literal_p->prop.length = (prop_length_t) length; literal_p->type = LEXER_UNUSED_LITERAL; literal_p->status_flags = 0; diff --git a/deps/jerry/jerry-core/parser/js/js-lexer.h b/deps/jerry/jerry-core/parser/js/js-lexer.h index 855276f..96dfe84 100644 --- a/deps/jerry/jerry-core/parser/js/js-lexer.h +++ b/deps/jerry/jerry-core/parser/js/js-lexer.h @@ -233,7 +233,7 @@ typedef enum typedef struct { const uint8_t *char_p; /**< start of identifier or string token */ - uint16_t length; /**< length or index of a literal */ + prop_length_t length; /**< length or index of a literal */ uint8_t type; /**< type of the current literal */ uint8_t has_escape; /**< has escape sequences */ } lexer_lit_location_t; diff --git a/deps/jerry/jerry-core/parser/js/js-parser-internal.h b/deps/jerry/jerry-core/parser/js/js-parser-internal.h index 06f5873..0a5d6b1 100644 --- a/deps/jerry/jerry-core/parser/js/js-parser-internal.h +++ b/deps/jerry/jerry-core/parser/js/js-parser-internal.h @@ -305,10 +305,15 @@ typedef struct #endif /* PARSER_DUMP_BYTE_CODE */ #ifdef JERRY_DEBUGGER - parser_breakpoint_info_t breakpoint_info[JERRY_DEBUGGER_SEND_MAX (parser_list_t)]; /**< extra data for breakpoints */ + /** extra data for each breakpoint */ + parser_breakpoint_info_t breakpoint_info[JERRY_DEBUGGER_MAX_BUFFER_SIZE / sizeof (parser_breakpoint_info_t)]; uint16_t breakpoint_info_count; /**< current breakpoint index */ - parser_line_counter_t last_breakpoint_line; /**< last line where breakpoint was inserted */ + parser_line_counter_t last_breakpoint_line; /**< last line where breakpoint has been inserted */ #endif /* JERRY_DEBUGGER */ + +#ifdef JERRY_ENABLE_LINE_INFO + parser_line_counter_t last_line_info_line; /**< last line where line info has been inserted */ +#endif /* JERRY_ENABLE_LINE_INFO */ } parser_context_t; /** @@ -484,6 +489,12 @@ void parser_send_breakpoints (parser_context_t *context_p, jerry_debugger_header #endif /* JERRY_DEBUGGER */ +#ifdef JERRY_ENABLE_LINE_INFO + +void parser_emit_line_info (parser_context_t *context_p, uint32_t line, bool flush_cbc); + +#endif /* JERRY_ENABLE_LINE_INFO */ + /** * @} * @} diff --git a/deps/jerry/jerry-core/parser/js/js-parser-limits.h b/deps/jerry/jerry-core/parser/js/js-parser-limits.h index d4c8e99..0177426 100644 --- a/deps/jerry/jerry-core/parser/js/js-parser-limits.h +++ b/deps/jerry/jerry-core/parser/js/js-parser-limits.h @@ -32,10 +32,18 @@ #define PARSER_MAXIMUM_IDENT_LENGTH 255 #endif /* !PARSER_MAXIMUM_IDENT_LENGTH */ +/* Maximum string limit. + * Limit: 2147483647 / 65535. */ +#ifdef JERRY_CPOINTER_32_BIT +#define PARSER_MAXIMUM_STRING_LIMIT 2147483647 +#else /* !JERRY_CPOINTER_32_BIT */ +#define PARSER_MAXIMUM_STRING_LIMIT 65535 +#endif /* JERRY_CPOINTER_32_BIT */ + /* Maximum string length. - * Limit: 65535. */ + * Limit: PARSER_MAXIMUM_STRING_LIMIT. */ #ifndef PARSER_MAXIMUM_STRING_LENGTH -#define PARSER_MAXIMUM_STRING_LENGTH 65535 +#define PARSER_MAXIMUM_STRING_LENGTH PARSER_MAXIMUM_STRING_LIMIT #endif /* !PARSER_MAXIMUM_STRING_LENGTH */ /* Maximum number of literals. @@ -65,9 +73,9 @@ /* Checks. */ -#if (PARSER_MAXIMUM_STRING_LENGTH < 1) || (PARSER_MAXIMUM_STRING_LENGTH > 65535) +#if (PARSER_MAXIMUM_STRING_LENGTH < 1) || (PARSER_MAXIMUM_STRING_LENGTH > PARSER_MAXIMUM_STRING_LIMIT) #error "Maximum string length is not within range." -#endif /* (PARSER_MAXIMUM_STRING_LENGTH < 1) || (PARSER_MAXIMUM_STRING_LENGTH > 65535) */ +#endif /* (PARSER_MAXIMUM_STRING_LENGTH < 1) || (PARSER_MAXIMUM_STRING_LENGTH > PARSER_MAXIMUM_STRING_LIMIT) */ #if (PARSER_MAXIMUM_IDENT_LENGTH < 1) || (PARSER_MAXIMUM_IDENT_LENGTH > PARSER_MAXIMUM_STRING_LENGTH) #error "Maximum identifier length is not within range." diff --git a/deps/jerry/jerry-core/parser/js/js-parser-statm.c b/deps/jerry/jerry-core/parser/js/js-parser-statm.c index e06810b..28b978f 100644 --- a/deps/jerry/jerry-core/parser/js/js-parser-statm.c +++ b/deps/jerry/jerry-core/parser/js/js-parser-statm.c @@ -17,9 +17,9 @@ #ifndef JERRY_DISABLE_JS_PARSER -#ifdef JERRY_DEBUGGER +#if defined (JERRY_DEBUGGER) || defined (JERRY_ENABLE_LINE_INFO) #include "jcontext.h" -#endif /*JERRY_DEBUGGER */ +#endif /* JERRY_DEBUGGER || JERRY_ENABLE_LINE_INFO */ /** \addtogroup parser Parser * @{ @@ -314,9 +314,9 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */ JERRY_ASSERT (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); -#ifdef JERRY_DEBUGGER +#if defined (JERRY_DEBUGGER) || defined (JERRY_ENABLE_LINE_INFO) parser_line_counter_t ident_line_counter = context_p->token.line; -#endif /* JERRY_DEBUGGER */ +#endif /* JERRY_DEBUGGER || JERRY_ENABLE_LINE_INFO */ context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR; @@ -347,6 +347,13 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */ } #endif /* JERRY_DEBUGGER */ +#ifdef JERRY_ENABLE_LINE_INFO + if (ident_line_counter != context_p->last_line_info_line) + { + parser_emit_line_info (context_p, ident_line_counter, false); + } +#endif /* JERRY_ENABLE_LINE_INFO */ + parser_parse_expression (context_p, PARSE_EXPR_STATEMENT | PARSE_EXPR_NO_COMMA | PARSE_EXPR_HAS_LITERAL); } @@ -1080,6 +1087,10 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context * switch_case_was_found = false; default_case_was_found = false; +#ifdef JERRY_ENABLE_LINE_INFO + uint32_t last_line_info_line = context_p->last_line_info_line; +#endif /* JERRY_ENABLE_LINE_INFO */ + while (true) { parser_scan_until (context_p, &unused_range, LEXER_KEYW_CASE); @@ -1134,6 +1145,13 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context * lexer_next_token (context_p); +#ifdef JERRY_ENABLE_LINE_INFO + if (context_p->token.line != context_p->last_line_info_line) + { + parser_emit_line_info (context_p, context_p->token.line, true); + } +#endif /* JERRY_ENABLE_LINE_INFO */ + parser_parse_expression (context_p, PARSE_EXPR); if (context_p->token.type != LEXER_COLON) @@ -1148,6 +1166,10 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context * JERRY_ASSERT (switch_case_was_found || default_case_was_found); +#ifdef JERRY_ENABLE_LINE_INFO + context_p->last_line_info_line = last_line_info_line; +#endif /* JERRY_ENABLE_LINE_INFO */ + if (!switch_case_was_found) { /* There was no case statement, so the expression result @@ -1634,6 +1656,15 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ } #endif /* JERRY_DEBUGGER */ +#ifdef JERRY_ENABLE_LINE_INFO + if (JERRY_CONTEXT (resource_name) != ECMA_VALUE_UNDEFINED) + { + parser_emit_cbc_ext (context_p, CBC_EXT_RESOURCE_NAME); + parser_flush_cbc (context_p); + } + context_p->last_line_info_line = 0; +#endif /* JERRY_ENABLE_LINE_INFO */ + while (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_STRING_LITERAL) { @@ -1685,6 +1716,9 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ context_p->last_breakpoint_line = context_p->token.line; } #endif /* JERRY_DEBUGGER */ +#ifdef JERRY_ENABLE_LINE_INFO + parser_emit_line_info (context_p, context_p->token.line, false); +#endif /* JERRY_ENABLE_LINE_INFO */ lexer_construct_literal_object (context_p, &lit_location, LEXER_STRING_LITERAL); parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL); @@ -1755,6 +1789,20 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ } #endif /* JERRY_DEBUGGER */ +#ifdef JERRY_ENABLE_LINE_INFO + if (context_p->token.line != context_p->last_line_info_line + && context_p->token.type != LEXER_SEMICOLON + && context_p->token.type != LEXER_LEFT_BRACE + && context_p->token.type != LEXER_RIGHT_BRACE + && context_p->token.type != LEXER_KEYW_VAR + && context_p->token.type != LEXER_KEYW_FUNCTION + && context_p->token.type != LEXER_KEYW_CASE + && context_p->token.type != LEXER_KEYW_DEFAULT) + { + parser_emit_line_info (context_p, context_p->token.line, true); + } +#endif /* JERRY_ENABLE_LINE_INFO */ + switch (context_p->token.type) { case LEXER_SEMICOLON: diff --git a/deps/jerry/jerry-core/parser/js/js-parser-util.c b/deps/jerry/jerry-core/parser/js/js-parser-util.c index 4b2c554..e3c25b5 100644 --- a/deps/jerry/jerry-core/parser/js/js-parser-util.c +++ b/deps/jerry/jerry-core/parser/js/js-parser-util.c @@ -17,6 +17,10 @@ #ifndef JERRY_DISABLE_JS_PARSER +#ifdef JERRY_ENABLE_LINE_INFO +#include "jcontext.h" +#endif /* JERRY_ENABLE_LINE_INFO */ + /** \addtogroup parser Parser * @{ * @@ -352,6 +356,57 @@ parser_emit_cbc_push_number (parser_context_t *context_p, /**< context */ } } /* parser_emit_cbc_push_number */ +#ifdef JERRY_ENABLE_LINE_INFO + +/** + * Append a line info data + */ +void +parser_emit_line_info (parser_context_t *context_p, /**< context */ + uint32_t line, /**< current line */ + bool flush_cbc) /**< flush last byte code */ +{ + if (JERRY_CONTEXT (resource_name) == ECMA_VALUE_UNDEFINED) + { + return; + } + + if (flush_cbc && context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE) + { + parser_flush_cbc (context_p); + } + +#ifdef PARSER_DUMP_BYTE_CODE + if (context_p->is_show_opcodes) + { + JERRY_DEBUG_MSG (" [%3d] CBC_EXT_LINE %d\n", (int) context_p->stack_depth, line); + } +#endif /* PARSER_DUMP_BYTE_CODE */ + + parser_emit_two_bytes (context_p, CBC_EXT_OPCODE, CBC_EXT_LINE); + context_p->byte_code_size += 2; + + context_p->last_line_info_line = line; + + do + { + uint8_t byte = (uint8_t) (line & CBC_LOWER_SEVEN_BIT_MASK); + + line >>= 7; + + if (line > 0) + { + byte = (uint8_t) (byte | CBC_HIGHEST_BIT_MASK); + } + + PARSER_APPEND_TO_BYTE_CODE (context_p, byte); + context_p->byte_code_size++; + } + while (line > 0); +} /* parser_emit_line_info */ + +#endif /* JERRY_ENABLE_LINE_INFO */ + /** * Append a byte code with a branch argument */ diff --git a/deps/jerry/jerry-core/parser/js/js-parser.c b/deps/jerry/jerry-core/parser/js/js-parser.c index ef763c3..d09520d 100644 --- a/deps/jerry/jerry-core/parser/js/js-parser.c +++ b/deps/jerry/jerry-core/parser/js/js-parser.c @@ -106,7 +106,7 @@ parser_copy_identifiers (parser_context_t *context_p) /**< context */ /* The literal data is updated at every iteration to handle out-of memory. */ parent_p->literal_pool_data = parent_literal_pool.data; - parent_literal_p->prop.length = (uint16_t) length; + parent_literal_p->prop.length = (prop_length_t) length; parent_literal_p->type = LEXER_IDENT_LITERAL; parent_literal_p->status_flags = (uint8_t) (literal_p->status_flags & LEXER_FLAG_SOURCE_PTR); parent_literal_p->status_flags |= LEXER_FLAG_NO_REG_STORE | LEXER_FLAG_UNUSED_IDENT; @@ -534,7 +534,7 @@ parser_encode_literal (uint8_t *dst_p, /**< destination buffer */ static uint8_t * parser_generate_initializers (parser_context_t *context_p, /**< context */ uint8_t *dst_p, /**< destination buffer */ - jmem_cpointer_t *literal_pool_p, /**< start of literal pool */ + ecma_value_t *literal_pool_p, /**< start of literal pool */ uint16_t uninitialized_var_end, /**< end of the uninitialized var group */ uint16_t initialized_var_end, /**< end of the initialized var group */ uint16_t const_literal_end, /**< end of the const literal group */ @@ -543,7 +543,7 @@ parser_generate_initializers (parser_context_t *context_p, /**< context */ { parser_list_iterator_t literal_iterator; lexer_literal_t *literal_p; - uint16_t argument_count; + uint16_t argument_count, register_count; if (uninitialized_var_end > context_p->register_count) { @@ -618,6 +618,7 @@ parser_generate_initializers (parser_context_t *context_p, /**< context */ parser_list_iterator_init (&context_p->literal_pool, &literal_iterator); argument_count = 0; + register_count = context_p->register_count; while ((literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator))) { @@ -628,35 +629,42 @@ parser_generate_initializers (parser_context_t *context_p, /**< context */ if (literal_p->type == LEXER_IDENT_LITERAL || literal_p->type == LEXER_STRING_LITERAL) { -#ifdef PARSER_DUMP_BYTE_CODE - if (!(literal_p->status_flags & LEXER_FLAG_UNUSED_IDENT)) + if (literal_p->prop.index >= register_count) { - jmem_cpointer_t lit_cp = ecma_find_or_create_literal_string (literal_p->u.char_p, - literal_p->prop.length); - literal_pool_p[literal_p->prop.index] = lit_cp; - } +#ifdef PARSER_DUMP_BYTE_CODE + if (!(literal_p->status_flags & LEXER_FLAG_UNUSED_IDENT)) + { + ecma_value_t lit_value = ecma_find_or_create_literal_string (literal_p->u.char_p, + literal_p->prop.length); + literal_pool_p[literal_p->prop.index] = lit_value; + } - if (!context_p->is_show_opcodes - && !(literal_p->status_flags & LEXER_FLAG_SOURCE_PTR)) - { - jmem_heap_free_block ((void *) literal_p->u.char_p, literal_p->prop.length); - } + if (!context_p->is_show_opcodes + && !(literal_p->status_flags & LEXER_FLAG_SOURCE_PTR)) + { + jmem_heap_free_block ((void *) literal_p->u.char_p, literal_p->prop.length); + } #else /* !PARSER_DUMP_BYTE_CODE */ - if (!(literal_p->status_flags & LEXER_FLAG_UNUSED_IDENT)) - { - literal_pool_p[literal_p->prop.index] = literal_p->u.value; - } + if (!(literal_p->status_flags & LEXER_FLAG_UNUSED_IDENT)) + { + literal_pool_p[literal_p->prop.index] = literal_p->u.value; + } #endif /* PARSER_DUMP_BYTE_CODE */ + } } else if ((literal_p->type == LEXER_FUNCTION_LITERAL) || (literal_p->type == LEXER_REGEXP_LITERAL)) { - ECMA_SET_NON_NULL_POINTER (literal_pool_p[literal_p->prop.index], - literal_p->u.bytecode_p); + JERRY_ASSERT (literal_p->prop.index >= register_count); + + ECMA_SET_INTERNAL_VALUE_POINTER (literal_pool_p[literal_p->prop.index], + literal_p->u.bytecode_p); } else { - JERRY_ASSERT (literal_p->type == LEXER_NUMBER_LITERAL); + JERRY_ASSERT (literal_p->type == LEXER_NUMBER_LITERAL + && literal_p->prop.index >= register_count); + literal_pool_p[literal_p->prop.index] = literal_p->u.value; } } @@ -692,9 +700,12 @@ parser_generate_initializers (parser_context_t *context_p, /**< context */ JERRY_ASSERT (literal_p != NULL && literal_p->type == LEXER_FUNCTION_LITERAL); + init_index = literal_p->prop.index; - ECMA_SET_NON_NULL_POINTER (literal_pool_p[literal_p->prop.index], - literal_p->u.bytecode_p); + JERRY_ASSERT (init_index >= register_count); + + ECMA_SET_INTERNAL_VALUE_POINTER (literal_pool_p[init_index], + literal_p->u.bytecode_p); } *dst_p++ = CBC_INITIALIZE_VAR; @@ -1216,7 +1227,12 @@ parse_print_final_cbc (ecma_compiled_code_t *compiled_code_p, /**< compiled code byte_code_start_p += sizeof (cbc_uint8_arguments_t); } - byte_code_start_p += literal_end * sizeof (jmem_cpointer_t); + byte_code_start_p += (unsigned int) (literal_end - register_end) * sizeof (ecma_value_t); + if (unlikely (compiled_code_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED)) + { + byte_code_start_p += argument_end * sizeof (ecma_value_t); + } + byte_code_end_p = byte_code_start_p + length; byte_code_p = byte_code_start_p; @@ -1276,6 +1292,24 @@ parse_print_final_cbc (ecma_compiled_code_t *compiled_code_p, /**< compiled code flags = cbc_ext_flags[ext_opcode]; JERRY_DEBUG_MSG (" %3d : %s", (int) cbc_offset, cbc_ext_names[ext_opcode]); byte_code_p += 2; + +#ifdef JERRY_ENABLE_LINE_INFO + if (ext_opcode == CBC_EXT_LINE) + { + uint32_t value = 0; + uint8_t byte; + + do + { + byte = *byte_code_p++; + value = (value << 7) | (byte & CBC_LOWER_SEVEN_BIT_MASK); + } + while (byte & CBC_HIGHEST_BIT_MASK); + + JERRY_DEBUG_MSG (" %d\n", (int) value); + continue; + } +#endif /* JERRY_ENABLE_LINE_INFO */ } if (flags & (CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2)) @@ -1378,14 +1412,18 @@ parser_post_processing (parser_context_t *context_p) /**< context */ size_t last_position; size_t offset; size_t length; + size_t literal_length; size_t total_size; +#ifdef JERRY_ENABLE_SNAPSHOT_SAVE + size_t total_size_used; +#endif size_t initializers_length; uint8_t real_offset; uint8_t *byte_code_p; bool needs_uint16_arguments; cbc_opcode_t last_opcode = CBC_EXT_OPCODE; ecma_compiled_code_t *compiled_code_p; - jmem_cpointer_t *literal_pool_p; + ecma_value_t *literal_pool_p; uint8_t *dst_p; if ((size_t) context_p->stack_limit + (size_t) context_p->register_count > PARSER_MAXIMUM_STACK_LIMIT) @@ -1468,6 +1506,23 @@ parser_post_processing (parser_context_t *context_p) /**< context */ flags = cbc_ext_flags[ext_opcode]; PARSER_NEXT_BYTE (page_p, offset); length++; + +#ifdef JERRY_ENABLE_LINE_INFO + if (ext_opcode == CBC_EXT_LINE) + { + uint8_t last_byte = 0; + + do + { + last_byte = page_p->bytes[offset]; + PARSER_NEXT_BYTE (page_p, offset); + length++; + } + while (last_byte & CBC_HIGHEST_BIT_MASK); + + continue; + } +#endif /* JERRY_ENABLE_LINE_INFO */ } while (flags & (CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2)) @@ -1609,11 +1664,38 @@ parser_post_processing (parser_context_t *context_p) /**< context */ total_size = sizeof (cbc_uint16_arguments_t); } - total_size += length + context_p->literal_count * sizeof (jmem_cpointer_t); + literal_length = (size_t) (context_p->literal_count - context_p->register_count) * sizeof (ecma_value_t); + + total_size += literal_length + length; + + if ((context_p->status_flags & PARSER_ARGUMENTS_NEEDED) + && !(context_p->status_flags & PARSER_IS_STRICT)) + { + total_size += context_p->argument_count * sizeof (ecma_value_t); + } + +#ifdef JERRY_ENABLE_LINE_INFO + if (JERRY_CONTEXT (resource_name) != ECMA_VALUE_UNDEFINED) + { + total_size += sizeof (ecma_value_t); + } +#endif /* JERRY_ENABLE_LINE_INFO */ + +#ifdef JERRY_ENABLE_SNAPSHOT_SAVE + total_size_used = total_size; +#endif total_size = JERRY_ALIGNUP (total_size, JMEM_ALIGNMENT); compiled_code_p = (ecma_compiled_code_t *) parser_malloc (context_p, total_size); +#ifdef JERRY_ENABLE_SNAPSHOT_SAVE + // Avoid getting junk bytes at the end when bytes at the end remain unused: + if (total_size_used < total_size) + { + memset (((uint8_t *) compiled_code_p) + total_size_used, 0, total_size - total_size_used); + } +#endif + #ifdef JMEM_STATS jmem_stats_allocate_byte_code_bytes (total_size); #endif /* JMEM_STATS */ @@ -1664,6 +1746,12 @@ parser_post_processing (parser_context_t *context_p) /**< context */ if (context_p->status_flags & PARSER_ARGUMENTS_NEEDED) { compiled_code_p->status_flags |= CBC_CODE_FLAGS_ARGUMENTS_NEEDED; + + if (!(context_p->status_flags & PARSER_IS_STRICT)) + { + compiled_code_p->status_flags |= CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED; + } + /* Arguments is stored in the lexical environment. */ context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED; } @@ -1680,8 +1768,9 @@ parser_post_processing (parser_context_t *context_p) /**< context */ } #endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */ - literal_pool_p = (jmem_cpointer_t *) byte_code_p; - byte_code_p += context_p->literal_count * sizeof (jmem_cpointer_t); + literal_pool_p = (ecma_value_t *) byte_code_p; + literal_pool_p -= context_p->register_count; + byte_code_p += literal_length; dst_p = parser_generate_initializers (context_p, byte_code_p, @@ -1755,6 +1844,25 @@ parser_post_processing (parser_context_t *context_p) /**< context */ opcode_p++; real_offset++; PARSER_NEXT_BYTE_UPDATE (page_p, offset, real_offset); + +#ifdef JERRY_ENABLE_LINE_INFO + if (ext_opcode == CBC_EXT_LINE) + { + uint8_t last_byte = 0; + + do + { + last_byte = page_p->bytes[offset]; + *dst_p++ = last_byte; + + real_offset++; + PARSER_NEXT_BYTE_UPDATE (page_p, offset, real_offset); + } + while (last_byte & CBC_HIGHEST_BIT_MASK); + + continue; + } +#endif /* JERRY_ENABLE_LINE_INFO */ } if (flags & CBC_HAS_BRANCH_ARG) @@ -1882,17 +1990,19 @@ parser_post_processing (parser_context_t *context_p) /**< context */ { parser_list_iterator_t literal_iterator; lexer_literal_t *literal_p; + uint16_t register_count = context_p->register_count; parser_list_iterator_init (&context_p->literal_pool, &literal_iterator); while ((literal_p = (lexer_literal_t *) parser_list_iterator_next (&literal_iterator))) { - if (literal_p->status_flags & LEXER_FLAG_LATE_INIT) + if ((literal_p->status_flags & LEXER_FLAG_LATE_INIT) + && literal_p->prop.index >= register_count) { uint32_t source_data = literal_p->u.source_data; const uint8_t *char_p = context_p->source_end_p - (source_data & 0xfffff); - jmem_cpointer_t lit_cp = ecma_find_or_create_literal_string (char_p, + ecma_value_t lit_value = ecma_find_or_create_literal_string (char_p, source_data >> 20); - literal_pool_p[literal_p->prop.index] = lit_cp; + literal_pool_p[literal_p->prop.index] = lit_value; } } } @@ -1903,6 +2013,9 @@ parser_post_processing (parser_context_t *context_p) /**< context */ { parser_list_iterator_t literal_iterator; uint16_t argument_count = 0; + uint16_t register_count = context_p->register_count; + ecma_value_t *argument_base_p = (ecma_value_t *) (((uint8_t *) compiled_code_p) + total_size); + argument_base_p -= context_p->argument_count; parser_list_iterator_init (&context_p->literal_pool, &literal_iterator); while (argument_count < context_p->argument_count) @@ -1922,7 +2035,7 @@ parser_post_processing (parser_context_t *context_p) /**< context */ { if (literal_p->u.char_p == NULL) { - literal_pool_p[argument_count] = JMEM_CP_NULL; + argument_base_p[argument_count] = ECMA_VALUE_EMPTY; argument_count++; continue; } @@ -1935,17 +2048,32 @@ parser_post_processing (parser_context_t *context_p) /**< context */ JERRY_ASSERT (literal_p->type == LEXER_IDENT_LITERAL && (literal_p->status_flags & LEXER_FLAG_VAR)); - JERRY_ASSERT (argument_count < literal_p->prop.index); + JERRY_ASSERT (literal_p->prop.index >= register_count); - literal_pool_p[argument_count] = literal_pool_p[literal_p->prop.index]; + argument_base_p[argument_count] = literal_pool_p[literal_p->prop.index]; argument_count++; } } +#ifdef JERRY_ENABLE_LINE_INFO + if (JERRY_CONTEXT (resource_name) != ECMA_VALUE_UNDEFINED) + { + ecma_value_t *resource_name_p = (ecma_value_t *) (((uint8_t *) compiled_code_p) + total_size); + + if ((context_p->status_flags & PARSER_ARGUMENTS_NEEDED) + && !(context_p->status_flags & PARSER_IS_STRICT)) + { + resource_name_p -= context_p->argument_count; + } + + resource_name_p[-1] = JERRY_CONTEXT (resource_name); + } +#endif /* JERRY_ENABLE_LINE_INFO */ + if (context_p->status_flags & PARSER_NAMED_FUNCTION_EXP) { - ECMA_SET_NON_NULL_POINTER (literal_pool_p[const_literal_end], - compiled_code_p); + ECMA_SET_INTERNAL_VALUE_POINTER (literal_pool_p[const_literal_end], + compiled_code_p); } #ifdef JERRY_DEBUGGER @@ -2275,7 +2403,7 @@ parser_save_context (parser_context_t *context_p, /**< context */ JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE); #ifdef JERRY_DEBUGGER - if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED + if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) && context_p->breakpoint_info_count > 0) { parser_send_breakpoints (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST); @@ -2648,7 +2776,7 @@ parser_append_breakpoint_info (parser_context_t *context_p, /**< context */ context_p->status_flags |= PARSER_DEBUGGER_BREAKPOINT_APPENDED; - if (context_p->breakpoint_info_count >= JERRY_DEBUGGER_SEND_MAX (parser_list_t)) + if (context_p->breakpoint_info_count >= JERRY_DEBUGGER_SEND_MAX (parser_breakpoint_info_t)) { parser_send_breakpoints (context_p, type); } @@ -2730,6 +2858,7 @@ parser_parse_script (const uint8_t *arg_list_p, /**< function argument list */ /* It is unlikely that memory can be allocated in an out-of-memory * situation. However, a simple value can still be thrown. */ JERRY_CONTEXT (error_value) = ECMA_VALUE_NULL; + JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; return ECMA_VALUE_ERROR; } #ifdef JERRY_ENABLE_ERROR_MESSAGES @@ -2756,6 +2885,28 @@ parser_parse_script (const uint8_t *arg_list_p, /**< function argument list */ return ecma_raise_syntax_error (""); #endif /* JERRY_ENABLE_ERROR_MESSAGES */ } + +#ifdef JERRY_DEBUGGER + if ((JERRY_CONTEXT (debugger_flags) & (JERRY_DEBUGGER_CONNECTED | JERRY_DEBUGGER_PARSER_WAIT)) + == (JERRY_DEBUGGER_CONNECTED | JERRY_DEBUGGER_PARSER_WAIT)) + { + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_PARSER_WAIT_MODE); + jerry_debugger_send_type (JERRY_DEBUGGER_WAITING_AFTER_PARSE); + + while (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_PARSER_WAIT_MODE) + { + jerry_debugger_receive (NULL); + + if (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)) + { + break; + } + + jerry_debugger_sleep (); + } + } +#endif /* JERRY_DEBUGGER */ + return ECMA_VALUE_TRUE; #else /* JERRY_DISABLE_JS_PARSER */ JERRY_UNUSED (arg_list_p); diff --git a/deps/jerry/jerry-core/parser/regexp/re-bytecode.h b/deps/jerry/jerry-core/parser/regexp/re-bytecode.h index c166151..45846e0 100644 --- a/deps/jerry/jerry-core/parser/regexp/re-bytecode.h +++ b/deps/jerry/jerry-core/parser/regexp/re-bytecode.h @@ -85,7 +85,7 @@ typedef enum typedef struct { ecma_compiled_code_t header; /**< compiled code header */ - jmem_cpointer_t pattern_cp; /**< original RegExp pattern */ + ecma_value_t pattern; /**< original RegExp pattern */ uint32_t num_of_captures; /**< number of capturing brackets */ uint32_t num_of_non_captures; /**< number of non capturing brackets */ } re_compiled_code_t; diff --git a/deps/jerry/jerry-core/parser/regexp/re-compiler.c b/deps/jerry/jerry-core/parser/regexp/re-compiler.c index da318ac..9046fa4 100644 --- a/deps/jerry/jerry-core/parser/regexp/re-compiler.c +++ b/deps/jerry/jerry-core/parser/regexp/re-compiler.c @@ -52,8 +52,13 @@ re_append_char_class (void *re_ctx_p, /**< RegExp compiler context */ /** * Insert simple atom iterator + * + * @return empty ecma value - if inserted successfully + * error ecma value - otherwise + * + * Returned value must be freed with ecma_free_value */ -static void +static ecma_value_t re_insert_simple_iterator (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context */ uint32_t new_atom_start_offset) /**< atom start offset */ { @@ -63,7 +68,15 @@ re_insert_simple_iterator (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler con qmin = re_ctx_p->current_token.qmin; qmax = re_ctx_p->current_token.qmax; - JERRY_ASSERT (qmin <= qmax); + + if (qmin == 1 && qmax == 1) + { + return ECMA_VALUE_EMPTY; + } + else if (qmin > qmax) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("RegExp quantifier error: qmin > qmax.")); + } /* TODO: optimize bytecode length. Store 0 rather than INF */ @@ -83,6 +96,8 @@ re_insert_simple_iterator (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler con { re_insert_opcode (re_ctx_p->bytecode_ctx_p, offset, RE_OP_NON_GREEDY_ITERATOR); } + + return ECMA_VALUE_EMPTY; } /* re_insert_simple_iterator */ /** @@ -224,10 +239,14 @@ re_parse_alternative (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context while (ecma_is_value_empty (ret_value) && should_loop) { - ECMA_TRY_CATCH (empty, - re_parse_next_token (re_ctx_p->parser_ctx_p, - &(re_ctx_p->current_token)), - ret_value); + ecma_value_t next_token_result = re_parse_next_token (re_ctx_p->parser_ctx_p, + &(re_ctx_p->current_token)); + if (ECMA_IS_VALUE_ERROR (next_token_result)) + { + ret_value = next_token_result; + break; + } + JERRY_ASSERT (next_token_result == ECMA_VALUE_EMPTY); uint32_t new_atom_start_offset = re_get_bytecode_length (re_ctx_p->bytecode_ctx_p); @@ -271,10 +290,7 @@ re_parse_alternative (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context re_append_char (bc_ctx_p, re_canonicalize ((ecma_char_t) re_ctx_p->current_token.value, re_ctx_p->flags & RE_FLAG_IGNORE_CASE)); - if ((re_ctx_p->current_token.qmin != 1) || (re_ctx_p->current_token.qmax != 1)) - { - re_insert_simple_iterator (re_ctx_p, new_atom_start_offset); - } + ret_value = re_insert_simple_iterator (re_ctx_p, new_atom_start_offset); break; } case RE_TOK_PERIOD: @@ -282,10 +298,7 @@ re_parse_alternative (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context JERRY_TRACE_MSG ("Compile a period\n"); re_append_opcode (bc_ctx_p, RE_OP_PERIOD); - if ((re_ctx_p->current_token.qmin != 1) || (re_ctx_p->current_token.qmax != 1)) - { - re_insert_simple_iterator (re_ctx_p, new_atom_start_offset); - } + ret_value = re_insert_simple_iterator (re_ctx_p, new_atom_start_offset); break; } case RE_TOK_ALTERNATIVE: @@ -387,21 +400,17 @@ re_parse_alternative (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context : RE_OP_CHAR_CLASS); uint32_t offset = re_get_bytecode_length (re_ctx_p->bytecode_ctx_p); - ECMA_TRY_CATCH (empty_value, - re_parse_char_class (re_ctx_p->parser_ctx_p, - re_append_char_class, - re_ctx_p, - &(re_ctx_p->current_token)), - ret_value); - re_insert_u32 (bc_ctx_p, offset, re_ctx_p->parser_ctx_p->num_of_classes); + ret_value = re_parse_char_class (re_ctx_p->parser_ctx_p, + re_append_char_class, + re_ctx_p, + &(re_ctx_p->current_token)); - if ((re_ctx_p->current_token.qmin != 1) || (re_ctx_p->current_token.qmax != 1)) + if (!ECMA_IS_VALUE_ERROR (ret_value)) { - re_insert_simple_iterator (re_ctx_p, new_atom_start_offset); + re_insert_u32 (bc_ctx_p, offset, re_ctx_p->parser_ctx_p->num_of_classes); + ret_value = re_insert_simple_iterator (re_ctx_p, new_atom_start_offset); } - ECMA_FINALIZE (empty_value); - break; } case RE_TOK_END_GROUP: @@ -439,7 +448,6 @@ re_parse_alternative (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context break; } } - ECMA_FINALIZE (empty); } return ret_value; @@ -463,8 +471,7 @@ re_find_bytecode_in_cache (ecma_string_t *pattern_str_p, /**< pattern string */ if (cached_bytecode_p != NULL) { - ecma_string_t *cached_pattern_str_p; - cached_pattern_str_p = ECMA_GET_NON_NULL_POINTER (ecma_string_t, cached_bytecode_p->pattern_cp); + ecma_string_t *cached_pattern_str_p = ecma_get_string_from_value (cached_bytecode_p->pattern); if ((cached_bytecode_p->header.status_flags & RE_FLAGS_MASK) == flags && ecma_compare_ecma_strings (cached_pattern_str_p, pattern_str_p)) @@ -557,10 +564,16 @@ re_compile_bytecode (const re_compiled_code_t **out_bytecode_p, /**< [out] point re_ctx.num_of_captures = 1; re_append_opcode (&bc_ctx, RE_OP_SAVE_AT_START); - ECMA_TRY_CATCH (empty, re_parse_alternative (&re_ctx, true), ret_value); + ecma_value_t parse_alt_result = re_parse_alternative (&re_ctx, true); + ECMA_FINALIZE_UTF8_STRING (pattern_start_p, pattern_start_size); + + if (ECMA_IS_VALUE_ERROR (parse_alt_result)) + { + ret_value = parse_alt_result; + } /* 2. Check for invalid backreference */ - if (re_ctx.highest_backref >= re_ctx.num_of_captures) + else if (re_ctx.highest_backref >= re_ctx.num_of_captures) { ret_value = ecma_raise_syntax_error ("Invalid backreference.\n"); } @@ -575,7 +588,7 @@ re_compile_bytecode (const re_compiled_code_t **out_bytecode_p, /**< [out] point re_compiled_code.header.refs = 1; re_compiled_code.header.status_flags = re_ctx.flags; ecma_ref_ecma_string (pattern_str_p); - ECMA_SET_NON_NULL_POINTER (re_compiled_code.pattern_cp, pattern_str_p); + re_compiled_code.pattern = ecma_make_string_value (pattern_str_p); re_compiled_code.num_of_captures = re_ctx.num_of_captures * 2; re_compiled_code.num_of_non_captures = re_ctx.num_of_non_captures; @@ -585,10 +598,6 @@ re_compile_bytecode (const re_compiled_code_t **out_bytecode_p, /**< [out] point sizeof (re_compiled_code_t)); } - ECMA_FINALIZE (empty); - - ECMA_FINALIZE_UTF8_STRING (pattern_start_p, pattern_start_size); - size_t byte_code_size = (size_t) (bc_ctx.block_end_p - bc_ctx.block_start_p); if (!ecma_is_value_empty (ret_value)) diff --git a/deps/jerry/jerry-core/parser/regexp/re-parser.c b/deps/jerry/jerry-core/parser/regexp/re-parser.c index 7479603..b26eba9 100644 --- a/deps/jerry/jerry-core/parser/regexp/re-parser.c +++ b/deps/jerry/jerry-core/parser/regexp/re-parser.c @@ -16,6 +16,7 @@ #include "ecma-exceptions.h" #include "ecma-globals.h" #include "ecma-try-catch-macro.h" +#include "jcontext.h" #include "jrt-libc-includes.h" #include "lit-char-helpers.h" #include "re-compiler.h" @@ -242,11 +243,6 @@ re_parse_iterator (re_parser_ctx_t *parser_ctx_p, /**< RegExp parser context */ JERRY_ASSERT (ecma_is_value_empty (ret_value)); - if (re_token_p->qmin > re_token_p->qmax) - { - ret_value = ecma_raise_syntax_error (ECMA_ERR_MSG ("RegExp quantifier error: qmin > qmax.")); - } - return ret_value; } /* re_parse_iterator */ @@ -318,7 +314,8 @@ re_parse_char_class (re_parser_ctx_t *parser_ctx_p, /**< number of classes */ bool is_range = false; parser_ctx_p->num_of_classes = 0; - if (lit_utf8_peek_prev (parser_ctx_p->input_curr_p) != LIT_CHAR_LEFT_SQUARE) + const ecma_char_t prev_char = lit_utf8_peek_prev (parser_ctx_p->input_curr_p); + if (prev_char != LIT_CHAR_LEFT_SQUARE && prev_char != LIT_CHAR_CIRCUMFLEX) { lit_utf8_decr (&parser_ctx_p->input_curr_p); lit_utf8_decr (&parser_ctx_p->input_curr_p); @@ -881,9 +878,39 @@ re_parse_next_token (re_parser_ctx_t *parser_ctx_p, /**< RegExp parser context * case LIT_CHAR_QUESTION: case LIT_CHAR_ASTERISK: case LIT_CHAR_PLUS: + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid RegExp token.")); + } case LIT_CHAR_LEFT_BRACE: { +#ifdef ENABLE_REGEXP_STRICT_MODE return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid RegExp token.")); +#else /* !ENABLE_REGEXP_STRICT_MODE */ + const lit_utf8_byte_t *input_curr_p = parser_ctx_p->input_curr_p; + + lit_utf8_decr (&parser_ctx_p->input_curr_p); + ret_value = re_parse_iterator (parser_ctx_p, out_token_p); + if (ecma_is_value_empty (ret_value)) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Invalid RegExp token.")); + } + + JERRY_ASSERT (ECMA_IS_VALUE_ERROR (ret_value)); + ecma_free_value (JERRY_CONTEXT (error_value)); + + parser_ctx_p->input_curr_p = input_curr_p; + + out_token_p->type = RE_TOK_CHAR; + out_token_p->value = ch; + ret_value = re_parse_iterator (parser_ctx_p, out_token_p); + + if (!ecma_is_value_empty (ret_value)) + { + parser_ctx_p->input_curr_p = input_curr_p; + ret_value = ECMA_VALUE_EMPTY; + } +#endif /* ENABLE_REGEXP_STRICT_MODE */ + break; } case LIT_CHAR_NULL: { diff --git a/deps/jerry/jerry-core/vm/opcodes-ecma-relational-equality.c b/deps/jerry/jerry-core/vm/opcodes-ecma-relational-equality.c index 28d6dea..aa7e909 100644 --- a/deps/jerry/jerry-core/vm/opcodes-ecma-relational-equality.c +++ b/deps/jerry/jerry-core/vm/opcodes-ecma-relational-equality.c @@ -104,26 +104,13 @@ ecma_value_t opfunc_instanceof (ecma_value_t left_value, /**< left value */ ecma_value_t right_value) /**< right value */ { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - if (!ecma_is_value_object (right_value)) { - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Expected an object in 'instanceof' check.")); - } - else - { - ecma_object_t *right_value_obj_p = ecma_get_object_from_value (right_value); - - ECMA_TRY_CATCH (is_instance_of, - ecma_op_object_has_instance (right_value_obj_p, left_value), - ret_value); - - ret_value = is_instance_of; - - ECMA_FINALIZE (is_instance_of); + return ecma_raise_type_error (ECMA_ERR_MSG ("Expected an object in 'instanceof' check.")); } - return ret_value; + ecma_object_t *right_value_obj_p = ecma_get_object_from_value (right_value); + return ecma_op_object_has_instance (right_value_obj_p, left_value); } /* opfunc_instanceof */ /** @@ -138,25 +125,23 @@ ecma_value_t opfunc_in (ecma_value_t left_value, /**< left value */ ecma_value_t right_value) /**< right value */ { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - if (!ecma_is_value_object (right_value)) { - ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Expected an object in 'in' check.")); + return ecma_raise_type_error (ECMA_ERR_MSG ("Expected an object in 'in' check.")); } - else - { - ECMA_TRY_CATCH (str_left_value, ecma_op_to_string (left_value), ret_value); - ecma_string_t *left_value_prop_name_p = ecma_get_string_from_value (str_left_value); - ecma_object_t *right_value_obj_p = ecma_get_object_from_value (right_value); + ecma_value_t left_string_value = ecma_op_to_string (left_value); + if (ECMA_IS_VALUE_ERROR (left_string_value)) + { + return left_string_value; + } - ret_value = ecma_make_boolean_value (ecma_op_object_has_property (right_value_obj_p, left_value_prop_name_p)); + ecma_string_t *left_value_prop_name_p = ecma_get_string_from_value (left_string_value); + ecma_object_t *right_value_obj_p = ecma_get_object_from_value (right_value); - ECMA_FINALIZE (str_left_value); - } + ecma_free_value (left_string_value); - return ret_value; + return ecma_make_boolean_value (ecma_op_object_has_property (right_value_obj_p, left_value_prop_name_p)); } /* opfunc_in */ /** diff --git a/deps/jerry/jerry-core/vm/opcodes.c b/deps/jerry/jerry-core/vm/opcodes.c index 60648b2..b887d99 100644 --- a/deps/jerry/jerry-core/vm/opcodes.c +++ b/deps/jerry/jerry-core/vm/opcodes.c @@ -92,47 +92,7 @@ opfunc_logical_not (ecma_value_t left_value) /**< left value */ ecma_value_t opfunc_typeof (ecma_value_t left_value) /**< left value */ { - ecma_value_t ret_value = ECMA_VALUE_EMPTY; - - ecma_string_t *type_str_p = NULL; - - if (ecma_is_value_undefined (left_value)) - { - type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_UNDEFINED); - } - else if (ecma_is_value_null (left_value)) - { - type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_OBJECT); - } - else if (ecma_is_value_boolean (left_value)) - { - type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_BOOLEAN); - } - else if (ecma_is_value_number (left_value)) - { - type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_NUMBER); - } - else if (ecma_is_value_string (left_value)) - { - type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_STRING); - } - else - { - JERRY_ASSERT (ecma_is_value_object (left_value)); - - if (ecma_op_is_callable (left_value)) - { - type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_FUNCTION); - } - else - { - type_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_OBJECT); - } - } - - ret_value = ecma_make_string_value (type_str_p); - - return ret_value; + return ecma_make_magic_string_value (ecma_get_typeof_lit_id (left_value)); } /* opfunc_typeof */ /** @@ -208,45 +168,40 @@ vm_op_delete_prop (ecma_value_t object, /**< base object */ ecma_value_t property, /**< property name */ bool is_strict) /**< strict mode */ { - ecma_value_t completion_value = ECMA_VALUE_EMPTY; - if (ecma_is_value_undefined (object)) { - completion_value = ECMA_VALUE_TRUE; + return ECMA_VALUE_TRUE; } - else - { - completion_value = ECMA_VALUE_EMPTY; - ECMA_TRY_CATCH (check_coercible_ret, - ecma_op_check_object_coercible (object), - completion_value); - ECMA_TRY_CATCH (str_name_value, - ecma_op_to_string (property), - completion_value); - - JERRY_ASSERT (ecma_is_value_string (str_name_value)); - ecma_string_t *name_string_p = ecma_get_string_from_value (str_name_value); - - ECMA_TRY_CATCH (obj_value, ecma_op_to_object (object), completion_value); + ecma_value_t check_coercible = ecma_op_check_object_coercible (object); + if (ECMA_IS_VALUE_ERROR (check_coercible)) + { + return check_coercible; + } + JERRY_ASSERT (check_coercible == ECMA_VALUE_EMPTY); - JERRY_ASSERT (ecma_is_value_object (obj_value)); - ecma_object_t *obj_p = ecma_get_object_from_value (obj_value); - JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); + ecma_value_t str_name_value = ecma_op_to_string (property); + if (ECMA_IS_VALUE_ERROR (str_name_value)) + { + return str_name_value; + } - ECMA_TRY_CATCH (delete_op_ret_val, - ecma_op_object_delete (obj_p, name_string_p, is_strict), - completion_value); + JERRY_ASSERT (ecma_is_value_string (str_name_value)); + ecma_string_t *name_string_p = ecma_get_string_from_value (str_name_value); - completion_value = delete_op_ret_val; + ecma_value_t obj_value = ecma_op_to_object (object); + /* The ecma_op_check_object_coercible call already checked the op_to_object error cases. */ + JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (obj_value)); + JERRY_ASSERT (ecma_is_value_object (obj_value)); + ecma_object_t *obj_p = ecma_get_object_from_value (obj_value); + JERRY_ASSERT (!ecma_is_lexical_environment (obj_p)); - ECMA_FINALIZE (delete_op_ret_val); - ECMA_FINALIZE (obj_value); - ECMA_FINALIZE (str_name_value); - ECMA_FINALIZE (check_coercible_ret); - } + ecma_value_t delete_op_ret = ecma_op_object_delete (obj_p, name_string_p, is_strict); + JERRY_ASSERT (ecma_is_value_boolean (delete_op_ret) || (is_strict == true && ECMA_IS_VALUE_ERROR (delete_op_ret))); + ecma_free_value (obj_value); + ecma_free_value (str_name_value); - return completion_value; + return delete_op_ret; } /* vm_op_delete_prop */ /** @@ -256,12 +211,12 @@ vm_op_delete_prop (ecma_value_t object, /**< base object */ * Returned value must be freed with ecma_free_value */ ecma_value_t -vm_op_delete_var (jmem_cpointer_t name_literal, /**< name literal */ +vm_op_delete_var (ecma_value_t name_literal, /**< name literal */ ecma_object_t *lex_env_p) /**< lexical environment */ { ecma_value_t completion_value = ECMA_VALUE_EMPTY; - ecma_string_t *var_name_str_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, name_literal); + ecma_string_t *var_name_str_p = ecma_get_string_from_value (name_literal); ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (lex_env_p, var_name_str_p); @@ -285,43 +240,39 @@ vm_op_delete_var (jmem_cpointer_t name_literal, /**< name literal */ * See also: * ECMA-262 v5, 12.6.4 * - * @return completion value - * Returned value must be freed with ecma_free_value + * @return chain list of property names */ -ecma_collection_header_t * +ecma_collection_chunk_t * opfunc_for_in (ecma_value_t left_value, /**< left value */ ecma_value_t *result_obj_p) /**< expression object */ { - ecma_value_t compl_val = ECMA_VALUE_EMPTY; - ecma_collection_header_t *prop_names_p = NULL; + ecma_collection_chunk_t *prop_names_p = NULL; /* 3. */ - if (!ecma_is_value_undefined (left_value) - && !ecma_is_value_null (left_value)) + if (ecma_is_value_undefined (left_value) + || ecma_is_value_null (left_value)) { - /* 4. */ - ECMA_TRY_CATCH (obj_expr_value, - ecma_op_to_object (left_value), - compl_val); + return prop_names_p; + } - ecma_object_t *obj_p = ecma_get_object_from_value (obj_expr_value); - prop_names_p = ecma_op_object_get_property_names (obj_p, false, true, true); + /* 4. */ + ecma_value_t obj_expr_value = ecma_op_to_object (left_value); + /* ecma_op_to_object will only raise error on null/undefined values but those are handled above. */ + JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (obj_expr_value)); + ecma_object_t *obj_p = ecma_get_object_from_value (obj_expr_value); + ecma_collection_header_t *prop_names_coll_p = ecma_op_object_get_property_names (obj_p, false, true, true); - if (prop_names_p->unit_number != 0) - { - ecma_ref_object (obj_p); - *result_obj_p = ecma_make_object_value (obj_p); - } - else - { - ecma_dealloc_collection_header (prop_names_p); - prop_names_p = NULL; - } + if (prop_names_coll_p->item_count != 0) + { + prop_names_p = ECMA_GET_POINTER (ecma_collection_chunk_t, + prop_names_coll_p->first_chunk_cp); - ECMA_FINALIZE (obj_expr_value); + ecma_ref_object (obj_p); + *result_obj_p = ecma_make_object_value (obj_p); } - JERRY_ASSERT (ecma_is_value_empty (compl_val)); + jmem_heap_free_block (prop_names_coll_p, sizeof (ecma_collection_header_t)); + ecma_free_value (obj_expr_value); return prop_names_p; } /* opfunc_for_in */ diff --git a/deps/jerry/jerry-core/vm/opcodes.h b/deps/jerry/jerry-core/vm/opcodes.h index f2c73c3..5114578 100644 --- a/deps/jerry/jerry-core/vm/opcodes.h +++ b/deps/jerry/jerry-core/vm/opcodes.h @@ -91,9 +91,9 @@ ecma_value_t vm_op_delete_prop (ecma_value_t object, ecma_value_t property, bool is_strict); ecma_value_t -vm_op_delete_var (jmem_cpointer_t name_literal, ecma_object_t *lex_env_p); +vm_op_delete_var (ecma_value_t name_literal, ecma_object_t *lex_env_p); -ecma_collection_header_t * +ecma_collection_chunk_t * opfunc_for_in (ecma_value_t left_value, ecma_value_t *result_obj_p); /** diff --git a/deps/jerry/jerry-core/vm/vm-defines.h b/deps/jerry/jerry-core/vm/vm-defines.h index 7ae91ee..9ad4c3a 100644 --- a/deps/jerry/jerry-core/vm/vm-defines.h +++ b/deps/jerry/jerry-core/vm/vm-defines.h @@ -46,11 +46,15 @@ typedef struct vm_frame_ctx_t uint8_t *byte_code_start_p; /**< byte code start pointer */ ecma_value_t *registers_p; /**< register start pointer */ ecma_value_t *stack_top_p; /**< stack top pointer */ - jmem_cpointer_t *literal_start_p; /**< literal list start pointer */ + ecma_value_t *literal_start_p; /**< literal list start pointer */ ecma_object_t *lex_env_p; /**< current lexical environment */ struct vm_frame_ctx_t *prev_context_p; /**< previous context */ ecma_value_t this_binding; /**< this binding */ ecma_value_t call_block_result; /**< preserve block result during a call */ +#ifdef JERRY_ENABLE_LINE_INFO + ecma_value_t resource_name; /**< current resource name (usually a file name) */ + uint32_t current_line; /**< currently executed line */ +#endif /* JERRY_ENABLE_LINE_INFO */ uint16_t context_depth; /**< current context depth */ uint8_t is_eval_code; /**< eval mode flag */ uint8_t call_operation; /**< perform a call or construct operation */ diff --git a/deps/jerry/jerry-core/vm/vm-stack.c b/deps/jerry/jerry-core/vm/vm-stack.c index 004001f..d0278b7 100644 --- a/deps/jerry/jerry-core/vm/vm-stack.c +++ b/deps/jerry/jerry-core/vm/vm-stack.c @@ -67,21 +67,30 @@ vm_stack_context_abort (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ } case VM_CONTEXT_FOR_IN: { - jmem_cpointer_t current = (jmem_cpointer_t) vm_stack_top_p[-2]; + ecma_collection_chunk_t *chunk_p; + chunk_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (ecma_collection_chunk_t, vm_stack_top_p[-2]); + uint32_t index = vm_stack_top_p[-3]; - while (current != JMEM_CP_NULL) + while (chunk_p != NULL) { - ecma_collection_chunk_t *chunk_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_collection_chunk_t, - current); + ecma_value_t value = chunk_p->items[index]; - lit_utf8_byte_t *data_ptr = chunk_p->data; - ecma_free_value (*(ecma_value_t *) data_ptr); + if (unlikely (ecma_is_value_collection_chunk (value))) + { + ecma_collection_chunk_t *next_chunk_p = ecma_get_collection_chunk_from_value (value); + jmem_heap_free_block (chunk_p, sizeof (ecma_collection_chunk_t)); - current = chunk_p->next_chunk_cp; - ecma_dealloc_collection_chunk (chunk_p); + chunk_p = next_chunk_p; + index = 0; + } + else + { + ecma_free_value (value); + index++; + } } - ecma_free_value (vm_stack_top_p[-3]); + ecma_free_value (vm_stack_top_p[-4]); VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION); vm_stack_top_p -= PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION; diff --git a/deps/jerry/jerry-core/vm/vm-utils.c b/deps/jerry/jerry-core/vm/vm-utils.c new file mode 100644 index 0000000..a79a4b9 --- /dev/null +++ b/deps/jerry/jerry-core/vm/vm-utils.c @@ -0,0 +1,133 @@ +/* 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 "ecma-array-object.h" +#include "ecma-helpers.h" +#include "jcontext.h" +#include "vm.h" + +/** + * Check whether currently executed code is strict mode code + * + * @return true - current code is executed in strict mode, + * false - otherwise + */ +bool +vm_is_strict_mode (void) +{ + JERRY_ASSERT (JERRY_CONTEXT (vm_top_context_p) != NULL); + + return JERRY_CONTEXT (vm_top_context_p)->bytecode_header_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE; +} /* vm_is_strict_mode */ + +/** + * Check whether currently performed call (on top of call-stack) is performed in form, + * meeting conditions of 'Direct Call to Eval' (see also: ECMA-262 v5, 15.1.2.1.1) + * + * Warning: + * the function should only be called from implementation + * of built-in 'eval' routine of Global object + * + * @return true - currently performed call is performed through 'eval' identifier, + * without 'this' argument, + * false - otherwise + */ +inline bool __attr_always_inline___ +vm_is_direct_eval_form_call (void) +{ + return (JERRY_CONTEXT (status_flags) & ECMA_STATUS_DIRECT_EVAL) != 0; +} /* vm_is_direct_eval_form_call */ + +/** + * Get backtrace. The backtrace is an array of strings where + * each string contains the position of the corresponding frame. + * The array length is zero if the backtrace is not available. + * + * @return array ecma value + */ +ecma_value_t +vm_get_backtrace (uint32_t max_depth) /**< maximum backtrace depth, 0 = unlimited */ +{ +#ifdef JERRY_ENABLE_LINE_INFO + ecma_value_t result_array = ecma_op_create_array_object (NULL, 0, false); + + if (max_depth == 0) + { + max_depth = UINT32_MAX; + } + + vm_frame_ctx_t *context_p = JERRY_CONTEXT (vm_top_context_p); + ecma_object_t *array_p = ecma_get_object_from_value (result_array); + uint32_t index = 0; + + while (context_p != NULL) + { + if (context_p->resource_name == ECMA_VALUE_UNDEFINED) + { + context_p = context_p->prev_context_p; + continue; + } + + ecma_string_t *str_p = ecma_get_string_from_value (context_p->resource_name); + + if (ecma_string_is_empty (str_p)) + { + const char *unknown_str_p = ":"; + str_p = ecma_new_ecma_string_from_utf8 ((const lit_utf8_byte_t *) unknown_str_p, + (lit_utf8_size_t) strlen (unknown_str_p)); + } + else + { + ecma_ref_ecma_string (str_p); + str_p = ecma_append_magic_string_to_string (str_p, LIT_MAGIC_STRING_COLON_CHAR); + } + + ecma_string_t *line_str_p = ecma_new_ecma_string_from_uint32 (context_p->current_line); + str_p = ecma_concat_ecma_strings (str_p, line_str_p); + ecma_deref_ecma_string (line_str_p); + + ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (index); + ecma_property_value_t *prop_value_p; + prop_value_p = ecma_create_named_data_property (array_p, + index_str_p, + ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE, + NULL); + ecma_deref_ecma_string (index_str_p); + + prop_value_p->value = ecma_make_string_value (str_p); + + context_p = context_p->prev_context_p; + index++; + + if (index >= max_depth) + { + break; + } + } + + if (index > 0) + { + JERRY_ASSERT (ecma_get_object_type (array_p) == ECMA_OBJECT_TYPE_ARRAY); + + ((ecma_extended_object_t *) array_p)->u.array.length = index; + } + + return result_array; +#else /* !JERRY_ENABLE_LINE_INFO */ + JERRY_UNUSED (max_depth); + + return ecma_op_create_array_object (NULL, 0, false); +#endif /* JERRY_ENABLE_LINE_INFO */ +} /* vm_get_backtrace */ diff --git a/deps/jerry/jerry-core/vm/vm.c b/deps/jerry/jerry-core/vm/vm.c index 3dd6346..8b094df 100644 --- a/deps/jerry/jerry-core/vm/vm.c +++ b/deps/jerry/jerry-core/vm/vm.c @@ -55,23 +55,15 @@ vm_op_get_value (ecma_value_t object, /**< base object */ { ecma_object_t *object_p = ecma_get_object_from_value (object); ecma_string_t *property_name_p = NULL; - ecma_string_t uint32_string; if (ecma_is_value_integer_number (property)) { ecma_integer_value_t int_value = ecma_get_integer_from_value (property); -#ifdef JERRY_CPOINTER_32_BIT - bool limit_check = (int_value >= 0); -#else /* !JERRY_CPOINTER_32_BIT */ - bool limit_check = (int_value >= 0 && int_value < (ecma_integer_value_t) (UINT16_MAX + 1)); -#endif - - if (limit_check) + if (int_value >= 0 && int_value <= ECMA_DIRECT_STRING_MAX_IMM) { - /* Statically allocated string for searching. */ - ecma_init_ecma_string_from_uint32 (&uint32_string, (uint32_t) int_value); - property_name_p = &uint32_string; + property_name_p = (ecma_string_t *) ECMA_CREATE_DIRECT_STRING (ECMA_DIRECT_STRING_UINT, + (uintptr_t) int_value); } } else if (ecma_is_value_string (property)) @@ -283,7 +275,15 @@ vm_run_eval (ecma_compiled_code_t *bytecode_data_p, /**< byte-code data */ ecma_deref_object (lex_env_p); ecma_free_value (this_binding); + +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + if (!(bytecode_data_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) + { + ecma_bytecode_deref (bytecode_data_p); + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ ecma_bytecode_deref (bytecode_data_p); +#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ return completion_value; } /* vm_run_eval */ @@ -295,10 +295,26 @@ vm_run_eval (ecma_compiled_code_t *bytecode_data_p, /**< byte-code data */ */ static ecma_value_t vm_construct_literal_object (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ - jmem_cpointer_t lit_cp) /**< literal */ + ecma_value_t lit_value) /**< literal */ { - ecma_compiled_code_t *bytecode_p = ECMA_GET_NON_NULL_POINTER (ecma_compiled_code_t, - lit_cp); +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + ecma_compiled_code_t *bytecode_p; + + if (likely (!(frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION))) + { + bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, + lit_value); + } + else + { + uint8_t *byte_p = ((uint8_t *) frame_ctx_p->bytecode_header_p) + lit_value; + bytecode_p = (ecma_compiled_code_t *) byte_p; + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ + ecma_compiled_code_t *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_compiled_code_t, + lit_value); +#endif /* JERRY_ENABLE_SNAPSHOT_EXEC */ + bool is_function = ((bytecode_p->status_flags & CBC_CODE_FLAGS_FUNCTION) != 0); if (is_function) @@ -428,7 +444,7 @@ opfunc_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ arguments_list_len); } - JERRY_CONTEXT (is_direct_eval_form_call) = false; + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL; /* Free registers. */ for (uint32_t i = 0; i < arguments_list_len; i++) @@ -523,8 +539,8 @@ opfunc_construct (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } \ else \ { \ - ecma_string_t *name_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, \ - literal_start_p[literal_index]); \ + ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); \ + \ result = ecma_op_resolve_reference_value (frame_ctx_p->lex_env_p, \ name_p); \ \ @@ -537,23 +553,13 @@ opfunc_construct (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } \ else if (literal_index < const_literal_end) \ { \ - ecma_string_t *value_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, \ - literal_start_p[literal_index]); \ - \ - if (unlikely (ECMA_STRING_GET_CONTAINER (value_p) == ECMA_STRING_LITERAL_NUMBER)) \ - { \ - (target_value) = ecma_fast_copy_value (value_p->u.lit_number); \ - } \ - else \ - { \ - ecma_ref_ecma_string (value_p); \ - (target_value) = ecma_make_string_value (value_p); \ - } \ + (target_value) = ecma_fast_copy_value (literal_start_p[literal_index]); \ } \ else \ { \ /* Object construction. */ \ - (target_value) = vm_construct_literal_object (frame_ctx_p, literal_start_p[literal_index]); \ + (target_value) = vm_construct_literal_object (frame_ctx_p, \ + literal_start_p[literal_index]); \ } \ } \ while (0) @@ -571,10 +577,19 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ uint16_t encoding_limit; uint16_t encoding_delta; uint16_t register_end; - jmem_cpointer_t *literal_start_p = frame_ctx_p->literal_start_p; + ecma_value_t *literal_start_p = frame_ctx_p->literal_start_p; bool is_strict = ((frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE) != 0); - jmem_cpointer_t self_reference; - ECMA_SET_NON_NULL_POINTER (self_reference, bytecode_header_p); + ecma_value_t self_reference; + +#ifdef JERRY_ENABLE_SNAPSHOT_EXEC + self_reference = 0; + if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_STATIC_FUNCTION)) + { + ECMA_SET_INTERNAL_VALUE_POINTER (self_reference, bytecode_header_p); + } +#else /* !JERRY_ENABLE_SNAPSHOT_EXEC */ + ECMA_SET_INTERNAL_VALUE_POINTER (self_reference, bytecode_header_p); +#endif /* Prepare. */ if (!(bytecode_header_p->status_flags & CBC_CODE_FLAGS_FULL_LITERAL_ENCODING)) @@ -613,8 +628,7 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ while (literal_index <= literal_index_end) { - ecma_string_t *name_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, - literal_start_p[literal_index]); + ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); vm_var_decl (frame_ctx_p, name_p); literal_index++; } @@ -644,6 +658,7 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { uint32_t value_index; ecma_value_t lit_value; + bool is_immutable_binding = false; READ_LITERAL_INDEX (value_index); @@ -653,6 +668,7 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } else { + is_immutable_binding = (self_reference == literal_start_p[value_index]); lit_value = vm_construct_literal_object (frame_ctx_p, literal_start_p[value_index]); } @@ -663,14 +679,9 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } else { - ecma_string_t *name_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, - literal_start_p[literal_index]); + ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); - if (self_reference == literal_start_p[value_index]) - { - ecma_op_create_immutable_binding (frame_ctx_p->lex_env_p, name_p, lit_value); - } - else + if (likely (!is_immutable_binding)) { vm_var_decl (frame_ctx_p, name_p); @@ -690,6 +701,10 @@ vm_init_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_free_value (JERRY_CONTEXT (error_value)); } } + else + { + ecma_op_create_immutable_binding (frame_ctx_p->lex_env_p, name_p, lit_value); + } if (value_index >= register_end) { @@ -730,7 +745,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { const ecma_compiled_code_t *bytecode_header_p = frame_ctx_p->bytecode_header_p; uint8_t *byte_code_p = frame_ctx_p->byte_code_p; - jmem_cpointer_t *literal_start_p = frame_ctx_p->literal_start_p; + ecma_value_t *literal_start_p = frame_ctx_p->literal_start_p; ecma_value_t *stack_top_p; uint16_t encoding_limit; @@ -888,8 +903,10 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } else { - JERRY_CONTEXT (error_value) = ecma_clear_error_reference (result); + JERRY_CONTEXT (error_value) = ecma_clear_error_reference (result, false); } + + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_EXCEPTION; result = ECMA_VALUE_ERROR; goto error; } @@ -1144,10 +1161,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } else { - ecma_string_t *name_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, - literal_start_p[literal_index]); - ecma_object_t *ref_base_lex_env_p; + ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); + ecma_object_t *ref_base_lex_env_p; ref_base_lex_env_p = ecma_op_resolve_reference_base (frame_ctx_p->lex_env_p, name_p); @@ -1405,6 +1421,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ case VM_OC_THROW: { JERRY_CONTEXT (error_value) = left_value; + JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; + result = ECMA_VALUE_ERROR; left_value = ECMA_VALUE_UNDEFINED; goto error; @@ -1416,7 +1434,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } case VM_OC_EVAL: { - JERRY_CONTEXT (is_direct_eval_form_call) = true; + JERRY_CONTEXT (status_flags) |= ECMA_STATUS_DIRECT_EVAL; JERRY_ASSERT (*byte_code_p >= CBC_CALL && *byte_code_p <= CBC_CALL2_PROP_BLOCK); continue; } @@ -1644,8 +1662,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } else { - ecma_string_t *name_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, - literal_start_p[literal_index]); + ecma_string_t *name_p = ecma_get_string_from_value (literal_start_p[literal_index]); ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (frame_ctx_p->lex_env_p, name_p); @@ -2274,10 +2291,10 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); ecma_value_t expr_obj_value = ECMA_VALUE_UNDEFINED; - ecma_collection_header_t *header_p = opfunc_for_in (value, &expr_obj_value); + ecma_collection_chunk_t *prop_names_p = opfunc_for_in (value, &expr_obj_value); ecma_free_value (value); - if (header_p == NULL) + if (prop_names_p == NULL) { byte_code_p = byte_code_start_p + branch_offset; continue; @@ -2288,62 +2305,92 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ VM_PLUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION); stack_top_p += PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION; stack_top_p[-1] = (ecma_value_t) VM_CREATE_CONTEXT (VM_CONTEXT_FOR_IN, branch_offset); - stack_top_p[-2] = header_p->first_chunk_cp; - stack_top_p[-3] = expr_obj_value; + ECMA_SET_INTERNAL_VALUE_ANY_POINTER (stack_top_p[-2], prop_names_p); + stack_top_p[-3] = 0; + stack_top_p[-4] = expr_obj_value; - ecma_dealloc_collection_header (header_p); continue; } case VM_OC_FOR_IN_GET_NEXT: { ecma_value_t *context_top_p = frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth; - ecma_collection_chunk_t *chunk_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_collection_chunk_t, context_top_p[-2]); + + ecma_collection_chunk_t *chunk_p; + chunk_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (ecma_collection_chunk_t, context_top_p[-2]); JERRY_ASSERT (VM_GET_CONTEXT_TYPE (context_top_p[-1]) == VM_CONTEXT_FOR_IN); - lit_utf8_byte_t *data_ptr = chunk_p->data; - result = *(ecma_value_t *) data_ptr; - context_top_p[-2] = chunk_p->next_chunk_cp; + uint32_t index = context_top_p[-3]; - ecma_dealloc_collection_chunk (chunk_p); + JERRY_ASSERT (!ecma_is_value_collection_chunk (chunk_p->items[index])); - *stack_top_p++ = result; + *stack_top_p++ = chunk_p->items[index]; + index++; + + if (likely (!ecma_is_value_collection_chunk (chunk_p->items[index]))) + { + context_top_p[-3] = index; + continue; + } + + context_top_p[-3] = 0; + + ecma_collection_chunk_t *next_chunk_p = ecma_get_collection_chunk_from_value (chunk_p->items[index]); + ECMA_SET_INTERNAL_VALUE_ANY_POINTER (context_top_p[-2], next_chunk_p); + + jmem_heap_free_block (chunk_p, sizeof (ecma_collection_chunk_t)); continue; } case VM_OC_FOR_IN_HAS_NEXT: { JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + ecma_collection_chunk_t *chunk_p; + chunk_p = ECMA_GET_INTERNAL_VALUE_ANY_POINTER (ecma_collection_chunk_t, stack_top_p[-2]); + + uint32_t index = stack_top_p[-3]; + ecma_object_t *object_p = ecma_get_object_from_value (stack_top_p[-4]); + while (true) { - if (stack_top_p[-2] == JMEM_CP_NULL) + if (chunk_p == NULL) { - ecma_free_value (stack_top_p[-3]); + ecma_deref_object (object_p); VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION); stack_top_p -= PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION; break; } - ecma_collection_chunk_t *chunk_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_collection_chunk_t, stack_top_p[-2]); + ecma_string_t *prop_name_p = ecma_get_string_from_value (chunk_p->items[index]); - lit_utf8_byte_t *data_ptr = chunk_p->data; - ecma_string_t *prop_name_p = ecma_get_string_from_value (*(ecma_value_t *) data_ptr); + if (likely (ecma_op_object_has_property (object_p, prop_name_p))) + { + byte_code_p = byte_code_start_p + branch_offset; + break; + } + + index++; + ecma_value_t value = chunk_p->items[index]; - if (!ecma_op_object_has_property (ecma_get_object_from_value (stack_top_p[-3]), - prop_name_p)) + if (likely (!ecma_is_value_collection_chunk (value))) { - stack_top_p[-2] = chunk_p->next_chunk_cp; - ecma_deref_ecma_string (prop_name_p); - ecma_dealloc_collection_chunk (chunk_p); + stack_top_p[-3] = index; } else { - byte_code_p = byte_code_start_p + branch_offset; - break; + index = 0; + stack_top_p[-3] = 0; + + ecma_collection_chunk_t *next_chunk_p = ecma_get_collection_chunk_from_value (value); + ECMA_SET_INTERNAL_VALUE_ANY_POINTER (stack_top_p[-2], next_chunk_p); + + jmem_heap_free_block (chunk_p, sizeof (ecma_collection_chunk_t)); + chunk_p = next_chunk_p; } - } + ecma_deref_ecma_string (prop_name_p); + } continue; } case VM_OC_TRY: @@ -2419,11 +2466,16 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ case VM_CONTEXT_FINALLY_THROW: { JERRY_CONTEXT (error_value) = stack_top_p[-2]; + JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION; VM_MINUS_EQUAL_U16 (frame_ctx_p->context_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION); stack_top_p -= PARSER_TRY_CONTEXT_STACK_ALLOCATION; result = ECMA_VALUE_ERROR; + +#ifdef JERRY_DEBUGGER + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN); +#endif /* JERRY_DEBUGGER */ goto error; } case VM_CONTEXT_FINALLY_RETURN: @@ -2482,6 +2534,11 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ frame_ctx_p->byte_code_p = byte_code_start_p; jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_BREAKPOINT_HIT); + if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_EXCEPTION_THROWN) + { + result = ECMA_VALUE_ERROR; + goto error; + } #endif /* JERRY_DEBUGGER */ continue; } @@ -2504,6 +2561,11 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ || JERRY_CONTEXT (debugger_stop_context) == JERRY_CONTEXT (vm_top_context_p))) { jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_BREAKPOINT_HIT); + if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_EXCEPTION_THROWN) + { + result = ECMA_VALUE_ERROR; + goto error; + } continue; } @@ -2525,10 +2587,61 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ || JERRY_CONTEXT (debugger_stop_context) == JERRY_CONTEXT (vm_top_context_p))) { jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_BREAKPOINT_HIT); + if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_EXCEPTION_THROWN) + { + result = ECMA_VALUE_ERROR; + goto error; + } } #endif /* JERRY_DEBUGGER */ continue; } +#ifdef JERRY_ENABLE_LINE_INFO + case VM_OC_RESOURCE_NAME: + { + ecma_length_t formal_params_number = 0; + + if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_NON_STRICT_ARGUMENTS_NEEDED) + { + if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) + { + cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p; + + formal_params_number = args_p->argument_end; + } + else + { + cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p; + + formal_params_number = args_p->argument_end; + } + } + + uint8_t *byte_p = (uint8_t *) bytecode_header_p; + byte_p += ((size_t) bytecode_header_p->size) << JMEM_ALIGNMENT_LOG; + + ecma_value_t *resource_name_p = (ecma_value_t *) byte_p; + resource_name_p -= formal_params_number; + + frame_ctx_p->resource_name = resource_name_p[-1]; + continue; + } + case VM_OC_LINE: + { + uint32_t value = 0; + uint8_t byte; + + do + { + byte = *byte_code_p++; + value = (value << 7) | (byte & CBC_LOWER_SEVEN_BIT_MASK); + } + while (byte & CBC_HIGHEST_BIT_MASK); + + frame_ctx_p->current_line = value; + continue; + } +#endif /* JERRY_ENABLE_LINE_INFO */ default: { JERRY_UNREACHABLE (); @@ -2557,8 +2670,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } else { - ecma_string_t *var_name_str_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, - literal_start_p[literal_index]); + ecma_string_t *var_name_str_p = ecma_get_string_from_value (literal_start_p[literal_index]); + ecma_object_t *ref_base_lex_env_p = ecma_op_resolve_reference_base (frame_ctx_p->lex_env_p, var_name_str_p); @@ -2660,13 +2773,32 @@ error: stack_top_p = frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth; #ifdef JERRY_DEBUGGER + const uint32_t dont_stop = (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION + | JERRY_DEBUGGER_VM_IGNORE + | JERRY_DEBUGGER_VM_EXCEPTION_THROWN); + if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) && !(frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_DEBUGGER_IGNORE) - && !(JERRY_CONTEXT (debugger_flags) & (JERRY_DEBUGGER_VM_IGNORE_EXCEPTION | JERRY_DEBUGGER_VM_IGNORE))) + && !(JERRY_CONTEXT (debugger_flags) & dont_stop)) { + /* Save the error to a local value, because the engine enters breakpoint mode after, + therefore an evaluation error, or user-created error throw would overwrite it. */ + ecma_value_t current_error_value = JERRY_CONTEXT (error_value); + if (jerry_debugger_send_exception_string ()) { jerry_debugger_breakpoint_hit (JERRY_DEBUGGER_EXCEPTION_HIT); + + if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_EXCEPTION_THROWN) + { + ecma_free_value (current_error_value); + } + else + { + JERRY_CONTEXT (error_value) = current_error_value; + } + + JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN); } } #endif /* JERRY_DEBUGGER */ @@ -2684,10 +2816,6 @@ error: if (!ECMA_IS_VALUE_ERROR (result)) { - JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); - - stack_top_p = frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth; - if (vm_stack_find_finally (frame_ctx_p, &stack_top_p, VM_CONTEXT_FINALLY_RETURN, @@ -2701,7 +2829,7 @@ error: continue; } } - else + else if (JERRY_CONTEXT (status_flags) & ECMA_STATUS_EXCEPTION) { if (vm_stack_find_finally (frame_ctx_p, &stack_top_p, @@ -2710,29 +2838,28 @@ error: { JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); +#ifdef JERRY_DEBUGGER + JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN); +#endif /* JERRY_DEBUGGER */ + byte_code_p = frame_ctx_p->byte_code_p; if (VM_GET_CONTEXT_TYPE (stack_top_p[-1]) == VM_CONTEXT_CATCH) { - uint32_t literal_index; - ecma_object_t *catch_env_p; - ecma_string_t *catch_name_p; - *stack_top_p++ = JERRY_CONTEXT (error_value); JERRY_ASSERT (byte_code_p[0] == CBC_ASSIGN_SET_IDENT); - literal_index = byte_code_p[1]; + uint32_t literal_index = byte_code_p[1]; + if (literal_index >= encoding_limit) { literal_index = ((literal_index << 8) | byte_code_p[2]) - encoding_delta; } - catch_env_p = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p); - - catch_name_p = JMEM_CP_GET_NON_NULL_POINTER (ecma_string_t, - literal_start_p[literal_index]); + ecma_object_t *catch_env_p = ecma_create_decl_lex_env (frame_ctx_p->lex_env_p); + ecma_string_t *catch_name_p = ecma_get_string_from_value (literal_start_p[literal_index]); ecma_op_create_mutable_binding (catch_env_p, catch_name_p, false); stack_top_p[-2 - 1] = ecma_make_object_value (frame_ctx_p->lex_env_p); @@ -2744,40 +2871,19 @@ error: stack_top_p[-2] = JERRY_CONTEXT (error_value); } -#ifdef JERRY_VM_EXEC_STOP - if (JERRY_CONTEXT (vm_exec_stop_cb) != NULL - && --JERRY_CONTEXT (vm_exec_stop_counter) == 0) - { - result = JERRY_CONTEXT (vm_exec_stop_cb) (JERRY_CONTEXT (vm_exec_stop_user_p)); - - if (ecma_is_value_undefined (result)) - { - JERRY_CONTEXT (vm_exec_stop_counter) = JERRY_CONTEXT (vm_exec_stop_frequency); - } - else - { - JERRY_CONTEXT (vm_exec_stop_counter) = 1; - - left_value = ECMA_VALUE_UNDEFINED; - right_value = ECMA_VALUE_UNDEFINED; - - if (!ecma_is_value_error_reference (result)) - { - JERRY_CONTEXT (error_value) = result; - } - else - { - JERRY_CONTEXT (error_value) = ecma_clear_error_reference (result); - } - result = ECMA_VALUE_ERROR; - goto error; - } - } -#endif /* JERRY_VM_EXEC_STOP */ - continue; } } + else + { + do + { + JERRY_ASSERT (frame_ctx_p->registers_p + register_end + frame_ctx_p->context_depth == stack_top_p); + + stack_top_p = vm_stack_context_abort (frame_ctx_p, stack_top_p); + } + while (frame_ctx_p->context_depth > 0); + } ecma_free_value (block_result); return result; @@ -2841,7 +2947,7 @@ vm_execute (vm_frame_ctx_t *frame_ctx_p, /**< frame context */ } } - JERRY_CONTEXT (is_direct_eval_form_call) = false; + JERRY_CONTEXT (status_flags) &= (uint32_t) ~ECMA_STATUS_DIRECT_EVAL; JERRY_CONTEXT (vm_top_context_p) = frame_ctx_p; @@ -2899,29 +3005,29 @@ vm_run (const ecma_compiled_code_t *bytecode_header_p, /**< byte-code data heade const ecma_value_t *arg_list_p, /**< arguments list */ ecma_length_t arg_list_len) /**< length of arguments list */ { - jmem_cpointer_t *literal_p; + ecma_value_t *literal_p; vm_frame_ctx_t frame_ctx; uint32_t call_stack_size; if (bytecode_header_p->status_flags & CBC_CODE_FLAGS_UINT16_ARGUMENTS) { cbc_uint16_arguments_t *args_p = (cbc_uint16_arguments_t *) bytecode_header_p; - uint8_t *byte_p = (uint8_t *) bytecode_header_p; + call_stack_size = (uint32_t) (args_p->register_end + args_p->stack_limit); - literal_p = (jmem_cpointer_t *) (byte_p + sizeof (cbc_uint16_arguments_t)); + literal_p = (ecma_value_t *) ((uint8_t *) bytecode_header_p + sizeof (cbc_uint16_arguments_t)); + literal_p -= args_p->register_end; frame_ctx.literal_start_p = literal_p; literal_p += args_p->literal_end; - call_stack_size = (uint32_t) (args_p->register_end + args_p->stack_limit); } else { cbc_uint8_arguments_t *args_p = (cbc_uint8_arguments_t *) bytecode_header_p; - uint8_t *byte_p = (uint8_t *) bytecode_header_p; + call_stack_size = (uint32_t) (args_p->register_end + args_p->stack_limit); - literal_p = (jmem_cpointer_t *) (byte_p + sizeof (cbc_uint8_arguments_t)); + literal_p = (ecma_value_t *) ((uint8_t *) bytecode_header_p + sizeof (cbc_uint8_arguments_t)); + literal_p -= args_p->register_end; frame_ctx.literal_start_p = literal_p; literal_p += args_p->literal_end; - call_stack_size = (uint32_t) (args_p->register_end + args_p->stack_limit); } frame_ctx.bytecode_header_p = bytecode_header_p; @@ -2930,6 +3036,10 @@ vm_run (const ecma_compiled_code_t *bytecode_header_p, /**< byte-code data heade frame_ctx.lex_env_p = lex_env_p; frame_ctx.prev_context_p = JERRY_CONTEXT (vm_top_context_p); frame_ctx.this_binding = this_binding_value; +#ifdef JERRY_ENABLE_LINE_INFO + frame_ctx.resource_name = ECMA_VALUE_UNDEFINED; + frame_ctx.current_line = 0; +#endif /* JERRY_ENABLE_LINE_INFO */ frame_ctx.context_depth = 0; frame_ctx.is_eval_code = is_eval_code; frame_ctx.call_operation = VM_NO_EXEC_OP; @@ -2941,38 +3051,6 @@ vm_run (const ecma_compiled_code_t *bytecode_header_p, /**< byte-code data heade return vm_execute (&frame_ctx, arg_list_p, arg_list_len); } /* vm_run */ -/** - * Check whether currently executed code is strict mode code - * - * @return true - current code is executed in strict mode, - * false - otherwise - */ -bool -vm_is_strict_mode (void) -{ - JERRY_ASSERT (JERRY_CONTEXT (vm_top_context_p) != NULL); - - return JERRY_CONTEXT (vm_top_context_p)->bytecode_header_p->status_flags & CBC_CODE_FLAGS_STRICT_MODE; -} /* vm_is_strict_mode */ - -/** - * Check whether currently performed call (on top of call-stack) is performed in form, - * meeting conditions of 'Direct Call to Eval' (see also: ECMA-262 v5, 15.1.2.1.1) - * - * Warning: - * the function should only be called from implementation - * of built-in 'eval' routine of Global object - * - * @return true - currently performed call is performed through 'eval' identifier, - * without 'this' argument, - * false - otherwise - */ -inline bool __attr_always_inline___ -vm_is_direct_eval_form_call (void) -{ - return JERRY_CONTEXT (is_direct_eval_form_call); -} /* vm_is_direct_eval_form_call */ - /** * @} * @} diff --git a/deps/jerry/jerry-core/vm/vm.h b/deps/jerry/jerry-core/vm/vm.h index d243b8d..1aedee4 100644 --- a/deps/jerry/jerry-core/vm/vm.h +++ b/deps/jerry/jerry-core/vm/vm.h @@ -203,8 +203,10 @@ typedef enum VM_OC_FINALLY, /**< finally */ VM_OC_CONTEXT_END, /**< context end */ VM_OC_JUMP_AND_EXIT_CONTEXT, /**< jump and exit context */ - VM_OC_BREAKPOINT_ENABLED, /**< enabled breakpoint for debugger */ - VM_OC_BREAKPOINT_DISABLED, /**< disabled breakpoint for debugger */ + VM_OC_BREAKPOINT_ENABLED, /**< enabled breakpoint for debugger */ + VM_OC_BREAKPOINT_DISABLED, /**< disabled breakpoint for debugger */ + VM_OC_RESOURCE_NAME, /**< resource name of the current function */ + VM_OC_LINE, /**< line number of the next statement */ } vm_oc_types; /** @@ -286,6 +288,8 @@ ecma_value_t vm_run (const ecma_compiled_code_t *bytecode_header_p, ecma_value_t bool vm_is_strict_mode (void); bool vm_is_direct_eval_form_call (void); +ecma_value_t vm_get_backtrace (uint32_t max_depth); + /** * @} * @} diff --git a/deps/jerry/jerry-debugger/jerry-client-ws.html b/deps/jerry/jerry-debugger/jerry-client-ws.html index b2d7548..9cc3097 100644 --- a/deps/jerry/jerry-debugger/jerry-client-ws.html +++ b/deps/jerry/jerry-debugger/jerry-client-ws.html @@ -35,6 +35,9 @@ textarea {
+ + diff --git a/samples/http-gpio-panel/server.js b/samples/http-gpio-panel/server.js new file mode 100644 index 0000000..dc0f444 --- /dev/null +++ b/samples/http-gpio-panel/server.js @@ -0,0 +1,224 @@ +/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +/** + * Description: + * + * This sample allows to control GPIO input/output pins through browser + * + * Usage: + * + * To run this example execute: + * + * $ iotjs server.js + * + * and navigate your browser to http://[your-ip-address]:8080 + * + */ +var http = require('http'), + fs = require('fs'), + Buffer = require('buffer'), + gpio = require('gpio'), + server = null, + port = 8080, + logs_enabled = true, + pinConfiguration = {}, + activePins = {}, + GPIO_DIRECTION = { + '0': gpio.DIRECTION.IN, + '1': gpio.DIRECTION.OUT + }, + GPIO_MODE = { + '0': gpio.MODE.NONE, + '1': gpio.MODE.PULLUP, + '2': gpio.MODE.PULLDOWN, + '3': gpio.MODE.FLOAT, + '4': gpio.MODE.PUSHPULL, + '5': gpio.MODE.OPENDRAIN + }; + +// splits url by "/" deliminator and removes empty entries +function extractPath(url) { + var urlParts = url.split('/'), + i = 0, + l = urlParts.length, + result = []; + for (; i < l; ++i) { + if (urlParts[i].length > 0) { + result.push(urlParts[i]); + } + } + return result; +} + +// processes request data stream and passes it to callback +function fetchRequestTextBody(req, callback) { + var body = []; + req.on('data', function (chunk) { + body.push(chunk); + }); + req.on('end', function () { + callback(body.join("")); + }); +} + +// sets 404 header and body as response +function notFound(res) { + res.writeHead(404); + res.end('404 not found'); +} + +// logs only when log_enabled is set to true +function log(/*...arg*/) { + if (logs_enabled) { + console.log.apply(console, [].slice.call(arguments)); + } +} + +// reads file from specified path +function fetchFile(path) { + var data = null; + + log('trying to open: ' + path); + if (fs.existsSync(path)) { + data = fs.readFileSync(path); + } + return data; +} + +// synchronizes pin states with the data that was send with +// request from panel +function syncPins(pins) { + var pin = '', + updatedConf = {}, + updatedPins = {}, + value = 0; + + // update and add + for (pin in pins) { + if (pins.hasOwnProperty(pin)) { + if (activePins[pin] === undefined) { + // open pin if it does not exist + log('opening new pin: ' + pin); + activePins[pin] = gpio.open({ + pin: parseInt(pin, 10), + direction: GPIO_DIRECTION[pins[pin].direction], + mode: GPIO_MODE[pins[pin].mode] + }, function (err) { + if (err) { + log('error while opening pin: ' + pin); + } else { + log('pin opened: ' + pin); + if(parseInt(pins[pin].direction, 10) === 1) { + activePins[pin].writeSync(parseInt(pins[pin].value, 10)); + } + } + }); + } else if(parseInt(pins[pin].direction, 10) === 1 && + pins[pin].value !== pinConfiguration[pin].value) { + // update value if pin exists and is writable + log('pin: ' + pin + ', new value: ' + parseInt(pins[pin].value, 10)); + activePins[pin].writeSync(parseInt(pins[pin].value, 10)); + } + + // save old value if pin exists + if (pinConfiguration[pin] !== undefined) { + value = pinConfiguration[pin].value; + } + + // update + pinConfiguration[pin] = pins[pin]; + + // if pin is 'readable' then restore the value + if(parseInt(pins[pin].direction, 10) === 0) { + pinConfiguration[pin].value = value; + } + } + } + + // handle pin removal + for (pin in pinConfiguration) { + if (pinConfiguration.hasOwnProperty(pin)) { + if (pins[pin] !== undefined) { + updatedConf[pin] = pinConfiguration[pin]; + updatedPins[pin] = activePins[pin]; + } else if (activePins[pin]) { + log('closing pin: ' + pin); + activePins[pin].closeSync(); + } + } + } + + // update internal data + activePins = updatedPins; + pinConfiguration = updatedConf; +} + +function handleRequest(req, res) { + var path = extractPath(req.url); + switch (path[0]) { + case 'update': + fetchRequestTextBody(req, function (data) { + syncPins(JSON.parse(data)); + res.writeHead(200); + res.end(JSON.stringify(pinConfiguration)); + }); + break; + case undefined: + // front page + path[0] = 'index.html'; + case 'favicon.ico': + // serve favicon as most browsers always fetch this + log('serving static: ' + path[0]); + var fileData = fetchFile(process.cwd() + '/' + path[0]); + if (fileData) { + res.writeHead(200); + res.end(fileData); + } else { + notFound(res); + } + break; + default: + // return 404 for all other requests + notFound(res); + break; + } +} + +// handles input pin state changes +setInterval(function () { + var pin = '', + value = null; + for (pin in activePins) { + if (activePins.hasOwnProperty(pin) && + parseInt(pinConfiguration[pin].direction, 10) === 0) { // check pin is + // if input pin + value = activePins[pin].readSync() ? '1' : '0'; + if (pinConfiguration[pin].value !== value) { // check if value changed + log('pin: ' + pin + ' value changed to: ' + value); + pinConfiguration[pin].value = value; + } + } + } +}, 500); + +server = http.createServer(handleRequest); +server.listen(port, function (err) { + if (err) { + log('error while starting server: ' + err); + } else { + log('listening for connections on port: ' + port); + } +}); diff --git a/samples/uart-iotjs-console/console.js b/samples/uart-iotjs-console/console.js new file mode 100644 index 0000000..16798e4 --- /dev/null +++ b/samples/uart-iotjs-console/console.js @@ -0,0 +1,192 @@ +/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ +/** + * Description: + * + * This sample runs a simple REPL mode console on the device UART port + * + * Usage: + * + * To run this sample, connect a UART device (ex. FTDI USB-UART, RPI UART pins) + * to RX/TX pin on the artik board (0 and 1 pin on CON709). Please note that + * the serial device used in this example is different than normal USB port on + * the Artik053 development board, so you need two connections, one to run + * the code and second to connect to REPL console. After connecting please run: + * + * $ iotjs console.js + * + * You can now run simple JS code and the device will evaluate it and return + * the results + */ + +var uart = require('uart'), + uartConfig = { + device: '/dev/ttyS1', + baudRate: 115200, + dataBits: 8 + }, + buffer = [], + serialDevice = null, + log_enabled = true, + MSG_INFO = 0, + MSG_ERROR = 1, + EVALUATE_CODE_CHR = 18, // CTRL+R + uartResponseCodes = { // chars to send on specific input char codes + 8: '\b', + 13: '\r\n' + }, + fakeConsole = { // fake console to allow sending console messages to user + messages: [] + }; + +// on linux the device is different +if (process.platform === 'linux' || + (process.iotjs && process.iotjs.board === 'RP2')) { + uartConfig.device = '/dev/serial0'; +} + +// tries to 'stringify' objects (and errors) +function obj2str(obj) { + if (obj instanceof Error) { + return obj.name + ': ' + obj.message; + } + + return JSON.stringify(obj); +} + +// stringify and array of data (ex. arguments of functions) +function arr2str(arr) { + var strArr = [], + i = 0, + l = arr.length; + for (; i < l; ++i) { + switch (typeof arr[i]) { + case 'object': + strArr.push(obj2str(arr[i])); + break; + case 'function': + strArr.push('function'); + break; + default: + case 'string': + case 'number': + strArr.push(arr[i]); + break; + } + } + return strArr.join(''); +} + +fakeConsole.log = function (/*...args*/) { + var body = arr2str([].slice.call(arguments)); + log('LOG: ' + body); + this.messages.push(body); +}; + +fakeConsole.error = function (/*...args*/) { + var body = arr2str([].slice.call(arguments)); + log('ERROR: ' + body); + this.messages.push(body); +}; + +fakeConsole.toString = function () { + return this.messages.join('\r\n') + '\r\n'; +}; + +fakeConsole.clear = function () { + this.messages = []; +}; + +// logs only if log_enabled flag is set to true +function log(/*...args*/) { + if (log_enabled) { + console.log.apply(console, [].slice.call(arguments)); + } +} + +// faleConsole needs to be available to 'eval'ed scripts +global.fakeConsole = fakeConsole; + +// execude code with 'eval' +// this is done only for this sample, normally using eval is a no-no, +// please avoid if possible +function evalInContext(data) { + data = data.replace(/console\.(log|error)/g, 'fakeConsole.$1'); + eval(data); +} + +// handles code thats to be evaluated and sends response to uart device +function handleCode(code) { + log('evaluating: >>>\r\n ' + code + ' \r\n>>>EOT'); + try { + evalInContext(code); + } catch (err) { + fakeConsole.error(err); + } + + serialDevice.write(fakeConsole.toString(), function (err) { + if (err) { + log('error while sending console data: ' + err); + } else { + fakeConsole.clear(); + } + }); +} + +// handles data received from uart device +function handleData(data) { + var arr = data.split(''), + chrCode = 0, + chr = '', + i = 0, + l = data.length, + localBuff = buffer; + + for (;i < l; ++i) { + chr = arr[i]; + chrCode = chr.charCodeAt(0); + + if (chrCode === 8) { // handle backspace + localBuff.splice(localBuff.length - 1, 1); + serialDevice.writeSync('\b \b'); // move back, erase by space, move back + } else if ((chrCode > 31 && chrCode < 127) || chrCode === 13) { + // and only visible chars and new lines + localBuff.push(chr); + serialDevice.writeSync(uartResponseCodes[chrCode] || chr); + } + + if (chrCode === EVALUATE_CODE_CHR) { // evaluate code on EVALUATE_CODE_CHR + handleCode(localBuff.join('')); + localBuff = []; // clear buffer after code evaluation + } + } + + buffer = localBuff; +} + +process.on('uncaughtException', function (err) { + // code errors need to be cached and redirected to uart console + log('uncaught exception: ' + err); + fakeConsole.error(err); +}); + +serialDevice = uart.open(uartConfig, function (err) { + if (err) { + log('could not opend device: ' + uartConfig.device + ', reason: ' + err); + } else { + log('waiting for user input'); + serialDevice.on('data', handleData); + } +}); diff --git a/src/iotjs.c b/src/iotjs.c index 998bf47..ef2be53 100644 --- a/src/iotjs.c +++ b/src/iotjs.c @@ -31,10 +31,7 @@ #include -/** - * Initialize JerryScript. - */ -static bool iotjs_jerry_init(iotjs_environment_t* env) { +static bool jerry_initialize(iotjs_environment_t* env) { // Set jerry run flags. jerry_init_flag_t jerry_flags = JERRY_INIT_EMPTY; @@ -56,6 +53,12 @@ static bool iotjs_jerry_init(iotjs_environment_t* env) { if (iotjs_environment_config(env)->debugger != NULL) { jerry_debugger_init(iotjs_environment_config(env)->debugger->port); + + if (!jerry_debugger_is_connected()) { + DLOG("jerry_debugger_init() failed"); + return false; + } + jerry_debugger_continue(); } @@ -66,7 +69,8 @@ static bool iotjs_jerry_init(iotjs_environment_t* env) { jerry_set_vm_exec_stop_callback(vm_exec_stop_callback, &env->state, 2); // Do parse and run to generate initial javascript environment. - jerry_value_t parsed_code = jerry_parse((jerry_char_t*)"", 0, false); + jerry_value_t parsed_code = + jerry_parse(NULL, 0, (jerry_char_t*)"", 0, JERRY_PARSE_NO_OPTS); if (jerry_value_has_error_flag(parsed_code)) { DLOG("jerry_parse() failed"); jerry_release_value(parsed_code); @@ -87,15 +91,44 @@ static bool iotjs_jerry_init(iotjs_environment_t* env) { } -static void iotjs_run(iotjs_environment_t* env) { +bool iotjs_initialize(iotjs_environment_t* env) { + // Initialize JerryScript + if (!jerry_initialize(env)) { + DLOG("iotjs_jerry_init failed"); + return false; + } + + // Set event loop. + if (!uv_default_loop()) { + DLOG("iotjs uvloop init failed"); + return false; + } + iotjs_environment_set_loop(env, uv_default_loop()); + + // Bind environment to global object. + const jerry_value_t global = jerry_get_global_object(); + jerry_set_object_native_pointer(global, env, NULL); + + // Initialize builtin process module. + const jerry_value_t process = iotjs_module_get("process"); + iotjs_jval_set_property_jval(global, "process", process); + + // Release the global object + jerry_release_value(global); + + return true; +} + + +void iotjs_run(iotjs_environment_t* env) { // Evaluating 'iotjs.js' returns a function. #ifndef ENABLE_SNAPSHOT jerry_value_t jmain = iotjs_jhelper_eval("iotjs.js", strlen("iotjs.js"), iotjs_s, iotjs_l, false); #else jerry_value_t jmain = - jerry_exec_snapshot_at((const void*)iotjs_js_modules_s, - iotjs_js_modules_l, module_iotjs_idx, false); + jerry_exec_snapshot((const void*)iotjs_js_modules_s, iotjs_js_modules_l, + module_iotjs_idx, 0); #endif if (jerry_value_has_error_flag(jmain) && !iotjs_environment_is_exiting(env)) { @@ -109,17 +142,6 @@ static void iotjs_run(iotjs_environment_t* env) { static int iotjs_start(iotjs_environment_t* env) { - // Bind environment to global object. - const jerry_value_t global = jerry_get_global_object(); - jerry_set_object_native_pointer(global, env, NULL); - - // Initialize builtin process module. - const jerry_value_t process = iotjs_module_get("process"); - iotjs_jval_set_property_jval(global, "process", process); - - // Release the global object - jerry_release_value(global); - iotjs_environment_set_state(env, kRunningMain); // Load and call iotjs.js. @@ -157,9 +179,6 @@ static int iotjs_start(iotjs_environment_t* env) { exit_code = iotjs_process_exitcode(); - // Release builtin modules. - iotjs_module_list_cleanup(); - return exit_code; } @@ -171,6 +190,27 @@ static void iotjs_uv_walk_to_close_callback(uv_handle_t* handle, void* arg) { iotjs_handlewrap_close(handle_wrap, NULL); } + +void iotjs_end(iotjs_environment_t* env) { + uv_loop_t* loop = iotjs_environment_loop(env); + // Close uv loop. + uv_walk(loop, iotjs_uv_walk_to_close_callback, NULL); + uv_run(loop, UV_RUN_DEFAULT); + + int res = uv_loop_close(loop); + IOTJS_ASSERT(res == 0); +} + + +void iotjs_terminate(iotjs_environment_t* env) { + // Release builtin modules. + iotjs_module_list_cleanup(); + + // Release JerryScript engine. + jerry_cleanup(); +} + + void iotjs_conf_console_out(int (*out)(int lv, const char* fmt, ...)) { iotjs_set_console_out(out); } @@ -178,8 +218,7 @@ void iotjs_conf_console_out(int (*out)(int lv, const char* fmt, ...)) { int iotjs_entry(int argc, char** argv) { int ret_code = 0; - // Initialize IoT.js - + // Initialize debug log and environments iotjs_debuglog_init(); iotjs_environment_t* env = iotjs_environment_get(); @@ -187,45 +226,35 @@ int iotjs_entry(int argc, char** argv) { argv)) { DLOG("iotjs_environment_parse_command_line_arguments failed"); ret_code = 1; - goto terminate; + goto exit; } - if (!iotjs_jerry_init(env)) { - DLOG("iotjs_jerry_init failed"); + // Initialize IoT.js + if (!iotjs_initialize(env)) { + DLOG("iotjs_initialize failed"); ret_code = 1; goto terminate; } - // Set event loop. - iotjs_environment_set_loop(env, uv_default_loop()); - - // Start IoT.js. - + // Start IoT.js ret_code = iotjs_start(env); - // Close uv loop. - uv_walk(iotjs_environment_loop(env), iotjs_uv_walk_to_close_callback, NULL); - uv_run(iotjs_environment_loop(env), UV_RUN_DEFAULT); + // Ends IoT.js + iotjs_end(env); - int res = uv_loop_close(iotjs_environment_loop(env)); - IOTJS_ASSERT(res == 0); +terminate: + iotjs_terminate(env); +exit: + if (iotjs_environment_config(env)->debugger && + iotjs_environment_config(env)->debugger->context_reset) { + iotjs_environment_release(); + iotjs_debuglog_release(); - // Release JerryScript engine. - jerry_cleanup(); - -terminate:; - bool context_reset = false; - if (iotjs_environment_config(env)->debugger != NULL) { - context_reset = iotjs_environment_config(env)->debugger->context_reset; + return iotjs_entry(argc, argv); } - // Release environment. - iotjs_environment_release(); + iotjs_environment_release(); iotjs_debuglog_release(); - - if (context_reset) { - return iotjs_entry(argc, argv); - } return ret_code; } diff --git a/src/iotjs_binding.c b/src/iotjs_binding.c index 89751f6..625eb1c 100644 --- a/src/iotjs_binding.c +++ b/src/iotjs_binding.c @@ -21,11 +21,7 @@ #include -static iotjs_jargs_t jargs_empty = {.unsafe = { 0, 0, NULL }, -#ifndef NDEBUG - .flag_create = IOTJS_VALID_MAGIC_SEQUENCE -#endif /* !NDEBUG */ -}; +static iotjs_jargs_t jargs_empty; jerry_value_t iotjs_jval_create_string(const iotjs_string_t* v) { @@ -44,18 +40,6 @@ jerry_value_t iotjs_jval_create_string(const iotjs_string_t* v) { } -jerry_value_t iotjs_jval_get_string_size(const iotjs_string_t* str) { - jerry_value_t str_val = iotjs_jval_create_string(str); - - jerry_size_t size = jerry_get_string_size(str_val); - jerry_value_t jval = jerry_create_number(size); - - jerry_release_value(str_val); - - return jval; -} - - jerry_value_t iotjs_jval_create_byte_array(uint32_t len, const char* data) { IOTJS_ASSERT(data != NULL); @@ -265,62 +249,25 @@ jerry_value_t iotjs_jval_get_property_by_index(jerry_value_t jarr, } -#ifndef NDEBUG -static jerry_value_t iotjs_jargs_get(const iotjs_jargs_t* jargs, - uint16_t index) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jargs_t, jargs); - - IOTJS_ASSERT(index < _this->argc); - return _this->argv[index]; -} -#endif - - jerry_value_t iotjs_jhelper_call(jerry_value_t jfunc, jerry_value_t jthis, const iotjs_jargs_t* jargs) { IOTJS_ASSERT(jerry_value_is_object(jfunc)); - jerry_value_t* jargv_ = NULL; jerry_length_t jargc_ = iotjs_jargs_length(jargs); -#ifdef NDEBUG - jargv_ = (jerry_value_t*)jargs->unsafe.argv; -#else - if (jargc_ > 0) { - unsigned buffer_size = sizeof(jerry_value_t) * jargc_; - jargv_ = (jerry_value_t*)iotjs_buffer_allocate(buffer_size); - for (unsigned i = 0; i < jargc_; ++i) { - jargv_[i] = iotjs_jargs_get(jargs, i); - } - } -#endif - - jerry_value_t jres = jerry_call_function(jfunc, jthis, jargv_, jargc_); - -#ifndef NDEBUG - if (jargv_) { - iotjs_buffer_release((char*)jargv_); - } -#endif + jerry_value_t jres = jerry_call_function(jfunc, jthis, jargs->argv, jargc_); return jres; } -jerry_value_t iotjs_jhelper_call_ok(jerry_value_t jfunc, jerry_value_t jthis, - const iotjs_jargs_t* jargs) { - jerry_value_t jres = iotjs_jhelper_call(jfunc, jthis, jargs); - IOTJS_ASSERT(!jerry_value_has_error_flag(jres)); - return jres; -} - - jerry_value_t iotjs_jhelper_eval(const char* name, size_t name_len, const uint8_t* data, size_t size, bool strict_mode) { - jerry_value_t jres = - jerry_parse_named_resource((const jerry_char_t*)name, name_len, - (const jerry_char_t*)data, size, strict_mode); + uint32_t opts = strict_mode ? JERRY_PARSE_STRICT_MODE : JERRY_PARSE_NO_OPTS; + + jerry_value_t jres = jerry_parse((const jerry_char_t*)name, name_len, + (const jerry_char_t*)data, size, opts); if (!jerry_value_has_error_flag(jres)) { jerry_value_t func = jres; @@ -349,12 +296,11 @@ iotjs_jargs_t iotjs_jargs_create(uint16_t capacity) { } iotjs_jargs_t jargs; - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_jargs_t, &jargs); - _this->capacity = capacity; - _this->argc = 0; + jargs.capacity = capacity; + jargs.argc = 0; unsigned buffer_size = sizeof(jerry_value_t) * capacity; - _this->argv = (jerry_value_t*)iotjs_buffer_allocate(buffer_size); + jargs.argv = (jerry_value_t*)iotjs_buffer_allocate(buffer_size); return jargs; } @@ -366,55 +312,49 @@ const iotjs_jargs_t* iotjs_jargs_get_empty() { void iotjs_jargs_destroy(iotjs_jargs_t* jargs) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_jargs_t, jargs); + IOTJS_ASSERT(jargs && jargs->argc <= jargs->capacity); - IOTJS_ASSERT(_this->argv == NULL || _this->argc > 0); - IOTJS_ASSERT(_this->argc <= _this->capacity); - - if (_this->capacity > 0) { - for (unsigned i = 0; i < _this->argc; ++i) { - jerry_release_value(_this->argv[i]); + if (jargs->capacity > 0) { + IOTJS_ASSERT(jargs->argv); + for (unsigned i = 0; i < jargs->argc; ++i) { + jerry_release_value(jargs->argv[i]); } - iotjs_buffer_release((char*)_this->argv); + IOTJS_RELEASE(jargs->argv); } else { - IOTJS_ASSERT(_this->argv == NULL); + IOTJS_ASSERT(jargs->argv == NULL); } } uint16_t iotjs_jargs_length(const iotjs_jargs_t* jargs) { - const IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jargs_t, jargs); - return _this->argc; + IOTJS_ASSERT(jargs); + return jargs->argc; } void iotjs_jargs_append_jval(iotjs_jargs_t* jargs, jerry_value_t x) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jargs_t, jargs); - IOTJS_ASSERT(_this->argc < _this->capacity); - _this->argv[_this->argc++] = jerry_acquire_value(x); + IOTJS_ASSERT(jargs && jargs->argc < jargs->capacity); + IOTJS_ASSERT(jargs->argv); + jargs->argv[jargs->argc++] = jerry_acquire_value(x); } void iotjs_jargs_append_undefined(iotjs_jargs_t* jargs) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jargs_t, jargs); iotjs_jargs_append_jval(jargs, jerry_create_undefined()); } void iotjs_jargs_append_null(iotjs_jargs_t* jargs) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jargs_t, jargs); iotjs_jargs_append_jval(jargs, jerry_create_null()); } void iotjs_jargs_append_bool(iotjs_jargs_t* jargs, bool x) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jargs_t, jargs); iotjs_jargs_append_jval(jargs, jerry_create_boolean(x)); } void iotjs_jargs_append_number(iotjs_jargs_t* jargs, double x) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jargs_t, jargs); jerry_value_t jval = jerry_create_number(x); iotjs_jargs_append_jval(jargs, jval); jerry_release_value(jval); @@ -422,7 +362,6 @@ void iotjs_jargs_append_number(iotjs_jargs_t* jargs, double x) { void iotjs_jargs_append_string(iotjs_jargs_t* jargs, const iotjs_string_t* x) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jargs_t, jargs); jerry_value_t jval = iotjs_jval_create_string(x); iotjs_jargs_append_jval(jargs, jval); jerry_release_value(jval); @@ -430,7 +369,6 @@ void iotjs_jargs_append_string(iotjs_jargs_t* jargs, const iotjs_string_t* x) { void iotjs_jargs_append_error(iotjs_jargs_t* jargs, const char* msg) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jargs_t, jargs); jerry_value_t error = iotjs_jval_create_error_without_error_flag(msg); iotjs_jargs_append_jval(jargs, error); jerry_release_value(error); @@ -438,7 +376,6 @@ void iotjs_jargs_append_error(iotjs_jargs_t* jargs, const char* msg) { void iotjs_jargs_append_string_raw(iotjs_jargs_t* jargs, const char* x) { - IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_jargs_t, jargs); jerry_value_t jval = jerry_create_string((const jerry_char_t*)x); iotjs_jargs_append_jval(jargs, jval); jerry_release_value(jval); @@ -447,10 +384,9 @@ void iotjs_jargs_append_string_raw(iotjs_jargs_t* jargs, const char* x) { void iotjs_jargs_replace(iotjs_jargs_t* jargs, uint16_t index, jerry_value_t x) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_jargs_t, jargs); - - IOTJS_ASSERT(index < _this->argc); + IOTJS_ASSERT(jargs && index < jargs->argc); + IOTJS_ASSERT(jargs->argv); - jerry_release_value(_this->argv[index]); - _this->argv[index] = jerry_acquire_value(x); + jerry_release_value(jargs->argv[index]); + jargs->argv[index] = jerry_acquire_value(x); } diff --git a/src/iotjs_binding.h b/src/iotjs_binding.h index 586c4ef..1ee2d80 100644 --- a/src/iotjs_binding.h +++ b/src/iotjs_binding.h @@ -16,6 +16,9 @@ #ifndef IOTJS_BINDING_H #define IOTJS_BINDING_H +#include +#include + #include "iotjs_util.h" #include "jerryscript.h" @@ -30,9 +33,6 @@ jerry_value_t iotjs_jval_create_byte_array(uint32_t len, const char* data); jerry_value_t iotjs_jval_create_function(jerry_external_handler_t handler); jerry_value_t iotjs_jval_create_error_without_error_flag(const char* msg); -jerry_value_t iotjs_jval_get_string_size(const iotjs_string_t* str); - - /* Type Converters */ bool iotjs_jval_as_boolean(jerry_value_t); double iotjs_jval_as_number(jerry_value_t); @@ -72,7 +72,7 @@ typedef struct { uint16_t capacity; uint16_t argc; jerry_value_t* argv; -} IOTJS_VALIDATED_STRUCT(iotjs_jargs_t); +} iotjs_jargs_t; iotjs_jargs_t iotjs_jargs_create(uint16_t capacity); @@ -99,59 +99,58 @@ void iotjs_jargs_replace(iotjs_jargs_t* jargs, uint16_t index, jerry_value_t x); jerry_value_t iotjs_jhelper_call(jerry_value_t jfunc, jerry_value_t jthis, const iotjs_jargs_t* jargs); -// Calls javascript function. -jerry_value_t iotjs_jhelper_call_ok(jerry_value_t jfunc, jerry_value_t jthis, - const iotjs_jargs_t* jargs); - // Evaluates javascript source file. jerry_value_t iotjs_jhelper_eval(const char* name, size_t name_len, const uint8_t* data, size_t size, bool strict_mode); +/* Note: + * Defines started with underscores should not be used + * outside of this header. + */ #define JS_CREATE_ERROR(TYPE, message) \ - jerry_create_error(JERRY_ERROR_##TYPE, (const jerry_char_t*)message); + jerry_create_error(JERRY_ERROR_##TYPE, (const jerry_char_t*)message) #define JS_CHECK(predicate) \ if (!(predicate)) { \ return JS_CREATE_ERROR(COMMON, "Internal error"); \ } -#define JS_CHECK_TYPE(jval, type) JS_CHECK(jerry_value_is_##type(jval)); +#define __JS_CHECK_TYPE(index, type) jerry_value_is_##type(jargv[index]) -#define JS_CHECK_ARG(index, type) JS_CHECK_TYPE(jargv[index], type); +#define JS_CHECK_ARG(index, type) JS_CHECK(__JS_CHECK_TYPE(index, type)) #define JS_CHECK_ARG_IF_EXIST(index, type) \ if (jargc > index) { \ - JS_CHECK_TYPE(jargv[index], type); \ + JS_CHECK(__JS_CHECK_TYPE(index, type)) \ } #define JS_CHECK_ARGS_0() #define JS_CHECK_ARGS_1(type0) \ - JS_CHECK_ARGS_0(); \ - JS_CHECK_ARG(0, type0); + JS_CHECK_ARGS_0() \ + __JS_CHECK_TYPE(0, type0) #define JS_CHECK_ARGS_2(type0, type1) \ - JS_CHECK_ARGS_1(type0); \ - JS_CHECK_ARG(1, type1); + JS_CHECK_ARGS_1(type0) \ + &&__JS_CHECK_TYPE(1, type1) #define JS_CHECK_ARGS_3(type0, type1, type2) \ - JS_CHECK_ARGS_2(type0, type1); \ - JS_CHECK_ARG(2, type2); + JS_CHECK_ARGS_2(type0, type1) \ + &&__JS_CHECK_TYPE(2, type2) #define JS_CHECK_ARGS_4(type0, type1, type2, type3) \ - JS_CHECK_ARGS_3(type0, type1, type2); \ - JS_CHECK_ARG(3, type3); + JS_CHECK_ARGS_3(type0, type1, type2) \ + &&__JS_CHECK_TYPE(3, type3) #define JS_CHECK_ARGS_5(type0, type1, type2, type3, type4) \ - JS_CHECK_ARGS_4(type0, type1, type2, type3); \ - JS_CHECK_ARG(4, type4); + JS_CHECK_ARGS_4(type0, type1, type2, type3) \ + &&__JS_CHECK_TYPE(4, type4) #define JS_CHECK_ARGS(argc, ...) \ - JS_CHECK(jargc >= argc); \ - JS_CHECK_ARGS_##argc(__VA_ARGS__) + JS_CHECK(jargc >= argc && JS_CHECK_ARGS_##argc(__VA_ARGS__)) -#define JS_CHECK_THIS() JS_CHECK_TYPE(jthis, object); +#define JS_CHECK_THIS() JS_CHECK(jerry_value_is_object(jthis)) #define JS_GET_ARG(index, type) iotjs_jval_as_##type(jargv[index]) @@ -168,7 +167,6 @@ jerry_value_t iotjs_jhelper_eval(const char* name, size_t name_len, const jerry_value_t jargv[], \ const jerry_length_t jargc) - #if defined(EXPERIMENTAL) && !defined(DEBUG) // This code branch is to be in #ifdef NDEBUG #define DJS_CHECK_ARG(index, type) ((void)0) @@ -182,53 +180,67 @@ jerry_value_t iotjs_jhelper_eval(const char* name, size_t name_len, #define DJS_CHECK_ARG_IF_EXIST(index, type) JS_CHECK_ARG_IF_EXIST(index, type) #endif -#define JS_DECLARE_THIS_PTR(type, name) \ +#define __JS_DECLARE_PTR(type, name, value) \ iotjs_##type##_t* name; \ do { \ JNativeInfoType* out_native_info; \ - jerry_get_object_native_pointer(jthis, (void**)&name, &out_native_info); \ + jerry_get_object_native_pointer(value, (void**)&name, &out_native_info); \ if (!name || out_native_info != &this_module_native_info) { \ return JS_CREATE_ERROR(COMMON, ""); \ } \ } while (0) -#define JS_DECLARE_OBJECT_PTR(index, type, name) \ - iotjs_##type##_t* name; \ - do { \ - JNativeInfoType* out_native_info; \ - jerry_get_object_native_pointer(jargv[index], (void**)&name, \ - &out_native_info); \ - if (!name || out_native_info != &this_module_native_info) { \ - return JS_CREATE_ERROR(COMMON, ""); \ - } \ - } while (0) +#define JS_DECLARE_THIS_PTR(type, name) __JS_DECLARE_PTR(type, name, jthis) + +#define JS_DECLARE_OBJECT_PTR(index, type, name) \ + __JS_DECLARE_PTR(type, name, jargv[index]) -#define JS_GET_REQUIRED_ARG_VALUE(index, target, property, type) \ +#define __JS_GET_REQUIRED_VALUE(target, property, type, value) \ do { \ - if (jerry_value_is_undefined(jargv[index])) { \ + if (jerry_value_is_undefined(value)) { \ return JS_CREATE_ERROR(TYPE, "Missing argument, required " property); \ - } else if (jerry_value_is_##type(jargv[index])) { \ - target = iotjs_jval_as_##type(jargv[index]); \ + } else if (jerry_value_is_##type(value)) { \ + target = iotjs_jval_as_##type(value); \ } else { \ return JS_CREATE_ERROR(TYPE, "Bad arguments, required " property \ " is not a " #type); \ } \ } while (0) -#define DJS_GET_REQUIRED_CONF_VALUE(src, target, property, type) \ - do { \ - jerry_value_t jtmp = iotjs_jval_get_property(src, property); \ - if (jerry_value_is_undefined(jtmp)) { \ - return JS_CREATE_ERROR(TYPE, "Missing argument, required " property); \ - } else if (jerry_value_is_##type(jtmp)) { \ - target = iotjs_jval_as_##type(jtmp); \ - } else { \ - return JS_CREATE_ERROR(TYPE, "Bad arguments, required " property \ - " is not a " #type); \ - } \ - jerry_release_value(jtmp); \ +#define JS_GET_REQUIRED_ARG_VALUE(index, target, property, type) \ + __JS_GET_REQUIRED_VALUE(target, property, type, jargv[index]) + +#define JS_GET_REQUIRED_CONF_VALUE(src, target, property, type) \ + do { \ + jerry_value_t jtmp = iotjs_jval_get_property(src, property); \ + __JS_GET_REQUIRED_VALUE(target, property, type, jtmp); \ + jerry_release_value(jtmp); \ } while (0) jerry_value_t vm_exec_stop_callback(void* user_p); +/** + * Dynamic module defintions (.iotjs) + */ +#define IOTJS_CURRENT_MODULE_VERSION ((uint32_t)1) + +typedef jerry_value_t (*ModuleInitializer)(void); + +typedef struct { + uint32_t iotjs_module_version; + uint32_t module_version; + ModuleInitializer initializer; +} iotjs_module; + +typedef iotjs_module* (*iotjs_module_info_getter)(void); + +#define IOTJS_MODULE_ENTRYPOINT iotjs_module_info +#define IOTJS_MODULE(IOTJS_VERSION, MODULE_VERSION, NAME) \ + static const iotjs_module __module = { \ + IOTJS_VERSION, MODULE_VERSION, init_##NAME, \ + }; \ + const iotjs_module* IOTJS_MODULE_ENTRYPOINT(void) { \ + return &__module; \ + } + #endif /* IOTJS_BINDING_H */ diff --git a/src/iotjs_binding_helper.c b/src/iotjs_binding_helper.c index 221df76..3c6caf5 100644 --- a/src/iotjs_binding_helper.c +++ b/src/iotjs_binding_helper.c @@ -53,21 +53,22 @@ void iotjs_process_emit_exit(int code) { jerry_value_t jexit = iotjs_jval_get_property(process, IOTJS_MAGIC_STRING_EMITEXIT); - IOTJS_ASSERT(jerry_value_is_function(jexit)); - iotjs_jargs_t jargs = iotjs_jargs_create(1); - iotjs_jargs_append_number(&jargs, code); + if (jerry_value_is_function(jexit)) { + iotjs_jargs_t jargs = iotjs_jargs_create(1); + iotjs_jargs_append_number(&jargs, code); - jerry_value_t jres = iotjs_jhelper_call(jexit, process, &jargs); + jerry_value_t jres = iotjs_jhelper_call(jexit, process, &jargs); - iotjs_jargs_destroy(&jargs); - jerry_release_value(jexit); + if (jerry_value_has_error_flag(jres)) { + iotjs_set_process_exitcode(2); + } - if (jerry_value_has_error_flag(jres)) { - iotjs_set_process_exitcode(2); + iotjs_jargs_destroy(&jargs); + jerry_release_value(jres); } - jerry_release_value(jres); + jerry_release_value(jexit); } @@ -86,12 +87,15 @@ bool iotjs_process_next_tick() { IOTJS_ASSERT(jerry_value_is_function(jon_next_tick)); jerry_value_t jres = - iotjs_jhelper_call_ok(jon_next_tick, jerry_create_undefined(), - iotjs_jargs_get_empty()); + iotjs_jhelper_call(jon_next_tick, jerry_create_undefined(), + iotjs_jargs_get_empty()); - IOTJS_ASSERT(jerry_value_is_boolean(jres)); + bool ret = false; + + if (!jerry_value_has_error_flag(jres)) { + ret = iotjs_jval_as_boolean(jres); + } - bool ret = iotjs_jval_as_boolean(jres); jerry_release_value(jres); jerry_release_value(jon_next_tick); @@ -113,6 +117,10 @@ void iotjs_make_callback(jerry_value_t jfunction, jerry_value_t jthis, jerry_value_t iotjs_make_callback_with_result(jerry_value_t jfunction, jerry_value_t jthis, const iotjs_jargs_t* jargs) { + // If the environment is already exiting just return an undefined value. + if (iotjs_environment_is_exiting(iotjs_environment_get())) { + return jerry_create_undefined(); + } // Calls back the function. jerry_value_t jres = iotjs_jhelper_call(jfunction, jthis, jargs); if (jerry_value_has_error_flag(jres)) { @@ -134,12 +142,17 @@ int iotjs_process_exitcode() { jerry_value_t jexitcode = iotjs_jval_get_property(process, IOTJS_MAGIC_STRING_EXITCODE); - IOTJS_ASSERT(jerry_value_is_number(jexitcode)); - - const int exitcode = (int)iotjs_jval_as_number(jexitcode); + uint8_t exitcode = 0; + jerry_value_t num_val = jerry_value_to_number(jexitcode); + if (jerry_value_has_error_flag(num_val)) { + exitcode = 1; + jerry_value_clear_error_flag(&num_val); + } else { + exitcode = (uint8_t)iotjs_jval_as_number(num_val); + } + jerry_release_value(num_val); jerry_release_value(jexitcode); - - return exitcode; + return (int)exitcode; } diff --git a/src/iotjs_debuglog.c b/src/iotjs_debuglog.c index e88f0c7..adbf68c 100644 --- a/src/iotjs_debuglog.c +++ b/src/iotjs_debuglog.c @@ -26,7 +26,7 @@ void iotjs_set_console_out(iotjs_console_out_t output) { #ifdef ENABLE_DEBUG_LOG int iotjs_debug_level = DBGLEV_ERR; -FILE* iotjs_log_stream; +FILE* iotjs_log_stream = NULL; const char* iotjs_debug_prefix[4] = { "", "ERR", "WRN", "INF" }; #endif // ENABLE_DEBUG_LOG @@ -61,7 +61,8 @@ void iotjs_debuglog_init() { void iotjs_debuglog_release() { #ifdef ENABLE_DEBUG_LOG - if (iotjs_log_stream != stderr && iotjs_log_stream != stdout) { + if (iotjs_log_stream && iotjs_log_stream != stderr && + iotjs_log_stream != stdout) { fclose(iotjs_log_stream); } // some embed systems(ex, nuttx) may need this diff --git a/src/iotjs_debuglog.h b/src/iotjs_debuglog.h index 8629bcc..699790c 100644 --- a/src/iotjs_debuglog.h +++ b/src/iotjs_debuglog.h @@ -26,24 +26,37 @@ extern void iotjs_set_console_out(iotjs_console_out_t output); #ifdef ENABLE_DEBUG_LOG -#include extern int iotjs_debug_level; extern FILE* iotjs_log_stream; extern const char* iotjs_debug_prefix[4]; -#define IOTJS_DLOG(lvl, ...) \ - do { \ - if (0 <= lvl && lvl <= iotjs_debug_level && iotjs_log_stream) { \ - if (iotjs_console_out) { \ - iotjs_console_out(lvl, __VA_ARGS__); \ - } else { \ - fprintf(iotjs_log_stream, "[%s] ", iotjs_debug_prefix[lvl]); \ - fprintf(iotjs_log_stream, __VA_ARGS__); \ - fprintf(iotjs_log_stream, "\n"); \ - fflush(iotjs_log_stream); \ - } \ - } \ +#if defined(__TIZEN__) +#include +#define DLOG_TAG "IOTJS" +#define DLOG_PRINT(lvl, ...) \ + dlog_print((lvl == DBGLEV_ERR \ + ? DLOG_ERROR \ + : (lvl == DBGLEV_WARN ? DLOG_WARN : DLOG_INFO)), \ + DLOG_TAG, __VA_ARGS__); +#else +#include +#define DLOG_PRINT(lvl, ...) \ + fprintf(iotjs_log_stream, "[%s] ", iotjs_debug_prefix[lvl]); \ + fprintf(iotjs_log_stream, __VA_ARGS__); \ + fprintf(iotjs_log_stream, "\n"); \ + fflush(iotjs_log_stream); +#endif /* defined(__TIZEN__) */ + +#define IOTJS_DLOG(lvl, ...) \ + do { \ + if (0 <= lvl && lvl <= iotjs_debug_level && iotjs_log_stream) { \ + if (iotjs_console_out) { \ + iotjs_console_out(lvl, __VA_ARGS__); \ + } else { \ + DLOG_PRINT(lvl, __VA_ARGS__) \ + } \ + } \ } while (0) #define DLOG(...) IOTJS_DLOG(DBGLEV_ERR, __VA_ARGS__) #define DDLOG(...) IOTJS_DLOG(DBGLEV_WARN, __VA_ARGS__) diff --git a/src/iotjs_def.h b/src/iotjs_def.h index 9ae15a1..fb35ca6 100644 --- a/src/iotjs_def.h +++ b/src/iotjs_def.h @@ -22,17 +22,17 @@ #if defined(__NUTTX__) || defined(__TIZENRT__) #define IOTJS_MAX_READ_BUFFER_SIZE 1023 #define IOTJS_MAX_PATH_SIZE 120 -#else +#else /* !__NUTTX__ && !__TIZENRT__ */ #define IOTJS_MAX_READ_BUFFER_SIZE 65535 #define IOTJS_MAX_PATH_SIZE PATH_MAX -#endif -#endif +#endif /* __NUTTX__ || TIZENRT */ +#endif /* IOTJS_MAX_READ_BUFFER_SIZE */ #ifndef IOTJS_ASSERT #ifdef NDEBUG #define IOTJS_ASSERT(x) ((void)(x)) -#else +#else /* !NDEBUG */ extern void print_stacktrace(); extern void force_terminate(); #define IOTJS_ASSERT(x) \ @@ -44,8 +44,8 @@ extern void force_terminate(); force_terminate(); \ } \ } while (0) -#endif -#endif +#endif /* NDEBUG */ +#endif /* IOTJS_ASSERT */ #if defined(__arm__) #define TARGET_ARCH "arm" @@ -53,44 +53,40 @@ extern void force_terminate(); #define TARGET_ARCH "ia32" #elif defined(__x86_64__) #define TARGET_ARCH "x64" -#else +#else /* !__arm__ && !__i686__ && !__x86_64__ */ #define TARGET_ARCH "unknown" -#endif +#endif /* __arm__ */ #if defined(__linux__) +#if defined(__TIZEN__) +#define TARGET_OS "tizen" +#else #define TARGET_OS "linux" +#endif /* __TIZEN__ */ #elif defined(__NUTTX__) #define TARGET_OS "nuttx" #elif defined(__APPLE__) #define TARGET_OS "darwin" #elif defined(__TIZENRT__) #define TARGET_OS "tizenrt" -#else +#else /* !__linux__ && !__NUTTX__ !__APPLE__ && !__TIZENRT__*/ #define TARGET_OS "unknown" -#endif +#endif /* __linux__ */ #define IOTJS_VERSION "1.0.0" #if !defined(STRINGIFY) #define STRINGIFY(x) #x -#endif +#endif /* STRINGIFY */ #if !defined(TOSTRING) #define TOSTRING(x) STRINGIFY(x) -#endif - +#endif /* TOSTRING */ #if !defined(TARGET_BOARD) #define TARGET_BOARD "unknown" -#endif - - -#define IOTJS_VALID_MAGIC_SEQUENCE 0xfee1c001 /* feel cool */ -#define IOTJS_INVALID_MAGIC_SEQUENCE 0xfee1badd /* feel bad */ - -#define IOTJS_DECLARE_THIS(iotjs_classname_t, x) \ - iotjs_classname_t##_impl_t* _this = &(x)->unsafe; +#endif /* TARGET_BOARD */ /* Avoid compiler warnings if needed. */ #define IOTJS_UNUSED(x) ((void)(x)) @@ -101,71 +97,6 @@ extern void force_terminate(); .free_cb = (jerry_object_native_free_callback_t)iotjs_##name##_destroy \ } -#ifdef NDEBUG - -#define IOTJS_VALIDATED_STRUCT(iotjs_classname_t) \ - iotjs_classname_t##_impl_t; \ - typedef struct iotjs_classname_t { \ - iotjs_classname_t##_impl_t unsafe; \ - } iotjs_classname_t; - -#define IOTJS_VALIDATED_STRUCT_STATIC_INITIALIZER(...) __VA_ARGS__ - -#define IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_classname_t, x) \ - IOTJS_DECLARE_THIS(iotjs_classname_t, x); -#define IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_classname_t, x) \ - IOTJS_DECLARE_THIS(iotjs_classname_t, x); -#define IOTJS_VALIDATED_STRUCT_METHOD(iotjs_classname_t, x) \ - IOTJS_DECLARE_THIS(iotjs_classname_t, x); - -#define IOTJS_VALIDATABLE_STRUCT_DESTRUCTOR_VALIDATE(iotjs_classname_t, x) -#define IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_classname_t, x) - -#else /* !NDEBUG */ - -#define IOTJS_VALIDATED_STRUCT(iotjs_classname_t) \ - iotjs_classname_t##_impl_t; \ - typedef struct iotjs_classname_t { \ - iotjs_classname_t##_impl_t unsafe; \ - uint32_t flag_create; \ - char* valgrind_tracer; \ - } iotjs_classname_t; - -#define IOTJS_VALIDATED_STRUCT_STATIC_INITIALIZER(...) \ - { IOTJS_VALID_MAGIC_SEQUENCE, iotjs_buffer_allocate(4), __VA_ARGS__ } - -#define IOTJS_VALIDATE_FLAG(iotjs_classname_t, x) \ - if ((x)->flag_create != IOTJS_VALID_MAGIC_SEQUENCE) { \ - DLOG("`%s %s` is not initialized properly.", #iotjs_classname_t, #x); \ - IOTJS_ASSERT(false); \ - } - -#define IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_classname_t, x) \ - IOTJS_DECLARE_THIS(iotjs_classname_t, x); \ - /* IOTJS_ASSERT((x)->flag_create != IOTJS_VALID_MAGIC_SEQUENCE); */ \ - (x)->flag_create = IOTJS_VALID_MAGIC_SEQUENCE; \ - (x)->valgrind_tracer = iotjs_buffer_allocate(4); - -#define IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_classname_t, x) \ - IOTJS_DECLARE_THIS(iotjs_classname_t, x); \ - IOTJS_VALIDATE_FLAG(iotjs_classname_t, x); \ - (x)->flag_create = IOTJS_INVALID_MAGIC_SEQUENCE; \ - iotjs_buffer_release((x)->valgrind_tracer); - -#define IOTJS_VALIDATED_STRUCT_METHOD(iotjs_classname_t, x) \ - IOTJS_DECLARE_THIS(iotjs_classname_t, x); \ - IOTJS_VALIDATE_FLAG(iotjs_classname_t, x); - -#define IOTJS_VALIDATABLE_STRUCT_DESTRUCTOR_VALIDATE(iotjs_classname_t, x) \ - IOTJS_VALIDATE_FLAG(iotjs_classname_t, x); \ - (x)->flag_create = IOTJS_INVALID_MAGIC_SEQUENCE; \ - iotjs_buffer_release((x)->valgrind_tracer); - -#define IOTJS_VALIDATABLE_STRUCT_METHOD_VALIDATE(iotjs_classname_t, x) \ - IOTJS_VALIDATE_FLAG(iotjs_classname_t, x); - -#endif /* NDEBUG */ - #include #include #include /* PATH_MAX */ diff --git a/src/iotjs_env.c b/src/iotjs_env.c index dd4280c..e15dea4 100644 --- a/src/iotjs_env.c +++ b/src/iotjs_env.c @@ -17,8 +17,29 @@ #include "iotjs_def.h" #include "iotjs_env.h" +#include #include +typedef enum { + OPT_HELP, + OPT_MEM_STATS, + OPT_SHOW_OP, + OPT_DEBUG_SERVER, + OPT_DEBUGGER_WAIT_SOURCE, + OPT_DEBUG_PORT, + NUM_OF_OPTIONS +} cli_option_id_t; + +typedef struct { + const cli_option_id_t id; + const char* opt; + const char* longopt; + const char* help; + const uint32_t more; // The number of options coming with the given option +} cli_option_t; + +#define CLI_DEFAULT_HELP_STRING \ + "Usage: iotjs [options] {FILE | FILE.js} [arguments]\n" static iotjs_environment_t current_env; static bool initialized = false; @@ -45,10 +66,8 @@ void iotjs_environment_release() { return; iotjs_environment_t* env = iotjs_environment_get(); - if (env->config.debugger) - iotjs_buffer_release((char*)(env->config.debugger)); - if (env->argv) - iotjs_buffer_release((char*)env->argv); + IOTJS_RELEASE(env->config.debugger); + IOTJS_RELEASE(env->argv); initialized = false; } @@ -70,34 +89,109 @@ static void initialize(iotjs_environment_t* env) { bool iotjs_environment_parse_command_line_arguments(iotjs_environment_t* env, uint32_t argc, char** argv) { - // Parse IoT.js command line arguments. + // declare options + const cli_option_t opts[] = { + { + .id = OPT_HELP, + .opt = "h", + .longopt = "help", + .help = "print this help and exit", + }, + { + .id = OPT_MEM_STATS, + .longopt = "mem-stats", + .help = "dump memory statistics", + }, + { + .id = OPT_SHOW_OP, + .longopt = "show-opcodes", + .help = "dump parser byte-code", + }, + { + .id = OPT_DEBUG_SERVER, + .opt = "d", + .longopt = "start-debug-server", + .help = "start debug server and wait for a connecting client", + }, + { + .id = OPT_DEBUGGER_WAIT_SOURCE, + .opt = "w", + .longopt = "debugger-wait-source", + .help = "wait for an executable source from the client", + }, + { + .id = OPT_DEBUG_PORT, + .longopt = "debug-port", + .more = 1, + .help = "debug server port (default: 5001)", + }, + }; + + const cli_option_t* cur_opt; uint32_t i = 1; - uint8_t port_arg_len = strlen("--jerry-debugger-port="); + while (i < argc && argv[i][0] == '-') { - if (!strcmp(argv[i], "--memstat")) { - env->config.memstat = true; - } else if (!strcmp(argv[i], "--show-opcodes")) { - env->config.show_opcode = true; - } else if (!strcmp(argv[i], "--start-debug-server")) { - env->config.debugger = - (DebuggerConfig*)iotjs_buffer_allocate(sizeof(DebuggerConfig)); - env->config.debugger->port = 5001; - env->config.debugger->wait_source = false; - env->config.debugger->context_reset = false; - } else if (!strncmp(argv[i], "--jerry-debugger-port=", port_arg_len) && - env->config.debugger) { - size_t port_length = sizeof(strlen(argv[i] - port_arg_len - 1)); - char port[port_length]; - memcpy(&port, argv[i] + port_arg_len, port_length); - sscanf(port, "%hu", &env->config.debugger->port); - } else if (!strcmp(argv[i], "--debugger-wait-source") && - env->config.debugger) { - env->config.debugger->wait_source = true; - } else { + cur_opt = NULL; + + // check if the known option is given. + for (uint32_t k = 0; k < NUM_OF_OPTIONS; k++) { + if ((opts[k].opt && !strcmp(&argv[i][1], opts[k].opt)) || + (opts[k].longopt && !strcmp(&argv[i][2], opts[k].longopt))) { + cur_opt = &opts[k]; + break; + } + } + + if (cur_opt == NULL) { fprintf(stderr, "unknown command line option: %s\n", argv[i]); return false; } - ++i; + + switch (cur_opt->id) { + case OPT_HELP: { + fprintf(stderr, "%s\n Options:\n\n", CLI_DEFAULT_HELP_STRING); + for (uint32_t k = 0; k < NUM_OF_OPTIONS; k++) { + if (opts[k].opt) { + fprintf(stderr, " -%s, --%-21s %s\n", opts[k].opt, + opts[k].longopt, opts[k].help); + } else { + fprintf(stderr, " --%-25s %s\n", opts[k].longopt, opts[k].help); + } + } + fprintf(stderr, "\n"); + return false; + } break; + case OPT_MEM_STATS: { + env->config.memstat = true; + } break; + case OPT_SHOW_OP: { + env->config.show_opcode = true; + } break; + case OPT_DEBUG_SERVER: { + if (!env->config.debugger) { + env->config.debugger = + (DebuggerConfig*)iotjs_buffer_allocate(sizeof(DebuggerConfig)); + } + env->config.debugger->port = 5001; + env->config.debugger->wait_source = false; + env->config.debugger->context_reset = false; + } break; + case OPT_DEBUG_PORT: { + if (env->config.debugger) { + char* pos = NULL; + env->config.debugger->port = (uint16_t)strtoul(argv[i + 1], &pos, 10); + } + } break; + case OPT_DEBUGGER_WAIT_SOURCE: { + if (env->config.debugger) + env->config.debugger->wait_source = true; + } break; + default: + break; + } + + // increase index of argv + i += (1 + cur_opt->more); } // If IoT.js is waiting for source from the debugger client, @@ -107,8 +201,7 @@ bool iotjs_environment_parse_command_line_arguments(iotjs_environment_t* env, // There must be at least one argument after processing the IoT.js args, if (argc - i < 1) { - fprintf(stderr, - "Usage: iotjs [options] {script | script.js} [arguments]\n"); + fprintf(stderr, CLI_DEFAULT_HELP_STRING); return false; } diff --git a/src/iotjs_handlewrap.c b/src/iotjs_handlewrap.c index e5704d6..50b5be5 100644 --- a/src/iotjs_handlewrap.c +++ b/src/iotjs_handlewrap.c @@ -20,16 +20,14 @@ void iotjs_handlewrap_initialize(iotjs_handlewrap_t* handlewrap, jerry_value_t jobject, uv_handle_t* handle, JNativeInfoType* native_info) { - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_handlewrap_t, handlewrap); - // Increase ref count of Javascript object to guarantee it is alive until the // handle has closed. jerry_value_t jobjectref = jerry_acquire_value(jobject); - _this->jobject = jobjectref; + handlewrap->jobject = jobjectref; jerry_set_object_native_pointer(jobjectref, handlewrap, native_info); - _this->handle = handle; - _this->on_close_cb = NULL; + handlewrap->handle = handle; + handlewrap->on_close_cb = NULL; handle->data = handlewrap; @@ -38,10 +36,8 @@ void iotjs_handlewrap_initialize(iotjs_handlewrap_t* handlewrap, void iotjs_handlewrap_destroy(iotjs_handlewrap_t* handlewrap) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_handlewrap_t, handlewrap); - // Handle should have been release before this. - IOTJS_ASSERT(_this->handle == NULL); + IOTJS_ASSERT(handlewrap->handle == NULL); } @@ -61,34 +57,30 @@ iotjs_handlewrap_t* iotjs_handlewrap_from_jobject(jerry_value_t jobject) { uv_handle_t* iotjs_handlewrap_get_uv_handle(iotjs_handlewrap_t* handlewrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_handlewrap_t, handlewrap); iotjs_handlewrap_validate(handlewrap); - return _this->handle; + return handlewrap->handle; } jerry_value_t iotjs_handlewrap_jobject(iotjs_handlewrap_t* handlewrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_handlewrap_t, handlewrap); iotjs_handlewrap_validate(handlewrap); - return _this->jobject; + return handlewrap->jobject; } static void iotjs_handlewrap_on_close(iotjs_handlewrap_t* handlewrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_handlewrap_t, handlewrap); - // The handle closed. // Calls registered close handler function. - if (_this->on_close_cb) { - _this->on_close_cb(_this->handle); + if (handlewrap->on_close_cb) { + handlewrap->on_close_cb(handlewrap->handle); } // Set handle null. - _this->handle = NULL; + handlewrap->handle = NULL; // Decrease ref count of Javascript object. From now the object can be // reclaimed. - jerry_release_value(_this->jobject); + jerry_release_value(handlewrap->jobject); } @@ -100,11 +92,9 @@ static void iotjs_on_handle_closed(uv_handle_t* handle) { void iotjs_handlewrap_close(iotjs_handlewrap_t* handlewrap, OnCloseHandler on_close_cb) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_handlewrap_t, handlewrap); - - if (_this->handle != NULL && !uv_is_closing(_this->handle)) { - _this->on_close_cb = on_close_cb; - uv_close(_this->handle, iotjs_on_handle_closed); + if (handlewrap->handle != NULL && !uv_is_closing(handlewrap->handle)) { + handlewrap->on_close_cb = on_close_cb; + uv_close(handlewrap->handle, iotjs_on_handle_closed); } else { DDLOG("Attempt to close uninitialized or already closed handle"); } @@ -112,10 +102,8 @@ void iotjs_handlewrap_close(iotjs_handlewrap_t* handlewrap, void iotjs_handlewrap_validate(iotjs_handlewrap_t* handlewrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_handlewrap_t, handlewrap); - - IOTJS_ASSERT((iotjs_handlewrap_t*)_this == handlewrap); - IOTJS_ASSERT((void*)_this == _this->handle->data); - IOTJS_ASSERT((uintptr_t)_this == - iotjs_jval_get_object_native_handle(_this->jobject)); + IOTJS_ASSERT(handlewrap); + IOTJS_ASSERT((void*)handlewrap == handlewrap->handle->data); + IOTJS_ASSERT((uintptr_t)handlewrap == + iotjs_jval_get_object_native_handle(handlewrap->jobject)); } diff --git a/src/iotjs_handlewrap.h b/src/iotjs_handlewrap.h index 2307e73..4994456 100644 --- a/src/iotjs_handlewrap.h +++ b/src/iotjs_handlewrap.h @@ -45,7 +45,7 @@ typedef struct { jerry_value_t jobject; uv_handle_t* handle; OnCloseHandler on_close_cb; -} IOTJS_VALIDATED_STRUCT(iotjs_handlewrap_t); +} iotjs_handlewrap_t; // jobject: Object that connect with the uv handle diff --git a/src/iotjs_magic_strings.h b/src/iotjs_magic_strings.h index d4634e1..52187a0 100644 --- a/src/iotjs_magic_strings.h +++ b/src/iotjs_magic_strings.h @@ -33,6 +33,7 @@ #define IOTJS_MAGIC_STRING_ADDRESS "address" #define IOTJS_MAGIC_STRING_ARCH "arch" #define IOTJS_MAGIC_STRING_ARGV "argv" +#define IOTJS_MAGIC_STRING_BASE64 "base64" #if ENABLE_MODULE_UART #define IOTJS_MAGIC_STRING_BAUDRATE "baudRate" #endif @@ -56,17 +57,12 @@ #endif #define IOTJS_MAGIC_STRING_BUFFER "Buffer" #define IOTJS_MAGIC_STRING_BUILTIN_MODULES "builtin_modules" -#define IOTJS_MAGIC_STRING__BUFFER "_buffer" -#define IOTJS_MAGIC_STRING__BUILTIN "_builtin" -#if ENABLE_MODULE_SPI +#if ENABLE_MODULE_I2C || ENABLE_MODULE_SPI #define IOTJS_MAGIC_STRING_BUS "bus" #endif #define IOTJS_MAGIC_STRING_BYTELENGTH "byteLength" -#if ENABLE_MODULE_HTTPS -#define IOTJS_MAGIC_STRING_REJECTUNAUTHORIZED "rejectUnauthorized" -#endif #define IOTJS_MAGIC_STRING_BYTEPARSED "byteParsed" -#if ENABLE_MODULE_HTTPS +#if ENABLE_MODULE_HTTPS || ENABLE_MODULE_TLS #define IOTJS_MAGIC_STRING_CA "ca" #define IOTJS_MAGIC_STRING_CERT "cert" #endif @@ -117,6 +113,9 @@ #endif #define IOTJS_MAGIC_STRING_EMIT "emit" #define IOTJS_MAGIC_STRING_EMITEXIT "emitExit" +#if ENABLE_MODULE_TLS +#define IOTJS_MAGIC_STRING_END "end" +#endif #define IOTJS_MAGIC_STRING_ENV "env" #define IOTJS_MAGIC_STRING_ERRNAME "errname" #define IOTJS_MAGIC_STRING_EXECUTE "execute" @@ -142,7 +141,7 @@ #define IOTJS_MAGIC_STRING_HANDLER "handler" #define IOTJS_MAGIC_STRING_HANDLETIMEOUT "handleTimeout" #define IOTJS_MAGIC_STRING_HEADERS "headers" -#define IOTJS_MAGIC_STRING_HEXWRITE "hexWrite" +#define IOTJS_MAGIC_STRING_HEX "hex" #if ENABLE_MODULE_SPI #define IOTJS_MAGIC_STRING_HIGH_U "HIGH" #endif @@ -155,6 +154,7 @@ #define IOTJS_MAGIC_STRING__INCOMING "_incoming" #define IOTJS_MAGIC_STRING_IOTJS_ENV_U "IOTJS_ENV" #define IOTJS_MAGIC_STRING_IOTJS_PATH_U "IOTJS_PATH" +#define IOTJS_MAGIC_STRING_IOTJS_EXTRA_MODULE_PATH_U "IOTJS_EXTRA_MODULE_PATH" #define IOTJS_MAGIC_STRING_IOTJS "iotjs" #define IOTJS_MAGIC_STRING_IPV4 "IPv4" #define IOTJS_MAGIC_STRING_IPV6 "IPv6" @@ -162,6 +162,9 @@ #define IOTJS_MAGIC_STRING_ISDEVUP "isDevUp" #define IOTJS_MAGIC_STRING_ISDIRECTORY "isDirectory" #define IOTJS_MAGIC_STRING_ISFILE "isFile" +#if ENABLE_MODULE_TLS +#define IOTJS_MAGIC_STRING_ISSERVER "isServer" +#endif #define IOTJS_MAGIC_STRING_KEY "key" #define IOTJS_MAGIC_STRING_LENGTH "length" #define IOTJS_MAGIC_STRING_LISTEN "listen" @@ -190,6 +193,9 @@ #define IOTJS_MAGIC_STRING_ONDATA "onData" #define IOTJS_MAGIC_STRING_ONEND "onEnd" #define IOTJS_MAGIC_STRING_ONERROR "onError" +#if ENABLE_MODULE_TLS +#define IOTJS_MAGIC_STRING_ONHANDSHAKEDONE "onhandshakedone" +#endif #define IOTJS_MAGIC_STRING_ONHEADERSCOMPLETE "OnHeadersComplete" #define IOTJS_MAGIC_STRING_ONHEADERS "OnHeaders" #define IOTJS_MAGIC_STRING_ONMESSAGECOMPLETE "OnMessageComplete" @@ -199,6 +205,9 @@ #define IOTJS_MAGIC_STRING_ONSOCKET "onSocket" #define IOTJS_MAGIC_STRING_ONTIMEOUT "onTimeout" #define IOTJS_MAGIC_STRING__ONUNCAUGHTEXCEPTION "_onUncaughtException" +#if ENABLE_MODULE_TLS +#define IOTJS_MAGIC_STRING_ONWRITE "onwrite" +#endif #define IOTJS_MAGIC_STRING_ONWRITABLE "onWritable" #if ENABLE_MODULE_GPIO #define IOTJS_MAGIC_STRING_OPENDRAIN_U "OPENDRAIN" @@ -231,6 +240,9 @@ #endif #define IOTJS_MAGIC_STRING_REF "ref" #define IOTJS_MAGIC_STRING_REINITIALIZE "reinitialize" +#if ENABLE_MODULE_TLS || ENABLE_MODULE_HTTPS +#define IOTJS_MAGIC_STRING_REJECTUNAUTHORIZED "rejectUnauthorized" +#endif #define IOTJS_MAGIC_STRING_RENAME "rename" #define IOTJS_MAGIC_STRING_REQUEST_U "REQUEST" #define IOTJS_MAGIC_STRING_RESPONSE_U "RESPONSE" @@ -242,6 +254,9 @@ #define IOTJS_MAGIC_STRING_RMDIR "rmdir" #define IOTJS_MAGIC_STRING_SEND "send" #define IOTJS_MAGIC_STRING_SENDREQUEST "sendRequest" +#if ENABLE_MODULE_TLS +#define IOTJS_MAGIC_STRING_SERVERNAME "servername" +#endif #if ENABLE_MODULE_I2C #define IOTJS_MAGIC_STRING_SETADDRESS "setAddress" #endif @@ -286,7 +301,11 @@ #define IOTJS_MAGIC_STRING_STDERR "stderr" #define IOTJS_MAGIC_STRING_STDOUT "stdout" #define IOTJS_MAGIC_STRING_STOP "stop" -#define IOTJS_MAGIC_STRING_TOHEXSTRING "toHexString" +#if ENABLE_MODULE_TLS +#define IOTJS_MAGIC_STRING_TLSSOCKET "TLSSocket" +#define IOTJS_MAGIC_STRING_TLSCONTEXT "TlsContext" +#define IOTJS_MAGIC_STRING_TLSINIT "TlsInit" +#endif #define IOTJS_MAGIC_STRING_TOSTRING "toString" #if ENABLE_MODULE_SPI #define IOTJS_MAGIC_STRING_TRANSFER "transfer" @@ -299,9 +318,17 @@ #define IOTJS_MAGIC_STRING_VERSION "version" #define IOTJS_MAGIC_STRING_WRITEUINT8 "writeUInt8" #define IOTJS_MAGIC_STRING_WRITE "write" +#define IOTJS_MAGIC_STRING_WRITEDECODE "writeDecode" #define IOTJS_MAGIC_STRING_WRITESYNC "writeSync" #if ENABLE_MODULE_HTTPS #define IOTJS_MAGIC_STRING__WRITE "_write" #endif +#if ENABLE_MODULE_BRIDGE +#define IOTJS_MAGIC_STRING_MODULE_NAME "MODULE_NAME" +#endif +#if ENABLE_MODULE_TIZEN +#define IOTJS_MAGIC_STRING_TIZEN "tizen" +#define IOTJS_MAGIC_STRING_APP_CONTROL "appControl" +#endif #endif /* IOTJS_MAGIC_STRINGS_H */ diff --git a/src/iotjs_reqwrap.c b/src/iotjs_reqwrap.c index 2098943..60da0af 100644 --- a/src/iotjs_reqwrap.c +++ b/src/iotjs_reqwrap.c @@ -19,36 +19,31 @@ void iotjs_reqwrap_initialize(iotjs_reqwrap_t* reqwrap, jerry_value_t jcallback, uv_req_t* request) { - IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_reqwrap_t, reqwrap); - _this->jcallback = jerry_acquire_value(jcallback); - _this->request = request; - _this->request->data = reqwrap; + reqwrap->jcallback = jerry_acquire_value(jcallback); + reqwrap->request = request; + reqwrap->request->data = reqwrap; } void iotjs_reqwrap_destroy(iotjs_reqwrap_t* reqwrap) { - IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_reqwrap_t, reqwrap); - jerry_release_value(_this->jcallback); + jerry_release_value(reqwrap->jcallback); } static void iotjs_reqwrap_validate(iotjs_reqwrap_t* reqwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_reqwrap_t, reqwrap); - IOTJS_ASSERT(_this->request->data == reqwrap); + IOTJS_ASSERT(reqwrap->request->data == reqwrap); } jerry_value_t iotjs_reqwrap_jcallback(iotjs_reqwrap_t* reqwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_reqwrap_t, reqwrap); iotjs_reqwrap_validate(reqwrap); - return _this->jcallback; + return reqwrap->jcallback; } uv_req_t* iotjs_reqwrap_req(iotjs_reqwrap_t* reqwrap) { - IOTJS_VALIDATED_STRUCT_METHOD(iotjs_reqwrap_t, reqwrap); iotjs_reqwrap_validate(reqwrap); - return _this->request; + return reqwrap->request; } diff --git a/src/iotjs_reqwrap.h b/src/iotjs_reqwrap.h index fd8ca22..2f41eed 100644 --- a/src/iotjs_reqwrap.h +++ b/src/iotjs_reqwrap.h @@ -30,7 +30,7 @@ typedef struct { jerry_value_t jcallback; uv_req_t* request; -} IOTJS_VALIDATED_STRUCT(iotjs_reqwrap_t); +} iotjs_reqwrap_t; void iotjs_reqwrap_initialize(iotjs_reqwrap_t* reqwrap, jerry_value_t jcallback, diff --git a/src/iotjs_string.c b/src/iotjs_string.c index 8d5b608..b4fddc1 100644 --- a/src/iotjs_string.c +++ b/src/iotjs_string.c @@ -65,10 +65,8 @@ iotjs_string_t iotjs_string_create_with_buffer(char* buffer, size_t size) { void iotjs_string_destroy(iotjs_string_t* str) { - if (str->data != NULL) { - iotjs_buffer_release(str->data); - str->size = 0; - } + IOTJS_RELEASE(str->data); + str->size = 0; } @@ -76,16 +74,6 @@ bool iotjs_string_is_empty(const iotjs_string_t* str) { return str->size == 0; } - -void iotjs_string_make_empty(iotjs_string_t* str) { - if (str->data != NULL) { - iotjs_buffer_release(str->data); - str->size = 0; - str->data = NULL; - } -} - - void iotjs_string_append(iotjs_string_t* str, const char* data, size_t size) { IOTJS_ASSERT(data != NULL); diff --git a/src/iotjs_string.h b/src/iotjs_string.h index cd7edff..2f3d708 100644 --- a/src/iotjs_string.h +++ b/src/iotjs_string.h @@ -33,9 +33,6 @@ void iotjs_string_destroy(iotjs_string_t* str); // Check if string is empty bool iotjs_string_is_empty(const iotjs_string_t* str); -// Make string empty -void iotjs_string_make_empty(iotjs_string_t* str); - // Append `data` to tail of the string. void iotjs_string_append(iotjs_string_t* str, const char* data, size_t size); diff --git a/src/iotjs_util.c b/src/iotjs_util.c index 7d88973..243ee6b 100644 --- a/src/iotjs_util.c +++ b/src/iotjs_util.c @@ -21,7 +21,7 @@ #include #include -#if defined(__linux__) +#if defined(__linux__) && !defined(__OPENWRT__) #include #endif @@ -32,11 +32,13 @@ iotjs_string_t iotjs_file_read(const char* path) { return empty_content; } - fseek(file, 0, SEEK_END); + int fseek_ret = fseek(file, 0, SEEK_END); + IOTJS_ASSERT(fseek_ret == 0); long ftell_ret = ftell(file); IOTJS_ASSERT(ftell_ret >= 0); size_t len = (size_t)ftell_ret; - fseek(file, 0, SEEK_SET); + fseek_ret = fseek(file, 0, SEEK_SET); + IOTJS_ASSERT(fseek_ret == 0); char* buffer = iotjs_buffer_allocate(len + 1); @@ -74,7 +76,7 @@ char* iotjs_buffer_allocate(size_t size) { char* iotjs_buffer_allocate_from_number_array(size_t size, const jerry_value_t array) { char* buffer = iotjs_buffer_allocate(size); - for (uint8_t i = 0; i < size; i++) { + for (size_t i = 0; i < size; i++) { jerry_value_t jdata = iotjs_jval_get_property_by_index(array, i); buffer[i] = iotjs_jval_as_number(jdata); jerry_release_value(jdata); @@ -90,12 +92,13 @@ char* iotjs_buffer_reallocate(char* buffer, size_t size) { void iotjs_buffer_release(char* buffer) { - IOTJS_ASSERT(buffer != NULL); - free(buffer); + if (buffer) { + free(buffer); + } } void print_stacktrace() { -#if defined(__linux__) && defined(DEBUG) +#if defined(__linux__) && defined(DEBUG) && !defined(__OPENWRT__) // TODO: support other platforms const int numOfStackTrace = 100; void* buffer[numOfStackTrace]; @@ -127,7 +130,7 @@ void print_stacktrace() { } free(strings); -#endif // defined(__linux__) && defined(DEBUG) +#endif // defined(__linux__) && defined(DEBUG) && !defined(__OPENWRT__) } void force_terminate() { diff --git a/src/iotjs_util.h b/src/iotjs_util.h index 14168c6..9574b69 100644 --- a/src/iotjs_util.h +++ b/src/iotjs_util.h @@ -33,7 +33,10 @@ void iotjs_buffer_release(char* buff); (type*)iotjs_buffer_allocate(sizeof(type)) #define IOTJS_RELEASE(ptr) /* Release memory allocated by IOTJS_ALLOC() */ \ - iotjs_buffer_release((char*)ptr) + ({ \ + iotjs_buffer_release((char*)ptr); \ + ptr = NULL; \ + }) #endif /* IOTJS_UTIL_H */ diff --git a/src/js/bridge.js b/src/js/bridge.js new file mode 100644 index 0000000..81f6269 --- /dev/null +++ b/src/js/bridge.js @@ -0,0 +1,30 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +function Bridge(moduleName) { + this.moduleName = moduleName; +} + +Bridge.prototype.send = function(command, message, callback) { + native.send(this.moduleName, command, message, function(err, results) { + callback(err, results); + }); +}; + +Bridge.prototype.sendSync = function(command, message) { + return native.send(this.moduleName, command, message); +}; + +module.exports = Bridge; diff --git a/src/js/buffer.js b/src/js/buffer.js index 538c4e5..81cae16 100644 --- a/src/js/buffer.js +++ b/src/js/buffer.js @@ -30,6 +30,18 @@ function checkOffset(offset, ext, length) { } +function getEncodingType(encoding) { + switch (encoding) { + case 'hex': + return 0; + case 'base64': + return 1; + default: + return -1; + } +} + + // Buffer constructor // [1] new Buffer(size) // [2] new Buffer(buffer) @@ -51,18 +63,16 @@ function Buffer(subject, encoding) { throw new TypeError('Bad arguments: Buffer(string|number|Buffer|Array)'); } - this._builtin = new native(this, this.length); + // 'native' is the buffer object created via the C API. + native(this, this.length); if (util.isString(subject)) { - if (encoding !== undefined && util.isString(encoding)) { - switch (encoding) { - case 'hex': - if (this._builtin.hexWrite(subject, 0, this.length) != this.length) { - throw new TypeError('Invalid hex string'); - } - break; - default: - this.write(subject); + if (typeof encoding === 'string') { + encoding = getEncodingType(encoding); + if (encoding != -1) { + native.writeDecode(this, encoding, subject, 0, this.length); + } else { + this.write(subject); } } else { this.write(subject); @@ -71,23 +81,36 @@ function Buffer(subject, encoding) { subject.copy(this); } else if (util.isArray(subject)) { for (var i = 0; i < this.length; ++i) { - this._builtin.writeUInt8(subject[i], i); + native.writeUInt8(this, subject[i], i); } } } -// Buffer.byteLength(string) +// Buffer.byteLength(string, encoding) Buffer.byteLength = function(str, encoding) { - var len = native.byteLength(str); + var bytes = native.byteLength(str); - if (encoding !== undefined && util.isString(encoding)) { + if (typeof encoding === 'string') { + /* Might be invalid for incorrectly encoded strings. */ switch (encoding) { case 'hex': - return len >>> 1; + return bytes >>> 1; + case 'base64': + var len = str.length; + + if (len >= 4 && str.charCodeAt(len - 1) === 0x3D) { + len--; + + if (str.charCodeAt(len - 2) === 0x3D) { + len--; + } + } + + return len; } } - return len; + return bytes; }; @@ -98,7 +121,8 @@ Buffer.concat = function(list) { } var length = 0; - for (var i = 0; i < list.length; ++i) { + var i; + for (i = 0; i < list.length; ++i) { if (!util.isBuffer(list[i])) { throw new TypeError('Bad arguments: Buffer.concat([Buffer])'); } @@ -107,7 +131,7 @@ Buffer.concat = function(list) { var buffer = new Buffer(length); var pos = 0; - for (var i = 0; i < list.length; ++i) { + for (i = 0; i < list.length; ++i) { list[i].copy(buffer, pos); pos += list[i].length; } @@ -117,9 +141,7 @@ Buffer.concat = function(list) { // Buffer.isBuffer(object) -Buffer.isBuffer = function(object) { - return util.isBuffer(object); -}; +Buffer.isBuffer = util.isBuffer; // buffer.equals(otherBuffer) @@ -128,7 +150,7 @@ Buffer.prototype.equals = function(otherBuffer) { throw new TypeError('Bad arguments: buffer.equals(Buffer)'); } - return this._builtin.compare(otherBuffer._builtin) == 0; + return native.compare(this, otherBuffer) == 0; }; @@ -138,7 +160,7 @@ Buffer.prototype.compare = function(otherBuffer) { throw new TypeError('Bad arguments: buffer.compare(Buffer)'); } - return this._builtin.compare(otherBuffer._builtin); + return native.compare(this, otherBuffer); }; @@ -163,7 +185,7 @@ Buffer.prototype.copy = function(target, targetStart, sourceStart, sourceEnd) { throw new RangeError('Attempt to write outside buffer bounds'); } - return this._builtin.copy(target, targetStart, sourceStart, sourceEnd); + return native.copy(this, target, targetStart, sourceStart, sourceEnd); }; @@ -173,7 +195,7 @@ Buffer.prototype.copy = function(target, targetStart, sourceStart, sourceEnd) { // [3] buffer.write(string, offset, length) // * offset - default to 0 // * length - default to buffer.length - offset -Buffer.prototype.write = function(string, offset, length) { +Buffer.prototype.write = function(string, offset, length, encoding) { if (!util.isString(string)) { throw new TypeError('Bad arguments: buff.write(string)'); } @@ -186,7 +208,14 @@ Buffer.prototype.write = function(string, offset, length) { var remaining = this.length - offset; length = length === undefined ? remaining : ~~length; - return this._builtin.write(string, offset, length); + if (typeof encoding === 'string') { + encoding = getEncodingType(encoding); + if (encoding != -1) { + return native.writeDecode(this, encoding, string, offset, length); + } + } + + return native.write(this, string, offset, length); }; @@ -200,25 +229,28 @@ Buffer.prototype.slice = function(start, end) { start = start === undefined ? 0 : ~~start; end = end === undefined ? this.length : ~~end; - return this._builtin.slice(start, end); + return native.slice(this, start, end); }; // buff.toString([encoding,[,start[, end]]]) // [1] buff.toString() -// [2] buff.toString(start) -// [3] buff.toString(start, end) -// [4] buff.toString('hex') +// [2] buff.toString(encoding) +// [3] buff.toString(encoding, start) +// [4] buff.toString(encoding, start, end) // * start - default to 0 // * end - default to buff.length -Buffer.prototype.toString = function(start, end) { - if (util.isString(start) && start === 'hex' && end === undefined) { - return this._builtin.toHexString(); +Buffer.prototype.toString = function(encoding, start, end) { + if (typeof encoding === 'string') { + encoding = getEncodingType(encoding); + } else { + encoding = -1; } + start = start === undefined ? 0 : ~~start; end = end === undefined ? this.length : ~~end; - return this._builtin.toString(start, end); + return native.toString(this, encoding, start, end); }; @@ -230,7 +262,7 @@ Buffer.prototype.writeUInt8 = function(value, offset, noAssert) { offset = offset >>> 0; if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0); - this._builtin.writeUInt8(value & 0xff, offset); + native.writeUInt8(this, value & 0xff, offset); return offset + 1; }; @@ -243,8 +275,8 @@ Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) { offset = offset >>> 0; if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0); - this._builtin.writeUInt8(value & 0xff, offset); - this._builtin.writeUInt8((value >>> 8) & 0xff, offset + 1); + native.writeUInt8(this, value & 0xff, offset); + native.writeUInt8(this, (value >>> 8) & 0xff, offset + 1); return offset + 2; }; @@ -257,10 +289,10 @@ Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) { offset = offset >>> 0; if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0); - this._builtin.writeUInt8((value >>> 24) & 0xff, offset + 3); - this._builtin.writeUInt8((value >>> 16) & 0xff, offset + 2); - this._builtin.writeUInt8((value >>> 8) & 0xff, offset + 1); - this._builtin.writeUInt8(value & 0xff, offset); + native.writeUInt8(this, (value >>> 24) & 0xff, offset + 3); + native.writeUInt8(this, (value >>> 16) & 0xff, offset + 2); + native.writeUInt8(this, (value >>> 8) & 0xff, offset + 1); + native.writeUInt8(this, value & 0xff, offset); return offset + 4; }; @@ -272,7 +304,7 @@ Buffer.prototype.readUInt8 = function(offset, noAssert) { offset = offset >>> 0; if (!noAssert) checkOffset(offset, 1, this.length); - return this._builtin.readUInt8(offset); + return native.readUInt8(this, offset); }; @@ -283,7 +315,7 @@ Buffer.prototype.readInt8 = function(offset, noAssert) { offset = offset >>> 0; if (!noAssert) checkOffset(offset, 1, this.length); - var val = this._builtin.readUInt8(offset); + var val = native.readUInt8(this, offset); return !(val & 0x80) ? val : (0xff - val + 1) * -1; }; @@ -295,8 +327,8 @@ Buffer.prototype.readUInt16LE = function(offset, noAssert) { offset = offset >>> 0; if (!noAssert) checkOffset(offset, 2, this.length); - return this._builtin.readUInt8(offset) | - (this._builtin.readUInt8(offset + 1) << 8); + return native.readUInt8(this, offset) | + (native.readUInt8(this, offset + 1) << 8); }; @@ -305,7 +337,7 @@ Buffer.prototype.fill = function(value) { if (util.isNumber(value)) { value = value & 255; for (var i = 0; i < this.length; i++) { - this._builtin.writeUInt8(value, i); + native.writeUInt8(this, value, i); } } return this; diff --git a/src/js/dgram.js b/src/js/dgram.js index d4b523a..7318c9b 100644 --- a/src/js/dgram.js +++ b/src/js/dgram.js @@ -15,7 +15,7 @@ var EventEmitter = require('events').EventEmitter; var util = require('util'); -var udp = require('udp'); +var Udp = require('udp'); var BIND_STATE_UNBOUND = 0; var BIND_STATE_BINDING = 1; @@ -39,7 +39,7 @@ function lookup4(address, callback) { function newHandle(type) { if (type == 'udp4') { - var handle = new udp(); + var handle = new Udp(); handle.lookup = lookup4; return handle; } @@ -102,8 +102,6 @@ Socket.prototype.bind = function(port, address, callback) { this._bindState = BIND_STATE_BINDING; - var address; - if (util.isFunction(port)) { callback = port; port = 0; @@ -138,7 +136,7 @@ Socket.prototype.bind = function(port, address, callback) { self._handle._reuseAddr = self._reuseAddr; - var err = self._handle.bind(ip, port | 0); + err = self._handle.bind(ip, port | 0); if (err) { var ex = util.exceptionWithHostPort(err, 'bind', ip, port); self.emit('error', ex); @@ -311,7 +309,7 @@ function doSend(ex, self, ip, list, address, port, callback) { if (err && callback) { // don't emit as error, dgram_legacy.js compatibility - var ex = exceptionWithHostPort(err, 'send', address, port); + ex = util.exceptionWithHostPort(err, 'send', address, port); process.nextTick(callback, ex); } } @@ -447,7 +445,7 @@ Socket.prototype._stopReceiving = function() { function onMessage(nread, handle, buf, rinfo) { var self = handle.owner; if (nread < 0) { - return self.emit('error', errnoException(nread, 'recvmsg')); + return self.emit('error', util.errnoException(nread, 'recvmsg')); } rinfo.size = buf.length; // compatibility diff --git a/src/js/fs.js b/src/js/fs.js index 62e6131..2019af2 100644 --- a/src/js/fs.js +++ b/src/js/fs.js @@ -30,7 +30,7 @@ fs.exists = function(path, callback) { return; } - var cb = function(err, stat) { + var cb = function(err/* , stat */) { if (callback) callback(err ? false : true); }; @@ -86,7 +86,7 @@ fs.closeSync = function(fd) { }; -fs.open = function(path, flags, mode, callback) { +fs.open = function(path, flags, mode/* , callback */) { fsBuiltin.open(checkArgString(path, 'path'), convertFlags(flags), convertMode(mode, 438), diff --git a/src/js/gpio.js b/src/js/gpio.js index adc6409..3c1098e 100644 --- a/src/js/gpio.js +++ b/src/js/gpio.js @@ -26,7 +26,7 @@ var gpio = { }, DIRECTION: native.DIRECTION, EDGE: native.EDGE, - MODE: native.MODE + MODE: native.MODE, }; module.exports = gpio; diff --git a/src/js/http.js b/src/js/http.js index c149ecf..1ff4c2c 100644 --- a/src/js/http.js +++ b/src/js/http.js @@ -13,17 +13,43 @@ * limitations under the License. */ -var Server = require('http_server').Server; +var net = require('net'); var ClientRequest = require('http_client').ClientRequest; -var HTTPParser = require('httpparser'); +var HTTPParser = require('http_parser'); +var HTTPServer = require('http_server'); +var util = require('util'); exports.ClientRequest = ClientRequest; exports.request = function(options, cb) { - return new ClientRequest(options, cb); + // Create socket. + var socket = new net.Socket(); + options.port = options.port || 80; + + return new ClientRequest(options, cb, socket); +}; + +function Server(requestListener) { + if (!(this instanceof Server)) { + return new Server(requestListener); + } + + net.Server.call(this, {allowHalfOpen: true}, + HTTPServer.connectionListener); + + HTTPServer.initServer.call(this, {}, requestListener); +} +util.inherits(Server, net.Server); + +Server.prototype.setTimeout = function(ms, cb) { + this.timeout = ms; + if (cb) { + this.on('timeout', cb); + } }; +exports.Server = Server; exports.createServer = function(requestListener) { return new Server(requestListener); diff --git a/src/js/http_client.js b/src/js/http_client.js index fc3db7b..1668375 100644 --- a/src/js/http_client.js +++ b/src/js/http_client.js @@ -14,19 +14,17 @@ */ var util = require('util'); -var net = require('net'); var OutgoingMessage = require('http_outgoing').OutgoingMessage; var common = require('http_common'); -var HTTPParser = require('httpparser').HTTPParser; +var HTTPParser = require('http_parser').HTTPParser; -function ClientRequest(options, cb) { +function ClientRequest(options, cb, socket) { OutgoingMessage.call(this); // get port, host and method. - var port = options.port = options.port || 80; - var host = options.host = options.hostname || options.host || '127.0.0.1'; var method = options.method || 'GET'; var path = options.path || '/'; + options.host = options.hostname || options.host || '127.0.0.1'; // If `options` contains header information, save it. if (options.headers) { @@ -37,10 +35,10 @@ function ClientRequest(options, cb) { } } - if (host && !this.getHeader('host')) { - var hostHeader = host; - if (port && +port !== 80) { - hostHeader += ':' + port; + if (options.host && !this.getHeader('host')) { + var hostHeader = options.host; + if (this._port && +this._port !== 80) { + hostHeader += ':' + this._port; } this.setHeader('Host', hostHeader); } @@ -53,22 +51,29 @@ function ClientRequest(options, cb) { this.once('response', cb); } - // Create socket. - var socket = new net.Socket(); - - // connect server. - socket.connect(port, host); - - // setup connection information. - setupConnection(this, socket); + this.socket = socket; + this.options = options; } util.inherits(ClientRequest, OutgoingMessage); exports.ClientRequest = ClientRequest; +ClientRequest.prototype.end = function(data, encoding, callback) { + var self = this; + + // connect server. + this.socket.connect(this.options, function() { + self._connected = true; + OutgoingMessage.prototype.end.call(self, data, encoding, callback); + }); + + // setup connection information. + setupConnection(this); +}; -function setupConnection(req, socket) { +function setupConnection(req) { + var socket = req.socket; var parser = common.createHTTPParser(); parser.reinitialize(HTTPParser.RESPONSE); socket.parser = parser; @@ -79,15 +84,12 @@ function setupConnection(req, socket) { parser._headers = []; parser.onIncoming = parserOnIncomingClient; - req.socket = socket; - req.connection = socket; req.parser = parser; socket.on('error', socketOnError); socket.on('data', socketOnData); socket.on('end', socketOnEnd); socket.on('close', socketOnClose); - socket.on('lookup', socketOnLookup); // socket emitted when a socket is assigned to req process.nextTick(function() { @@ -115,7 +117,7 @@ function emitError(socket, err) { if (err) { var host; - if (host = req.getHeader('host')) { + if ((host = req.getHeader('host'))) { err.message += ': ' + (host ? host : ''); } req.emit('error', err); @@ -125,9 +127,6 @@ function emitError(socket, err) { function socketOnClose() { var socket = this; var req = socket._httpMessage; - var parser = socket.parser; - - socket.read(); req.emit('close'); @@ -148,10 +147,6 @@ function socketOnError(err) { emitError(this, err); } -function socketOnLookup(err, ip, family) { - emitError(this, err); -} - function socketOnData(d) { var socket = this; var req = this._httpMessage; @@ -170,7 +165,7 @@ function socketOnEnd() { // This is called by parserOnHeadersComplete after response header is parsed. // TODO: keepalive support -function parserOnIncomingClient(res, shouldKeepAlive) { +function parserOnIncomingClient(res/* , shouldKeepAlive */) { var socket = this.socket; var req = socket._httpMessage; @@ -204,20 +199,19 @@ var responseOnEnd = function() { } }; +ClientRequest.prototype.abort = function() { + this.emit('abort'); + if (this.socket) { + cleanUpSocket(this.socket); + } +}; ClientRequest.prototype.setTimeout = function(ms, cb) { var self = this; if (cb) self.once('timeout', cb); - var emitTimeout = function() { + setTimeout(function() { self.emit('timeout'); - }; - - // In IoT.js, socket is already assigned, - // thus, it is sufficient to trigger timeout on socket 'connect' event. - this.socket.once('connect', function() { - self.socket.setTimeout(ms, emitTimeout); - }); - + }, ms); }; diff --git a/src/js/http_common.js b/src/js/http_common.js index da9c496..6250492 100644 --- a/src/js/http_common.js +++ b/src/js/http_common.js @@ -15,7 +15,7 @@ var util = require('util'); var IncomingMessage = require('http_incoming').IncomingMessage; -var HTTPParser = require('httpparser').HTTPParser; +var HTTPParser = require('http_parser').HTTPParser; var createHTTPParser = function() { // REQUEST is the default type. diff --git a/src/js/http_incoming.js b/src/js/http_incoming.js index 72249c1..df16f6b 100644 --- a/src/js/http_incoming.js +++ b/src/js/http_incoming.js @@ -21,7 +21,6 @@ function IncomingMessage(socket) { stream.Readable.call(this); this.socket = socket; - this.connection = socket; this.readable = true; diff --git a/src/js/http_outgoing.js b/src/js/http_outgoing.js index ae0e6d9..3c48216 100644 --- a/src/js/http_outgoing.js +++ b/src/js/http_outgoing.js @@ -27,9 +27,12 @@ function OutgoingMessage() { this.finished = false; this._sentHeader = false; + this._connected = false; + + // storage for chunks when there is no connection established + this._chunks = []; this.socket = null; - this.connection = null; // response header string : same 'content' as this._headers this._header = null; // response header obj : (key, value) pairs @@ -85,19 +88,13 @@ OutgoingMessage.prototype.end = function(data, encoding, callback) { this.finished = true; - this._finish(); + this.emit('prefinish'); return true; }; -OutgoingMessage.prototype._finish = function() { - this.emit('prefinish'); -}; - - // This sends chunk directly into socket -// TODO: buffering of chunk in the case of socket is not available OutgoingMessage.prototype._send = function(chunk, encoding, callback) { if (util.isFunction(encoding)) { callback = encoding; @@ -112,7 +109,20 @@ OutgoingMessage.prototype._send = function(chunk, encoding, callback) { this._sentHeader = true; } - return this.connection.write(chunk, encoding, callback); + if (!this._connected) { + this._chunks.push(chunk); + return false; + } else { + while (this._chunks.length) { + this.socket.write(this._chunks.shift(), encoding, callback); + } + } + + if (this.socket) { + return this.socket.write(chunk, encoding, callback); + } + + return false; }; @@ -125,10 +135,7 @@ OutgoingMessage.prototype.write = function(chunk, encoding, callback) { return true; } - var ret = this._send(chunk, encoding, callback); - - return ret; - + return this._send(chunk, encoding, callback); }; @@ -182,13 +189,15 @@ OutgoingMessage.prototype.getHeader = function(name) { OutgoingMessage.prototype.setTimeout = function(ms, cb) { - if (cb) + if (cb) { this.once('timeout', cb); + } if (!this.socket) { this.once('socket', function(socket) { - socket.setTimeout(msecs); + socket.setTimeout(ms); }); - } else - this.socket.setTimeout(msecs); + } else { + this.socket.setTimeout(ms); + } }; diff --git a/src/js/http_server.js b/src/js/http_server.js index b7a4144..8aeb9f7 100644 --- a/src/js/http_server.js +++ b/src/js/http_server.js @@ -14,7 +14,6 @@ */ var util = require('util'); -var net = require('net'); var OutgoingMessage = require('http_outgoing').OutgoingMessage; var common = require('http_common'); @@ -122,9 +121,9 @@ ServerResponse.prototype.writeHead = function(statusCode, reason, obj) { ServerResponse.prototype.assignSocket = function(socket) { + this._connected = true; socket._httpMessage = this; this.socket = socket; - this.connection = socket; socket.on('close', onServerResponseClose); this.emit('socket', socket); }; @@ -139,24 +138,18 @@ function onServerResponseClose() { ServerResponse.prototype.detachSocket = function() { this.socket._httpMessage = null; - this.socket = this.connection = null; + this.socket = null; + this._connected = false; }; -function Server(requestListener) { - if (!(this instanceof Server)) { - return new Server(requestListener); - } - - net.Server.call(this, {allowHalfOpen: true}); - +function initServer(options, requestListener) { if (util.isFunction(requestListener)) { this.addListener('request', requestListener); } this.httpAllowHalfOpen = false; - this.on('connection', connectionListener); this.on('clientError', function(err, conn) { conn.destroy(err); }); @@ -164,19 +157,7 @@ function Server(requestListener) { this.timeout = 2 * 1000 * 60; // default timeout is 2 min } -util.inherits(Server, net.Server); -exports.Server = Server; - - -// TODO: Implement Server.prototype.setTimeout function -// For this, socket.prototype.setTimeout is needed. -Server.prototype.setTimeout = function(ms, cb) { - this.timeout = ms; - if (cb) { - this.on('timeout', cb); - } -}; - +exports.initServer = initServer; function connectionListener(socket) { var server = this; @@ -204,6 +185,7 @@ function connectionListener(socket) { } } +exports.connectionListener = connectionListener; function socketOnData(data) { var socket = this; @@ -272,7 +254,7 @@ function socketOnError(err) { // This is called by parserOnHeadersComplete after req header is parsed. // TODO: keepalive support -function parserOnIncoming(req, shouldKeepAlive) { +function parserOnIncoming(req/* , shouldKeepAlive */) { var socket = req.socket; var server = socket._server; diff --git a/src/js/https.js b/src/js/https.js index 7719092..2d0556c 100644 --- a/src/js/https.js +++ b/src/js/https.js @@ -13,15 +13,46 @@ * limitations under the License. */ -var client = require('https_client'); +var tls = require('tls'); +var net = require('net'); +var ClientRequest = require('http_client').ClientRequest; +var HTTPParser = require('http_parser'); +var HTTPServer = require('http_server'); +var util = require('util'); -var ClientRequest = exports.ClientRequest = client.ClientRequest; +exports.ClientRequest = ClientRequest; exports.request = function(options, cb) { - return new ClientRequest(options, cb); + options.port = options.port || 443; + // Create socket. + var socket = new tls.TLSSocket(new net.Socket(), options); + + return new ClientRequest(options, cb, socket); +}; + +function Server(options, requestListener) { + if (!(this instanceof Server)) { + return new Server(options, requestListener); + } + options.allowHalfOpen = true; + tls.Server.call(this, options, HTTPServer.connectionListener); + + HTTPServer.initServer.call(this, options, requestListener); +} +util.inherits(Server, tls.Server); + +Server.prototype.setTimeout = function(ms, cb) { + this.timeout = ms; + if (cb) { + this.on('timeout', cb); + } +}; + +exports.createServer = function(options, requestListener) { + return new Server(options, requestListener); }; -exports.METHODS = client.METHODS; +exports.METHODS = HTTPParser.methods; exports.get = function(options, cb) { var req = exports.request(options, cb); diff --git a/src/js/https_client.js b/src/js/https_client.js deleted file mode 100644 index 9f2601f..0000000 --- a/src/js/https_client.js +++ /dev/null @@ -1,163 +0,0 @@ -/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors - * - * 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. - */ - -var util = require('util'); -var incoming = require('https_incoming'); -var stream = require('stream'); -var Buffer = require('buffer'); -var httpsNative = require('https_native'); - -var methods = {'0': 'DELETE', '1': 'GET', '2': 'HEAD', '3': 'POST', - '4': 'PUT', '5': 'CONNECT', '6': 'OPTIONS', '7': 'TRACE'}; -exports.METHODS = methods; - -function ClientRequest(options, cb) { - this.stream = stream.Writable.call(this, options); - - // get port, host and method. - var port = options.port = options.port || 443; - var host = options.host = options.hostname || options.host || '127.0.0.1'; - var path = options.path || '/'; - var protocol = options.protocol || 'https:'; - - this.host = protocol + '//' + host + ':' + port + path; - this.method = options.method || 'GET'; - this.ca = options.ca || ''; - this.cert = options.cert || ''; - this.key = options.key || ''; - - if (options.rejectUnauthorized == null) { - this.rejectUnauthorized = true; - } else { - this.rejectUnauthorized = options.rejectUnauthorized; - } - - var isMethodGood = false; - for (var key in methods) { - if (methods.hasOwnProperty(key)) { - if (this.method === methods[key]) { - isMethodGood = true; - break; - } - } - } - - if (!isMethodGood) { - var err = new Error('Incorrect options.method.'); - this.emit('error', err); - return; - } - - this._incoming = new incoming.IncomingMessage(this); - this._incoming.url = this.host; - this._incoming.method = this.method; - this.aborted = null; - - // Register response event handler. - if (cb) { - this.once('response', cb); - } - this.once('finish', this.onFinish); - - httpsNative.createRequest(this); - - if (options.auth) { - var headerString = 'Authorization: Basic ' + toBase64(options.auth); - httpsNative.addHeader(headerString, this); - } - if (options.headers) { - var keys = Object.keys(options.headers); - for (var i = 0, l = keys.length; i < l; i++) { - var key = keys[i]; - httpsNative.addHeader(key + ': ' + options.headers[key], this); - } - } - httpsNative.sendRequest(this); -} - -util.inherits(ClientRequest, stream.Writable); - -// Concrete stream overriding the empty underlying _write method. -ClientRequest.prototype._write = function(chunk, callback, onwrite) { - httpsNative._write(this, chunk.toString(), callback, onwrite); -}; - -ClientRequest.prototype.headersComplete = function() { - var self = this; - self.emit('response', self._incoming); - return (self.method == 'HEAD'); -}; - -ClientRequest.prototype.onError = function(ret) { - this.emit('error', ret); -}; - -ClientRequest.prototype.onFinish = function() { - httpsNative.finishRequest(this); -}; - -ClientRequest.prototype.setTimeout = function(ms, cb) { - this._incoming.setTimeout(ms, cb); -}; - -ClientRequest.prototype.abort = function(doNotEmit) { - if (!this.aborted) { - httpsNative.abort(this); - var date = new Date(); - this.aborted = date.getTime(); - - if (this._incoming.parser) { - this._incoming.parser.finish(); - this._incoming.parser = null; - } - - if (!doNotEmit) { - this.emit('abort'); - } - } -}; - -exports.ClientRequest = ClientRequest; - -function toBase64(input) { - var output = ''; - var chr1, chr2, chr3, enc1, enc2, enc3, enc4; - var i = 0; - // Convert to UTF-8 - input = Buffer(input).toString(); - var _keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' + - '0123456789+/='; - while (i < input.length) { - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); - - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } else if (isNaN(chr3)) { - enc4 = 64; - } - - output = output + - _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + - _keyStr.charAt(enc3) + _keyStr.charAt(enc4); - } - return output; -} diff --git a/src/js/https_incoming.js b/src/js/https_incoming.js deleted file mode 100644 index f4ea613..0000000 --- a/src/js/https_incoming.js +++ /dev/null @@ -1,252 +0,0 @@ -/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors - * - * 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. - */ - -var util = require('util'); -var stream = require('stream'); -var Buffer = require('buffer'); -var httpsNative = require('https_native'); -var HTTPParser = require('httpparser').HTTPParser; - -function IncomingMessage(clientRequest) { - stream.Readable.call(this); - this.clientRequest = clientRequest; - - this.headers = {}; - this.started = false; - this.completed = false; - this.timeoutCallback = null; - // for response (client) - this.statusCode = null; - this.statusMessage = null; - this.url = null; - this.method = null; - - this.parser = createHTTPParser(this); - - this.onData = cbOnData; - this.onClosed = cbOnClosed; - this.onEnd = cbOnEnd; - this.onError = cbOnError; - this.onSocket = cbOnSocket; - this.onTimeout = cbOnTimeout; - this.onWritable = cbOnWritable; -} - -util.inherits(IncomingMessage, stream.Readable); -exports.IncomingMessage = IncomingMessage; - -IncomingMessage.prototype.read = function(n) { - this.read = stream.Readable.prototype.read; - return this.read(n); -}; - -IncomingMessage.prototype.setTimeout = function(ms, cb) { - if (cb) { - this.timeoutCallback = cb; - this.once('timeout', cb); - } - httpsNative.setTimeout(ms, this.clientRequest); -}; - -IncomingMessage.prototype.addHeaders = function(headers) { - if (!this.headers) { - this.headers = {}; - } - if (!headers) { - return; - } - - for (var i = 0; i < headers.length; i = i + 2) { - this.headers[headers[i]] = headers[i + 1]; - } -}; - -// HTTP PARSER Constructor -var createHTTPParser = function(incoming) { - var parser = new HTTPParser(HTTPParser.RESPONSE); - parser.incoming = incoming; - // cb during http parsing from C side(http_parser) - parser.OnHeaders = parserOnHeaders; - parser.OnHeadersComplete = parserOnHeadersComplete; - parser.OnBody = parserOnBody; - parser.OnMessageComplete = parserOnMessageComplete; - return parser; -}; - -// ------------- HTTP PARSER CALLBACKS ------------- -// This is called when http header is fragmented and -// HTTPParser sends it to JS in separate pieces. -function parserOnHeaders(headers, url) { - var parser = this; - parser.incoming.addHeaders(headers); -} - -// This is called when header part in http msg is parsed. -function parserOnHeadersComplete(info) { - var parser = this; - var headers = info.headers; - - if (!headers) { - headers = parser._headers; - parser.incoming.addHeaders(headers); - parser._headers = {}; - } else { - parser.incoming.addHeaders(headers); - } - - // add header fields of headers to incoming.headers - parser.incoming.addHeaders(headers); - parser.incoming.statusCode = info.status; - parser.incoming.statusMessage = info.status_msg; - parser.incoming.started = true; - - // For client side, if response to 'HEAD' request, we will skip parsing body - if (parser.incoming.statusCode == 100) { - return false; - } - return parser.incoming.clientRequest.headersComplete(); -} - -// parserOnBody is called when HTTPParser parses http msg(incoming) and -// get body part(buf from start at length of len) -function parserOnBody(buf, start, len) { - var parser = this; - var incoming = parser.incoming; - - if (!incoming) { - return; - } - - // Push body part into incoming stream, which will emit 'data' event - var body = buf.slice(start, start + len); - incoming.push(body); -} - -// This is called when parsing of incoming http msg done -function parserOnMessageComplete() { - var parser = this; - var incoming = parser.incoming; - - if (incoming) { - if (incoming.statusCode == 100) { - incoming.headers = {}; - incoming.statusCode = null; - incoming.statusMessage = null; - incoming.started = false; - } else { - incoming.completed = true; - // no more data from incoming, stream will emit 'end' event - incoming.push(null); - } - } -} - -// ------------ LIBCURL PARSER CALLBACKS ----------------- -// Called by libcurl when Request is Done. Finish parser and unref -function cbOnEnd() { - var incoming = this; - var parser = incoming.parser; - if (parser) { - // Unref all links to parser, make parser GCed - parser.finish(); - parser = null; - incoming.parser = null; - } -} - -function cbOnClosed() { - var incoming = this; - var parser = incoming.parser; - var clientRequest = incoming.clientRequest; - - if (incoming.started && !incoming.completed) { - // Socket closed before we emitted 'end' - incoming.on('end', function() { - incoming.emit('close'); - clientRequest.emit('close'); - }); - incoming.push(null); - } else if (!incoming.started) { - incoming.emit('close'); - clientRequest.emit('close'); - // Socket closed before response starts. - var err = new Error('Could Not Start Connection'); - clientRequest.onError(err); - } else { - clientRequest.emit('close'); - } - - if (parser) { - // Unref all links to parser, make parser GCed - parser.finish(); - parser = null; - incoming.parser = null; - } -} - -// Called by libcurl when Request is Done. Finish parser and unref -function cbOnData(chunk) { - var incoming = this; - - if (!incoming) { - return false; - } - - var parser = incoming.parser; - var clientRequest = incoming.clientRequest; - - chunk = new Buffer(chunk); - var ret = parser.execute(chunk); - - if (ret instanceof Error) { - parser.finish(); - // Unref all links to parser, make parser GCed - parser = null; - clientRequest.onError(ret); - return false; - } - return true; -} - -function cbOnError(er) { - var incoming = this; - var clientRequest = incoming.clientRequest; - var err = new Error(er); - clientRequest.onError(err); - clientRequest.abort(true); - incoming.emit('error', err); -} - -function cbOnTimeout() { - var incoming = this; - var clientRequest = incoming.clientRequest; - incoming.emit('timeout'); - if (!incoming.timeoutCallback) { - clientRequest.abort.call(clientRequest, false); - } - incoming.emit('aborted'); -} - -function cbOnSocket() { - var incoming = this; - var clientRequest = incoming.clientRequest; - clientRequest.emit('socket'); -} - -function cbOnWritable() { - var incoming = this; - var clientRequest = incoming.clientRequest; - clientRequest._readyToWrite(); -} diff --git a/src/js/iotjs.js b/src/js/iotjs.js index c466ead..01c029f 100644 --- a/src/js/iotjs.js +++ b/src/js/iotjs.js @@ -129,7 +129,13 @@ } } else { // Exit if there are no handler for uncaught exception. - console.error('uncaughtException: ' + error); + console.error(error); + if (Array.isArray(error.stack)) { + error.stack.forEach(function(line) { + console.log(' at ' + line); + }); + } + process.exit(1); } } @@ -138,24 +144,29 @@ process.exitCode = 0; process._exiting = false; process.emitExit = function(code) { + if (typeof code !== 'number') { + code = 0; + } if (!process._exiting) { process._exiting = true; if (code || code == 0) { process.exitCode = code; } - process.emit('exit', process.exitCode || 0); + process.emit('exit', process.exitCode); } }; process.exit = function(code) { - try { - process.emitExit(code); - } catch (e) { - process.exitCode = 1; - process._onUncaughtException(e); - } finally { - process.doExit(process.exitCode || 0); + if (!process._exiting) { + try { + process.emitExit(code); + } catch (e) { + process.exitCode = 1; + process._onUncaughtException(e); + } finally { + process.doExit(process.exitCode); + } } }; diff --git a/src/js/module.js b/src/js/module.js index e414aa4..3a1620c 100644 --- a/src/js/module.js +++ b/src/js/module.js @@ -17,18 +17,19 @@ var Native = require('native'); var fs = Native.require('fs'); -function iotjs_module_t(id, parent) { +function Module(id, parent) { this.id = id; this.exports = {}; this.filename = null; this.parent = parent; } -module.exports = iotjs_module_t; +module.exports = Module; -iotjs_module_t.cache = {}; -iotjs_module_t.remoteCache = {}; +Module.cache = {}; +// Cache to store not yet compiled remote modules +Module.remoteCache = {}; var cwd; @@ -41,19 +42,33 @@ if (cwd) { moduledirs.push(cwd + '/'); moduledirs.push(cwd + '/iotjs_modules/'); } + if (process.env.HOME) { moduledirs.push(process.env.HOME + '/iotjs_modules/'); } + if (process.env.IOTJS_PATH) { moduledirs.push(process.env.IOTJS_PATH + '/iotjs_modules/'); } +if (process.env.IOTJS_EXTRA_MODULE_PATH) { + var extra_paths = process.env.IOTJS_EXTRA_MODULE_PATH.split(':'); + extra_paths.forEach(function(path) { + if (path.slice(-1) !== '/') { + path += '/'; + } + moduledirs.push(path); + }); +} + +var dynamicloader = Native.require('dynamicloader'); + function tryPath(modulePath, ext) { - return iotjs_module_t.tryPath(modulePath) || - iotjs_module_t.tryPath(modulePath + ext); + return Module.tryPath(modulePath) || + Module.tryPath(modulePath + ext); } -iotjs_module_t.resolveDirectories = function(id, parent) { +Module.resolveDirectories = function(id, parent) { var dirs = moduledirs; if (parent) { if (!parent.dirs) { @@ -65,7 +80,7 @@ iotjs_module_t.resolveDirectories = function(id, parent) { }; -iotjs_module_t.resolveFilepath = function(id, directories) { +Module.resolveFilepath = function(id, directories) { for (var i = 0; i < directories.length; i++) { var dir = directories[i]; var modulePath = dir + id; @@ -74,62 +89,67 @@ iotjs_module_t.resolveFilepath = function(id, directories) { modulePath = process.cwd() + '/' + modulePath; } - if (process.platform === 'tizenrt' && + if ((process.platform === 'tizenrt' || process.platform === 'nuttx') && (modulePath.indexOf('../') != -1 || modulePath.indexOf('./') != -1)) { - modulePath = iotjs_module_t.normalizePath(modulePath); + modulePath = Module.normalizePath(modulePath); } var filepath, ext = '.js'; // id[.ext] - if (filepath = tryPath(modulePath, ext)) { + if ((filepath = tryPath(modulePath, ext))) { return filepath; } // 3. package path id/ var jsonpath = modulePath + '/package.json'; - filepath = iotjs_module_t.tryPath(jsonpath); - if (filepath) { + + if (Module.tryPath(jsonpath)) { var pkgSrc = process.readSource(jsonpath); var pkgMainFile = JSON.parse(pkgSrc).main; // pkgmain[.ext] - if (filepath = tryPath(modulePath + '/' + pkgMainFile, ext)) { + if (pkgMainFile && + (filepath = tryPath(modulePath + '/' + pkgMainFile, ext))) { return filepath; } + } - // index[.ext] as default - if (filepath = tryPath(modulePath + '/index', ext)) { - return filepath; - } + // index[.ext] as default + if ((filepath = tryPath(modulePath + '/index', ext))) { + return filepath; } + // id[.iotjs] + if (dynamicloader && (filepath = tryPath(modulePath, '.iotjs'))) { + return filepath; + } } return false; }; -iotjs_module_t.resolveModPath = function(id, parent) { +Module.resolveModPath = function(id, parent) { if (parent != null && id === parent.id) { return false; } // 0. resolve Directory for lookup - var directories = iotjs_module_t.resolveDirectories(id, parent); + var directories = Module.resolveDirectories(id, parent); - var filepath = iotjs_module_t.resolveFilepath(id, directories); + var filepath = Module.resolveFilepath(id, directories); if (filepath) { - return iotjs_module_t.normalizePath(filepath); + return Module.normalizePath(filepath); } return false; }; -iotjs_module_t.normalizePath = function(path) { +Module.normalizePath = function(path) { var beginning = ''; if (path.indexOf('/') === 0) { beginning = '/'; @@ -157,7 +177,7 @@ iotjs_module_t.normalizePath = function(path) { }; -iotjs_module_t.tryPath = function(path) { +Module.tryPath = function(path) { try { var stats = fs.statSync(path); if (stats && !stats.isDirectory()) { @@ -169,13 +189,19 @@ iotjs_module_t.tryPath = function(path) { }; -iotjs_module_t.load = function(id, parent) { +Module.load = function(id, parent) { if (process.builtin_modules[id]) { return Native.require(id); } - var module = new iotjs_module_t(id, parent); - var modPath = iotjs_module_t.resolveModPath(module.id, module.parent); - var cachedModule = iotjs_module_t.cache[modPath]; + if (Module.remoteCache[id]) { + Module.compileRemoteSource(id, Module.remoteCache[id]); + delete Module.remoteCache[id]; + return Module.cache[id].exports; + } + + var module = new Module(id, parent); + var modPath = Module.resolveModPath(module.id, module.parent); + var cachedModule = Module.cache[modPath]; if (cachedModule) { return cachedModule.exports; @@ -187,23 +213,29 @@ iotjs_module_t.load = function(id, parent) { module.filename = modPath; module.dirs = [modPath.substring(0, modPath.lastIndexOf('/') + 1)]; + Module.cache[modPath] = module; + var ext = modPath.substr(modPath.lastIndexOf('.') + 1); - var source = process.readSource(modPath); + var source; if (ext === 'js') { + source = process.readSource(modPath); module.compile(modPath, source); } else if (ext === 'json') { + source = process.readSource(modPath); module.exports = JSON.parse(source); + } else if (dynamicloader && ext === 'iotjs') { + module.exports = dynamicloader(modPath); } - iotjs_module_t.cache[modPath] = module; + Module.cache[modPath] = module; return module.exports; }; -iotjs_module_t.loadRemote = function(filename, source) { - var module = new iotjs_module_t(filename, null); - var cachedModule = iotjs_module_t.cache[filename]; +Module.compileRemoteSource = function(filename, source) { + var module = new Module(filename, null); + var cachedModule = Module.cache[filename]; if (cachedModule) { return cachedModule.exports; @@ -211,30 +243,33 @@ iotjs_module_t.loadRemote = function(filename, source) { module.filename = filename; module.compile(filename, source); - iotjs_module_t.remoteCache[filename] = module; + Module.cache[filename] = module; return module.exports; }; -iotjs_module_t.prototype.compile = function(filename, source) { +Module.prototype.compile = function(filename, source) { var fn = process.compile(filename, source); fn.call(this.exports, this.exports, this.require.bind(this), this); }; -iotjs_module_t.runMain = function() { +Module.runMain = function() { if (process.debuggerWaitSource) { - var fn = process.debuggerGetSource(); - fn.forEach(function (e) { - iotjs_module_t.loadRemote(e[0], e[1]); + var sources = process.debuggerGetSource(); + sources.forEach(function(rModule) { + Module.remoteCache[rModule[0]] = rModule[1]; }); + // Name of the first module + var fModName = sources[sources.length - 1][0]; + Module.compileRemoteSource(fModName, Module.remoteCache[fModName]); } else { - iotjs_module_t.load(process.argv[1], null); + Module.load(process.argv[1], null); } while (process._onNextTick()); }; -iotjs_module_t.prototype.require = function(id) { - return iotjs_module_t.load(id, this); +Module.prototype.require = function(id) { + return Module.load(id, this); }; diff --git a/src/js/net.js b/src/js/net.js index 35e8f39..e3e7038 100644 --- a/src/js/net.js +++ b/src/js/net.js @@ -18,10 +18,10 @@ var EventEmitter = require('events').EventEmitter; var stream = require('stream'); var util = require('util'); var assert = require('assert'); -var tcp = require('tcp'); +var Tcp = require('tcp'); function createTCP() { - var _tcp = new tcp(); + var _tcp = new Tcp(); return _tcp; } @@ -286,14 +286,14 @@ function connect(socket, ip, port) { } else { socket.destroy(); emitError(socket, new Error('connect failed - status: ' + - tcp.errname(status))); + Tcp.errname(status))); } }; var err = socket._handle.connect(ip, port, afterConnect); if (err) { emitError(socket, new Error('connect failed - status: ' + - tcp.errname(err))); + Tcp.errname(err))); } } @@ -434,7 +434,7 @@ function onSocketFinish() { return self.destroy(); } else { // Readable stream alive, shutdown only outgoing stream. - var err = self._handle.shutdown(function() { + self._handle.shutdown(function() { if (self._readableState.ended) { self.destroy(); } @@ -522,7 +522,7 @@ Server.prototype.listen = function() { self._handle.createTCP = createTCP; self._handle.owner = self; - var err = self._handle.listen(backlog); + err = self._handle.listen(backlog); if (err) { self._handle.close(); @@ -594,7 +594,7 @@ function onconnection(status, clientHandle) { var server = this.owner; if (status) { - server.emit('error', new Error('accept error: ' + tcp.errname(status))); + server.emit('error', new Error('accept error: ' + Tcp.errname(status))); return; } diff --git a/src/js/pwm.js b/src/js/pwm.js index 0fb2fcb..cf159ef 100644 --- a/src/js/pwm.js +++ b/src/js/pwm.js @@ -22,7 +22,7 @@ var pwm = { }, openSync: function(config) { return new native(config); - } + }, }; module.exports = pwm; diff --git a/src/js/spi.js b/src/js/spi.js index cbbff4a..f7da851 100644 --- a/src/js/spi.js +++ b/src/js/spi.js @@ -25,7 +25,7 @@ var spi = { }, MODE: native.MODE, CHIPSELECT: native.CHIPSELECT, - BITORDER: native.BITORDER + BITORDER: native.BITORDER, }; module.exports = spi; diff --git a/src/js/stream.js b/src/js/stream.js index bc04b5a..5bf2a52 100644 --- a/src/js/stream.js +++ b/src/js/stream.js @@ -14,17 +14,15 @@ */ -var eventEmitter = require('events').EventEmitter; +var StreamInternal = require('stream_internal'); var util = require('util'); function Stream() { - eventEmitter.call(this); + StreamInternal.call(this); } - -util.inherits(Stream, eventEmitter); - +util.inherits(Stream, StreamInternal); exports.Stream = Stream; diff --git a/src/js/stream_duplex.js b/src/js/stream_duplex.js index 7beb75c..a147a61 100644 --- a/src/js/stream_duplex.js +++ b/src/js/stream_duplex.js @@ -25,6 +25,8 @@ function Duplex(options) { } Readable.call(this, options); + options = options || {}; + options._isDuplex = true; Writable.call(this, options); } diff --git a/src/js/stream_internal.js b/src/js/stream_internal.js new file mode 100644 index 0000000..db3805c --- /dev/null +++ b/src/js/stream_internal.js @@ -0,0 +1,27 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + + +var eventEmitter = require('events').EventEmitter; +var util = require('util'); + + +function Stream() { + eventEmitter.call(this); +} + +util.inherits(Stream, eventEmitter); + +module.exports = Stream; diff --git a/src/js/stream_readable.js b/src/js/stream_readable.js index dd384fc..eb53461 100644 --- a/src/js/stream_readable.js +++ b/src/js/stream_readable.js @@ -14,9 +14,8 @@ */ -var Stream = require('stream').Stream; +var Stream = require('stream_internal'); var util = require('util'); -var assert = require('assert'); function ReadableState(options) { @@ -70,10 +69,6 @@ Readable.prototype.read = function(n) { res = null; } - if (state.ended && state.length == 0) { - emitEnd(this); - } - return res; }; @@ -106,9 +101,7 @@ Readable.prototype.resume = function() { var state = this._readableState; if (!state.flowing) { state.flowing = true; - if (state.length > 0) { - emitData(this, readBuffer(this)); - } + this.read(); } return this; }; @@ -159,6 +152,7 @@ function readBuffer(stream, n) { res = Buffer.concat(state.buffer); state.buffer = []; state.length = 0; + emitData(stream, res); } else { throw new Error('not implemented'); } @@ -183,8 +177,9 @@ function emitEnd(stream) { function emitData(stream, data) { var state = stream._readableState; - assert.equal(readBuffer(stream), null); - stream.emit('data', data); + if (state.buffer.length === 0 || state.length === 0) { + stream.emit('data', data); + } if (state.ended && state.length == 0) { emitEnd(stream); diff --git a/src/js/stream_writable.js b/src/js/stream_writable.js index fcb8966..cdefbf4 100644 --- a/src/js/stream_writable.js +++ b/src/js/stream_writable.js @@ -14,10 +14,8 @@ */ -var stream = require('stream'); +var Stream = require('stream_internal'); var util = require('util'); -var Stream = stream.Stream; -var Duplex = stream.Duplex; var defaultHighWaterMark = 128; @@ -36,7 +34,7 @@ function WritableState(options) { this.length = 0; // high water mark. - // The point where write() starts retuning false. + // The point where write() starts returning false. this.highWaterMark = (options && util.isNumber(options.highWaterMark)) ? options.highWaterMark : defaultHighWaterMark; @@ -62,7 +60,7 @@ function WritableState(options) { function Writable(options) { - if (!(this instanceof Writable) && !(this instanceof stream.Duplex)) { + if (!(this instanceof Writable) && options._isDuplex !== true) { return new Writable(options); } @@ -102,7 +100,7 @@ Writable.prototype.write = function(chunk, callback) { // This function object never to be called. concrete stream should override // this method. -Writable.prototype._write = function(chunk, callback, onwrite) { +Writable.prototype._write = function(/* chunk, callback, onwrite */) { throw new Error('unreachable'); }; diff --git a/src/js/tizen.js b/src/js/tizen.js new file mode 100644 index 0000000..566011c --- /dev/null +++ b/src/js/tizen.js @@ -0,0 +1,145 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +var Bridge = require('bridge'); +var EventEmitter = require('events').EventEmitter; +var util = require('util'); + +var APP_CONTROL_EVENT_TYPE = 'appControl'; + +var BUNDLE_KEY_OPERATION = '__APP_SVC_OP_TYPE__'; +var BUNDLE_KEY_URI = '__APP_SVC_URI__'; +var BUNDLE_KEY_MIME = '__APP_SVC_MIME_TYPE__'; +var BUNDLE_KEY_LAUNCH_MODE = '__APP_SVC_LAUNCH_MODE__'; +var BUNDLE_KEY_CATEGORY = '__APP_SVC_CATEGORY__'; +var BUNDLE_KEY_PACKAGE = '__APP_SVC_PKG_NAME__'; + +var bridge = new Bridge(native.MODULE_NAME); + +var startsWith = function(searchString, position) { + position = position || 0; + return this.substr(position, searchString.length) === searchString; +}; + + +function ApplicationControl(bundle) { + if (!util.isObject(bundle)) { + return this; + } + + this.operation = bundle[BUNDLE_KEY_OPERATION]; + this.uri = bundle[BUNDLE_KEY_URI]; + this.mime = bundle[BUNDLE_KEY_MIME]; + this.launch_mode = bundle[BUNDLE_KEY_LAUNCH_MODE]; + this.category = bundle[BUNDLE_KEY_CATEGORY]; + this.app_id = bundle[BUNDLE_KEY_PACKAGE]; + + var extra_data = {}; + for (var prop in bundle) { + if (bundle.hasOwnProperty(prop) && !startsWith.call(prop, '__')) { + extra_data[prop] = bundle[prop]; + } + } + this.extra_data = Object.keys(extra_data).length ? extra_data : undefined; + + return this; +} + + +function Bundle(appcontrol) { + if (!util.isObject(appcontrol)) { + return this; + } + + var bundle = this; + + if (util.isString(appcontrol.operation)) { + bundle[BUNDLE_KEY_OPERATION] = appcontrol.operation; + } + + if (util.isString(appcontrol.uri)) { + bundle[BUNDLE_KEY_URI] = appcontrol.uri; + } + + if (util.isString(appcontrol.mime)) { + bundle[BUNDLE_KEY_MIME] = appcontrol.mime; + } + + if (util.isString(appcontrol.launch_mode)) { + if (appcontrol.launch_mode === 'group' || + appcontrol.launch_mode === 'single') { + bundle[BUNDLE_KEY_LAUNCH_MODE] = appcontrol.launch_mode; + } + } + + if (util.isString(appcontrol.category)) { + bundle[BUNDLE_KEY_CATEGORY] = appcontrol.category; + } + + if (util.isString(appcontrol.app_id)) { + bundle[BUNDLE_KEY_PACKAGE] = appcontrol.app_id; + } + + var extra_data = appcontrol.extra_data; + if (util.isObject(extra_data)) { + for (var prop in extra_data) { + if (extra_data.hasOwnProperty(prop)) { + // a bundle is a dictionary which consists of key and value pairs + bundle[prop] = extra_data[prop].toString(); + } + } + } + + return this; +} + + +function on(type, listener) { + var callback = listener; + + if (type === APP_CONTROL_EVENT_TYPE) { + // replace callback for application control + callback = function(msg) { + if (util.isString(msg)) { + try { + var json = JSON.parse(msg); + listener(new ApplicationControl(json)); + } catch (e) { + return; // ignore msg. data should be a json string + } + } + }; + } + + return EventEmitter.prototype.on.call(this, type, callback); +} + + +function launchAppControl(option) { + var bundle = new Bundle(option); + return 'OK' === bridge.sendSync('launchAppControl', JSON.stringify(bundle)); +} + + +var getResPath = function() { + return this.bridge.sendSync('getResPath', ''); +}; + + +module.exports = util.mixin(native, EventEmitter.prototype, { + launchAppControl: launchAppControl, + getResPath: getResPath, + on: on, +}); diff --git a/src/js/tls.js b/src/js/tls.js new file mode 100644 index 0000000..47341f5 --- /dev/null +++ b/src/js/tls.js @@ -0,0 +1,270 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +var net = require('net'); +var util = require('util'); +var EventEmitter = require('events').EventEmitter; + +function TLSSocket(socket, options) { + if (!(this instanceof TLSSocket)) { + return new TLSSocket(socket, options); + } + + if ('_tlsSocket' in socket) { + throw Error('Socket already bound'); + } + + this._socket = socket; + socket._tlsSocket = this; + + EventEmitter.call(this); + + this.authorized = false; + + this._socket.on('connect', this.onconnect); + this._socket.on('data', this.ondata); + this._socket.on('error', this.onerror); + this._socket.on('close', this.onclose); + this._socket.on('finish', this.onfinish); + this._socket.on('end', this.onend); + + // Native handle + var secureContext = options.secureContext; + if (!secureContext) { + secureContext = createSecureContext(options); + } + + native.TlsInit(this, options, secureContext); + this._socketState = socket._socketState; +} +util.inherits(TLSSocket, EventEmitter); + +TLSSocket.prototype._read = native.read; +TLSSocket.prototype._write = native.write; +TLSSocket.prototype._connect = native.connect; + +TLSSocket.prototype.connect = function(options, callback) { + this._connect(options.servername || options.host || 'localhost'); + + if (util.isFunction(callback)) { + this.on('secureConnect', callback); + } + + this._socket.connect(options); +}; + +TLSSocket.prototype.write = function(data, callback) { + if (!Buffer.isBuffer(data)) { + data = new Buffer(data); + } + + data = this._write(data); + return this._socket.write(data, callback); +}; + +TLSSocket.prototype.pause = function() { + this._socket.pause(); +}; + +TLSSocket.prototype.resume = function() { + this._socket.resume(); +}; + +TLSSocket.prototype.end = function(data, callback) { + if (data) { + if (!Buffer.isBuffer(data)) { + data = new Buffer(data); + } + data = this._write(data, true); + } else { + data = this._write(null, true); + } + + this._socket.end(data, callback); +}; + +TLSSocket.prototype.destroy = function() { + this._socket.destroy(); +}; + +TLSSocket.prototype.destroySoon = function() { + this._socket.destroySoon(); +}; + +TLSSocket.prototype.onconnect = function() { + var self = this._tlsSocket; + self._read(null); +}; + +TLSSocket.prototype.encrypted = function() { + return true; +}; + +TLSSocket.prototype.address = function() { + return this._socket.address(); +}; + +TLSSocket.prototype.localAddress = function() { + return this._socket.address().address; +}; + +TLSSocket.prototype.setTimeout = function(msecs, callback) { + return this._socket.setTimeout(msecs, callback); +}; + +TLSSocket.prototype.ondata = function(data) { + var self = this._tlsSocket; + self._read(data); +}; + +TLSSocket.prototype.onerror = function(error) { + this._tlsSocket.emit('error', error); +}; + +TLSSocket.prototype.onclose = function() { + this._tlsSocket.emit('close'); +}; + +TLSSocket.prototype.onfinish = function() { + this._tlsSocket.emit('finish'); +}; + +TLSSocket.prototype.onend = function() { + this._tlsSocket.emit('end'); +}; + +TLSSocket.prototype.onwrite = function(data) { + return this._socket.write(data); +}; + +TLSSocket.prototype.onread = function(chunk) { + this.emit('data', chunk); +}; + +TLSSocket.prototype.onhandshakedone = function(error, authorized) { + this.authorized = authorized; + + var server = this._server; + + if (error) { + error = Error('handshake failed'); + + if (server) { + server.emit('tlsClientError', error, this); + } else { + this.emit('error', error); + } + this.end(); + return; + } + + if (server) { + server.emit('secureConnection', this); + } else { + this.emit('secureConnect'); + } +}; + +function tlsConnectionListener(rawSocket) { + var tlsSocket = new TLSSocket(rawSocket, { + isServer: true, + secureContext: this._secureContext, + }); + + tlsSocket._server = this; +} + +function Server(options, listener) { + if (!(this instanceof Server)) { + return new Server(options, listener); + } + + this._secureContext = createSecureContext(options); + + // constructor call + net.Server.call(this, options, tlsConnectionListener); + + if (listener) { + this.on('secureConnection', listener); + } +} +util.inherits(Server, net.Server); + +function createSecureContext(options) { + return new native.TlsContext(options); +} + +function createServer(options, secureConnectionListener) { + return new Server(options, secureConnectionListener); +} + +function connect(arg0, arg1, arg2, callback) { + var options; + var tlsSocket; + if (typeof arg0 == 'object') { + options = Object.create(arg0, { + isServer: { value: false, enumerable: true }, + }); + options.host = options.host || 'localhost'; + options.port = options.port || 443; + options.rejectUnauthorized = options.rejectUnauthorized || false; + callback = arg1; + } else if (typeof arg0 == 'number') { + if (typeof arg1 == 'string') { + if (typeof arg2 == 'object') { + options = Object.create(arg2, { + isServer: { value: false, enumerable: true }, + }); + options.port = arg0; + options.host = arg1; + options.rejectUnauthorized = options.rejectUnauthorized || false; + } else { + options = { + isServer: false, + rejectUnauthorized: false, + port: arg0, + host: arg1, + }; + callback = arg2; + } + } else if (typeof arg1 == 'object') { + options = Object.create(arg1, { + isServer: { value: false, enumerable: true }, + }); + options.port = arg0; + options.host = options.host || 'localhost'; + options.rejectUnauthorized = options.rejectUnauthorized || false; + callback = arg2; + } else { + options = { + isServer: false, + rejectUnauthorized: false, + host: 'localhost', + port: arg0, + }; + callback = arg1; + } + } + tlsSocket = new TLSSocket(new net.Socket(), options); + tlsSocket.connect(options, callback); + + return tlsSocket; +} + +exports.TLSSocket = TLSSocket; +exports.Server = Server; +exports.createSecureContext = createSecureContext; +exports.createServer = createServer; +exports.connect = connect; diff --git a/src/js/uart.js b/src/js/uart.js index 4493553..42579ab 100644 --- a/src/js/uart.js +++ b/src/js/uart.js @@ -14,21 +14,18 @@ */ var EventEmitter = require('events').EventEmitter; +var util = require('util'); + +util.mixin(native.prototype, EventEmitter.prototype); var uart = { open: function(config, callback) { - for(var prop in EventEmitter.prototype) { - native.prototype[prop] = EventEmitter.prototype[prop]; - } var uartPort = new native(config, function(err) { callback(err); }); return uartPort; }, openSync: function(config) { - for(var prop in EventEmitter.prototype) { - native.prototype[prop] = EventEmitter.prototype[prop]; - } return new native(config); }, }; diff --git a/src/js/util.js b/src/js/util.js index f59eb2d..1a5fe07 100644 --- a/src/js/util.js +++ b/src/js/util.js @@ -74,16 +74,36 @@ function inherits(ctor, superCtor) { } +function mixin(target) { + if (isNullOrUndefined(target)) { + throw new TypeError('target cannot be null or undefined'); + } + + for (var i = 1; i < arguments.length; ++i) { + var source = arguments[i]; + if (!isNullOrUndefined(source)) { + for (var prop in source) { + if (source.hasOwnProperty(prop)) { + target[prop] = source[prop]; + } + } + } + } + + return target; +} + function format(s) { + var i; if (!isString(s)) { var arrs = []; - for (var i = 0; i < arguments.length; ++i) { + for (i = 0; i < arguments.length; ++i) { arrs.push(formatValue(arguments[i])); } return arrs.join(' '); } - var i = 1; + i = 1; var args = arguments; var arg_string; var str = ''; @@ -217,4 +237,5 @@ exports.exceptionWithHostPort = exceptionWithHostPort; exports.errnoException = errnoException; exports.stringToNumber = stringToNumber; exports.inherits = inherits; +exports.mixin = mixin; exports.format = format; diff --git a/src/modules.json b/src/modules.json index 0eb22d8..f11a667 100644 --- a/src/modules.json +++ b/src/modules.json @@ -1,7 +1,7 @@ { "modules": { "iotjs_basic_modules": { - "require": ["assert", "dns", "http", "net", "stream", "testdriver"] + "require": ["assert", "dns", "http", "net", "stream"] }, "iotjs_core_modules": { "require": ["buffer", "console", "events", "fs", "module", "process", @@ -22,7 +22,8 @@ "native_files": ["modules/iotjs_module_adc.c"] } }, - "native_files": ["modules/iotjs_module_adc.c"], + "native_files": ["modules/iotjs_module_adc.c", + "modules/iotjs_module_periph_common.c"], "init": "InitAdc", "js_file": "js/adc.js" }, @@ -133,6 +134,11 @@ "js_file": "js/dns.js", "require": ["util"] }, + "dynamicloader": { + "native_files": ["modules/iotjs_module_dynamicloader.c"], + "init": "InitDynamicloader", + "external_libs": ["dl"] + }, "events": { "js_file": "js/events.js", "require": ["util"] @@ -158,22 +164,23 @@ "native_files": ["modules/tizenrt/iotjs_module_gpio-tizenrt.c"] } }, - "native_files": ["modules/iotjs_module_gpio.c"], + "native_files": ["modules/iotjs_module_gpio.c", + "modules/iotjs_module_periph_common.c"], "init": "InitGpio", "js_file": "js/gpio.js" }, "http": { "js_file": "js/http.js", "require": ["http_client", "http_common", "http_incoming", - "http_outgoing", "http_server", "httpparser"] + "http_outgoing", "http_server", "http_parser"] }, "http_client": { "js_file": "js/http_client.js", - "require": ["http_common", "http_outgoing", "httpparser", "net", "util"] + "require": ["http_common", "http_outgoing", "http_parser", "net", "util"] }, "http_common": { "js_file": "js/http_common.js", - "require": ["http_incoming", "httpparser"] + "require": ["http_incoming", "http_parser"] }, "http_incoming": { "js_file": "js/http_incoming.js", @@ -187,26 +194,13 @@ "js_file": "js/http_server.js", "require": ["http_common", "http_outgoing", "net", "util"] }, - "httpparser": { - "native_files": ["modules/iotjs_module_httpparser.c"], - "init": "InitHttpparser" + "http_parser": { + "native_files": ["modules/iotjs_module_http_parser.c"], + "init": "InitHttpParser" }, "https": { "js_file": "js/https.js", - "require": ["https_client", "https_incoming", "https_native"], - "external_libs": ["curl"] - }, - "https_client": { - "js_file": "js/https_client.js", - "require": ["buffer", "https_incoming", "stream", "util"] - }, - "https_incoming": { - "js_file": "js/https_incoming.js", - "require": ["buffer", "stream", "util"] - }, - "https_native": { - "native_files": ["modules/iotjs_module_https.c"], - "init": "InitHttps" + "require": ["http_client", "http_parser", "http_server", "net", "tls"] }, "i2c": { "platforms": { @@ -223,11 +217,20 @@ "native_files": ["modules/tizenrt/iotjs_module_i2c-tizenrt.c"] } }, - "native_files": ["modules/iotjs_module_i2c.c"], + "native_files": ["modules/iotjs_module_i2c.c", + "modules/iotjs_module_periph_common.c"], "init": "InitI2c", "js_file": "js/i2c.js" }, "module": { + "platforms": { + "linux": { + "require": ["dynamicloader"] + }, + "tizen": { + "require": ["dynamicloader"] + } + }, "js_file": "js/module.js", "require": ["fs"] }, @@ -247,11 +250,15 @@ "nuttx": { "native_files": ["modules/nuttx/iotjs_module_pwm-nuttx.c"] }, + "tizen": { + "native_files": ["modules/tizen/iotjs_module_pwm-tizen.c"] + }, "tizenrt": { "native_files": ["modules/tizenrt/iotjs_module_pwm-tizenrt.c"] } }, - "native_files": ["modules/iotjs_module_pwm.c"], + "native_files": ["modules/iotjs_module_pwm.c", + "modules/iotjs_module_periph_common.c"], "init": "InitPwm", "js_file": "js/pwm.js" }, @@ -263,11 +270,15 @@ "nuttx": { "native_files": ["modules/nuttx/iotjs_module_spi-nuttx.c"] }, + "tizen": { + "native_files": ["modules/tizen/iotjs_module_spi-tizen.c"] + }, "tizenrt": { "native_files": ["modules/tizenrt/iotjs_module_spi-tizenrt.c"] } }, - "native_files": ["modules/iotjs_module_spi.c"], + "native_files": ["modules/iotjs_module_spi.c", + "modules/iotjs_module_periph_common.c"], "init": "InitSpi", "js_file": "js/spi.js" }, @@ -282,13 +293,17 @@ }, "stream": { "js_file": "js/stream.js", - "require": ["events", "stream_duplex", "stream_readable", + "require": ["stream_duplex", "stream_internal", "stream_readable", "stream_writable", "util"] }, "stream_duplex": { "js_file": "js/stream_duplex.js", "require": ["stream_readable", "stream_writable", "util"] }, + "stream_internal": { + "js_file": "js/stream_internal.js", + "require": ["events", "util"] + }, "stream_readable": { "js_file": "js/stream_readable.js", "require": ["assert", "util"] @@ -301,17 +316,19 @@ "native_files": ["modules/iotjs_module_tcp.c"], "init": "InitTcp" }, - "testdriver": { - "native_files": ["modules/iotjs_module_testdriver.c"], - "init": "InitTestdriver", - "require": ["assert"] - }, "timers": { "native_files": ["modules/iotjs_module_timer.c"], "init": "InitTimer", "js_file": "js/timers.js", "require": ["util"] }, + "tls": { + "native_files": ["modules/iotjs_module_tls.c"], + "init": "InitTls", + "js_file": "js/tls.js", + "cmakefile": "../cmake/mbedtls.cmake", + "require": ["net", "util"] + }, "uart": { "platforms": { "linux": { @@ -320,11 +337,15 @@ "nuttx": { "native_files": ["modules/nuttx/iotjs_module_uart-nuttx.c"] }, + "tizen": { + "native_files": ["modules/tizen/iotjs_module_uart-tizen.c"] + }, "tizenrt": { "native_files": ["modules/tizenrt/iotjs_module_uart-tizenrt.c"] } }, - "native_files": ["modules/iotjs_module_uart.c"], + "native_files": ["modules/iotjs_module_uart.c", + "modules/iotjs_module_periph_common.c"], "init": "InitUart", "js_file": "js/uart.js", "require": ["events"] @@ -335,6 +356,22 @@ }, "util": { "js_file": "js/util.js" + }, + "bridge": { + "native_files": ["modules/iotjs_module_bridge.c"], + "init": "InitBridge", + "js_file": "js/bridge.js" + }, + "tizen": { + "platforms": { + "tizen": { + "native_files": ["modules/tizen/iotjs_module_tizen-tizen.c"] + } + }, + "native_files": ["modules/iotjs_module_tizen.c"], + "init": "InitTizen", + "js_file": "js/tizen.js", + "require": ["bridge", "events", "util"] } } } diff --git a/src/modules/iotjs_module_adc.c b/src/modules/iotjs_module_adc.c index 07377be..533941c 100644 --- a/src/modules/iotjs_module_adc.c +++ b/src/modules/iotjs_module_adc.c @@ -17,145 +17,36 @@ #include "iotjs_module_adc.h" -static JNativeInfoType this_module_native_info = {.free_cb = NULL }; +IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(adc); +IOTJS_DEFINE_PERIPH_CREATE_FUNCTION(adc); -static iotjs_adc_t* adc_create(const jerry_value_t jadc) { - iotjs_adc_t* adc = IOTJS_ALLOC(iotjs_adc_t); - iotjs_adc_create_platform_data(adc); - adc->jobject = jadc; - jerry_set_object_native_pointer(jadc, adc, &this_module_native_info); - - return adc; -} - - -static void adc_destroy(iotjs_adc_t* adc) { +static void iotjs_adc_destroy(iotjs_adc_t* adc) { iotjs_adc_destroy_platform_data(adc->platform_data); IOTJS_RELEASE(adc); } - -static iotjs_adc_reqwrap_t* adc_reqwrap_create(const jerry_value_t jcallback, - iotjs_adc_t* adc, AdcOp op) { - iotjs_adc_reqwrap_t* adc_reqwrap = IOTJS_ALLOC(iotjs_adc_reqwrap_t); - - iotjs_reqwrap_initialize(&adc_reqwrap->reqwrap, jcallback, - (uv_req_t*)&adc_reqwrap->req); - - adc_reqwrap->req_data.op = op; - adc_reqwrap->adc_data = adc; - return adc_reqwrap; -} - -static void adc_reqwrap_destroy(iotjs_adc_reqwrap_t* adc_reqwrap) { - iotjs_reqwrap_destroy(&adc_reqwrap->reqwrap); - IOTJS_RELEASE(adc_reqwrap); -} - - static void adc_worker(uv_work_t* work_req) { - iotjs_adc_reqwrap_t* req_wrap = - (iotjs_adc_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)work_req)); - iotjs_adc_reqdata_t* req_data = &req_wrap->req_data; - iotjs_adc_t* adc = req_wrap->adc_data; + iotjs_periph_reqwrap_t* req_wrap = + (iotjs_periph_reqwrap_t*)(iotjs_reqwrap_from_request( + (uv_req_t*)work_req)); + iotjs_adc_t* adc = (iotjs_adc_t*)req_wrap->data; - switch (req_data->op) { + switch (req_wrap->op) { case kAdcOpOpen: - req_data->result = iotjs_adc_open(adc); + req_wrap->result = iotjs_adc_open(adc); break; case kAdcOpRead: - req_data->result = iotjs_adc_read(adc); + req_wrap->result = iotjs_adc_read(adc); break; case kAdcOpClose: - req_data->result = iotjs_adc_close(adc); + req_wrap->result = iotjs_adc_close(adc); break; default: IOTJS_ASSERT(!"Invalid Adc Operation"); } } - -static const char* adc_error_string(uint8_t op) { - switch (op) { - case kAdcOpClose: - return "Close error, cannot close ADC"; - case kAdcOpOpen: - return "Open error, cannot open ADC"; - case kAdcOpRead: - return "Read error, cannot read ADC"; - default: - return "Unknown ADC error"; - } -} - - -static void adc_after_worker(uv_work_t* work_req, int status) { - iotjs_adc_reqwrap_t* req_wrap = - (iotjs_adc_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)work_req)); - iotjs_adc_reqdata_t* req_data = &req_wrap->req_data; - - iotjs_jargs_t jargs = iotjs_jargs_create(2); - bool result = req_data->result; - - if (status) { - iotjs_jargs_append_error(&jargs, "ADC System Error"); - } else { - switch (req_data->op) { - case kAdcOpOpen: - if (!result) { - iotjs_jargs_append_error(&jargs, adc_error_string(req_data->op)); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - case kAdcOpRead: - if (!result) { - iotjs_jargs_append_error(&jargs, adc_error_string(req_data->op)); - } else { - iotjs_adc_t* adc = req_wrap->adc_data; - - iotjs_jargs_append_null(&jargs); - iotjs_jargs_append_number(&jargs, adc->value); - } - break; - case kAdcOpClose: - if (!result) { - iotjs_jargs_append_error(&jargs, adc_error_string(req_data->op)); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - default: { - IOTJS_ASSERT(!"ADC after worker failed"); - break; - } - } - } - - const jerry_value_t jcallback = iotjs_reqwrap_jcallback(&req_wrap->reqwrap); - if (jerry_value_is_function(jcallback)) { - iotjs_make_callback(jcallback, jerry_create_undefined(), &jargs); - } - - if (req_data->op == kAdcOpClose) { - adc_destroy(req_wrap->adc_data); - } - - iotjs_jargs_destroy(&jargs); - adc_reqwrap_destroy(req_wrap); -} - - -#define ADC_CALL_ASYNC(op, jcallback) \ - do { \ - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); \ - iotjs_adc_reqwrap_t* req_wrap = adc_reqwrap_create(jcallback, adc, op); \ - uv_work_t* req = &req_wrap->req; \ - uv_queue_work(loop, req, adc_worker, adc_after_worker); \ - } while (0) - - JS_FUNCTION(AdcCons) { DJS_CHECK_THIS(); DJS_CHECK_ARGS(1, object); @@ -181,9 +72,9 @@ JS_FUNCTION(AdcCons) { // If the callback doesn't exist, it is completed synchronously. // Otherwise, it will be executed asynchronously. if (!jerry_value_is_null(jcallback)) { - ADC_CALL_ASYNC(kAdcOpOpen, jcallback); + iotjs_periph_call_async(adc, jcallback, kAdcOpOpen, adc_worker); } else if (!iotjs_adc_open(adc)) { - return JS_CREATE_ERROR(COMMON, adc_error_string(kAdcOpOpen)); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kAdcOpOpen)); } return jerry_create_undefined(); @@ -194,7 +85,8 @@ JS_FUNCTION(Read) { JS_DECLARE_THIS_PTR(adc, adc); DJS_CHECK_ARG_IF_EXIST(0, function); - ADC_CALL_ASYNC(kAdcOpRead, JS_GET_ARG_IF_EXIST(0, function)); + iotjs_periph_call_async(adc, JS_GET_ARG_IF_EXIST(0, function), kAdcOpRead, + adc_worker); return jerry_create_undefined(); } @@ -203,7 +95,7 @@ JS_FUNCTION(ReadSync) { JS_DECLARE_THIS_PTR(adc, adc); if (!iotjs_adc_read(adc)) { - return JS_CREATE_ERROR(COMMON, adc_error_string(kAdcOpRead)); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kAdcOpRead)); } return jerry_create_number(adc->value); @@ -213,7 +105,8 @@ JS_FUNCTION(Close) { JS_DECLARE_THIS_PTR(adc, adc); DJS_CHECK_ARG_IF_EXIST(0, function); - ADC_CALL_ASYNC(kAdcOpClose, JS_GET_ARG_IF_EXIST(0, function)); + iotjs_periph_call_async(adc, JS_GET_ARG_IF_EXIST(0, function), kAdcOpClose, + adc_worker); return jerry_create_undefined(); } @@ -222,9 +115,8 @@ JS_FUNCTION(CloseSync) { JS_DECLARE_THIS_PTR(adc, adc); bool ret = iotjs_adc_close(adc); - adc_destroy(adc); if (!ret) { - return JS_CREATE_ERROR(COMMON, adc_error_string(kAdcOpClose)); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kAdcOpClose)); } return jerry_create_undefined(); diff --git a/src/modules/iotjs_module_adc.h b/src/modules/iotjs_module_adc.h index 9a49344..16020c8 100644 --- a/src/modules/iotjs_module_adc.h +++ b/src/modules/iotjs_module_adc.h @@ -18,15 +18,9 @@ #define IOTJS_MODULE_ADC_H #include "iotjs_def.h" +#include "iotjs_module_periph_common.h" #include "iotjs_reqwrap.h" - -typedef enum { - kAdcOpOpen, - kAdcOpRead, - kAdcOpClose, -} AdcOp; - // Forward declaration of platform data. These are only used by platform code. // Generic ADC module never dereferences platform data pointer. typedef struct iotjs_adc_platform_data_s iotjs_adc_platform_data_t; @@ -37,21 +31,6 @@ typedef struct { int32_t value; } iotjs_adc_t; - -typedef struct { - bool result; - AdcOp op; -} iotjs_adc_reqdata_t; - - -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_work_t req; - iotjs_adc_reqdata_t req_data; - iotjs_adc_t* adc_data; -} iotjs_adc_reqwrap_t; - - bool iotjs_adc_read(iotjs_adc_t* adc); bool iotjs_adc_close(iotjs_adc_t* adc); bool iotjs_adc_open(iotjs_adc_t* adc); diff --git a/src/modules/iotjs_module_bridge.c b/src/modules/iotjs_module_bridge.c new file mode 100644 index 0000000..909e8d4 --- /dev/null +++ b/src/modules/iotjs_module_bridge.c @@ -0,0 +1,414 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 "iotjs_def.h" +#include "iotjs_module_bridge.h" +#include "iotjs_reqwrap.h" +#include + +typedef enum { + CALL_STATUS_ERROR = 0, + CALL_STATUS_INIT, + CALL_STATUS_CALLED, + CALL_STATUS_SETMSG, +} iotjs_bridge_status_t; + +typedef struct _iotjs_bridge_object_t iotjs_bridge_object_t; +typedef struct { + jerry_value_t jobject; + jerry_value_t jcallback; + uv_mutex_t call_lock; + uv_work_t req; + uv_async_t* async; + iotjs_string_t module; + iotjs_string_t command; + iotjs_string_t message; + iotjs_string_t ret_msg; + iotjs_bridge_status_t status; + iotjs_bridge_object_t* bridgeobj; +} iotjs_bridge_call_t; + +struct _iotjs_bridge_object_t { + jerry_value_t jobject; + iotjs_bridge_call_t** calls; + size_t calls_alloc; // allocated size of calls +}; + +typedef struct { + char* module_name; + iotjs_bridge_func callback; +} relation_info_t; + +static relation_info_t* g_module_list = 0; +static unsigned int g_module_count = 0; + +IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(bridge_object); + +static unsigned int iotjs_bridge_init() { + if (g_module_list == 0) { + g_module_list = (relation_info_t*)iotjs_buffer_allocate( + sizeof(relation_info_t) * iotjs_module_count); + IOTJS_ASSERT(g_module_list); + } + return iotjs_module_count; +} + +int iotjs_bridge_register(char* module_name, iotjs_bridge_func callback) { + int empty_slot = -1; + iotjs_bridge_init(); + for (int i = 0; i < (int)iotjs_module_count; i++) { + if (g_module_list[i].module_name == 0) { + if (empty_slot == -1) + empty_slot = i; + } else { + if (strncmp(g_module_list[i].module_name, module_name, + strlen(module_name)) == 0) { + return i; + } + } + } + if (empty_slot != -1) { + g_module_list[empty_slot].module_name = + iotjs_buffer_allocate(strlen(module_name) + 1); + IOTJS_ASSERT(g_module_list[empty_slot].module_name); + strncpy(g_module_list[empty_slot].module_name, module_name, + strlen(module_name)); + g_module_list[empty_slot].callback = callback; + g_module_count++; + } + return empty_slot; +} + +static int iotjs_bridge_call(const char* module_name, const char* command, + const char* message, void* handle) { + int ret = -1; + for (int i = 0; i < (int)iotjs_module_count; i++) { + if (g_module_list[i].module_name != 0) { + if (strncmp(g_module_list[i].module_name, module_name, + strlen(module_name) + 1) == 0) { + g_module_list[i].callback(command, message, handle); + ret = 0; + break; + } + } + } + return ret; +} + +void iotjs_bridge_set_err(void* handle, char* err) { + iotjs_bridge_call_t* bridgecall = (iotjs_bridge_call_t*)handle; + IOTJS_ASSERT(iotjs_string_is_empty(&bridgecall->ret_msg)); + + if (err == NULL) { + err = "internal error"; + } + if (!jerry_value_is_undefined(bridgecall->jcallback)) { + uv_mutex_lock(&bridgecall->call_lock); + } + bridgecall->ret_msg = iotjs_string_create_with_size(err, strlen(err) + 1); + bridgecall->status = CALL_STATUS_ERROR; + + if (bridgecall->async != NULL) { + IOTJS_ASSERT(bridgecall->async->data == bridgecall); + uv_async_send(bridgecall->async); + } + if (!jerry_value_is_undefined(bridgecall->jcallback)) { + uv_mutex_unlock(&bridgecall->call_lock); + } +} + +void iotjs_bridge_set_msg(void* handle, char* msg) { + iotjs_bridge_call_t* bridgecall = (iotjs_bridge_call_t*)handle; + IOTJS_ASSERT(iotjs_string_is_empty(&bridgecall->ret_msg)); + size_t size = 0; + if (msg == NULL) { + msg = ""; + } else { + size = strlen(msg) + 1; + } + if (size > MAX_RETURN_MESSAGE) { + iotjs_bridge_set_err(handle, "The message exceeds the maximum"); + } else { + if (!jerry_value_is_undefined(bridgecall->jcallback)) { + uv_mutex_lock(&bridgecall->call_lock); + } + bridgecall->ret_msg = iotjs_string_create_with_size(msg, size); + bridgecall->status = CALL_STATUS_SETMSG; + + if (bridgecall->async != NULL) { + IOTJS_ASSERT(bridgecall->async->data == bridgecall); + uv_async_send(bridgecall->async); + } + if (!jerry_value_is_undefined(bridgecall->jcallback)) { + uv_mutex_unlock(&bridgecall->call_lock); + } + } +} + +static iotjs_bridge_call_t* iotjs_bridge_call_init( + iotjs_bridge_call_t* bridgecall, const jerry_value_t bridge, + const jerry_value_t jcallback, iotjs_string_t module, + iotjs_string_t command, iotjs_string_t message) { + if (bridge) { + bridgecall->jobject = jerry_acquire_value(bridge); + } else { + bridgecall->jobject = jerry_create_undefined(); + } + if (!jerry_value_is_null(jcallback)) { + bridgecall->jcallback = jerry_acquire_value(jcallback); + bridgecall->req.data = (void*)bridgecall; + uv_mutex_init(&bridgecall->call_lock); + } else { + bridgecall->jcallback = jerry_create_undefined(); + } + bridgecall->async = NULL; + bridgecall->module = module; + bridgecall->command = command; + bridgecall->message = message; + bridgecall->ret_msg = iotjs_string_create(); + bridgecall->status = CALL_STATUS_INIT; + bridgecall->bridgeobj = NULL; + + return bridgecall; +} + +static void iotjs_bridge_call_destroy(iotjs_bridge_call_t* bridgecall) { + if (!jerry_value_is_undefined(bridgecall->jobject)) { + jerry_release_value(bridgecall->jobject); + } + if (!jerry_value_is_undefined(bridgecall->jcallback)) { + uv_mutex_destroy(&bridgecall->call_lock); + jerry_release_value(bridgecall->jcallback); + } + if (bridgecall->async) { + uv_close((uv_handle_t*)bridgecall->async, NULL); + IOTJS_RELEASE(bridgecall->async); + } + iotjs_string_destroy(&bridgecall->module); + iotjs_string_destroy(&bridgecall->command); + iotjs_string_destroy(&bridgecall->message); + iotjs_string_destroy(&bridgecall->ret_msg); + bridgecall->bridgeobj = NULL; + IOTJS_RELEASE(bridgecall); +} + +static iotjs_bridge_object_t* iotjs_bridge_get_object(jerry_value_t obj_val) { + iotjs_bridge_object_t* bridgeobj = NULL; + bool is_ok = false; + is_ok = jerry_get_object_native_pointer(obj_val, (void**)&bridgeobj, NULL); + if (!is_ok) { + bridgeobj = IOTJS_ALLOC(iotjs_bridge_object_t); + bridgeobj->jobject = obj_val; + bridgeobj->calls = NULL; + bridgeobj->calls_alloc = 0; + jerry_set_object_native_pointer(obj_val, bridgeobj, + &this_module_native_info); + } + IOTJS_ASSERT(bridgeobj != NULL); + IOTJS_ASSERT(bridgeobj->jobject == obj_val); + return bridgeobj; +} + +static void iotjs_bridge_object_destroy(iotjs_bridge_object_t* bridgeobj) { + if (bridgeobj->calls_alloc == 0) { + if (bridgeobj->calls != NULL) { + iotjs_bridge_call_destroy((iotjs_bridge_call_t*)bridgeobj->calls); + } + } else { + for (size_t i = 0; i < bridgeobj->calls_alloc; i++) { + if (bridgeobj->calls[i] != NULL) { + iotjs_bridge_call_destroy(bridgeobj->calls[i]); + } + } + IOTJS_ASSERT(bridgeobj->calls); + iotjs_buffer_release((char*)bridgeobj->calls); + } + IOTJS_RELEASE(bridgeobj); +} + +static int iotjs_bridge_add_call(iotjs_bridge_object_t* bridgeobj, + iotjs_bridge_call_t* callobj) { + IOTJS_ASSERT(bridgeobj); + IOTJS_ASSERT(callobj); + callobj->bridgeobj = bridgeobj; + if (bridgeobj->calls_alloc == 0) { + if (bridgeobj->calls == NULL) { + bridgeobj->calls = (iotjs_bridge_call_t**)callobj; + } else { + iotjs_bridge_call_t* prev_obj = (iotjs_bridge_call_t*)bridgeobj->calls; + bridgeobj->calls = (iotjs_bridge_call_t**)iotjs_buffer_allocate( + sizeof(iotjs_bridge_call_t*) * 4); + bridgeobj->calls_alloc = 4; + bridgeobj->calls[0] = prev_obj; + bridgeobj->calls[1] = callobj; + } + } else { + for (size_t i = 0; i < bridgeobj->calls_alloc; i++) { + if (bridgeobj->calls[i] == 0) { + bridgeobj->calls[i] = callobj; + return bridgeobj->calls_alloc; + } + } + size_t prev_size = sizeof(iotjs_bridge_call_t*) * bridgeobj->calls_alloc; + bridgeobj->calls = + (iotjs_bridge_call_t**)iotjs_buffer_reallocate((char*)bridgeobj->calls, + prev_size * 2); + bridgeobj->calls[bridgeobj->calls_alloc] = callobj; + bridgeobj->calls_alloc *= 2; + } + return bridgeobj->calls_alloc; +} + +static int iotjs_bridge_remove_call(iotjs_bridge_call_t* callobj) { + iotjs_bridge_object_t* bridgeobj = callobj->bridgeobj; + + if (bridgeobj->calls_alloc == 0) { + if (bridgeobj->calls != NULL) { + iotjs_bridge_call_destroy((iotjs_bridge_call_t*)bridgeobj->calls); + bridgeobj->calls = NULL; + } + } else { + for (size_t i = 0; i < bridgeobj->calls_alloc; i++) { + if (bridgeobj->calls[i] == callobj) { + iotjs_bridge_call_destroy(bridgeobj->calls[i]); + bridgeobj->calls[i] = NULL; + } + } + } + return 0; +} + +static void iotjs_bridge_js_call(iotjs_bridge_call_t* bridgecall) { + iotjs_jargs_t jargs = iotjs_jargs_create(2); + if (bridgecall->status == CALL_STATUS_ERROR) { // internal error + iotjs_jargs_append_error(&jargs, iotjs_string_data(&bridgecall->ret_msg)); + iotjs_jargs_append_null(&jargs); + } else { + iotjs_jargs_append_null(&jargs); + iotjs_jargs_append_string_raw(&jargs, + iotjs_string_data(&bridgecall->ret_msg)); + } + jerry_value_t jcallback = bridgecall->jcallback; + if (jerry_value_is_function(jcallback)) { + iotjs_make_callback(jcallback, jerry_create_undefined(), &jargs); + } + iotjs_jargs_destroy(&jargs); +} + +static void aysnc_callback(uv_async_t* async) { + iotjs_bridge_call_t* bridgecall = (iotjs_bridge_call_t*)async->data; + iotjs_bridge_js_call(bridgecall); + iotjs_bridge_remove_call(bridgecall); +} + +void after_worker(uv_work_t* req, int status) { + iotjs_bridge_call_t* bridgecall = (iotjs_bridge_call_t*)req->data; + uv_mutex_lock(&bridgecall->call_lock); + if ((bridgecall->status == CALL_STATUS_ERROR) || + (bridgecall->status == CALL_STATUS_SETMSG)) { + iotjs_bridge_js_call(bridgecall); + uv_mutex_unlock(&bridgecall->call_lock); + iotjs_bridge_remove_call(bridgecall); + } else { + uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); + uv_async_t* async = IOTJS_ALLOC(uv_async_t); + async->data = (void*)bridgecall; + uv_async_init(loop, async, aysnc_callback); + uv_mutex_unlock(&bridgecall->call_lock); + } +} + +void bridge_worker(uv_work_t* req) { + iotjs_bridge_call_t* bridgecall = (iotjs_bridge_call_t*)req->data; + bridgecall->status = CALL_STATUS_CALLED; + int ret = iotjs_bridge_call(iotjs_string_data(&bridgecall->module), + iotjs_string_data(&bridgecall->command), + iotjs_string_data(&bridgecall->message), + (void*)bridgecall); + if (ret < 0) { + iotjs_bridge_set_err(bridgecall, "Can't find the module"); + } +} + +/** + * send async message + */ +JS_FUNCTION(MessageAsync) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(3, string, string, string); + DJS_CHECK_ARG_IF_EXIST(3, function); + + jerry_value_t bridge_module = JS_GET_THIS(); + iotjs_string_t module_name = JS_GET_ARG(0, string); + iotjs_string_t module_command = JS_GET_ARG(1, string); + iotjs_string_t command_message = JS_GET_ARG(2, string); + jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(3, function); + + if (!jerry_value_is_null(jcallback)) { // async call + uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); + iotjs_bridge_object_t* bridgeobj = iotjs_bridge_get_object(bridge_module); + iotjs_bridge_call_t* bridgecall = IOTJS_ALLOC(iotjs_bridge_call_t); + iotjs_bridge_call_init(bridgecall, bridge_module, jcallback, module_name, + module_command, command_message); + iotjs_bridge_add_call(bridgeobj, bridgecall); + + uv_queue_work(loop, &bridgecall->req, bridge_worker, after_worker); + + } else { // sync call + jerry_value_t jmsg; + iotjs_bridge_call_t bridgecall_local; + iotjs_bridge_call_t* bridgecall = &bridgecall_local; + + iotjs_bridge_call_init(bridgecall, 0, 0, module_name, module_command, + command_message); + int ret = iotjs_bridge_call(iotjs_string_data(&module_name), + iotjs_string_data(&module_command), + iotjs_string_data(&command_message), + (void*)bridgecall); + if (ret < 0) { + iotjs_bridge_set_err(bridgecall, "Can't find the module"); + } + if (bridgecall->status == CALL_STATUS_ERROR) { // error.. + if (iotjs_string_is_empty(&bridgecall->ret_msg)) { + jmsg = JS_CREATE_ERROR(COMMON, (jerry_char_t*)"Unknown native error.."); + } else { + jmsg = JS_CREATE_ERROR(COMMON, iotjs_string_data(&bridgecall->ret_msg)); + } + } else { + if (iotjs_string_is_empty(&bridgecall->ret_msg)) { + jmsg = jerry_create_string((jerry_char_t*)""); + } else { + jmsg = jerry_create_string( + (jerry_char_t*)iotjs_string_data(&bridgecall->ret_msg)); + } + } + iotjs_string_destroy(&bridgecall->module); + iotjs_string_destroy(&bridgecall->command); + iotjs_string_destroy(&bridgecall->message); + iotjs_string_destroy(&bridgecall->ret_msg); + return jmsg; + } + + return jerry_create_string((jerry_char_t*)""); +} + +/** + * Init method called by IoT.js + */ +jerry_value_t InitBridge() { + jerry_value_t messagModule = jerry_create_object(); + iotjs_jval_set_method(messagModule, "send", MessageAsync); + iotjs_bridge_init(); + return messagModule; +} diff --git a/src/modules/iotjs_module_bridge.h b/src/modules/iotjs_module_bridge.h new file mode 100644 index 0000000..360102e --- /dev/null +++ b/src/modules/iotjs_module_bridge.h @@ -0,0 +1,31 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 IOTJS_BRIDGE_H +#define IOTJS_BRIDGE_H + +#define MAX_RETURN_MESSAGE 512 * 2 + +/* + */ +typedef void (*iotjs_bridge_func)(const char* command, const char* message, + void* return_handle); + +int iotjs_bridge_register(char* module_name, iotjs_bridge_func callback); + +void iotjs_bridge_set_err(void* return_handle, char* err); +void iotjs_bridge_set_msg(void* return_handle, char* msg); + +#endif diff --git a/src/modules/iotjs_module_buffer.c b/src/modules/iotjs_module_buffer.c index 99dbe0f..b69c41b 100644 --- a/src/modules/iotjs_module_buffer.c +++ b/src/modules/iotjs_module_buffer.c @@ -20,16 +20,21 @@ #include #include +typedef enum { + BUFFER_HEX_ENC = 0, + BUFFER_BASE64_ENC = 1, +} buffer_encoding_type_t; + IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(bufferwrap); -iotjs_bufferwrap_t* iotjs_bufferwrap_create(const jerry_value_t jbuiltin, +iotjs_bufferwrap_t* iotjs_bufferwrap_create(const jerry_value_t jobject, size_t length) { iotjs_bufferwrap_t* bufferwrap = IOTJS_ALLOC(iotjs_bufferwrap_t); - bufferwrap->jobject = jbuiltin; - jerry_set_object_native_pointer(jbuiltin, bufferwrap, + bufferwrap->jobject = jobject; + jerry_set_object_native_pointer(jobject, bufferwrap, &this_module_native_info); if (length > 0) { @@ -43,49 +48,34 @@ iotjs_bufferwrap_t* iotjs_bufferwrap_create(const jerry_value_t jbuiltin, IOTJS_ASSERT( bufferwrap == - (iotjs_bufferwrap_t*)(iotjs_jval_get_object_native_handle(jbuiltin))); + (iotjs_bufferwrap_t*)(iotjs_jval_get_object_native_handle(jobject))); return bufferwrap; } static void iotjs_bufferwrap_destroy(iotjs_bufferwrap_t* bufferwrap) { - if (bufferwrap->buffer != NULL) { - iotjs_buffer_release(bufferwrap->buffer); - } + IOTJS_RELEASE(bufferwrap->buffer); IOTJS_RELEASE(bufferwrap); } -iotjs_bufferwrap_t* iotjs_bufferwrap_from_jbuiltin( - const jerry_value_t jbuiltin) { - IOTJS_ASSERT(jerry_value_is_object(jbuiltin)); - iotjs_bufferwrap_t* buffer = - (iotjs_bufferwrap_t*)iotjs_jval_get_object_native_handle(jbuiltin); - IOTJS_ASSERT(buffer != NULL); - return buffer; -} - - iotjs_bufferwrap_t* iotjs_bufferwrap_from_jbuffer(const jerry_value_t jbuffer) { IOTJS_ASSERT(jerry_value_is_object(jbuffer)); - jerry_value_t jbuiltin = - iotjs_jval_get_property(jbuffer, IOTJS_MAGIC_STRING__BUILTIN); - iotjs_bufferwrap_t* buffer = iotjs_bufferwrap_from_jbuiltin(jbuiltin); - jerry_release_value(jbuiltin); + iotjs_bufferwrap_t* buffer = + (iotjs_bufferwrap_t*)iotjs_jval_get_object_native_handle(jbuffer); + IOTJS_ASSERT(buffer != NULL); return buffer; } size_t iotjs_bufferwrap_length(iotjs_bufferwrap_t* bufferwrap) { + IOTJS_ASSERT(bufferwrap != NULL); #ifndef NDEBUG - jerry_value_t jbuf = - iotjs_jval_get_property(bufferwrap->jobject, IOTJS_MAGIC_STRING__BUFFER); jerry_value_t jlength = - iotjs_jval_get_property(jbuf, IOTJS_MAGIC_STRING_LENGTH); + iotjs_jval_get_property(bufferwrap->jobject, IOTJS_MAGIC_STRING_LENGTH); size_t length = iotjs_jval_as_number(jlength); IOTJS_ASSERT(length == bufferwrap->length); - jerry_release_value(jbuf); jerry_release_value(jlength); #endif return bufferwrap->length; @@ -103,13 +93,16 @@ static size_t bound_range(size_t index, size_t low, size_t upper) { } -static int8_t hex2bin(char c) { - if (c >= '0' && c <= '9') +static int8_t hex_to_bin(char c) { + if (c >= '0' && c <= '9') { return (int8_t)(c - '0'); - if (c >= 'A' && c <= 'F') + } + if (c >= 'A' && c <= 'F') { return (int8_t)(10 + (c - 'A')); - if (c >= 'a' && c <= 'f') + } + if (c >= 'a' && c <= 'f') { return (int8_t)(10 + (c - 'a')); + } return (int8_t)(-1); } @@ -117,17 +110,105 @@ static int8_t hex2bin(char c) { static size_t hex_decode(char* buf, size_t len, const char* src, const size_t srcLen) { - size_t i; + const char* bufStart = buf; + const char* bufEnd = buf + len; + const char* srcEnd = src + srcLen; - for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) { - int8_t a = hex2bin(src[i * 2 + 0]); - int8_t b = hex2bin(src[i * 2 + 1]); - if (a == -1 || b == -1) - return i; - buf[i] = (a << 4) | b; + if ((srcLen & 0x1) != 0) { + return 0; } - return i; + while (src < srcEnd) { + int8_t a = hex_to_bin(src[0]); + int8_t b = hex_to_bin(src[1]); + + if (a == -1 || b == -1) { + return 0; + } + + if (buf < bufEnd) { + *buf++ = (a << 4) | b; + } + + src += 2; + } + + return (size_t)((buf - bufStart) + 1); +} + + +static int32_t base64_to_bin(char c) { + if (c >= 'A' && c <= 'Z') { + return (int32_t)(c - 'A'); + } + if (c >= 'a' && c <= 'z') { + return (int32_t)(26 + (c - 'a')); + } + if (c >= '0' && c <= '9') { + return (int32_t)(52 + (c - '0')); + } + if (c == '+') { + return 62; + } + if (c == '/') { + return 63; + } + + return (int32_t)(-1); +} + + +static size_t base64_decode(char* buf, size_t len, const char* src, + const size_t srcLen) { + if (srcLen == 0) { + return 0 + 1; + } + + if ((srcLen & 0x3) != 0) { + return 0; + } + + const char* bufStart = buf; + const char* bufEnd = buf + len; + const char* srcEnd = src + srcLen; + + if (srcEnd[-1] == '=') { + srcEnd--; + if (srcEnd[-1] == '=') { + srcEnd--; + } + } + + int32_t current_bits = 0; + int32_t shift = 8; + + while (src < srcEnd) { + int32_t value = base64_to_bin(*src++); + + if (value == -1) { + return 0; + } + + current_bits = (current_bits << 6) | value; + shift -= 2; + + if (shift == 6) { + continue; + } + + int32_t byte = (current_bits >> shift); + current_bits &= (1 << shift) - 1; + + if (shift == 0) { + shift = 8; + } + + if (buf < bufEnd) { + *buf++ = (char)byte; + } + } + + return (size_t)((buf - bufStart) + 1); } @@ -187,6 +268,20 @@ size_t iotjs_bufferwrap_copy(iotjs_bufferwrap_t* bufferwrap, const char* src, return iotjs_bufferwrap_copy_internal(bufferwrap, src, 0, len, 0); } +static size_t index_normalizer(int64_t index, size_t max_length) { + size_t idx; + if (index < 0) { + if ((size_t)(-index) > max_length) { + idx = SIZE_MAX; + } else { + idx = (size_t)index + max_length; + } + } else { + idx = (size_t)index; + } + + return bound_range(idx, 0, max_length); +} jerry_value_t iotjs_bufferwrap_create_buffer(size_t len) { jerry_value_t jglobal = jerry_get_global_object(); @@ -196,14 +291,13 @@ jerry_value_t iotjs_bufferwrap_create_buffer(size_t len) { jerry_release_value(jglobal); IOTJS_ASSERT(jerry_value_is_function(jbuffer)); - iotjs_jargs_t jargs = iotjs_jargs_create(1); - iotjs_jargs_append_number(&jargs, len); + jerry_value_t arg = jerry_create_number(len); - jerry_value_t jres = - iotjs_jhelper_call_ok(jbuffer, jerry_create_undefined(), &jargs); + jerry_value_t jres = jerry_construct_object(jbuffer, &arg, 1); + IOTJS_ASSERT(!jerry_value_has_error_flag(jres)); IOTJS_ASSERT(jerry_value_is_object(jres)); - iotjs_jargs_destroy(&jargs); + jerry_release_value(arg); jerry_release_value(jbuffer); return jres; @@ -211,23 +305,18 @@ jerry_value_t iotjs_bufferwrap_create_buffer(size_t len) { JS_FUNCTION(Buffer) { - DJS_CHECK_THIS(); DJS_CHECK_ARGS(2, object, number); - const jerry_value_t jbuiltin = JS_GET_THIS(); - const jerry_value_t jbuffer = JS_GET_ARG(0, object); + const jerry_value_t jobject = JS_GET_ARG(0, object); size_t length = JS_GET_ARG(1, number); - iotjs_jval_set_property_jval(jbuiltin, IOTJS_MAGIC_STRING__BUFFER, jbuffer); - - iotjs_bufferwrap_create(jbuiltin, length); + iotjs_bufferwrap_create(jobject, length); return jerry_create_undefined(); } - JS_FUNCTION(Compare) { - JS_DECLARE_THIS_PTR(bufferwrap, src_buffer_wrap); - JS_DECLARE_OBJECT_PTR(0, bufferwrap, dst_buffer_wrap); + JS_DECLARE_OBJECT_PTR(0, bufferwrap, src_buffer_wrap); + JS_DECLARE_OBJECT_PTR(1, bufferwrap, dst_buffer_wrap); int compare = iotjs_bufferwrap_compare(src_buffer_wrap, dst_buffer_wrap); return jerry_create_number(compare); @@ -235,23 +324,23 @@ JS_FUNCTION(Compare) { JS_FUNCTION(Copy) { - JS_DECLARE_THIS_PTR(bufferwrap, src_buffer_wrap); - DJS_CHECK_ARGS(4, object, number, number, number); + DJS_CHECK_ARGS(5, object, object, number, number, number); + JS_DECLARE_OBJECT_PTR(0, bufferwrap, src_buffer_wrap); - const jerry_value_t jdst_buffer = JS_GET_ARG(0, object); + const jerry_value_t jdst_buffer = JS_GET_ARG(1, object); iotjs_bufferwrap_t* dst_buffer_wrap = iotjs_bufferwrap_from_jbuffer(jdst_buffer); size_t dst_length = iotjs_bufferwrap_length(dst_buffer_wrap); size_t src_length = iotjs_bufferwrap_length(src_buffer_wrap); - size_t dst_start = iotjs_convert_double_to_sizet(JS_GET_ARG(1, number)); + size_t dst_start = iotjs_convert_double_to_sizet(JS_GET_ARG(2, number)); dst_start = bound_range(dst_start, 0, dst_length); - size_t src_start = iotjs_convert_double_to_sizet(JS_GET_ARG(2, number)); + size_t src_start = iotjs_convert_double_to_sizet(JS_GET_ARG(3, number)); src_start = bound_range(src_start, 0, src_length); - size_t src_end = iotjs_convert_double_to_sizet(JS_GET_ARG(3, number)); + size_t src_end = iotjs_convert_double_to_sizet(JS_GET_ARG(4, number)); src_end = bound_range(src_end, 0, src_length); if (src_end < src_start) { @@ -267,16 +356,16 @@ JS_FUNCTION(Copy) { JS_FUNCTION(Write) { - JS_DECLARE_THIS_PTR(bufferwrap, buffer_wrap); - DJS_CHECK_ARGS(3, string, number, number); + DJS_CHECK_ARGS(4, object, string, number, number); + JS_DECLARE_OBJECT_PTR(0, bufferwrap, buffer_wrap); - iotjs_string_t src = JS_GET_ARG(0, string); + iotjs_string_t src = JS_GET_ARG(1, string); size_t buffer_length = iotjs_bufferwrap_length(buffer_wrap); - size_t offset = iotjs_convert_double_to_sizet(JS_GET_ARG(1, number)); + size_t offset = iotjs_convert_double_to_sizet(JS_GET_ARG(2, number)); offset = bound_range(offset, 0, buffer_length); - size_t length = iotjs_convert_double_to_sizet(JS_GET_ARG(2, number)); + size_t length = iotjs_convert_double_to_sizet(JS_GET_ARG(3, number)); length = bound_range(length, 0, buffer_length - offset); length = bound_range(length, 0, iotjs_string_size(&src)); @@ -291,14 +380,14 @@ JS_FUNCTION(Write) { JS_FUNCTION(WriteUInt8) { - JS_DECLARE_THIS_PTR(bufferwrap, buffer_wrap); - DJS_CHECK_ARGS(2, number, number); + DJS_CHECK_ARGS(3, object, number, number); + JS_DECLARE_OBJECT_PTR(0, bufferwrap, buffer_wrap); - const char src[] = { (char)JS_GET_ARG(0, number) }; + const char src[] = { (char)JS_GET_ARG(1, number) }; size_t length = 1; size_t buffer_length = iotjs_bufferwrap_length(buffer_wrap); - size_t offset = iotjs_convert_double_to_sizet(JS_GET_ARG(1, number)); + size_t offset = iotjs_convert_double_to_sizet(JS_GET_ARG(2, number)); offset = bound_range(offset, 0, buffer_length); length = bound_range(length, 0, buffer_length - offset); length = bound_range(length, 0, 1); @@ -310,41 +399,51 @@ JS_FUNCTION(WriteUInt8) { } -JS_FUNCTION(HexWrite) { - JS_DECLARE_THIS_PTR(bufferwrap, buffer_wrap); - DJS_CHECK_ARGS(3, string, number, number); +JS_FUNCTION(WriteDecode) { + DJS_CHECK_ARGS(5, object, number, string, number, number); + JS_DECLARE_OBJECT_PTR(0, bufferwrap, buffer_wrap); - iotjs_string_t src = JS_GET_ARG(0, string); + double type = JS_GET_ARG(1, number); + iotjs_string_t src = JS_GET_ARG(2, string); size_t buffer_length = iotjs_bufferwrap_length(buffer_wrap); - size_t offset = iotjs_convert_double_to_sizet(JS_GET_ARG(1, number)); + size_t offset = iotjs_convert_double_to_sizet(JS_GET_ARG(3, number)); offset = bound_range(offset, 0, buffer_length); - size_t length = iotjs_convert_double_to_sizet(JS_GET_ARG(2, number)); + size_t length = iotjs_convert_double_to_sizet(JS_GET_ARG(4, number)); length = bound_range(length, 0, buffer_length - offset); const char* src_data = iotjs_string_data(&src); unsigned src_length = iotjs_string_size(&src); - char* src_buf = iotjs_buffer_allocate(length); - size_t nbytes = hex_decode(src_buf, length, src_data, src_length); + size_t nbytes; + char* dst_data = buffer_wrap->buffer + offset; + const char* error_msg; - size_t copied = - iotjs_bufferwrap_copy_internal(buffer_wrap, src_buf, 0, nbytes, offset); + if (type == BUFFER_HEX_ENC) { + nbytes = hex_decode(dst_data, length, src_data, src_length); + error_msg = "Invalid hex string"; + } else { + nbytes = base64_decode(dst_data, length, src_data, src_length); + error_msg = "Invalid base64 string"; + } - iotjs_buffer_release(src_buf); iotjs_string_destroy(&src); - return jerry_create_number(copied); + if (nbytes == 0) + return jerry_create_error(JERRY_ERROR_TYPE, (const jerry_char_t*)error_msg); + + return jerry_create_number(nbytes - 1); } JS_FUNCTION(ReadUInt8) { - JS_DECLARE_THIS_PTR(bufferwrap, buffer_wrap); - DJS_CHECK_ARGS(1, number); + DJS_CHECK_ARGS(2, object, number); + JS_DECLARE_OBJECT_PTR(0, bufferwrap, buffer_wrap); + size_t buffer_length = iotjs_bufferwrap_length(buffer_wrap); - size_t offset = iotjs_convert_double_to_sizet(JS_GET_ARG(0, number)); + size_t offset = iotjs_convert_double_to_sizet(JS_GET_ARG(1, number)); offset = bound_range(offset, 0, buffer_length - 1); char* buffer = buffer_wrap->buffer; @@ -359,36 +458,14 @@ JS_FUNCTION(ReadUInt8) { JS_FUNCTION(Slice) { - JS_DECLARE_THIS_PTR(bufferwrap, buffer_wrap); - DJS_CHECK_ARGS(2, number, number); + DJS_CHECK_ARGS(3, object, number, number); + JS_DECLARE_OBJECT_PTR(0, bufferwrap, buffer_wrap); - int64_t start = JS_GET_ARG(0, number); - int64_t end = JS_GET_ARG(1, number); - size_t start_idx, end_idx; - - if (start < 0) { - size_t len = iotjs_bufferwrap_length(buffer_wrap); - if ((size_t)(-start) > len) { - start_idx = SIZE_MAX; - } else { - start_idx = (size_t)start + len; - } - } else { - start_idx = (size_t)start; - } - start_idx = bound_range(start_idx, 0, iotjs_bufferwrap_length(buffer_wrap)); - - if (end < 0) { - size_t len = iotjs_bufferwrap_length(buffer_wrap); - if ((size_t)(-end) > len) { - end_idx = SIZE_MAX; - } else { - end_idx = (size_t)end + len; - } - } else { - end_idx = (size_t)end; - } - end_idx = bound_range(end_idx, 0, iotjs_bufferwrap_length(buffer_wrap)); + int64_t start = JS_GET_ARG(1, number); + int64_t end = JS_GET_ARG(2, number); + size_t len = iotjs_bufferwrap_length(buffer_wrap); + size_t start_idx = index_normalizer(start, len); + size_t end_idx = index_normalizer(end, len); if (end_idx < start_idx) { end_idx = start_idx; @@ -406,87 +483,159 @@ JS_FUNCTION(Slice) { } +static char to_hex_char(uint8_t digit) { + return (char)((digit < 10) ? (digit + '0') : (digit + 'a' - 10)); +} + + +static jerry_value_t to_hex_string(const uint8_t* data, size_t length) { + if (length == 0) { + return jerry_create_string_sz(NULL, 0); + } + + const uint8_t* end = data + length; + + size_t buffer_length = length * 2; + char* buffer = iotjs_buffer_allocate(buffer_length); + const jerry_char_t* str = (const jerry_char_t*)buffer; + + while (data < end) { + *buffer++ = to_hex_char(*data >> 4); + *buffer++ = to_hex_char(*data & 0xf); + data++; + } + + jerry_value_t ret_value = jerry_create_string_sz(str, buffer_length); + IOTJS_RELEASE(str); + + return ret_value; +} + +static char to_base64_char(uint8_t digit) { + if (digit <= 25) { + return (char)digit + 'A'; + } + if (digit <= 51) { + return (char)digit + 'a' - 26; + } + if (digit <= 61) { + return (char)digit + '0' - 52; + } + + return (digit == 62) ? '+' : '/'; +} + +static jerry_value_t to_base64_string(const uint8_t* data, size_t length) { + if (length == 0) { + return jerry_create_string_sz(NULL, 0); + } + + const uint8_t* end = data + length; + + size_t buffer_length = ((length + 2) / 3) * 4; + char* buffer = iotjs_buffer_allocate(buffer_length); + const jerry_char_t* str = (const jerry_char_t*)buffer; + + uint32_t current_bits = 0; + int32_t shift = 2; + + while (data < end) { + current_bits = (current_bits << 8) | *data++; + + *buffer++ = to_base64_char(current_bits >> shift); + current_bits &= (uint32_t)((1 << shift) - 1); + + shift += 2; + + if (shift == 8) { + *buffer++ = to_base64_char(current_bits); + current_bits = 0; + shift = 2; + } + } + + char* buffer_end = (char*)str + buffer_length; + if (buffer < buffer_end) { + buffer[0] = to_base64_char(current_bits << (8 - shift)); + buffer[1] = '='; + + if (buffer + 2 < buffer_end) + buffer[2] = '='; + } + + jerry_value_t ret_value = jerry_create_string_sz(str, buffer_length); + IOTJS_RELEASE(str); + + return ret_value; +} + + JS_FUNCTION(ToString) { - JS_DECLARE_THIS_PTR(bufferwrap, buffer_wrap); - DJS_CHECK_ARGS(2, number, number); + DJS_CHECK_ARGS(4, object, number, number, number); + JS_DECLARE_OBJECT_PTR(0, bufferwrap, buffer_wrap); + + double type = JS_GET_ARG(1, number); - size_t start = iotjs_convert_double_to_sizet(JS_GET_ARG(0, number)); + size_t start = iotjs_convert_double_to_sizet(JS_GET_ARG(2, number)); start = bound_range(start, 0, iotjs_bufferwrap_length(buffer_wrap)); - size_t end = iotjs_convert_double_to_sizet(JS_GET_ARG(1, number)); + size_t end = iotjs_convert_double_to_sizet(JS_GET_ARG(3, number)); end = bound_range(end, 0, iotjs_bufferwrap_length(buffer_wrap)); if (end < start) { end = start; } - size_t length = end - start; - - const char* data = buffer_wrap->buffer + start; - length = strnlen(data, length); + if (start > buffer_wrap->length) { + start = buffer_wrap->length; + } - if (!jerry_is_valid_utf8_string((const jerry_char_t*)data, length)) { - return JS_CREATE_ERROR(TYPE, "Invalid UTF-8 string"); + if (end > buffer_wrap->length) { + end = buffer_wrap->length; } - return jerry_create_string_sz_from_utf8((const jerry_char_t*)data, length); -} + size_t length = end - start; + const char* data = buffer_wrap->buffer + start; -JS_FUNCTION(ToHexString) { - JS_DECLARE_THIS_PTR(bufferwrap, buffer_wrap); + if (type == BUFFER_HEX_ENC) { + return to_hex_string((const uint8_t*)data, length); + } - size_t length = iotjs_bufferwrap_length(buffer_wrap); - const char* data = buffer_wrap->buffer; - JS_CHECK(data != NULL); + if (type == BUFFER_BASE64_ENC) { + return to_base64_string((const uint8_t*)data, length); + } - char* buffer = iotjs_buffer_allocate(length * 2); - iotjs_string_t str = iotjs_string_create_with_buffer(buffer, length * 2); + /* Stops at first zero. */ + length = strnlen(data, length); - for (size_t i = 0; i < length; i++) { - memcpy(buffer, &"0123456789abcdef"[data[i] >> 4 & 0xF], 1); - buffer++; - memcpy(buffer, &"0123456789abcdef"[data[i] >> 0 & 0xF], 1); - buffer++; + if (!jerry_is_valid_utf8_string((const jerry_char_t*)data, length)) { + return JS_CREATE_ERROR(TYPE, "Invalid UTF-8 string"); } - jerry_value_t ret_value = iotjs_jval_create_string(&str); - iotjs_string_destroy(&str); - - return ret_value; + return jerry_create_string_sz_from_utf8((const jerry_char_t*)data, length); } JS_FUNCTION(ByteLength) { - DJS_CHECK_THIS(); DJS_CHECK_ARGS(1, string); - iotjs_string_t str = JS_GET_ARG(0, string); - jerry_value_t size = iotjs_jval_get_string_size(&str); - - iotjs_string_destroy(&str); - return size; + jerry_size_t size = jerry_get_string_size(jargv[0]); + return jerry_create_number(size); } jerry_value_t InitBuffer() { jerry_value_t buffer = jerry_create_external_function(Buffer); - - jerry_value_t prototype = jerry_create_object(); - iotjs_jval_set_property_jval(buffer, IOTJS_MAGIC_STRING_PROTOTYPE, prototype); iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_BYTELENGTH, ByteLength); - - iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_COMPARE, Compare); - iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_COPY, Copy); - iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_WRITE, Write); - iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_HEXWRITE, HexWrite); - iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_WRITEUINT8, WriteUInt8); - iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_READUINT8, ReadUInt8); - iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_SLICE, Slice); - iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_TOSTRING, ToString); - iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_TOHEXSTRING, ToHexString); - - jerry_release_value(prototype); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_COMPARE, Compare); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_COPY, Copy); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_WRITE, Write); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_WRITEDECODE, WriteDecode); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_WRITEUINT8, WriteUInt8); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_READUINT8, ReadUInt8); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_SLICE, Slice); + iotjs_jval_set_method(buffer, IOTJS_MAGIC_STRING_TOSTRING, ToString); return buffer; } diff --git a/src/modules/iotjs_module_buffer.h b/src/modules/iotjs_module_buffer.h index 6a46c58..29db89c 100644 --- a/src/modules/iotjs_module_buffer.h +++ b/src/modules/iotjs_module_buffer.h @@ -27,8 +27,6 @@ typedef struct { iotjs_bufferwrap_t* iotjs_bufferwrap_create(const jerry_value_t jbuiltin, size_t length); -iotjs_bufferwrap_t* iotjs_bufferwrap_from_jbuiltin( - const jerry_value_t jbuiltin); iotjs_bufferwrap_t* iotjs_bufferwrap_from_jbuffer(const jerry_value_t jbuffer); size_t iotjs_bufferwrap_length(iotjs_bufferwrap_t* bufferwrap); diff --git a/src/modules/iotjs_module_dynamicloader.c b/src/modules/iotjs_module_dynamicloader.c new file mode 100644 index 0000000..73ea675 --- /dev/null +++ b/src/modules/iotjs_module_dynamicloader.c @@ -0,0 +1,82 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 + +#include "iotjs_def.h" + +#include + +#define XSTR(ARG) #ARG +#define STR(ARG) XSTR(ARG) + + +jerry_value_t iotjs_load_module(const char* path) { + if (path == NULL) { + const char* error = "Invalid module path"; + return jerry_create_error(JERRY_ERROR_TYPE, (const jerry_char_t*)error); + } + + void* dynamic_lib = dlopen(path, RTLD_NOW); + + if (dynamic_lib == NULL) { + const char* error = "Can not open module"; + return jerry_create_error(JERRY_ERROR_TYPE, (const jerry_char_t*)error); + } + + void* loader_function = dlsym(dynamic_lib, STR(IOTJS_MODULE_ENTRYPOINT)); + if (loader_function == NULL) { + dlclose(dynamic_lib); + const char* error = "Entrypoint not found in module"; + return jerry_create_error(JERRY_ERROR_TYPE, (const jerry_char_t*)error); + } + + const iotjs_module* module = + (const iotjs_module*)((iotjs_module_info_getter)loader_function)(); + + if (module == NULL) { + dlclose(dynamic_lib); + const char* error = "Invalid module info"; + return jerry_create_error(JERRY_ERROR_TYPE, (const jerry_char_t*)error); + } + + if (module->iotjs_module_version != IOTJS_CURRENT_MODULE_VERSION) { + dlclose(dynamic_lib); + const char* error = "Incorrect version requested in the module"; + return jerry_create_error(JERRY_ERROR_TYPE, (const jerry_char_t*)error); + } + + return module->initializer(); +} + + +JS_FUNCTION(DLload) { + DJS_CHECK_ARGS(1, string); + + iotjs_string_t file = JS_GET_ARG(0, string); + const char* filename = iotjs_string_data(&file); + + jerry_value_t jresult = iotjs_load_module(filename); + + iotjs_string_destroy(&file); + + return jresult; +} + + +jerry_value_t InitDynamicloader() { + jerry_value_t loader = jerry_create_external_function(DLload); + return loader; +} diff --git a/src/modules/iotjs_module_fs.c b/src/modules/iotjs_module_fs.c index c820575..8ed5032 100644 --- a/src/modules/iotjs_module_fs.c +++ b/src/modules/iotjs_module_fs.c @@ -119,53 +119,49 @@ static jerry_value_t AfterSync(uv_fs_t* req, int err, jerry_value_t jerror = iotjs_create_uv_exception(err, syscall_name); jerry_value_set_error_flag(&jerror); return jerror; - } else { - switch (req->fs_type) { - case UV_FS_CLOSE: - break; - case UV_FS_OPEN: - case UV_FS_READ: - case UV_FS_WRITE: - return jerry_create_number(err); - case UV_FS_FSTAT: - case UV_FS_STAT: { - uv_stat_t* s = &(req->statbuf); - return MakeStatObject(s); - } - case UV_FS_MKDIR: - case UV_FS_RMDIR: - case UV_FS_UNLINK: - case UV_FS_RENAME: - return jerry_create_undefined(); - case UV_FS_SCANDIR: { - int r; - uv_dirent_t ent; - uint32_t idx = 0; - jerry_value_t ret = jerry_create_array(0); - while ((r = uv_fs_scandir_next(req, &ent)) != UV_EOF) { - jerry_value_t name = - jerry_create_string((const jerry_char_t*)ent.name); - iotjs_jval_set_property_by_index(ret, idx, name); - jerry_release_value(name); - idx++; - } - return ret; - } - default: { - IOTJS_ASSERT(false); - break; + } + + switch (req->fs_type) { + case UV_FS_CLOSE: + break; + case UV_FS_OPEN: + case UV_FS_READ: + case UV_FS_WRITE: + return jerry_create_number(err); + case UV_FS_FSTAT: + case UV_FS_STAT: { + uv_stat_t* s = &(req->statbuf); + return MakeStatObject(s); + } + case UV_FS_MKDIR: + case UV_FS_RMDIR: + case UV_FS_UNLINK: + case UV_FS_RENAME: + return jerry_create_undefined(); + case UV_FS_SCANDIR: { + int r; + uv_dirent_t ent; + uint32_t idx = 0; + jerry_value_t ret = jerry_create_array(0); + while ((r = uv_fs_scandir_next(req, &ent)) != UV_EOF) { + jerry_value_t name = jerry_create_string((const jerry_char_t*)ent.name); + iotjs_jval_set_property_by_index(ret, idx, name); + jerry_release_value(name); + idx++; } + return ret; + } + default: { + IOTJS_ASSERT(false); + break; } - return jerry_create_undefined(); } + return jerry_create_undefined(); } static inline bool IsWithinBounds(size_t off, size_t len, size_t max) { - if (off > max) - return false; - - if (max - off < len) + if (off >= max || max - off < len) return false; return true; @@ -253,12 +249,8 @@ JS_FUNCTION(Read) { iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); char* data = buffer_wrap->buffer; size_t data_length = iotjs_bufferwrap_length(buffer_wrap); - JS_CHECK(data != NULL); - JS_CHECK(data_length > 0); + JS_CHECK(data != NULL && data_length > 0); - if (offset >= data_length) { - return JS_CREATE_ERROR(RANGE, "offset out of bound"); - } if (!IsWithinBounds(offset, length, data_length)) { return JS_CREATE_ERROR(RANGE, "length out of bound"); } @@ -292,12 +284,8 @@ JS_FUNCTION(Write) { iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); char* data = buffer_wrap->buffer; size_t data_length = iotjs_bufferwrap_length(buffer_wrap); - JS_CHECK(data != NULL); - JS_CHECK(data_length > 0); + JS_CHECK(data != NULL && data_length > 0); - if (offset >= data_length) { - return JS_CREATE_ERROR(RANGE, "offset out of bound"); - } if (!IsWithinBounds(offset, length, data_length)) { return JS_CREATE_ERROR(RANGE, "length out of bound"); } diff --git a/src/modules/iotjs_module_gpio.c b/src/modules/iotjs_module_gpio.c index d8603e3..37cf5bb 100644 --- a/src/modules/iotjs_module_gpio.c +++ b/src/modules/iotjs_module_gpio.c @@ -13,174 +13,45 @@ * limitations under the License. */ -#include - #include "iotjs_def.h" #include "iotjs_module_gpio.h" -#include IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(gpio); -static iotjs_gpio_t* gpio_create(jerry_value_t jgpio) { - iotjs_gpio_t* gpio = IOTJS_ALLOC(iotjs_gpio_t); - iotjs_gpio_create_platform_data(gpio); - gpio->jobject = jgpio; - jerry_set_object_native_pointer(jgpio, gpio, &this_module_native_info); - - return gpio; -} - - -static iotjs_gpio_reqwrap_t* gpio_reqwrap_create(jerry_value_t jcallback, - iotjs_gpio_t* gpio, - GpioOp op) { - iotjs_gpio_reqwrap_t* gpio_reqwrap = IOTJS_ALLOC(iotjs_gpio_reqwrap_t); - - iotjs_reqwrap_initialize(&gpio_reqwrap->reqwrap, jcallback, - (uv_req_t*)&gpio_reqwrap->req); - - gpio_reqwrap->req_data.op = op; - gpio_reqwrap->gpio_data = gpio; - return gpio_reqwrap; -} - - -static void gpio_reqwrap_destroy(iotjs_gpio_reqwrap_t* gpio_reqwrap) { - iotjs_reqwrap_destroy(&gpio_reqwrap->reqwrap); - IOTJS_RELEASE(gpio_reqwrap); -} - - -static void gpio_reqwrap_dispatched(iotjs_gpio_reqwrap_t* gpio_reqwrap) { - gpio_reqwrap_destroy(gpio_reqwrap); -} - - -static uv_work_t* gpio_reqwrap_req(iotjs_gpio_reqwrap_t* gpio_reqwrap) { - return &gpio_reqwrap->req; -} - - -static jerry_value_t gpio_reqwrap_jcallback( - iotjs_gpio_reqwrap_t* gpio_reqwrap) { - return iotjs_reqwrap_jcallback(&gpio_reqwrap->reqwrap); -} - - -static iotjs_gpio_reqwrap_t* gpio_reqwrap_from_request(uv_work_t* req) { - return (iotjs_gpio_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)req)); -} - - -static iotjs_gpio_reqdata_t* gpio_reqwrap_data( - iotjs_gpio_reqwrap_t* gpio_reqwrap) { - return &gpio_reqwrap->req_data; -} - - -static iotjs_gpio_t* gpio_instance_from_reqwrap( - iotjs_gpio_reqwrap_t* gpio_reqwrap) { - return gpio_reqwrap->gpio_data; -} - +IOTJS_DEFINE_PERIPH_CREATE_FUNCTION(gpio); static void iotjs_gpio_destroy(iotjs_gpio_t* gpio) { iotjs_gpio_destroy_platform_data(gpio->platform_data); IOTJS_RELEASE(gpio); } - -static iotjs_gpio_t* gpio_instance_from_jval(const jerry_value_t jgpio) { - uintptr_t handle = iotjs_jval_get_object_native_handle(jgpio); - return (iotjs_gpio_t*)handle; -} - - static void gpio_worker(uv_work_t* work_req) { - iotjs_gpio_reqwrap_t* req_wrap = gpio_reqwrap_from_request(work_req); - iotjs_gpio_reqdata_t* req_data = gpio_reqwrap_data(req_wrap); - iotjs_gpio_t* gpio = gpio_instance_from_reqwrap(req_wrap); + iotjs_periph_reqwrap_t* req_wrap = + (iotjs_periph_reqwrap_t*)(iotjs_reqwrap_from_request( + (uv_req_t*)work_req)); + iotjs_gpio_t* gpio = (iotjs_gpio_t*)req_wrap->data; - switch (req_data->op) { + switch (req_wrap->op) { case kGpioOpOpen: - req_data->result = iotjs_gpio_open(gpio); + req_wrap->result = iotjs_gpio_open(gpio); break; case kGpioOpWrite: - req_data->result = iotjs_gpio_write(gpio); + req_wrap->result = iotjs_gpio_write(gpio); break; case kGpioOpRead: - req_data->result = iotjs_gpio_read(gpio); + req_wrap->result = iotjs_gpio_read(gpio); break; case kGpioOpClose: - req_data->result = iotjs_gpio_close(gpio); + req_wrap->result = iotjs_gpio_close(gpio); break; default: - IOTJS_ASSERT(!"Invalid Gpio Operation"); + IOTJS_ASSERT(!"Invalid Operation"); } } - -static void gpio_after_worker(uv_work_t* work_req, int status) { - iotjs_gpio_reqwrap_t* req_wrap = gpio_reqwrap_from_request(work_req); - iotjs_gpio_reqdata_t* req_data = gpio_reqwrap_data(req_wrap); - - iotjs_jargs_t jargs = iotjs_jargs_create(2); - bool result = req_data->result; - - if (status) { - iotjs_jargs_append_error(&jargs, "GPIO System Error"); - } else { - switch (req_data->op) { - case kGpioOpOpen: - if (!result) { - iotjs_jargs_append_error(&jargs, "GPIO Open Error"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - case kGpioOpWrite: - if (!result) { - iotjs_jargs_append_error(&jargs, "GPIO Write Error"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - case kGpioOpRead: - if (!result) { - iotjs_jargs_append_error(&jargs, "GPIO Read Error"); - } else { - iotjs_gpio_t* gpio = gpio_instance_from_reqwrap(req_wrap); - - iotjs_jargs_append_null(&jargs); - iotjs_jargs_append_bool(&jargs, gpio->value); - } - break; - case kGpioOpClose: - if (!result) { - iotjs_jargs_append_error(&jargs, "GPIO Close Error"); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - default: - IOTJS_ASSERT(!"Unreachable"); - break; - } - } - - const jerry_value_t jcallback = gpio_reqwrap_jcallback(req_wrap); - if (jerry_value_is_function(jcallback)) { - iotjs_make_callback(jcallback, jerry_create_undefined(), &jargs); - } - - iotjs_jargs_destroy(&jargs); - gpio_reqwrap_dispatched(req_wrap); -} - - -static void gpio_set_configurable(iotjs_gpio_t* gpio, - jerry_value_t jconfigurable) { +static jerry_value_t gpio_set_configuration(iotjs_gpio_t* gpio, + jerry_value_t jconfigurable) { jerry_value_t jpin = iotjs_jval_get_property(jconfigurable, IOTJS_MAGIC_STRING_PIN); gpio->pin = iotjs_jval_as_number(jpin); @@ -190,10 +61,18 @@ static void gpio_set_configurable(iotjs_gpio_t* gpio, jerry_value_t jdirection = iotjs_jval_get_property(jconfigurable, IOTJS_MAGIC_STRING_DIRECTION); - if (!jerry_value_is_undefined(jdirection)) { - gpio->direction = (GpioDirection)iotjs_jval_as_number(jdirection); - } else { + if (jerry_value_is_undefined(jdirection)) { gpio->direction = kGpioDirectionOut; + } else { + if (jerry_value_is_number(jdirection)) { + gpio->direction = (GpioDirection)iotjs_jval_as_number(jdirection); + } else { + gpio->direction = __kGpioDirectionMax; + } + if (gpio->direction >= __kGpioDirectionMax) { + return JS_CREATE_ERROR( + TYPE, "Bad arguments - gpio.direction should be DIRECTION.IN or OUT"); + } } jerry_release_value(jdirection); @@ -201,10 +80,34 @@ static void gpio_set_configurable(iotjs_gpio_t* gpio, jerry_value_t jmode = iotjs_jval_get_property(jconfigurable, IOTJS_MAGIC_STRING_MODE); - if (!jerry_value_is_undefined(jmode)) { - gpio->mode = (GpioMode)iotjs_jval_as_number(jmode); - } else { + if (jerry_value_is_undefined(jmode)) { gpio->mode = kGpioModeNone; + } else { + if (jerry_value_is_number(jmode)) { + gpio->mode = (GpioMode)iotjs_jval_as_number(jmode); + } else { + gpio->mode = __kGpioModeMax; + } + if (gpio->mode >= __kGpioModeMax) { + return JS_CREATE_ERROR(TYPE, + "Bad arguments - gpio.mode should be MODE.NONE, " + "PULLUP, PULLDOWN, FLOAT, PUSHPULL or OPENDRAIN"); + + } else if (gpio->direction == kGpioDirectionIn && + gpio->mode != kGpioModeNone && gpio->mode != kGpioModePullup && + gpio->mode != kGpioModePulldown) { + return JS_CREATE_ERROR(TYPE, + "Bad arguments - DIRECTION.IN only supports " + "MODE.NONE, PULLUP and PULLDOWN"); + + } else if (gpio->direction == kGpioDirectionOut && + gpio->mode != kGpioModeNone && gpio->mode != kGpioModeFloat && + gpio->mode != kGpioModePushpull && + gpio->mode != kGpioModeOpendrain) { + return JS_CREATE_ERROR(TYPE, + "Bad arguments - DIRECTION.OUT only supports " + "MODE.NONE, FLOAT, PUSHPULL and OPENDRAIN"); + } } jerry_release_value(jmode); @@ -212,23 +115,24 @@ static void gpio_set_configurable(iotjs_gpio_t* gpio, jerry_value_t jedge = iotjs_jval_get_property(jconfigurable, IOTJS_MAGIC_STRING_EDGE); - if (!jerry_value_is_undefined(jedge)) { - gpio->edge = (GpioEdge)iotjs_jval_as_number(jedge); - } else { + if (jerry_value_is_undefined(jedge)) { gpio->edge = kGpioEdgeNone; + } else { + if (jerry_value_is_number(jedge)) { + gpio->edge = (GpioEdge)iotjs_jval_as_number(jedge); + } else { + gpio->edge = __kGpioEdgeMax; + } + if (gpio->edge >= __kGpioEdgeMax) { + return JS_CREATE_ERROR(TYPE, + "Bad arguments - gpio.edge should be EDGE.NONE, " + "RISING, FALLING or BOTH"); + } } jerry_release_value(jedge); -} - - -#define GPIO_CALL_ASYNC(op, jcallback) \ - do { \ - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); \ - iotjs_gpio_reqwrap_t* req_wrap = gpio_reqwrap_create(jcallback, gpio, op); \ - uv_work_t* req = gpio_reqwrap_req(req_wrap); \ - uv_queue_work(loop, req, gpio_worker, gpio_after_worker); \ - } while (0) + return jerry_create_undefined(); +} JS_FUNCTION(GpioCons) { DJS_CHECK_THIS(); @@ -238,45 +142,47 @@ JS_FUNCTION(GpioCons) { // Create GPIO object const jerry_value_t jgpio = JS_GET_THIS(); iotjs_gpio_t* gpio = gpio_create(jgpio); - IOTJS_ASSERT(gpio == gpio_instance_from_jval(jgpio)); - gpio_set_configurable(gpio, JS_GET_ARG(0, object)); + jerry_value_t config_res = + gpio_set_configuration(gpio, JS_GET_ARG(0, object)); + if (jerry_value_has_error_flag(config_res)) { + return config_res; + } + IOTJS_ASSERT(jerry_value_is_undefined(config_res)); const jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); // If the callback doesn't exist, it is completed synchronously. // Otherwise, it will be executed asynchronously. if (!jerry_value_is_null(jcallback)) { - GPIO_CALL_ASYNC(kGpioOpOpen, jcallback); + iotjs_periph_call_async(gpio, jcallback, kGpioOpOpen, gpio_worker); } else if (!iotjs_gpio_open(gpio)) { - return JS_CREATE_ERROR(COMMON, "GPIO Error: cannot open GPIO"); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kGpioOpOpen)); } return jerry_create_undefined(); } - JS_FUNCTION(Close) { JS_DECLARE_THIS_PTR(gpio, gpio); DJS_CHECK_ARG_IF_EXIST(0, function); - GPIO_CALL_ASYNC(kGpioOpClose, JS_GET_ARG_IF_EXIST(0, function)); + iotjs_periph_call_async(gpio, JS_GET_ARG_IF_EXIST(0, function), kGpioOpClose, + gpio_worker); return jerry_create_undefined(); } - JS_FUNCTION(CloseSync) { JS_DECLARE_THIS_PTR(gpio, gpio); if (!iotjs_gpio_close(gpio)) { - return JS_CREATE_ERROR(COMMON, "GPIO CloseSync Error"); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kGpioOpClose)); } return jerry_create_undefined(); } - JS_FUNCTION(Write) { JS_DECLARE_THIS_PTR(gpio, gpio); @@ -286,19 +192,19 @@ JS_FUNCTION(Write) { } else if (jerry_value_is_boolean(jargv[0])) { value = jerry_get_boolean_value(jargv[0]); } else { - return JS_CREATE_ERROR(COMMON, "GPIO Write Error - Wrong argument type"); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kGpioOpWrite)); } DJS_CHECK_ARG_IF_EXIST(1, function); gpio->value = value; - GPIO_CALL_ASYNC(kGpioOpWrite, JS_GET_ARG_IF_EXIST(1, function)); + iotjs_periph_call_async(gpio, JS_GET_ARG_IF_EXIST(1, function), kGpioOpWrite, + gpio_worker); return jerry_create_undefined(); } - JS_FUNCTION(WriteSync) { JS_DECLARE_THIS_PTR(gpio, gpio); @@ -315,34 +221,32 @@ JS_FUNCTION(WriteSync) { gpio->value = value; if (!iotjs_gpio_write(gpio)) { - return JS_CREATE_ERROR(COMMON, "GPIO WriteSync Error"); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kGpioOpWrite)); } return jerry_create_undefined(); } - JS_FUNCTION(Read) { JS_DECLARE_THIS_PTR(gpio, gpio); DJS_CHECK_ARG_IF_EXIST(0, function); - GPIO_CALL_ASYNC(kGpioOpRead, JS_GET_ARG_IF_EXIST(0, function)); + iotjs_periph_call_async(gpio, JS_GET_ARG_IF_EXIST(0, function), kGpioOpRead, + gpio_worker); return jerry_create_undefined(); } - JS_FUNCTION(ReadSync) { JS_DECLARE_THIS_PTR(gpio, gpio); if (!iotjs_gpio_read(gpio)) { - return JS_CREATE_ERROR(COMMON, "GPIO ReadSync Error"); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kGpioOpRead)); } return jerry_create_boolean(gpio->value); } - jerry_value_t InitGpio() { jerry_value_t jgpioConstructor = jerry_create_external_function(GpioCons); diff --git a/src/modules/iotjs_module_gpio.h b/src/modules/iotjs_module_gpio.h index 3d195a1..3c78b59 100644 --- a/src/modules/iotjs_module_gpio.h +++ b/src/modules/iotjs_module_gpio.h @@ -19,15 +19,16 @@ #include "iotjs_def.h" +#include "iotjs_module_periph_common.h" #include "iotjs_reqwrap.h" typedef enum { kGpioDirectionIn = 0, kGpioDirectionOut, + __kGpioDirectionMax } GpioDirection; - typedef enum { kGpioModeNone = 0, kGpioModePullup, @@ -35,30 +36,17 @@ typedef enum { kGpioModeFloat, kGpioModePushpull, kGpioModeOpendrain, + __kGpioModeMax } GpioMode; - typedef enum { kGpioEdgeNone = 0, kGpioEdgeRising, kGpioEdgeFalling, kGpioEdgeBoth, + __kGpioEdgeMax } GpioEdge; - -typedef enum { - kGpioOpOpen, - kGpioOpWrite, - kGpioOpRead, - kGpioOpClose, -} GpioOp; - - -typedef struct { - GpioOp op; - bool result; -} iotjs_gpio_reqdata_t; - typedef struct iotjs_gpio_platform_data_s iotjs_gpio_platform_data_t; // This Gpio class provides interfaces for GPIO operation. @@ -73,15 +61,6 @@ typedef struct { GpioEdge edge; } iotjs_gpio_t; - -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_work_t req; - iotjs_gpio_reqdata_t req_data; - iotjs_gpio_t* gpio_data; -} iotjs_gpio_reqwrap_t; - - bool iotjs_gpio_open(iotjs_gpio_t* gpio); bool iotjs_gpio_write(iotjs_gpio_t* gpio); bool iotjs_gpio_read(iotjs_gpio_t* gpio); diff --git a/src/modules/iotjs_module_http_parser.c b/src/modules/iotjs_module_http_parser.c new file mode 100644 index 0000000..e3f56e5 --- /dev/null +++ b/src/modules/iotjs_module_http_parser.c @@ -0,0 +1,510 @@ +/* Copyright 2015-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 "iotjs_def.h" +#include "iotjs_module_buffer.h" +#include +#include +#include + +#include "http_parser.h" + + +// If # of header fields == HEADER_MAX, flush header to JS side. +// This is weired : # of maximum headers in C equals to HEADER_MAX-1. +// This is because , OnHeaders cb, we increase n_fields first, +// and check whether field == HEADER_MAX. +// ex) HEADER_MAX 2 means that we can keep at most 1 header field/value +// during http parsing. +// Increase this to minimize inter JS-C call +#define HEADER_MAX 10 + + +typedef struct { + jerry_value_t jobject; + + http_parser parser; + + iotjs_string_t url; + iotjs_string_t status_msg; + + iotjs_string_t fields[HEADER_MAX]; + iotjs_string_t values[HEADER_MAX]; + size_t n_fields; + size_t n_values; + + jerry_value_t cur_jbuf; + char* cur_buf; + size_t cur_buf_len; + + bool flushed; +} iotjs_http_parserwrap_t; + + +typedef enum http_parser_type http_parser_type; + + +static void iotjs_http_parserwrap_initialize( + iotjs_http_parserwrap_t* http_parserwrap, http_parser_type type) { + http_parser_init(&http_parserwrap->parser, type); + iotjs_string_destroy(&http_parserwrap->url); + iotjs_string_destroy(&http_parserwrap->status_msg); + http_parserwrap->n_fields = 0; + http_parserwrap->n_values = 0; + http_parserwrap->flushed = false; + http_parserwrap->cur_jbuf = jerry_create_null(); + http_parserwrap->cur_buf = NULL; + http_parserwrap->cur_buf_len = 0; +} + + +IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(http_parserwrap); + + +static void iotjs_http_parserwrap_create(const jerry_value_t jparser, + http_parser_type type) { + iotjs_http_parserwrap_t* http_parserwrap = + IOTJS_ALLOC(iotjs_http_parserwrap_t); + http_parserwrap->jobject = jparser; + jerry_set_object_native_pointer(jparser, http_parserwrap, + &this_module_native_info); + + http_parserwrap->url = iotjs_string_create(); + http_parserwrap->status_msg = iotjs_string_create(); + for (size_t i = 0; i < HEADER_MAX; i++) { + http_parserwrap->fields[i] = iotjs_string_create(); + http_parserwrap->values[i] = iotjs_string_create(); + } + + iotjs_http_parserwrap_initialize(http_parserwrap, type); + http_parserwrap->parser.data = http_parserwrap; + + IOTJS_ASSERT(jerry_value_is_object(http_parserwrap->jobject)); +} + + +static void iotjs_http_parserwrap_destroy( + iotjs_http_parserwrap_t* http_parserwrap) { + iotjs_string_destroy(&http_parserwrap->url); + iotjs_string_destroy(&http_parserwrap->status_msg); + for (size_t i = 0; i < HEADER_MAX; i++) { + iotjs_string_destroy(&http_parserwrap->fields[i]); + iotjs_string_destroy(&http_parserwrap->values[i]); + } + + IOTJS_RELEASE(http_parserwrap); +} + + +static jerry_value_t iotjs_http_parserwrap_make_header( + iotjs_http_parserwrap_t* http_parserwrap) { + jerry_value_t jheader = jerry_create_array(http_parserwrap->n_values * 2); + for (size_t i = 0; i < http_parserwrap->n_values; i++) { + jerry_value_t f = iotjs_jval_create_string(&http_parserwrap->fields[i]); + jerry_value_t v = iotjs_jval_create_string(&http_parserwrap->values[i]); + iotjs_jval_set_property_by_index(jheader, i * 2, f); + iotjs_jval_set_property_by_index(jheader, i * 2 + 1, v); + jerry_release_value(f); + jerry_release_value(v); + } + return jheader; +} + + +static void iotjs_http_parserwrap_flush( + iotjs_http_parserwrap_t* http_parserwrap) { + const jerry_value_t jobj = http_parserwrap->jobject; + jerry_value_t func = + iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONHEADERS); + IOTJS_ASSERT(jerry_value_is_function(func)); + + iotjs_jargs_t argv = iotjs_jargs_create(2); + jerry_value_t jheader = iotjs_http_parserwrap_make_header(http_parserwrap); + iotjs_jargs_append_jval(&argv, jheader); + jerry_release_value(jheader); + if (http_parserwrap->parser.type == HTTP_REQUEST && + !iotjs_string_is_empty(&http_parserwrap->url)) { + iotjs_jargs_append_string(&argv, &http_parserwrap->url); + } + + iotjs_make_callback(func, jobj, &argv); + + iotjs_string_destroy(&http_parserwrap->url); + iotjs_jargs_destroy(&argv); + jerry_release_value(func); + http_parserwrap->flushed = true; +} + + +static void iotjs_http_parserwrap_set_buf( + iotjs_http_parserwrap_t* http_parserwrap, jerry_value_t jbuf, char* buf, + size_t sz) { + http_parserwrap->cur_jbuf = jbuf; + http_parserwrap->cur_buf = buf; + http_parserwrap->cur_buf_len = sz; +} + + +// http-parser callbacks +static int iotjs_http_parserwrap_on_message_begin(http_parser* parser) { + iotjs_http_parserwrap_t* http_parserwrap = + (iotjs_http_parserwrap_t*)(parser->data); + iotjs_string_destroy(&http_parserwrap->url); + iotjs_string_destroy(&http_parserwrap->status_msg); + return 0; +} + + +static int iotjs_http_parserwrap_on_url(http_parser* parser, const char* at, + size_t length) { + iotjs_http_parserwrap_t* http_parserwrap = + (iotjs_http_parserwrap_t*)(parser->data); + iotjs_string_append(&http_parserwrap->url, at, length); + return 0; +} + + +static int iotjs_http_parserwrap_on_status(http_parser* parser, const char* at, + size_t length) { + iotjs_http_parserwrap_t* http_parserwrap = + (iotjs_http_parserwrap_t*)(parser->data); + iotjs_string_append(&http_parserwrap->status_msg, at, length); + return 0; +} + + +static int iotjs_http_parserwrap_on_header_field(http_parser* parser, + const char* at, + size_t length) { + iotjs_http_parserwrap_t* http_parserwrap = + (iotjs_http_parserwrap_t*)(parser->data); + if (http_parserwrap->n_fields == http_parserwrap->n_values) { + http_parserwrap->n_fields++; + // values and fields are flushed to JS + // before corresponding OnHeaderValue is called. + if (http_parserwrap->n_fields == HEADER_MAX) { + iotjs_http_parserwrap_flush(http_parserwrap); // to JS world + http_parserwrap->n_fields = 1; + http_parserwrap->n_values = 0; + } + iotjs_string_destroy( + &http_parserwrap->fields[http_parserwrap->n_fields - 1]); + } + IOTJS_ASSERT(http_parserwrap->n_fields == http_parserwrap->n_values + 1); + iotjs_string_append(&http_parserwrap->fields[http_parserwrap->n_fields - 1], + at, length); + + return 0; +} + + +static int iotjs_http_parserwrap_on_header_value(http_parser* parser, + const char* at, + size_t length) { + iotjs_http_parserwrap_t* http_parserwrap = + (iotjs_http_parserwrap_t*)(parser->data); + if (http_parserwrap->n_fields != http_parserwrap->n_values) { + http_parserwrap->n_values++; + iotjs_string_destroy( + &http_parserwrap->values[http_parserwrap->n_values - 1]); + } + + IOTJS_ASSERT(http_parserwrap->n_fields == http_parserwrap->n_values); + + iotjs_string_append(&http_parserwrap->values[http_parserwrap->n_values - 1], + at, length); + + return 0; +} + + +static int iotjs_http_parserwrap_on_headers_complete(http_parser* parser) { + iotjs_http_parserwrap_t* http_parserwrap = + (iotjs_http_parserwrap_t*)(parser->data); + const jerry_value_t jobj = http_parserwrap->jobject; + jerry_value_t func = + iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONHEADERSCOMPLETE); + IOTJS_ASSERT(jerry_value_is_function(func)); + + // URL + iotjs_jargs_t argv = iotjs_jargs_create(1); + jerry_value_t info = jerry_create_object(); + + if (http_parserwrap->flushed) { + // If some headers already are flushed, + // flush the remaining headers. + // In Flush function, url is already flushed to JS. + iotjs_http_parserwrap_flush(http_parserwrap); + } else { + // Here, there was no flushed header. + // We need to make a new header object with all header fields + jerry_value_t jheader = iotjs_http_parserwrap_make_header(http_parserwrap); + iotjs_jval_set_property_jval(info, IOTJS_MAGIC_STRING_HEADERS, jheader); + jerry_release_value(jheader); + if (http_parserwrap->parser.type == HTTP_REQUEST) { + IOTJS_ASSERT(!iotjs_string_is_empty(&http_parserwrap->url)); + iotjs_jval_set_property_string(info, IOTJS_MAGIC_STRING_URL, + &http_parserwrap->url); + } + } + http_parserwrap->n_fields = http_parserwrap->n_values = 0; + + // Method + if (http_parserwrap->parser.type == HTTP_REQUEST) { + iotjs_jval_set_property_number(info, IOTJS_MAGIC_STRING_METHOD, + http_parserwrap->parser.method); + } + // Status + else if (http_parserwrap->parser.type == HTTP_RESPONSE) { + iotjs_jval_set_property_number(info, IOTJS_MAGIC_STRING_STATUS, + http_parserwrap->parser.status_code); + iotjs_jval_set_property_string(info, IOTJS_MAGIC_STRING_STATUS_MSG, + &http_parserwrap->status_msg); + } + + + // For future support, current http_server module does not support + // upgrade and keepalive. + // upgrade + iotjs_jval_set_property_boolean(info, IOTJS_MAGIC_STRING_UPGRADE, + http_parserwrap->parser.upgrade); + // shouldkeepalive + iotjs_jval_set_property_boolean(info, IOTJS_MAGIC_STRING_SHOULDKEEPALIVE, + http_should_keep_alive( + &http_parserwrap->parser)); + + + iotjs_jargs_append_jval(&argv, info); + + jerry_value_t res = iotjs_make_callback_with_result(func, jobj, &argv); + + int ret = 1; + if (jerry_value_is_boolean(res)) { + ret = iotjs_jval_as_boolean(res); + } else if (jerry_value_is_object(res)) { + // if exception throw occurs in iotjs_make_callback_with_result, then the + // result can be an object. + ret = 0; + } + + iotjs_jargs_destroy(&argv); + jerry_release_value(func); + jerry_release_value(res); + jerry_release_value(info); + + return ret; +} + + +static int iotjs_http_parserwrap_on_body(http_parser* parser, const char* at, + size_t length) { + iotjs_http_parserwrap_t* http_parserwrap = + (iotjs_http_parserwrap_t*)(parser->data); + const jerry_value_t jobj = http_parserwrap->jobject; + jerry_value_t func = iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONBODY); + IOTJS_ASSERT(jerry_value_is_function(func)); + + iotjs_jargs_t argv = iotjs_jargs_create(3); + iotjs_jargs_append_jval(&argv, http_parserwrap->cur_jbuf); + iotjs_jargs_append_number(&argv, at - http_parserwrap->cur_buf); + iotjs_jargs_append_number(&argv, length); + + + iotjs_make_callback(func, jobj, &argv); + + iotjs_jargs_destroy(&argv); + jerry_release_value(func); + + return 0; +} + + +static int iotjs_http_parserwrap_on_message_complete(http_parser* parser) { + iotjs_http_parserwrap_t* http_parserwrap = + (iotjs_http_parserwrap_t*)(parser->data); + const jerry_value_t jobj = http_parserwrap->jobject; + jerry_value_t func = + iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONMESSAGECOMPLETE); + IOTJS_ASSERT(jerry_value_is_function(func)); + + iotjs_make_callback(func, jobj, iotjs_jargs_get_empty()); + + jerry_release_value(func); + + return 0; +} + + +const struct http_parser_settings settings = { + iotjs_http_parserwrap_on_message_begin, + iotjs_http_parserwrap_on_url, + iotjs_http_parserwrap_on_status, + iotjs_http_parserwrap_on_header_field, + iotjs_http_parserwrap_on_header_value, + iotjs_http_parserwrap_on_headers_complete, + iotjs_http_parserwrap_on_body, + iotjs_http_parserwrap_on_message_complete, + NULL, /* on_chunk_header */ + NULL, /* on_chunk_complete */ +}; + + +static jerry_value_t iotjs_http_parser_return_parserrror( + http_parser* nativeparser) { + enum http_errno err = HTTP_PARSER_ERRNO(nativeparser); + + jerry_value_t eobj = + iotjs_jval_create_error_without_error_flag("Parse Error"); + iotjs_jval_set_property_number(eobj, IOTJS_MAGIC_STRING_BYTEPARSED, 0); + iotjs_jval_set_property_string_raw(eobj, IOTJS_MAGIC_STRING_CODE, + http_errno_name(err)); + return eobj; +} + + +JS_FUNCTION(Reinitialize) { + JS_DECLARE_THIS_PTR(http_parserwrap, parser); + DJS_CHECK_ARGS(1, number); + + http_parser_type httpparser_type = (http_parser_type)(JS_GET_ARG(0, number)); + + if (httpparser_type != HTTP_REQUEST && httpparser_type != HTTP_RESPONSE) { + return JS_CREATE_ERROR(TYPE, "Invalid type"); + } + + iotjs_http_parserwrap_initialize(parser, httpparser_type); + + return jerry_create_undefined(); +} + + +JS_FUNCTION(Finish) { + JS_DECLARE_THIS_PTR(http_parserwrap, parser); + + http_parser* nativeparser = &parser->parser; + size_t rv = http_parser_execute(nativeparser, &settings, NULL, 0); + + if (rv != 0) { + return iotjs_http_parser_return_parserrror(nativeparser); + } + + return jerry_create_undefined(); +} + + +JS_FUNCTION(Execute) { + JS_DECLARE_THIS_PTR(http_parserwrap, parser); + DJS_CHECK_ARGS(1, object); + + jerry_value_t jbuffer = JS_GET_ARG(0, object); + iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); + char* buf_data = buffer_wrap->buffer; + size_t buf_len = iotjs_bufferwrap_length(buffer_wrap); + JS_CHECK(buf_data != NULL && buf_len > 0); + + iotjs_http_parserwrap_set_buf(parser, jbuffer, buf_data, buf_len); + + http_parser* nativeparser = &parser->parser; + size_t nparsed = + http_parser_execute(nativeparser, &settings, buf_data, buf_len); + + iotjs_http_parserwrap_set_buf(parser, jerry_create_null(), NULL, 0); + + + if (!nativeparser->upgrade && nparsed != buf_len) { + // nparsed should equal to buf_len except UPGRADE protocol + return iotjs_http_parser_return_parserrror(nativeparser); + } else { + return jerry_create_number(nparsed); + } +} + + +static jerry_value_t iotjs_http_parser_pause(jerry_value_t jthis, int paused) { + JS_DECLARE_THIS_PTR(http_parserwrap, parser); + + http_parser* nativeparser = &parser->parser; + http_parser_pause(nativeparser, paused); + return jerry_create_undefined(); +} + + +JS_FUNCTION(Pause) { + return iotjs_http_parser_pause(jthis, 1); +} + + +JS_FUNCTION(Resume) { + return iotjs_http_parser_pause(jthis, 0); +} + + +JS_FUNCTION(HTTPParserCons) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, number); + + const jerry_value_t jparser = JS_GET_THIS(); + + http_parser_type httpparser_type = (http_parser_type)(JS_GET_ARG(0, number)); + + if (httpparser_type != HTTP_REQUEST && httpparser_type != HTTP_RESPONSE) { + return JS_CREATE_ERROR(TYPE, "Invalid type"); + } + + iotjs_http_parserwrap_create(jparser, httpparser_type); + return jerry_create_undefined(); +} + + +jerry_value_t InitHttpParser() { + jerry_value_t http_parser = jerry_create_object(); + + jerry_value_t jParserCons = jerry_create_external_function(HTTPParserCons); + iotjs_jval_set_property_jval(http_parser, IOTJS_MAGIC_STRING_HTTPPARSER, + jParserCons); + + iotjs_jval_set_property_number(jParserCons, IOTJS_MAGIC_STRING_REQUEST_U, + HTTP_REQUEST); + iotjs_jval_set_property_number(jParserCons, IOTJS_MAGIC_STRING_RESPONSE_U, + HTTP_RESPONSE); + + jerry_value_t methods = jerry_create_object(); +#define V(num, name, string) \ + iotjs_jval_set_property_string_raw(methods, #num, #string); + HTTP_METHOD_MAP(V) +#undef V + + iotjs_jval_set_property_jval(jParserCons, IOTJS_MAGIC_STRING_METHODS, + methods); + + jerry_value_t prototype = jerry_create_object(); + + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_EXECUTE, Execute); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_REINITIALIZE, + Reinitialize); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_FINISH, Finish); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_PAUSE, Pause); + iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_RESUME, Resume); + + iotjs_jval_set_property_jval(jParserCons, IOTJS_MAGIC_STRING_PROTOTYPE, + prototype); + + jerry_release_value(jParserCons); + jerry_release_value(methods); + jerry_release_value(prototype); + + return http_parser; +} diff --git a/src/modules/iotjs_module_httpparser.c b/src/modules/iotjs_module_httpparser.c deleted file mode 100644 index 868466c..0000000 --- a/src/modules/iotjs_module_httpparser.c +++ /dev/null @@ -1,502 +0,0 @@ -/* Copyright 2015-present Samsung Electronics Co., Ltd. and other contributors - * - * 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 "iotjs_def.h" -#include "iotjs_module_buffer.h" -#include -#include -#include - -#include "http_parser.h" - - -// If # of header fields == HEADER_MAX, flush header to JS side. -// This is weired : # of maximum headers in C equals to HEADER_MAX-1. -// This is because , OnHeaders cb, we increase n_fields first, -// and check whether field == HEADER_MAX. -// ex) HEADER_MAX 2 means that we can keep at most 1 header field/value -// during http parsing. -// Increase this to minimize inter JS-C call -#define HEADER_MAX 10 - - -typedef struct { - jerry_value_t jobject; - - http_parser parser; - - iotjs_string_t url; - iotjs_string_t status_msg; - - iotjs_string_t fields[HEADER_MAX]; - iotjs_string_t values[HEADER_MAX]; - size_t n_fields; - size_t n_values; - - jerry_value_t cur_jbuf; - char* cur_buf; - size_t cur_buf_len; - - bool flushed; -} iotjs_httpparserwrap_t; - - -typedef enum http_parser_type http_parser_type; - - -static void iotjs_httpparserwrap_initialize( - iotjs_httpparserwrap_t* httpparserwrap, http_parser_type type) { - http_parser_init(&httpparserwrap->parser, type); - iotjs_string_make_empty(&httpparserwrap->url); - iotjs_string_make_empty(&httpparserwrap->status_msg); - httpparserwrap->n_fields = 0; - httpparserwrap->n_values = 0; - httpparserwrap->flushed = false; - httpparserwrap->cur_jbuf = jerry_create_null(); - httpparserwrap->cur_buf = NULL; - httpparserwrap->cur_buf_len = 0; -} - - -IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(httpparserwrap); - - -static void iotjs_httpparserwrap_create(const jerry_value_t jparser, - http_parser_type type) { - iotjs_httpparserwrap_t* httpparserwrap = IOTJS_ALLOC(iotjs_httpparserwrap_t); - httpparserwrap->jobject = jparser; - jerry_set_object_native_pointer(jparser, httpparserwrap, - &this_module_native_info); - - httpparserwrap->url = iotjs_string_create(); - httpparserwrap->status_msg = iotjs_string_create(); - for (size_t i = 0; i < HEADER_MAX; i++) { - httpparserwrap->fields[i] = iotjs_string_create(); - httpparserwrap->values[i] = iotjs_string_create(); - } - - iotjs_httpparserwrap_initialize(httpparserwrap, type); - httpparserwrap->parser.data = httpparserwrap; - - IOTJS_ASSERT(jerry_value_is_object(httpparserwrap->jobject)); -} - - -static void iotjs_httpparserwrap_destroy( - iotjs_httpparserwrap_t* httpparserwrap) { - iotjs_string_destroy(&httpparserwrap->url); - iotjs_string_destroy(&httpparserwrap->status_msg); - for (size_t i = 0; i < HEADER_MAX; i++) { - iotjs_string_destroy(&httpparserwrap->fields[i]); - iotjs_string_destroy(&httpparserwrap->values[i]); - } - - IOTJS_RELEASE(httpparserwrap); -} - - -static jerry_value_t iotjs_httpparserwrap_make_header( - iotjs_httpparserwrap_t* httpparserwrap) { - jerry_value_t jheader = jerry_create_array(httpparserwrap->n_values * 2); - for (size_t i = 0; i < httpparserwrap->n_values; i++) { - jerry_value_t f = iotjs_jval_create_string(&httpparserwrap->fields[i]); - jerry_value_t v = iotjs_jval_create_string(&httpparserwrap->values[i]); - iotjs_jval_set_property_by_index(jheader, i * 2, f); - iotjs_jval_set_property_by_index(jheader, i * 2 + 1, v); - jerry_release_value(f); - jerry_release_value(v); - } - return jheader; -} - - -static void iotjs_httpparserwrap_flush(iotjs_httpparserwrap_t* httpparserwrap) { - const jerry_value_t jobj = httpparserwrap->jobject; - jerry_value_t func = - iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONHEADERS); - IOTJS_ASSERT(jerry_value_is_function(func)); - - iotjs_jargs_t argv = iotjs_jargs_create(2); - jerry_value_t jheader = iotjs_httpparserwrap_make_header(httpparserwrap); - iotjs_jargs_append_jval(&argv, jheader); - jerry_release_value(jheader); - if (httpparserwrap->parser.type == HTTP_REQUEST && - !iotjs_string_is_empty(&httpparserwrap->url)) { - iotjs_jargs_append_string(&argv, &httpparserwrap->url); - } - - iotjs_make_callback(func, jobj, &argv); - - iotjs_string_make_empty(&httpparserwrap->url); - iotjs_jargs_destroy(&argv); - jerry_release_value(func); - httpparserwrap->flushed = true; -} - - -static void iotjs_httpparserwrap_set_buf(iotjs_httpparserwrap_t* httpparserwrap, - jerry_value_t jbuf, char* buf, - size_t sz) { - httpparserwrap->cur_jbuf = jbuf; - httpparserwrap->cur_buf = buf; - httpparserwrap->cur_buf_len = sz; -} - - -// http-parser callbacks -static int iotjs_httpparserwrap_on_message_begin(http_parser* parser) { - iotjs_httpparserwrap_t* httpparserwrap = - (iotjs_httpparserwrap_t*)(parser->data); - iotjs_string_make_empty(&httpparserwrap->url); - iotjs_string_make_empty(&httpparserwrap->status_msg); - return 0; -} - - -static int iotjs_httpparserwrap_on_url(http_parser* parser, const char* at, - size_t length) { - iotjs_httpparserwrap_t* httpparserwrap = - (iotjs_httpparserwrap_t*)(parser->data); - iotjs_string_append(&httpparserwrap->url, at, length); - return 0; -} - - -static int iotjs_httpparserwrap_on_status(http_parser* parser, const char* at, - size_t length) { - iotjs_httpparserwrap_t* httpparserwrap = - (iotjs_httpparserwrap_t*)(parser->data); - iotjs_string_append(&httpparserwrap->status_msg, at, length); - return 0; -} - - -static int iotjs_httpparserwrap_on_header_field(http_parser* parser, - const char* at, size_t length) { - iotjs_httpparserwrap_t* httpparserwrap = - (iotjs_httpparserwrap_t*)(parser->data); - if (httpparserwrap->n_fields == httpparserwrap->n_values) { - httpparserwrap->n_fields++; - // values and fields are flushed to JS - // before corresponding OnHeaderValue is called. - if (httpparserwrap->n_fields == HEADER_MAX) { - iotjs_httpparserwrap_flush(httpparserwrap); // to JS world - httpparserwrap->n_fields = 1; - httpparserwrap->n_values = 0; - } - iotjs_string_make_empty( - &httpparserwrap->fields[httpparserwrap->n_fields - 1]); - } - IOTJS_ASSERT(httpparserwrap->n_fields == httpparserwrap->n_values + 1); - iotjs_string_append(&httpparserwrap->fields[httpparserwrap->n_fields - 1], at, - length); - - return 0; -} - - -static int iotjs_httpparserwrap_on_header_value(http_parser* parser, - const char* at, size_t length) { - iotjs_httpparserwrap_t* httpparserwrap = - (iotjs_httpparserwrap_t*)(parser->data); - if (httpparserwrap->n_fields != httpparserwrap->n_values) { - httpparserwrap->n_values++; - iotjs_string_make_empty( - &httpparserwrap->values[httpparserwrap->n_values - 1]); - } - - IOTJS_ASSERT(httpparserwrap->n_fields == httpparserwrap->n_values); - - iotjs_string_append(&httpparserwrap->values[httpparserwrap->n_values - 1], at, - length); - - return 0; -} - - -static int iotjs_httpparserwrap_on_headers_complete(http_parser* parser) { - iotjs_httpparserwrap_t* httpparserwrap = - (iotjs_httpparserwrap_t*)(parser->data); - const jerry_value_t jobj = httpparserwrap->jobject; - jerry_value_t func = - iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONHEADERSCOMPLETE); - IOTJS_ASSERT(jerry_value_is_function(func)); - - // URL - iotjs_jargs_t argv = iotjs_jargs_create(1); - jerry_value_t info = jerry_create_object(); - - if (httpparserwrap->flushed) { - // If some headers already are flushed, - // flush the remaining headers. - // In Flush function, url is already flushed to JS. - iotjs_httpparserwrap_flush(httpparserwrap); - } else { - // Here, there was no flushed header. - // We need to make a new header object with all header fields - jerry_value_t jheader = iotjs_httpparserwrap_make_header(httpparserwrap); - iotjs_jval_set_property_jval(info, IOTJS_MAGIC_STRING_HEADERS, jheader); - jerry_release_value(jheader); - if (httpparserwrap->parser.type == HTTP_REQUEST) { - IOTJS_ASSERT(!iotjs_string_is_empty(&httpparserwrap->url)); - iotjs_jval_set_property_string(info, IOTJS_MAGIC_STRING_URL, - &httpparserwrap->url); - } - } - httpparserwrap->n_fields = httpparserwrap->n_values = 0; - - // Method - if (httpparserwrap->parser.type == HTTP_REQUEST) { - iotjs_jval_set_property_number(info, IOTJS_MAGIC_STRING_METHOD, - httpparserwrap->parser.method); - } - // Status - else if (httpparserwrap->parser.type == HTTP_RESPONSE) { - iotjs_jval_set_property_number(info, IOTJS_MAGIC_STRING_STATUS, - httpparserwrap->parser.status_code); - iotjs_jval_set_property_string(info, IOTJS_MAGIC_STRING_STATUS_MSG, - &httpparserwrap->status_msg); - } - - - // For future support, current http_server module does not support - // upgrade and keepalive. - // upgrade - iotjs_jval_set_property_boolean(info, IOTJS_MAGIC_STRING_UPGRADE, - httpparserwrap->parser.upgrade); - // shouldkeepalive - iotjs_jval_set_property_boolean(info, IOTJS_MAGIC_STRING_SHOULDKEEPALIVE, - http_should_keep_alive( - &httpparserwrap->parser)); - - - iotjs_jargs_append_jval(&argv, info); - - jerry_value_t res = iotjs_make_callback_with_result(func, jobj, &argv); - - int ret = 1; - if (jerry_value_is_boolean(res)) { - ret = iotjs_jval_as_boolean(res); - } else if (jerry_value_is_object(res)) { - // if exception throw occurs in iotjs_make_callback_with_result, then the - // result can be an object. - ret = 0; - } - - iotjs_jargs_destroy(&argv); - jerry_release_value(func); - jerry_release_value(res); - jerry_release_value(info); - - return ret; -} - - -static int iotjs_httpparserwrap_on_body(http_parser* parser, const char* at, - size_t length) { - iotjs_httpparserwrap_t* httpparserwrap = - (iotjs_httpparserwrap_t*)(parser->data); - const jerry_value_t jobj = httpparserwrap->jobject; - jerry_value_t func = iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONBODY); - IOTJS_ASSERT(jerry_value_is_function(func)); - - iotjs_jargs_t argv = iotjs_jargs_create(3); - iotjs_jargs_append_jval(&argv, httpparserwrap->cur_jbuf); - iotjs_jargs_append_number(&argv, at - httpparserwrap->cur_buf); - iotjs_jargs_append_number(&argv, length); - - - iotjs_make_callback(func, jobj, &argv); - - iotjs_jargs_destroy(&argv); - jerry_release_value(func); - - return 0; -} - - -static int iotjs_httpparserwrap_on_message_complete(http_parser* parser) { - iotjs_httpparserwrap_t* httpparserwrap = - (iotjs_httpparserwrap_t*)(parser->data); - const jerry_value_t jobj = httpparserwrap->jobject; - jerry_value_t func = - iotjs_jval_get_property(jobj, IOTJS_MAGIC_STRING_ONMESSAGECOMPLETE); - IOTJS_ASSERT(jerry_value_is_function(func)); - - iotjs_make_callback(func, jobj, iotjs_jargs_get_empty()); - - jerry_release_value(func); - - return 0; -} - - -const struct http_parser_settings settings = { - iotjs_httpparserwrap_on_message_begin, - iotjs_httpparserwrap_on_url, - iotjs_httpparserwrap_on_status, - iotjs_httpparserwrap_on_header_field, - iotjs_httpparserwrap_on_header_value, - iotjs_httpparserwrap_on_headers_complete, - iotjs_httpparserwrap_on_body, - iotjs_httpparserwrap_on_message_complete, - NULL, /* on_chunk_header */ - NULL, /* on_chunk_complete */ -}; - - -static jerry_value_t iotjs_httpparser_return_parserrror( - http_parser* nativeparser) { - enum http_errno err = HTTP_PARSER_ERRNO(nativeparser); - - jerry_value_t eobj = - iotjs_jval_create_error_without_error_flag("Parse Error"); - iotjs_jval_set_property_number(eobj, IOTJS_MAGIC_STRING_BYTEPARSED, 0); - iotjs_jval_set_property_string_raw(eobj, IOTJS_MAGIC_STRING_CODE, - http_errno_name(err)); - return eobj; -} - - -JS_FUNCTION(Reinitialize) { - JS_DECLARE_THIS_PTR(httpparserwrap, parser); - DJS_CHECK_ARGS(1, number); - - http_parser_type httpparser_type = (http_parser_type)(JS_GET_ARG(0, number)); - IOTJS_ASSERT(httpparser_type == HTTP_REQUEST || - httpparser_type == HTTP_RESPONSE); - - iotjs_httpparserwrap_initialize(parser, httpparser_type); - - return jerry_create_undefined(); -} - - -JS_FUNCTION(Finish) { - JS_DECLARE_THIS_PTR(httpparserwrap, parser); - - http_parser* nativeparser = &parser->parser; - size_t rv = http_parser_execute(nativeparser, &settings, NULL, 0); - - if (rv != 0) { - return iotjs_httpparser_return_parserrror(nativeparser); - } - - return jerry_create_undefined(); -} - - -JS_FUNCTION(Execute) { - JS_DECLARE_THIS_PTR(httpparserwrap, parser); - DJS_CHECK_ARGS(1, object); - - jerry_value_t jbuffer = JS_GET_ARG(0, object); - iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); - char* buf_data = buffer_wrap->buffer; - size_t buf_len = iotjs_bufferwrap_length(buffer_wrap); - JS_CHECK(buf_data != NULL); - JS_CHECK(buf_len > 0); - - iotjs_httpparserwrap_set_buf(parser, jbuffer, buf_data, buf_len); - - http_parser* nativeparser = &parser->parser; - size_t nparsed = - http_parser_execute(nativeparser, &settings, buf_data, buf_len); - - iotjs_httpparserwrap_set_buf(parser, jerry_create_null(), NULL, 0); - - - if (!nativeparser->upgrade && nparsed != buf_len) { - // nparsed should equal to buf_len except UPGRADE protocol - return iotjs_httpparser_return_parserrror(nativeparser); - } else { - return jerry_create_number(nparsed); - } -} - - -static jerry_value_t iotjs_httpparser_pause(jerry_value_t jthis, int paused) { - JS_DECLARE_THIS_PTR(httpparserwrap, parser); - - http_parser* nativeparser = &parser->parser; - http_parser_pause(nativeparser, paused); - return jerry_create_undefined(); -} - - -JS_FUNCTION(Pause) { - return iotjs_httpparser_pause(jthis, 1); -} - - -JS_FUNCTION(Resume) { - return iotjs_httpparser_pause(jthis, 0); -} - - -JS_FUNCTION(HTTPParserCons) { - DJS_CHECK_THIS(); - DJS_CHECK_ARGS(1, number); - - const jerry_value_t jparser = JS_GET_THIS(); - - http_parser_type httpparser_type = (http_parser_type)(JS_GET_ARG(0, number)); - IOTJS_ASSERT(httpparser_type == HTTP_REQUEST || - httpparser_type == HTTP_RESPONSE); - iotjs_httpparserwrap_create(jparser, httpparser_type); - return jerry_create_undefined(); -} - - -jerry_value_t InitHttpparser() { - jerry_value_t httpparser = jerry_create_object(); - - jerry_value_t jParserCons = jerry_create_external_function(HTTPParserCons); - iotjs_jval_set_property_jval(httpparser, IOTJS_MAGIC_STRING_HTTPPARSER, - jParserCons); - - iotjs_jval_set_property_number(jParserCons, IOTJS_MAGIC_STRING_REQUEST_U, - HTTP_REQUEST); - iotjs_jval_set_property_number(jParserCons, IOTJS_MAGIC_STRING_RESPONSE_U, - HTTP_RESPONSE); - - jerry_value_t methods = jerry_create_object(); -#define V(num, name, string) \ - iotjs_jval_set_property_string_raw(methods, #num, #string); - HTTP_METHOD_MAP(V) -#undef V - - iotjs_jval_set_property_jval(jParserCons, IOTJS_MAGIC_STRING_METHODS, - methods); - - jerry_value_t prototype = jerry_create_object(); - - iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_EXECUTE, Execute); - iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_REINITIALIZE, - Reinitialize); - iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_FINISH, Finish); - iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_PAUSE, Pause); - iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_RESUME, Resume); - - iotjs_jval_set_property_jval(jParserCons, IOTJS_MAGIC_STRING_PROTOTYPE, - prototype); - - jerry_release_value(jParserCons); - jerry_release_value(methods); - jerry_release_value(prototype); - - return httpparser; -} diff --git a/src/modules/iotjs_module_https.c b/src/modules/iotjs_module_https.c deleted file mode 100644 index a6c16d5..0000000 --- a/src/modules/iotjs_module_https.c +++ /dev/null @@ -1,888 +0,0 @@ -/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors - * - * 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 "iotjs_module_https.h" -#include -#include -#include -#include -#include -#include -#include - -#include "iotjs_module_buffer.h" - -// A Per-Request Struct, native bound to https.ClientRequest -struct iotjs_https_t { - // Original Request Details - const char* URL; - HTTPS_Methods method; - struct curl_slist* header_list; - // TLS certs Options - const char* ca; - const char* cert; - const char* key; - bool reject_unauthorized; - // Content-Length for Post and Put - long content_length; - - // Handles - uv_loop_t* loop; - jerry_value_t jthis_native; - CURLM* curl_multi_handle; - uv_timer_t timeout; - CURL* curl_easy_handle; - // Curl Context - int running_handles; - int closing_handles; - bool request_done; - iotjs_https_poll_t* poll_data; - - // For SetTimeOut - uv_timer_t socket_timeout; - long timeout_ms; - double last_bytes_num; - uint64_t last_bytes_time; - - // For Writable Stream ClientRequest - size_t cur_read_index; - bool is_stream_writable; - bool data_to_read; - bool stream_ended; - bool to_destroy_read_onwrite; - iotjs_string_t read_chunk; - jerry_value_t read_callback; - jerry_value_t read_onwrite; - uv_timer_t async_read_onwrite; -}; - -struct iotjs_https_poll_t { - uv_poll_t poll_handle; - iotjs_https_poll_t* next; - iotjs_https_t* https_data; - curl_socket_t sockfd; - bool closing; -}; - -IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(https); - -//-------------Constructor------------ -iotjs_https_t* iotjs_https_create(const char* URL, const char* method, - const char* ca, const char* cert, - const char* key, - const bool reject_unauthorized, - jerry_value_t jthis) { - iotjs_https_t* https_data = IOTJS_ALLOC(iotjs_https_t); - - // Original Request Details - https_data->URL = URL; - https_data->header_list = NULL; - if (strcmp(method, STRING_GET) == 0) - https_data->method = HTTPS_GET; - else if (strcmp(method, STRING_POST) == 0) - https_data->method = HTTPS_POST; - else if (strcmp(method, STRING_PUT) == 0) - https_data->method = HTTPS_PUT; - else if (strcmp(method, STRING_DELETE) == 0) - https_data->method = HTTPS_DELETE; - else if (strcmp(method, STRING_HEAD) == 0) - https_data->method = HTTPS_HEAD; - else if (strcmp(method, STRING_CONNECT) == 0) - https_data->method = HTTPS_CONNECT; - else if (strcmp(method, STRING_OPTIONS) == 0) - https_data->method = HTTPS_OPTIONS; - else if (strcmp(method, STRING_TRACE) == 0) - https_data->method = HTTPS_TRACE; - else { - IOTJS_ASSERT(0); - } - - // TLS certs stuff - https_data->ca = ca; - https_data->cert = cert; - https_data->key = key; - https_data->reject_unauthorized = reject_unauthorized; - // Content Length stuff - https_data->content_length = -1; - - // Handles - https_data->loop = iotjs_environment_loop(iotjs_environment_get()); - https_data->jthis_native = jerry_acquire_value(jthis); - jerry_set_object_native_pointer(https_data->jthis_native, https_data, - &this_module_native_info); - https_data->curl_multi_handle = curl_multi_init(); - https_data->curl_easy_handle = curl_easy_init(); - https_data->timeout.data = (void*)https_data; - uv_timer_init(https_data->loop, &(https_data->timeout)); - https_data->request_done = false; - https_data->closing_handles = 3; - https_data->poll_data = NULL; - - // Timeout stuff - https_data->timeout_ms = -1; - https_data->last_bytes_num = -1; - https_data->last_bytes_time = 0; - https_data->socket_timeout.data = (void*)https_data; - uv_timer_init(https_data->loop, &(https_data->socket_timeout)); - - // ReadData stuff - https_data->cur_read_index = 0; - https_data->is_stream_writable = false; - https_data->stream_ended = false; - https_data->data_to_read = false; - https_data->to_destroy_read_onwrite = false; - https_data->async_read_onwrite.data = (void*)https_data; - uv_timer_init(https_data->loop, &(https_data->async_read_onwrite)); - // No Need to read data for following types of requests - if (https_data->method == HTTPS_GET || https_data->method == HTTPS_DELETE || - https_data->method == HTTPS_HEAD || https_data->method == HTTPS_OPTIONS || - https_data->method == HTTPS_TRACE) - https_data->stream_ended = true; - - return https_data; -} - -// Destructor -void iotjs_https_destroy(iotjs_https_t* https_data) { - https_data->URL = NULL; - IOTJS_RELEASE(https_data); -} - -//----------------Utility Functions------------------ -void iotjs_https_check_done(iotjs_https_t* https_data) { - char* done_url; - CURLMsg* message; - int pending; - bool error = false; - - while ((message = - curl_multi_info_read(https_data->curl_multi_handle, &pending))) { - switch (message->msg) { - case CURLMSG_DONE: - curl_easy_getinfo(message->easy_handle, CURLINFO_EFFECTIVE_URL, - &done_url); - break; - default: - error = true; - } - if (error) { - iotjs_jargs_t jarg = iotjs_jargs_create(1); - char error[] = "Unknown Error has occured."; - iotjs_string_t jresult_string = - iotjs_string_create_with_size(error, strlen(error)); - iotjs_jargs_append_string(&jarg, &jresult_string); - iotjs_https_jcallback(https_data, IOTJS_MAGIC_STRING_ONERROR, &jarg, - false); - iotjs_string_destroy(&jresult_string); - iotjs_jargs_destroy(&jarg); - } - if (https_data->stream_ended) { - iotjs_https_cleanup(https_data); - } else { - if (https_data->to_destroy_read_onwrite) { - iotjs_https_call_read_onwrite_async(https_data); - } - https_data->request_done = true; - } - break; - } -} - -// Cleanup before destructor -void iotjs_https_cleanup(iotjs_https_t* https_data) { - https_data->loop = NULL; - - uv_close((uv_handle_t*)&https_data->timeout, - (uv_close_cb)iotjs_https_uv_close_callback); - uv_close((uv_handle_t*)&https_data->socket_timeout, - (uv_close_cb)iotjs_https_uv_close_callback); - uv_close((uv_handle_t*)&https_data->async_read_onwrite, - (uv_close_cb)iotjs_https_uv_close_callback); - - iotjs_https_jcallback(https_data, IOTJS_MAGIC_STRING_ONEND, - iotjs_jargs_get_empty(), false); - iotjs_https_jcallback(https_data, IOTJS_MAGIC_STRING_ONCLOSED, - iotjs_jargs_get_empty(), false); - - curl_multi_remove_handle(https_data->curl_multi_handle, - https_data->curl_easy_handle); - curl_easy_cleanup(https_data->curl_easy_handle); - https_data->curl_easy_handle = NULL; - curl_multi_cleanup(https_data->curl_multi_handle); - https_data->curl_multi_handle = NULL; - curl_slist_free_all(https_data->header_list); - - if (https_data->poll_data != NULL) - iotjs_https_poll_close_all(https_data->poll_data); - - if (https_data->to_destroy_read_onwrite) { - const iotjs_jargs_t* jarg = iotjs_jargs_get_empty(); - jerry_value_t jthis = https_data->jthis_native; - IOTJS_ASSERT(jerry_value_is_function((https_data->read_onwrite))); - - if (!jerry_value_is_undefined((https_data->read_callback))) - iotjs_make_callback(https_data->read_callback, jthis, jarg); - - iotjs_make_callback(https_data->read_onwrite, jthis, jarg); - https_data->to_destroy_read_onwrite = false; - iotjs_string_destroy(&(https_data->read_chunk)); - jerry_release_value((https_data->read_onwrite)); - jerry_release_value((https_data->read_callback)); - } - return; -} - -// Set various parameters of curl handles -void iotjs_https_initialize_curl_opts(iotjs_https_t* https_data) { - // Setup Some parameters for multi handle - curl_multi_setopt(https_data->curl_multi_handle, CURLMOPT_SOCKETFUNCTION, - iotjs_https_curl_socket_callback); - curl_multi_setopt(https_data->curl_multi_handle, CURLMOPT_SOCKETDATA, - (void*)https_data); - curl_multi_setopt(https_data->curl_multi_handle, CURLMOPT_TIMERFUNCTION, - iotjs_https_curl_start_timeout_callback); - curl_multi_setopt(https_data->curl_multi_handle, CURLMOPT_TIMERDATA, - (void*)https_data); - - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_PROXY, ""); - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_HEADERDATA, - (void*)https_data); - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_WRITEFUNCTION, - iotjs_https_curl_write_callback); - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_WRITEDATA, - (void*)https_data); - - // Read and send data to server only for some request types - if (https_data->method == HTTPS_POST || https_data->method == HTTPS_PUT || - https_data->method == HTTPS_CONNECT) { - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_READFUNCTION, - iotjs_https_curl_read_callback); - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_READDATA, - (void*)https_data); - } - - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_SOCKOPTFUNCTION, - iotjs_https_curl_sockopt_callback); - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_SOCKOPTDATA, - (void*)https_data); - - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_URL, https_data->URL); - https_data->URL = NULL; - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_PROTOCOLS, - CURLPROTO_HTTP | CURLPROTO_HTTPS); - - if (strlen(https_data->ca) > 0) - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_CAINFO, - https_data->ca); - https_data->ca = NULL; - if (strlen(https_data->cert) > 0) - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_SSLCERT, - https_data->cert); - https_data->cert = NULL; - if (strlen(https_data->key) > 0) - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_SSLKEY, - https_data->key); - https_data->key = NULL; - if (!https_data->reject_unauthorized) { - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_SSL_VERIFYPEER, 0); - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_SSL_VERIFYHOST, 0); - } - - // Various request types - switch (https_data->method) { - case HTTPS_GET: - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_HTTPGET, 1L); - break; - case HTTPS_POST: - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_POST, 1L); - break; - case HTTPS_PUT: - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_UPLOAD, 1L); - break; - case HTTPS_DELETE: - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_CUSTOMREQUEST, - "DELETE"); - break; - case HTTPS_HEAD: - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_NOBODY, 1L); - break; - case HTTPS_CONNECT: - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_CUSTOMREQUEST, - "CONNECT"); - break; - case HTTPS_OPTIONS: - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_CUSTOMREQUEST, - "OPTIONS"); - break; - case HTTPS_TRACE: - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_CUSTOMREQUEST, - "TRACE"); - break; - } - - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_HTTP_TRANSFER_DECODING, - 0L); -} - -// Call any property of ClientRequest._Incoming -bool iotjs_https_jcallback(iotjs_https_t* https_data, const char* property, - const iotjs_jargs_t* jarg, bool resultvalue) { - jerry_value_t jthis = https_data->jthis_native; - bool retval = true; - if (jerry_value_is_null(jthis)) - return retval; - - jerry_value_t jincoming = - iotjs_jval_get_property(jthis, IOTJS_MAGIC_STRING__INCOMING); - jerry_value_t cb = iotjs_jval_get_property(jincoming, property); - - IOTJS_ASSERT(jerry_value_is_function(cb)); - if (!resultvalue) { - iotjs_make_callback(cb, jincoming, jarg); - } else { - jerry_value_t result = iotjs_make_callback_with_result(cb, jincoming, jarg); - retval = iotjs_jval_as_boolean(result); - jerry_release_value(result); - } - - jerry_release_value(jincoming); - jerry_release_value(cb); - return retval; -} - -// Call onWrite and callback after ClientRequest._write -void iotjs_https_call_read_onwrite(uv_timer_t* timer) { - iotjs_https_t* https_data = (iotjs_https_t*)(timer->data); - - uv_timer_stop(&(https_data->async_read_onwrite)); - if (jerry_value_is_null(https_data->jthis_native)) - return; - const iotjs_jargs_t* jarg = iotjs_jargs_get_empty(); - jerry_value_t jthis = https_data->jthis_native; - IOTJS_ASSERT(jerry_value_is_function((https_data->read_onwrite))); - - if (!jerry_value_is_undefined((https_data->read_callback))) - iotjs_make_callback(https_data->read_callback, jthis, jarg); - - iotjs_make_callback(https_data->read_onwrite, jthis, jarg); -} - -// Call the above method Asynchronously -void iotjs_https_call_read_onwrite_async(iotjs_https_t* https_data) { - uv_timer_start(&(https_data->async_read_onwrite), - iotjs_https_call_read_onwrite, 0, 0); -} - -// ------------Functions almost directly called by JS---------- -// Add a header to outgoing request -void iotjs_https_add_header(iotjs_https_t* https_data, - const char* char_header) { - https_data->header_list = - curl_slist_append(https_data->header_list, char_header); - if (https_data->method == HTTPS_POST || https_data->method == HTTPS_PUT) { - if (strncmp(char_header, "Content-Length: ", strlen("Content-Length: ")) == - 0) { - const char* numberString = char_header + strlen("Content-Length: "); - https_data->content_length = strtol(numberString, NULL, 10); - } - } -} - -// Recieved data to write from ClientRequest._write -void iotjs_https_data_to_write(iotjs_https_t* https_data, - iotjs_string_t read_chunk, - jerry_value_t callback, jerry_value_t onwrite) { - if (https_data->to_destroy_read_onwrite) { - https_data->to_destroy_read_onwrite = false; - iotjs_string_destroy(&(https_data->read_chunk)); - jerry_release_value((https_data->read_onwrite)); - jerry_release_value((https_data->read_callback)); - } - - https_data->read_chunk = read_chunk; - https_data->data_to_read = true; - - https_data->read_callback = jerry_acquire_value(callback); - https_data->read_onwrite = jerry_acquire_value(onwrite); - https_data->to_destroy_read_onwrite = true; - - if (https_data->request_done) { - iotjs_https_call_read_onwrite_async(https_data); - } else if (https_data->is_stream_writable) { - curl_easy_pause(https_data->curl_easy_handle, CURLPAUSE_CONT); - uv_timer_stop(&(https_data->timeout)); - uv_timer_start(&(https_data->timeout), iotjs_https_uv_timeout_callback, 1, - 0); - } -} - -// Finish writing all data from ClientRequest Stream -void iotjs_https_finish_request(iotjs_https_t* https_data) { - https_data->stream_ended = true; - if (https_data->request_done) { - iotjs_https_cleanup(https_data); - } else if (https_data->is_stream_writable) { - curl_easy_pause(https_data->curl_easy_handle, CURLPAUSE_CONT); - uv_timer_stop(&(https_data->timeout)); - uv_timer_start(&(https_data->timeout), iotjs_https_uv_timeout_callback, 1, - 0); - } -} - -// Start sending the request -void iotjs_https_send_request(iotjs_https_t* https_data) { - // Add all the headers to the easy handle - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_HTTPHEADER, - https_data->header_list); - - if (https_data->method == HTTPS_POST && https_data->content_length != -1) - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_POSTFIELDSIZE, - https_data->content_length); - else if (https_data->method == HTTPS_PUT && https_data->content_length != -1) - curl_easy_setopt(https_data->curl_easy_handle, CURLOPT_INFILESIZE, - https_data->content_length); - - curl_multi_add_handle(https_data->curl_multi_handle, - https_data->curl_easy_handle); -} - -// Set timeout for request. -void iotjs_https_set_timeout(long ms, iotjs_https_t* https_data) { - if (ms < 0) - return; - https_data->timeout_ms = ms; - uv_timer_start(&(https_data->socket_timeout), - iotjs_https_uv_socket_timeout_callback, 1, (uint64_t)ms); -} - - -//--------------CURL Callbacks------------------ -// Read callback is actually to write data to outgoing request -size_t iotjs_https_curl_read_callback(void* contents, size_t size, size_t nmemb, - void* userp) { - iotjs_https_t* https_data = (iotjs_https_t*)userp; - - // If stream wasnt made writable yet, make it so. - if (!https_data->is_stream_writable) { - https_data->is_stream_writable = true; - iotjs_https_jcallback(https_data, IOTJS_MAGIC_STRING_ONWRITABLE, - iotjs_jargs_get_empty(), false); - } - - if (https_data->data_to_read) { - size_t real_size = size * nmemb; - size_t chunk_size = iotjs_string_size(&(https_data->read_chunk)); - size_t left_to_copy_size = chunk_size - https_data->cur_read_index; - - if (real_size < 1) - return 0; - - // send some data - if (https_data->cur_read_index < chunk_size) { - size_t num_to_copy = - (left_to_copy_size < real_size) ? left_to_copy_size : real_size; - const char* buf = iotjs_string_data(&(https_data->read_chunk)); - buf = &buf[https_data->cur_read_index]; - strncpy((char*)contents, buf, num_to_copy); - https_data->cur_read_index = https_data->cur_read_index + num_to_copy; - return num_to_copy; - } - - // Finished sending one chunk of data - https_data->cur_read_index = 0; - https_data->data_to_read = false; - iotjs_https_call_read_onwrite_async(https_data); - } - - // If the data is sent, and stream hasn't ended, wait for more data - if (!https_data->stream_ended) { - return CURL_READFUNC_PAUSE; - } - - // All done, end the transfer - return 0; -} - -// Pass Curl events on its fd sockets -int iotjs_https_curl_socket_callback(CURL* easy, curl_socket_t sockfd, - int action, void* userp, void* socketp) { - iotjs_https_t* https_data = (iotjs_https_t*)userp; - if (action == CURL_POLL_IN || action == CURL_POLL_OUT || - action == CURL_POLL_INOUT) { - iotjs_https_poll_t* poll_data = NULL; - - if (!socketp) { - poll_data = iotjs_https_poll_create(https_data->loop, sockfd, https_data); - curl_multi_assign(https_data->curl_multi_handle, sockfd, - (void*)poll_data); - https_data->closing_handles = https_data->closing_handles + 1; - if (https_data->poll_data == NULL) - https_data->poll_data = poll_data; - else - iotjs_https_poll_append(https_data->poll_data, poll_data); - } else - poll_data = (iotjs_https_poll_t*)socketp; - - if (action == CURL_POLL_IN) - uv_poll_start(&poll_data->poll_handle, UV_READABLE, - iotjs_https_uv_poll_callback); - else if (action == CURL_POLL_OUT) - uv_poll_start(&poll_data->poll_handle, UV_WRITABLE, - iotjs_https_uv_poll_callback); - else if (action == CURL_POLL_INOUT) - uv_poll_start(&poll_data->poll_handle, UV_READABLE | UV_WRITABLE, - iotjs_https_uv_poll_callback); - } else { - if (socketp) { - iotjs_https_poll_t* poll_data = (iotjs_https_poll_t*)socketp; - iotjs_https_poll_close(poll_data); - curl_multi_assign(https_data->curl_multi_handle, sockfd, NULL); - } - } - return 0; -} - -// Socket Assigned Callback -int iotjs_https_curl_sockopt_callback(void* userp, curl_socket_t curlfd, - curlsocktype purpose) { - iotjs_https_t* https_data = (iotjs_https_t*)userp; - iotjs_https_jcallback(https_data, IOTJS_MAGIC_STRING_ONSOCKET, - iotjs_jargs_get_empty(), false); - return CURL_SOCKOPT_OK; -} - -// Curl wants us to signal after timeout -int iotjs_https_curl_start_timeout_callback(CURLM* multi, long timeout_ms, - void* userp) { - iotjs_https_t* https_data = (iotjs_https_t*)userp; - if (timeout_ms < 0) - uv_timer_stop(&(https_data->timeout)); - else { - if (timeout_ms == 0) - timeout_ms = 1; - if ((https_data->timeout_ms != -1) && (timeout_ms > https_data->timeout_ms)) - timeout_ms = https_data->timeout_ms; - uv_timer_start(&(https_data->timeout), iotjs_https_uv_timeout_callback, - (uint64_t)timeout_ms, 0); - } - return 0; -} - -// Write Callback is actually to read data from incoming response -size_t iotjs_https_curl_write_callback(void* contents, size_t size, - size_t nmemb, void* userp) { - iotjs_https_t* https_data = (iotjs_https_t*)userp; - size_t real_size = size * nmemb; - if (jerry_value_is_null(https_data->jthis_native)) - return real_size - 1; - - iotjs_jargs_t jarg = iotjs_jargs_create(1); - - jerry_value_t jbuffer = iotjs_bufferwrap_create_buffer((size_t)real_size); - iotjs_bufferwrap_t* buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); - iotjs_bufferwrap_copy(buffer_wrap, contents, (size_t)real_size); - - iotjs_jargs_append_jval(&jarg, jbuffer); - - bool result = - iotjs_https_jcallback(https_data, IOTJS_MAGIC_STRING_ONDATA, &jarg, true); - - jerry_release_value(jbuffer); - iotjs_jargs_destroy(&jarg); - - if (!result) { - return real_size - 1; - } - - return real_size; -} - - -//--------------LibTUV Callbacks------------------ -// Callback called on closing handles during cleanup -void iotjs_https_uv_close_callback(uv_handle_t* handle) { - iotjs_https_t* https_data = (iotjs_https_t*)handle->data; - https_data->closing_handles = https_data->closing_handles - 1; - if (https_data->closing_handles <= 0) { - if (https_data->poll_data != NULL) - iotjs_https_poll_destroy(https_data->poll_data); - jerry_release_value(https_data->jthis_native); - } -} - -// Callback called when poll detects actions on FD -void iotjs_https_uv_poll_callback(uv_poll_t* poll, int status, int events) { - iotjs_https_poll_t* poll_data = (iotjs_https_poll_t*)poll->data; - iotjs_https_t* https_data = (iotjs_https_t*)poll_data->https_data; - - int flags = 0; - if (status < 0) - flags = CURL_CSELECT_ERR; - if (!status && events & UV_READABLE) - flags |= CURL_CSELECT_IN; - if (!status && events & UV_WRITABLE) - flags |= CURL_CSELECT_OUT; - int running_handles; - curl_multi_socket_action(https_data->curl_multi_handle, poll_data->sockfd, - flags, &running_handles); - iotjs_https_check_done(https_data); -} - -// This function is for signalling to curl a given time has passed. -// This timeout is usually given by curl itself. -void iotjs_https_uv_timeout_callback(uv_timer_t* timer) { - iotjs_https_t* https_data = (iotjs_https_t*)(timer->data); - uv_timer_stop(timer); - curl_multi_socket_action(https_data->curl_multi_handle, CURL_SOCKET_TIMEOUT, - 0, &https_data->running_handles); - iotjs_https_check_done(https_data); -} - -// Callback called to check if request has timed out -void iotjs_https_uv_socket_timeout_callback(uv_timer_t* timer) { - iotjs_https_t* https_data = (iotjs_https_t*)(timer->data); - double download_bytes = 0; - double upload_bytes = 0; - uint64_t total_time_ms = 0; - - if (https_data->timeout_ms != -1) { - curl_easy_getinfo(https_data->curl_easy_handle, CURLINFO_SIZE_DOWNLOAD, - &download_bytes); - curl_easy_getinfo(https_data->curl_easy_handle, CURLINFO_SIZE_UPLOAD, - &upload_bytes); - total_time_ms = uv_now(https_data->loop); - double total_bytes = download_bytes + upload_bytes; - - if (https_data->last_bytes_num == total_bytes) { - if (total_time_ms > - ((uint64_t)https_data->timeout_ms + https_data->last_bytes_time)) { - if (!https_data->request_done) { - iotjs_https_jcallback(https_data, IOTJS_MAGIC_STRING_ONTIMEOUT, - iotjs_jargs_get_empty(), false); - } - uv_timer_stop(&(https_data->socket_timeout)); - } - } else { - https_data->last_bytes_num = total_bytes; - https_data->last_bytes_time = total_time_ms; - } - } -} - -//--------------https_poll Functions------------------ -iotjs_https_poll_t* iotjs_https_poll_create(uv_loop_t* loop, - curl_socket_t sockfd, - iotjs_https_t* https_data) { - iotjs_https_poll_t* poll_data = IOTJS_ALLOC(iotjs_https_poll_t); - poll_data->sockfd = sockfd; - poll_data->poll_handle.data = poll_data; - poll_data->https_data = https_data; - poll_data->closing = false; - poll_data->next = NULL; - uv_poll_init_socket(loop, &poll_data->poll_handle, sockfd); - return poll_data; -} - -void iotjs_https_poll_append(iotjs_https_poll_t* head, - iotjs_https_poll_t* poll_data) { - iotjs_https_poll_t* current = head; - iotjs_https_poll_t* next = current->next; - while (next != NULL) { - current = next; - next = current->next; - } - current->next = poll_data; -} - -void iotjs_https_poll_close(iotjs_https_poll_t* poll_data) { - if (poll_data->closing == false) { - poll_data->closing = true; - uv_poll_stop(&poll_data->poll_handle); - poll_data->poll_handle.data = poll_data->https_data; - uv_close((uv_handle_t*)&poll_data->poll_handle, - iotjs_https_uv_close_callback); - } - return; -} - -void iotjs_https_poll_close_all(iotjs_https_poll_t* head) { - iotjs_https_poll_t* current = head; - while (current != NULL) { - iotjs_https_poll_close(current); - current = current->next; - } -} - -void iotjs_https_poll_destroy(iotjs_https_poll_t* poll_data) { - if (poll_data->next != NULL) { - iotjs_https_poll_destroy(poll_data->next); - } - IOTJS_RELEASE(poll_data); -} - -// ------------JHANDLERS---------------- - -JS_FUNCTION(createRequest) { - DJS_CHECK_THIS(); - DJS_CHECK_ARGS(1, object); - - const jerry_value_t joptions = JS_GET_ARG(0, object); - - jerry_value_t jhost = - iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_HOST); - iotjs_string_t host = iotjs_jval_as_string(jhost); - jerry_release_value(jhost); - - jerry_value_t jmethod = - iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_METHOD); - iotjs_string_t method = iotjs_jval_as_string(jmethod); - jerry_release_value(jmethod); - - jerry_value_t jca = iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_CA); - iotjs_string_t ca = iotjs_jval_as_string(jca); - jerry_release_value(jca); - - jerry_value_t jcert = - iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_CERT); - iotjs_string_t cert = iotjs_jval_as_string(jcert); - jerry_release_value(jcert); - - jerry_value_t jkey = - iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_KEY); - iotjs_string_t key = iotjs_jval_as_string(jkey); - jerry_release_value(jkey); - - jerry_value_t jreject_unauthorized = - iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_REJECTUNAUTHORIZED); - const bool reject_unauthorized = iotjs_jval_as_boolean(jreject_unauthorized); - - if (curl_global_init(CURL_GLOBAL_SSL)) { - return jerry_create_null(); - } - - iotjs_https_t* https_data = - iotjs_https_create(iotjs_string_data(&host), iotjs_string_data(&method), - iotjs_string_data(&ca), iotjs_string_data(&cert), - iotjs_string_data(&key), reject_unauthorized, - joptions); - - iotjs_https_initialize_curl_opts(https_data); - - iotjs_string_destroy(&host); - iotjs_string_destroy(&method); - iotjs_string_destroy(&ca); - iotjs_string_destroy(&cert); - iotjs_string_destroy(&key); - return jerry_create_null(); -} - -JS_FUNCTION(addHeader) { - DJS_CHECK_THIS(); - - DJS_CHECK_ARGS(2, string, object); - iotjs_string_t header = JS_GET_ARG(0, string); - const char* char_header = iotjs_string_data(&header); - - jerry_value_t jarg = JS_GET_ARG(1, object); - iotjs_https_t* https_data = - (iotjs_https_t*)iotjs_jval_get_object_native_handle(jarg); - iotjs_https_add_header(https_data, char_header); - - iotjs_string_destroy(&header); - return jerry_create_null(); -} - -JS_FUNCTION(sendRequest) { - DJS_CHECK_THIS(); - - DJS_CHECK_ARG(0, object); - jerry_value_t jarg = JS_GET_ARG(0, object); - iotjs_https_t* https_data = - (iotjs_https_t*)iotjs_jval_get_object_native_handle(jarg); - iotjs_https_send_request(https_data); - return jerry_create_null(); -} - -JS_FUNCTION(setTimeout) { - DJS_CHECK_THIS(); - DJS_CHECK_ARGS(2, number, object); - - double ms = JS_GET_ARG(0, number); - jerry_value_t jarg = JS_GET_ARG(1, object); - - iotjs_https_t* https_data = - (iotjs_https_t*)iotjs_jval_get_object_native_handle(jarg); - iotjs_https_set_timeout((long)ms, https_data); - - return jerry_create_null(); -} - -JS_FUNCTION(_write) { - DJS_CHECK_THIS(); - DJS_CHECK_ARGS(2, object, string); - // Argument 3 can be null, so not checked directly, checked later - DJS_CHECK_ARG(3, function); - - jerry_value_t jarg = JS_GET_ARG(0, object); - iotjs_string_t read_chunk = JS_GET_ARG(1, string); - - jerry_value_t callback = jargv[2]; - jerry_value_t onwrite = JS_GET_ARG(3, function); - - iotjs_https_t* https_data = - (iotjs_https_t*)iotjs_jval_get_object_native_handle(jarg); - iotjs_https_data_to_write(https_data, read_chunk, callback, onwrite); - - // readchunk was copied to https_data, hence not destroyed. - return jerry_create_null(); -} - -JS_FUNCTION(finishRequest) { - DJS_CHECK_THIS(); - DJS_CHECK_ARG(0, object); - - jerry_value_t jarg = JS_GET_ARG(0, object); - iotjs_https_t* https_data = - (iotjs_https_t*)iotjs_jval_get_object_native_handle(jarg); - iotjs_https_finish_request(https_data); - - return jerry_create_null(); -} - -JS_FUNCTION(Abort) { - DJS_CHECK_THIS(); - DJS_CHECK_ARG(0, object); - - jerry_value_t jarg = JS_GET_ARG(0, object); - iotjs_https_t* https_data = - (iotjs_https_t*)iotjs_jval_get_object_native_handle(jarg); - iotjs_https_cleanup(https_data); - - return jerry_create_null(); -} - -jerry_value_t InitHttps() { - jerry_value_t https = jerry_create_object(); - - iotjs_jval_set_method(https, IOTJS_MAGIC_STRING_CREATEREQUEST, createRequest); - iotjs_jval_set_method(https, IOTJS_MAGIC_STRING_ADDHEADER, addHeader); - iotjs_jval_set_method(https, IOTJS_MAGIC_STRING_SENDREQUEST, sendRequest); - iotjs_jval_set_method(https, IOTJS_MAGIC_STRING_SETTIMEOUT, setTimeout); - iotjs_jval_set_method(https, IOTJS_MAGIC_STRING__WRITE, _write); - iotjs_jval_set_method(https, IOTJS_MAGIC_STRING_FINISHREQUEST, finishRequest); - iotjs_jval_set_method(https, IOTJS_MAGIC_STRING_ABORT, Abort); - - return https; -} diff --git a/src/modules/iotjs_module_https.h b/src/modules/iotjs_module_https.h deleted file mode 100644 index e44e741..0000000 --- a/src/modules/iotjs_module_https.h +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors - * - * 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 IOTJS_MODULE_HTTPS_H -#define IOTJS_MODULE_HTTPS_H - -#include "iotjs_def.h" -#include -#include - -typedef enum { - HTTPS_GET = 0, - HTTPS_POST, - HTTPS_PUT, - HTTPS_DELETE, - HTTPS_HEAD, - HTTPS_CONNECT, - HTTPS_OPTIONS, - HTTPS_TRACE -} HTTPS_Methods; - -#define STRING_GET "GET" -#define STRING_POST "POST" -#define STRING_PUT "PUT" -#define STRING_DELETE "DELETE" -#define STRING_HEAD "HEAD" -#define STRING_CONNECT "CONNECT" -#define STRING_OPTIONS "OPTIONS" -#define STRING_TRACE "TRACE" - -typedef struct iotjs_https_poll_t iotjs_https_poll_t; -typedef struct iotjs_https_t iotjs_https_t; - -iotjs_https_t* iotjs_https_create(const char* URL, const char* method, - const char* ca, const char* cert, - const char* key, - const bool reject_unauthorized, - jerry_value_t jthis); - -// Some utility functions -void iotjs_https_check_done(iotjs_https_t* https_data); -void iotjs_https_cleanup(iotjs_https_t* https_data); -void iotjs_https_initialize_curl_opts(iotjs_https_t* https_data); -jerry_value_t iotjs_https_jthis_from_https(iotjs_https_t* https_data); -bool iotjs_https_jcallback(iotjs_https_t* https_data, const char* property, - const iotjs_jargs_t* jarg, bool resultvalue); -void iotjs_https_call_read_onwrite(uv_timer_t* timer); -void iotjs_https_call_read_onwrite_async(iotjs_https_t* https_data); - -// Functions almost directly called by JS via JHANDLER -void iotjs_https_add_header(iotjs_https_t* https_data, const char* char_header); -void iotjs_https_data_to_write(iotjs_https_t* https_data, - iotjs_string_t read_chunk, - jerry_value_t callback, jerry_value_t onwrite); -void iotjs_https_finish_request(iotjs_https_t* https_data); -void iotjs_https_send_request(iotjs_https_t* https_data); -void iotjs_https_set_timeout(long ms, iotjs_https_t* https_data); - - -// CURL callbacks -size_t iotjs_https_curl_read_callback(void* contents, size_t size, size_t nmemb, - void* userp); -int iotjs_https_curl_socket_callback(CURL* easy, curl_socket_t sockfd, - int action, void* userp, void* socketp); -int iotjs_https_curl_sockopt_callback(void* userp, curl_socket_t curlfd, - curlsocktype purpose); -int iotjs_https_curl_start_timeout_callback(CURLM* multi, long timeout_ms, - void* userp); -size_t iotjs_https_curl_write_callback(void* contents, size_t size, - size_t nmemb, void* userp); - -// UV Callbacks -void iotjs_https_uv_close_callback(uv_handle_t* handle); -void iotjs_https_uv_poll_callback(uv_poll_t* poll, int status, int events); -void iotjs_https_uv_socket_timeout_callback(uv_timer_t* timer); -void iotjs_https_uv_timeout_callback(uv_timer_t* timer); - -iotjs_https_poll_t* iotjs_https_poll_create(uv_loop_t* loop, - curl_socket_t sockfd, - iotjs_https_t* https_data); -void iotjs_https_poll_append(iotjs_https_poll_t* head, - iotjs_https_poll_t* poll_data); -void iotjs_https_poll_close(iotjs_https_poll_t* poll_data); -void iotjs_https_poll_destroy(iotjs_https_poll_t* poll_data); -void iotjs_https_poll_close_all(iotjs_https_poll_t* head); - -#endif /* IOTJS_MODULE_HTTPS_H */ diff --git a/src/modules/iotjs_module_i2c.c b/src/modules/iotjs_module_i2c.c index 3c64348..a393375 100644 --- a/src/modules/iotjs_module_i2c.c +++ b/src/modules/iotjs_module_i2c.c @@ -20,31 +20,7 @@ IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(i2c); -static iotjs_i2c_t* i2c_create(const jerry_value_t ji2c) { - iotjs_i2c_t* i2c = IOTJS_ALLOC(iotjs_i2c_t); - iotjs_i2c_create_platform_data(i2c); - i2c->jobject = ji2c; - jerry_set_object_native_pointer(ji2c, i2c, &this_module_native_info); - - return i2c; -} - -static iotjs_i2c_reqwrap_t* i2c_reqwrap_create(const jerry_value_t jcallback, - iotjs_i2c_t* i2c, I2cOp op) { - iotjs_i2c_reqwrap_t* i2c_reqwrap = IOTJS_ALLOC(iotjs_i2c_reqwrap_t); - - iotjs_reqwrap_initialize(&i2c_reqwrap->reqwrap, jcallback, - (uv_req_t*)&i2c_reqwrap->req); - - i2c_reqwrap->req_data.op = op; - i2c_reqwrap->i2c_data = i2c; - return i2c_reqwrap; -} - -static void i2c_reqwrap_destroy(iotjs_i2c_reqwrap_t* i2c_reqwrap) { - iotjs_reqwrap_destroy(&i2c_reqwrap->reqwrap); - IOTJS_RELEASE(i2c_reqwrap); -} +IOTJS_DEFINE_PERIPH_CREATE_FUNCTION(i2c); static void iotjs_i2c_destroy(iotjs_i2c_t* i2c) { iotjs_i2c_destroy_platform_data(i2c->platform_data); @@ -52,107 +28,29 @@ static void iotjs_i2c_destroy(iotjs_i2c_t* i2c) { } static void i2c_worker(uv_work_t* work_req) { - iotjs_i2c_reqwrap_t* req_wrap = - (iotjs_i2c_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)work_req)); - iotjs_i2c_reqdata_t* req_data = &req_wrap->req_data; - iotjs_i2c_t* i2c = req_wrap->i2c_data; + iotjs_periph_reqwrap_t* req_wrap = + (iotjs_periph_reqwrap_t*)(iotjs_reqwrap_from_request( + (uv_req_t*)work_req)); + iotjs_i2c_t* i2c = (iotjs_i2c_t*)req_wrap->data; - switch (req_data->op) { + switch (req_wrap->op) { case kI2cOpOpen: - req_data->result = iotjs_i2c_open(i2c); + req_wrap->result = iotjs_i2c_open(i2c); break; case kI2cOpWrite: - req_data->result = iotjs_i2c_write(i2c); + req_wrap->result = iotjs_i2c_write(i2c); break; case kI2cOpRead: - req_data->result = iotjs_i2c_read(i2c); + req_wrap->result = iotjs_i2c_read(i2c); break; case kI2cOpClose: - req_data->result = iotjs_i2c_close(i2c); + req_wrap->result = iotjs_i2c_close(i2c); break; default: IOTJS_ASSERT(!"Invalid Operation"); } } -static const char* i2c_error_str(int op) { - switch (op) { - case kI2cOpOpen: - return "Open error, cannot open I2C"; - case kI2cOpWrite: - return "Write error, cannot write I2C"; - case kI2cOpRead: - return "Read error, cannot read I2C"; - case kI2cOpClose: - return "Close error, cannot close I2C"; - default: - return "Unknown error"; - } -} - -static void i2c_after_worker(uv_work_t* work_req, int status) { - iotjs_i2c_reqwrap_t* req_wrap = - (iotjs_i2c_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)work_req)); - iotjs_i2c_reqdata_t* req_data = &req_wrap->req_data; - - iotjs_jargs_t jargs = iotjs_jargs_create(2); - - if (status) { - iotjs_jargs_append_error(&jargs, "System error"); - } else { - switch (req_data->op) { - case kI2cOpOpen: - case kI2cOpWrite: - case kI2cOpClose: { - if (!req_data->result) { - iotjs_jargs_append_error(&jargs, i2c_error_str(req_data->op)); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - } - case kI2cOpRead: { - if (!req_data->result) { - iotjs_jargs_append_error(&jargs, i2c_error_str(req_data->op)); - } else { - iotjs_i2c_t* i2c = req_wrap->i2c_data; - - iotjs_jargs_append_null(&jargs); - jerry_value_t result = - iotjs_jval_create_byte_array(i2c->buf_len, i2c->buf_data); - iotjs_jargs_append_jval(&jargs, result); - jerry_release_value(result); - - if (i2c->buf_data != NULL) { - iotjs_buffer_release(i2c->buf_data); - } - } - break; - } - default: { - IOTJS_ASSERT(!"Unreachable"); - break; - } - } - } - - const jerry_value_t jcallback = iotjs_reqwrap_jcallback(&req_wrap->reqwrap); - if (jerry_value_is_function(jcallback)) { - iotjs_make_callback(jcallback, jerry_create_undefined(), &jargs); - } - - iotjs_jargs_destroy(&jargs); - i2c_reqwrap_destroy(req_wrap); -} - -#define I2C_CALL_ASYNC(op, jcallback) \ - do { \ - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); \ - iotjs_i2c_reqwrap_t* req_wrap = i2c_reqwrap_create(jcallback, i2c, op); \ - uv_work_t* req = &req_wrap->req; \ - uv_queue_work(loop, req, i2c_worker, i2c_after_worker); \ - } while (0) - JS_FUNCTION(I2cCons) { DJS_CHECK_THIS(); DJS_CHECK_ARGS(1, object); @@ -170,17 +68,17 @@ JS_FUNCTION(I2cCons) { return res; } - DJS_GET_REQUIRED_CONF_VALUE(jconfig, i2c->address, IOTJS_MAGIC_STRING_ADDRESS, - number); + JS_GET_REQUIRED_CONF_VALUE(jconfig, i2c->address, IOTJS_MAGIC_STRING_ADDRESS, + number); jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); // If the callback doesn't exist, it is completed synchronously. // Otherwise, it will be executed asynchronously. if (!jerry_value_is_null(jcallback)) { - I2C_CALL_ASYNC(kI2cOpOpen, jcallback); + iotjs_periph_call_async(i2c, jcallback, kI2cOpOpen, i2c_worker); } else if (!iotjs_i2c_open(i2c)) { - return JS_CREATE_ERROR(COMMON, "I2C Error: cannot open I2C"); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kI2cOpOpen)); } return jerry_create_undefined(); @@ -190,7 +88,8 @@ JS_FUNCTION(Close) { JS_DECLARE_THIS_PTR(i2c, i2c); DJS_CHECK_ARG_IF_EXIST(1, function); - I2C_CALL_ASYNC(kI2cOpClose, JS_GET_ARG_IF_EXIST(0, function)); + iotjs_periph_call_async(i2c, JS_GET_ARG_IF_EXIST(0, function), kI2cOpClose, + i2c_worker); return jerry_create_undefined(); } @@ -199,7 +98,7 @@ JS_FUNCTION(CloseSync) { JS_DECLARE_THIS_PTR(i2c, i2c); if (!iotjs_i2c_close(i2c)) { - return JS_CREATE_ERROR(COMMON, "I2C Error: cannot close"); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kI2cOpClose)); } return jerry_create_undefined(); @@ -215,10 +114,11 @@ static jerry_value_t i2c_write(iotjs_i2c_t* i2c, const jerry_value_t jargv[], i2c->buf_data = iotjs_buffer_allocate_from_number_array(i2c->buf_len, jarray); if (async) { - I2C_CALL_ASYNC(kI2cOpWrite, JS_GET_ARG_IF_EXIST(1, function)); + iotjs_periph_call_async(i2c, JS_GET_ARG_IF_EXIST(1, function), kI2cOpWrite, + i2c_worker); } else { if (!iotjs_i2c_write(i2c)) { - return JS_CREATE_ERROR(COMMON, "I2C Error: writeSync"); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kI2cOpWrite)); } } @@ -247,8 +147,8 @@ JS_FUNCTION(Read) { JS_GET_REQUIRED_ARG_VALUE(0, i2c->buf_len, IOTJS_MAGIC_STRING_LENGTH, number); - jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); - I2C_CALL_ASYNC(kI2cOpRead, jcallback); + iotjs_periph_call_async(i2c, JS_GET_ARG_IF_EXIST(1, function), kI2cOpRead, + i2c_worker); return jerry_create_undefined(); } @@ -260,7 +160,7 @@ JS_FUNCTION(ReadSync) { JS_GET_REQUIRED_ARG_VALUE(0, i2c->buf_len, IOTJS_MAGIC_STRING_LENGTH, number); if (!iotjs_i2c_read(i2c)) { - return JS_CREATE_ERROR(COMMON, "I2C Error: readSync"); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kI2cOpRead)); } return iotjs_jval_create_byte_array(i2c->buf_len, i2c->buf_data); diff --git a/src/modules/iotjs_module_i2c.h b/src/modules/iotjs_module_i2c.h index 7bf6184..c751653 100644 --- a/src/modules/iotjs_module_i2c.h +++ b/src/modules/iotjs_module_i2c.h @@ -18,21 +18,9 @@ #define IOTJS_MODULE_I2C_H #include "iotjs_def.h" +#include "iotjs_module_periph_common.h" #include "iotjs_reqwrap.h" -typedef enum { - kI2cOpOpen, - kI2cOpClose, - kI2cOpWrite, - kI2cOpRead, -} I2cOp; - - -typedef struct { - I2cOp op; - bool result; -} iotjs_i2c_reqdata_t; - // Forward declaration of platform data. These are only used by platform code. // Generic I2C module never dereferences platform data pointer. typedef struct iotjs_i2c_platform_data_s iotjs_i2c_platform_data_t; @@ -43,18 +31,9 @@ typedef struct { char* buf_data; uint8_t buf_len; - uint8_t byte; - uint8_t cmd; uint8_t address; } iotjs_i2c_t; -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_work_t req; - iotjs_i2c_reqdata_t req_data; - iotjs_i2c_t* i2c_data; -} iotjs_i2c_reqwrap_t; - jerry_value_t iotjs_i2c_set_platform_config(iotjs_i2c_t* i2c, const jerry_value_t jconfig); bool iotjs_i2c_open(iotjs_i2c_t* i2c); diff --git a/src/modules/iotjs_module_periph_common.c b/src/modules/iotjs_module_periph_common.c new file mode 100644 index 0000000..ec4dc5a --- /dev/null +++ b/src/modules/iotjs_module_periph_common.c @@ -0,0 +1,219 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 "iotjs_module_periph_common.h" +#include "iotjs_module_adc.h" +#include "iotjs_module_gpio.h" +#include "iotjs_module_i2c.h" +#include "iotjs_module_pwm.h" +#include "iotjs_module_spi.h" +#include "iotjs_module_uart.h" + +const char* iotjs_periph_error_str(uint8_t op) { + switch (op) { +#if ENABLE_MODULE_ADC + case kAdcOpClose: + return "Close error, cannot close ADC"; + case kAdcOpOpen: + return "Open error, cannot open ADC"; + case kAdcOpRead: + return "Read error, cannot read ADC"; +#endif /* ENABLE_MODULE_ADC */ +#if ENABLE_MODULE_GPIO + case kGpioOpOpen: + return "Open error, cannot open GPIO"; + case kGpioOpWrite: + return "Write error, cannot write GPIO"; + case kGpioOpRead: + return "Read error, cannot read GPIO"; + case kGpioOpClose: + return "Close error, cannot close GPIO"; +#endif /* ENABLE_MODULE_GPIO */ +#if ENABLE_MODULE_I2C + case kI2cOpOpen: + return "Open error, cannot open I2C"; + case kI2cOpWrite: + return "Write error, cannot write I2C"; + case kI2cOpRead: + return "Read error, cannot read I2C"; + case kI2cOpClose: + return "Close error, cannot close I2C"; +#endif /* ENABLE_MODULE_I2C */ +#if ENABLE_MODULE_PWM + case kPwmOpClose: + return "Cannot close PWM device"; + case kPwmOpOpen: + return "Failed to open PWM device"; + case kPwmOpSetDutyCycle: + return "Failed to set duty-cycle"; + case kPwmOpSetEnable: + return "Failed to set enable"; + case kPwmOpSetFrequency: + return "Failed to set frequency"; + case kPwmOpSetPeriod: + return "Failed to set period"; +#endif /* ENABLE_MODULE_PWM */ +#if ENABLE_MODULE_SPI + case kSpiOpClose: + return "Close error, cannot close SPI"; + case kSpiOpOpen: + return "Open error, cannot open SPI"; + case kSpiOpTransferArray: + case kSpiOpTransferBuffer: + return "Transfer error, cannot transfer from SPI device"; +#endif /* ENABLE_MODULE_SPI */ +#if ENABLE_MODULE_UART + case kUartOpClose: + return "Close error, failed to close UART device"; + case kUartOpOpen: + return "Open error, failed to open UART device"; + case kUartOpWrite: + return "Write error, cannot write to UART device"; +#endif /* ENABLE_MODULE_UART */ + default: + return "Unknown error"; + } +} + +static void after_worker(uv_work_t* work_req, int status) { + iotjs_periph_reqwrap_t* reqwrap = + (iotjs_periph_reqwrap_t*)iotjs_reqwrap_from_request((uv_req_t*)work_req); + + iotjs_jargs_t jargs = iotjs_jargs_create(2); + + if (status) { + iotjs_jargs_append_error(&jargs, "System error"); + } else { + if (!reqwrap->result) { + iotjs_jargs_append_error(&jargs, iotjs_periph_error_str(reqwrap->op)); + } else { + switch (reqwrap->op) { + case kAdcOpClose: + case kAdcOpOpen: + case kGpioOpClose: + case kGpioOpOpen: + case kGpioOpWrite: + case kI2cOpClose: + case kI2cOpOpen: + case kI2cOpWrite: + case kSpiOpClose: + case kSpiOpOpen: + case kPwmOpClose: + case kPwmOpOpen: + case kPwmOpSetDutyCycle: + case kPwmOpSetEnable: + case kPwmOpSetFrequency: + case kPwmOpSetPeriod: + case kUartOpClose: + case kUartOpOpen: + case kUartOpWrite: { + iotjs_jargs_append_null(&jargs); + break; + } + case kAdcOpRead: { +#if ENABLE_MODULE_ADC + iotjs_adc_t* adc = (iotjs_adc_t*)reqwrap->data; + + iotjs_jargs_append_null(&jargs); + iotjs_jargs_append_number(&jargs, adc->value); +#endif /* ENABLE_MODULE_ADC */ + break; + } + case kGpioOpRead: { +#if ENABLE_MODULE_GPIO + iotjs_gpio_t* gpio = (iotjs_gpio_t*)reqwrap->data; + + iotjs_jargs_append_null(&jargs); + iotjs_jargs_append_bool(&jargs, gpio->value); +#endif /* ENABLE_MODULE_GPIO */ + break; + } + case kI2cOpRead: { +#if ENABLE_MODULE_I2C + iotjs_i2c_t* i2c = (iotjs_i2c_t*)reqwrap->data; + + iotjs_jargs_append_null(&jargs); + jerry_value_t result = + iotjs_jval_create_byte_array(i2c->buf_len, i2c->buf_data); + iotjs_jargs_append_jval(&jargs, result); + jerry_release_value(result); + + IOTJS_RELEASE(i2c->buf_data); +#endif /* ENABLE_MODULE_I2C */ + break; + } + case kSpiOpTransferArray: + case kSpiOpTransferBuffer: { +#if ENABLE_MODULE_SPI + iotjs_spi_t* spi = (iotjs_spi_t*)reqwrap->data; + + iotjs_jargs_append_null(&jargs); + + // Append read data + jerry_value_t result = + iotjs_jval_create_byte_array(spi->buf_len, spi->rx_buf_data); + iotjs_jargs_append_jval(&jargs, result); + jerry_release_value(result); + + IOTJS_RELEASE(spi->rx_buf_data); +#endif /* ENABLE_MODULE_SPI */ + break; + } + default: { + IOTJS_ASSERT(!"Unreachable"); + break; + } + } + } +#if ENABLE_MODULE_SPI + if (reqwrap->op == kSpiOpTransferArray) { + iotjs_spi_t* spi = (iotjs_spi_t*)reqwrap->data; + IOTJS_RELEASE(spi->tx_buf_data); + } +#endif /* ENABLE_MODULE_SPI */ +#if ENABLE_MODULE_UART + if (reqwrap->op == kUartOpWrite) { + iotjs_uart_t* uart = (iotjs_uart_t*)reqwrap->data; + iotjs_string_destroy(&uart->buf_data); + } +#endif /* ENABLE_MODULE_UART */ + } + + jerry_value_t jcallback = iotjs_reqwrap_jcallback(&reqwrap->reqwrap); + if (jerry_value_is_function(jcallback)) { + iotjs_make_callback(jcallback, jerry_create_undefined(), &jargs); + } + + iotjs_jargs_destroy(&jargs); + iotjs_reqwrap_destroy(&reqwrap->reqwrap); + IOTJS_RELEASE(reqwrap); +} + +static iotjs_periph_reqwrap_t* reqwrap_create(const jerry_value_t jcallback, + void* data, uint8_t op) { + iotjs_periph_reqwrap_t* reqwrap = IOTJS_ALLOC(iotjs_periph_reqwrap_t); + iotjs_reqwrap_initialize((iotjs_reqwrap_t*)reqwrap, jcallback, + (uv_req_t*)&reqwrap->req); + reqwrap->op = op; + reqwrap->data = data; + return (iotjs_periph_reqwrap_t*)reqwrap; +} + +void iotjs_periph_call_async(void* data, jerry_value_t jcallback, uint8_t op, + uv_work_cb worker) { + uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); + iotjs_periph_reqwrap_t* req_wrap = reqwrap_create(jcallback, data, op); + uv_queue_work(loop, &req_wrap->req, worker, after_worker); +} diff --git a/src/modules/iotjs_module_periph_common.h b/src/modules/iotjs_module_periph_common.h new file mode 100644 index 0000000..1f6fd3d --- /dev/null +++ b/src/modules/iotjs_module_periph_common.h @@ -0,0 +1,70 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 IOTJS_MODULE_PERIPH_COMMON_H +#define IOTJS_MODULE_PERIPH_COMMON_H + +#include "iotjs_def.h" +#include "iotjs_reqwrap.h" + +typedef enum { + kAdcOpOpen, + kAdcOpRead, + kAdcOpClose, + kGpioOpOpen, + kGpioOpWrite, + kGpioOpRead, + kGpioOpClose, + kI2cOpOpen, + kI2cOpClose, + kI2cOpWrite, + kI2cOpRead, + kPwmOpClose, + kPwmOpOpen, + kPwmOpSetDutyCycle, + kPwmOpSetEnable, + kPwmOpSetFrequency, + kPwmOpSetPeriod, + kSpiOpClose, + kSpiOpOpen, + kSpiOpTransferArray, + kSpiOpTransferBuffer, + kUartOpClose, + kUartOpOpen, + kUartOpWrite +} iotjs_periph_op_t; + +typedef struct { + iotjs_reqwrap_t reqwrap; /* Note: must be the first */ + uv_work_t req; + uint8_t op; + bool result; + void* data; +} iotjs_periph_reqwrap_t; + +const char* iotjs_periph_error_str(uint8_t op); +void iotjs_periph_call_async(void* type_p, jerry_value_t jcallback, uint8_t op, + uv_work_cb worker); + +#define IOTJS_DEFINE_PERIPH_CREATE_FUNCTION(name) \ + static iotjs_##name##_t* name##_create(const jerry_value_t jobject) { \ + iotjs_##name##_t* data = IOTJS_ALLOC(iotjs_##name##_t); \ + iotjs_##name##_create_platform_data(data); \ + data->jobject = jobject; \ + jerry_set_object_native_pointer(jobject, data, &this_module_native_info); \ + return data; \ + } + +#endif /* IOTJS_MODULE_PERIPH_COMMON_H */ diff --git a/src/modules/iotjs_module_process.c b/src/modules/iotjs_module_process.c index bd84a37..66ab739 100644 --- a/src/modules/iotjs_module_process.c +++ b/src/modules/iotjs_module_process.c @@ -26,7 +26,8 @@ static jerry_value_t WrapEval(const char* name, size_t name_len, jerry_value_t res = jerry_parse_function((const jerry_char_t*)name, name_len, (const jerry_char_t*)args, strlen(args), - (const jerry_char_t*)source, length, false); + (const jerry_char_t*)source, length, + JERRY_PARSE_NO_OPTS); return res; } @@ -110,6 +111,9 @@ JS_FUNCTION(CompileModule) { jerry_value_t jrequire = JS_GET_ARG(1, function); jerry_value_t jid = iotjs_jval_get_property(jmodule, "id"); + if (!jerry_value_is_string(jid)) { + return JS_CREATE_ERROR(COMMON, "Unknown native module"); + } iotjs_string_t id = iotjs_jval_as_string(jid); jerry_release_value(jid); const char* name = iotjs_string_data(&id); @@ -133,8 +137,8 @@ JS_FUNCTION(CompileModule) { if (js_modules[i].name != NULL) { #ifdef ENABLE_SNAPSHOT - jres = jerry_exec_snapshot_at((const void*)iotjs_js_modules_s, - iotjs_js_modules_l, js_modules[i].idx, false); + jres = jerry_exec_snapshot((const void*)iotjs_js_modules_s, + iotjs_js_modules_l, js_modules[i].idx, 0); #else jres = WrapEval(name, iotjs_string_size(&id), (const char*)js_modules[i].code, js_modules[i].length); @@ -166,13 +170,13 @@ JS_FUNCTION(ReadSource) { iotjs_string_t path = JS_GET_ARG(0, string); const iotjs_environment_t* env = iotjs_environment_get(); - + int err; uv_fs_t fs_req; - uv_fs_stat(iotjs_environment_loop(env), &fs_req, iotjs_string_data(&path), - NULL); + err = uv_fs_stat(iotjs_environment_loop(env), &fs_req, + iotjs_string_data(&path), NULL); uv_fs_req_cleanup(&fs_req); - if (!S_ISREG(fs_req.statbuf.st_mode)) { + if (err || !S_ISREG(fs_req.statbuf.st_mode)) { iotjs_string_destroy(&path); return JS_CREATE_ERROR(COMMON, "ReadSource error, not a regular file"); } @@ -238,14 +242,14 @@ void SetNativeSources(jerry_value_t native_sources) { static void SetProcessEnv(jerry_value_t process) { - const char *homedir, *iotjspath, *iotjsenv; + const char *homedir, *iotjspath, *iotjsenv, *extra_module_path; - homedir = getenv("HOME"); + homedir = getenv(IOTJS_MAGIC_STRING_HOME_U); if (homedir == NULL) { homedir = ""; } - iotjspath = getenv("IOTJS_PATH"); + iotjspath = getenv(IOTJS_MAGIC_STRING_IOTJS_PATH_U); if (iotjspath == NULL) { #if defined(__NUTTX__) || defined(__TIZENRT__) iotjspath = "/mnt/sdcard"; @@ -260,12 +264,17 @@ static void SetProcessEnv(jerry_value_t process) { iotjsenv = ""; #endif + extra_module_path = getenv(IOTJS_MAGIC_STRING_IOTJS_EXTRA_MODULE_PATH_U); + jerry_value_t env = jerry_create_object(); iotjs_jval_set_property_string_raw(env, IOTJS_MAGIC_STRING_HOME_U, homedir); iotjs_jval_set_property_string_raw(env, IOTJS_MAGIC_STRING_IOTJS_PATH_U, iotjspath); iotjs_jval_set_property_string_raw(env, IOTJS_MAGIC_STRING_IOTJS_ENV_U, iotjsenv); + iotjs_jval_set_property_string_raw( + env, IOTJS_MAGIC_STRING_IOTJS_EXTRA_MODULE_PATH_U, + extra_module_path ? extra_module_path : ""); iotjs_jval_set_property_jval(process, IOTJS_MAGIC_STRING_ENV, env); diff --git a/src/modules/iotjs_module_pwm.c b/src/modules/iotjs_module_pwm.c index dc0cb3b..365f1ae 100644 --- a/src/modules/iotjs_module_pwm.c +++ b/src/modules/iotjs_module_pwm.c @@ -20,35 +20,7 @@ IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(pwm); -static iotjs_pwm_t* pwm_create(jerry_value_t jpwm) { - iotjs_pwm_t* pwm = IOTJS_ALLOC(iotjs_pwm_t); - iotjs_pwm_create_platform_data(pwm); - pwm->jobject = jpwm; - pwm->period = -1; - pwm->duty_cycle = 0; - jerry_set_object_native_pointer(jpwm, pwm, &this_module_native_info); - - return pwm; -} - -static iotjs_pwm_reqwrap_t* iotjs_pwm_reqwrap_create(jerry_value_t jcallback, - iotjs_pwm_t* pwm, - PwmOp op) { - iotjs_pwm_reqwrap_t* pwm_reqwrap = IOTJS_ALLOC(iotjs_pwm_reqwrap_t); - - iotjs_reqwrap_initialize(&pwm_reqwrap->reqwrap, jcallback, - (uv_req_t*)&pwm_reqwrap->req); - - pwm_reqwrap->req_data.op = op; - pwm_reqwrap->pwm_data = pwm; - - return pwm_reqwrap; -} - -static void pwm_reqwrap_destroy(iotjs_pwm_reqwrap_t* pwm_reqwrap) { - iotjs_reqwrap_destroy(&pwm_reqwrap->reqwrap); - IOTJS_RELEASE(pwm_reqwrap); -} +IOTJS_DEFINE_PERIPH_CREATE_FUNCTION(pwm); static void iotjs_pwm_destroy(iotjs_pwm_t* pwm) { iotjs_pwm_destroy_platform_data(pwm->platform_data); @@ -56,101 +28,52 @@ static void iotjs_pwm_destroy(iotjs_pwm_t* pwm) { } static void pwm_worker(uv_work_t* work_req) { - iotjs_pwm_reqwrap_t* req_wrap = - (iotjs_pwm_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)work_req)); - iotjs_pwm_reqdata_t* req_data = &req_wrap->req_data; - iotjs_pwm_t* pwm = req_wrap->pwm_data; + iotjs_periph_reqwrap_t* req_wrap = + (iotjs_periph_reqwrap_t*)(iotjs_reqwrap_from_request( + (uv_req_t*)work_req)); + iotjs_pwm_t* pwm = (iotjs_pwm_t*)req_wrap->data; - switch (req_data->op) { + switch (req_wrap->op) { case kPwmOpClose: - req_data->result = iotjs_pwm_close(pwm); + req_wrap->result = iotjs_pwm_close(pwm); break; case kPwmOpOpen: - req_data->result = iotjs_pwm_open(pwm); + req_wrap->result = iotjs_pwm_open(pwm); break; case kPwmOpSetDutyCycle: - req_data->result = iotjs_pwm_set_dutycycle(pwm); + req_wrap->result = iotjs_pwm_set_dutycycle(pwm); break; case kPwmOpSetEnable: - req_data->result = iotjs_pwm_set_enable(pwm); + req_wrap->result = iotjs_pwm_set_enable(pwm); break; case kPwmOpSetFrequency: /* update the period */ case kPwmOpSetPeriod: - req_data->result = iotjs_pwm_set_period(pwm); + req_wrap->result = iotjs_pwm_set_period(pwm); break; default: IOTJS_ASSERT(!"Invalid Operation"); } } -static const char* pwm_error_str(int op) { - switch (op) { - case kPwmOpClose: - return "Cannot close PWM device"; - case kPwmOpOpen: - return "Failed to open PWM device"; - case kPwmOpSetDutyCycle: - return "Failed to set duty-cycle"; - case kPwmOpSetEnable: - return "Failed to set enable"; - case kPwmOpSetFrequency: - return "Failed to set frequency"; - case kPwmOpSetPeriod: - return "Failed to set period"; - default: - return "Unknown error"; +static jerry_value_t pwm_set_configuration(iotjs_pwm_t* pwm, + jerry_value_t jconfig) { + JS_GET_REQUIRED_CONF_VALUE(jconfig, pwm->duty_cycle, + IOTJS_MAGIC_STRING_DUTYCYCLE, number); + if (pwm->duty_cycle < 0.0 || pwm->duty_cycle > 1.0) { + return JS_CREATE_ERROR(RANGE, "pwm.dutyCycle must be within 0.0 and 1.0"); } -} - -static void pwm_after_worker(uv_work_t* work_req, int status) { - iotjs_pwm_reqwrap_t* req_wrap = - (iotjs_pwm_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)work_req)); - iotjs_pwm_reqdata_t* req_data = &req_wrap->req_data; - iotjs_jargs_t jargs = iotjs_jargs_create(1); - - if (status) { - iotjs_jargs_append_error(&jargs, "System error"); - } else { - switch (req_data->op) { - case kPwmOpClose: - case kPwmOpOpen: - case kPwmOpSetDutyCycle: - case kPwmOpSetEnable: - case kPwmOpSetFrequency: - case kPwmOpSetPeriod: { - if (!req_data->result) { - iotjs_jargs_append_error(&jargs, pwm_error_str(req_data->op)); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - } - default: { - IOTJS_ASSERT(!"Unreachable"); - break; - } - } + JS_GET_REQUIRED_CONF_VALUE(jconfig, pwm->period, IOTJS_MAGIC_STRING_PERIOD, + number); + if (pwm->period < 0) { + return JS_CREATE_ERROR(RANGE, "pwm.period must be a positive value"); } - jerry_value_t jcallback = iotjs_reqwrap_jcallback(&req_wrap->reqwrap); - if (jerry_value_is_function(jcallback)) { - iotjs_make_callback(jcallback, jerry_create_undefined(), &jargs); - } + JS_GET_REQUIRED_CONF_VALUE(jconfig, pwm->pin, IOTJS_MAGIC_STRING_PIN, number); - iotjs_jargs_destroy(&jargs); - pwm_reqwrap_destroy(req_wrap); + return jerry_create_undefined(); } -#define PWM_CALL_ASYNC(op, jcallback) \ - do { \ - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); \ - iotjs_pwm_reqwrap_t* req_wrap = \ - iotjs_pwm_reqwrap_create(jcallback, pwm, op); \ - uv_work_t* req = &req_wrap->req; \ - uv_queue_work(loop, req, pwm_worker, pwm_after_worker); \ - } while (0) - JS_FUNCTION(PwmCons) { DJS_CHECK_THIS(); DJS_CHECK_ARGS(1, object); @@ -167,22 +90,22 @@ JS_FUNCTION(PwmCons) { if (jerry_value_has_error_flag(res)) { return res; } + IOTJS_ASSERT(jerry_value_is_undefined(res)); - DJS_GET_REQUIRED_CONF_VALUE(jconfig, pwm->duty_cycle, - IOTJS_MAGIC_STRING_DUTYCYCLE, number); - DJS_GET_REQUIRED_CONF_VALUE(jconfig, pwm->period, IOTJS_MAGIC_STRING_PERIOD, - number); - DJS_GET_REQUIRED_CONF_VALUE(jconfig, pwm->pin, IOTJS_MAGIC_STRING_PIN, - number); + res = pwm_set_configuration(pwm, jconfig); + if (jerry_value_has_error_flag(res)) { + return res; + } + IOTJS_ASSERT(jerry_value_is_undefined(res)); jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); // If the callback doesn't exist, it is completed synchronously. // Otherwise, it will be executed asynchronously. if (!jerry_value_is_null(jcallback)) { - PWM_CALL_ASYNC(kPwmOpOpen, jcallback); + iotjs_periph_call_async(pwm, jcallback, kPwmOpOpen, pwm_worker); } else if (!iotjs_pwm_open(pwm)) { - return JS_CREATE_ERROR(COMMON, pwm_error_str(kPwmOpOpen)); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kPwmOpOpen)); } return jerry_create_undefined(); @@ -192,7 +115,8 @@ JS_FUNCTION(Close) { JS_DECLARE_THIS_PTR(pwm, pwm); DJS_CHECK_ARG_IF_EXIST(1, function); - PWM_CALL_ASYNC(kPwmOpClose, JS_GET_ARG_IF_EXIST(0, function)); + iotjs_periph_call_async(pwm, JS_GET_ARG_IF_EXIST(0, function), kPwmOpClose, + pwm_worker); return jerry_create_undefined(); } @@ -201,7 +125,7 @@ JS_FUNCTION(CloseSync) { JS_DECLARE_THIS_PTR(pwm, pwm); if (!iotjs_pwm_close(pwm)) { - return JS_CREATE_ERROR(COMMON, pwm_error_str(kPwmOpClose)); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kPwmOpClose)); } return jerry_create_undefined(); @@ -215,8 +139,11 @@ JS_FUNCTION(SetDutyCycle) { jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); pwm->duty_cycle = JS_GET_ARG(0, number); + if (pwm->duty_cycle < 0.0 || pwm->duty_cycle > 1.0) { + return JS_CREATE_ERROR(RANGE, "pwm.dutyCycle must be within 0.0 and 1.0"); + } - PWM_CALL_ASYNC(kPwmOpSetDutyCycle, jcallback); + iotjs_periph_call_async(pwm, jcallback, kPwmOpSetDutyCycle, pwm_worker); return jerry_create_undefined(); } @@ -226,9 +153,12 @@ JS_FUNCTION(SetDutyCycleSync) { DJS_CHECK_ARGS(1, number); pwm->duty_cycle = JS_GET_ARG(0, number); + if (pwm->duty_cycle < 0.0 || pwm->duty_cycle > 1.0) { + return JS_CREATE_ERROR(RANGE, "pwm.dutyCycle must be within 0.0 and 1.0"); + } if (!iotjs_pwm_set_dutycycle(pwm)) { - return JS_CREATE_ERROR(COMMON, pwm_error_str(kPwmOpSetDutyCycle)); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kPwmOpSetDutyCycle)); } return jerry_create_undefined(); @@ -243,7 +173,7 @@ JS_FUNCTION(SetEnable) { pwm->enable = JS_GET_ARG(0, boolean); - PWM_CALL_ASYNC(kPwmOpSetEnable, jcallback); + iotjs_periph_call_async(pwm, jcallback, kPwmOpSetEnable, pwm_worker); return jerry_create_undefined(); } @@ -255,7 +185,7 @@ JS_FUNCTION(SetEnableSync) { pwm->enable = JS_GET_ARG(0, boolean); if (!iotjs_pwm_set_enable(pwm)) { - return JS_CREATE_ERROR(COMMON, pwm_error_str(kPwmOpSetEnable)); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kPwmOpSetEnable)); } return jerry_create_undefined(); @@ -265,17 +195,27 @@ static jerry_value_t pwm_set_period_or_frequency(iotjs_pwm_t* pwm, const jerry_value_t jargv[], const jerry_length_t jargc, uint8_t op, bool async) { + const double num_value = JS_GET_ARG(0, number); + if (op == kPwmOpSetFrequency) { - pwm->period = 1.0 / JS_GET_ARG(0, number); + if (num_value <= 0) { + return JS_CREATE_ERROR(RANGE, "frequency must be greater than 0"); + } + pwm->period = 1.0 / num_value; + } else { - pwm->period = JS_GET_ARG(0, number); + if (num_value < 0) { + return JS_CREATE_ERROR(RANGE, "period must be a positive value"); + } + pwm->period = num_value; } if (async) { - PWM_CALL_ASYNC(op, JS_GET_ARG_IF_EXIST(1, function)); + iotjs_periph_call_async(pwm, JS_GET_ARG_IF_EXIST(1, function), op, + pwm_worker); } else { if (!iotjs_pwm_set_period(pwm)) { - return JS_CREATE_ERROR(COMMON, pwm_error_str(op)); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(op)); } } diff --git a/src/modules/iotjs_module_pwm.h b/src/modules/iotjs_module_pwm.h index 8f128fa..f11fd6e 100644 --- a/src/modules/iotjs_module_pwm.h +++ b/src/modules/iotjs_module_pwm.h @@ -18,6 +18,7 @@ #define IOTJS_MODULE_PWM_H #include "iotjs_def.h" +#include "iotjs_module_periph_common.h" #include "iotjs_reqwrap.h" #if defined(__TIZENRT__) @@ -25,22 +26,6 @@ #include #endif - -typedef enum { - kPwmOpClose, - kPwmOpOpen, - kPwmOpSetDutyCycle, - kPwmOpSetEnable, - kPwmOpSetFrequency, - kPwmOpSetPeriod -} PwmOp; - - -typedef struct { - bool result; - PwmOp op; -} iotjs_pwm_reqdata_t; - // Forward declaration of platform data. These are only used by platform code. // Generic PWM module never dereferences platform data pointer. typedef struct iotjs_pwm_platform_data_s iotjs_pwm_platform_data_t; @@ -55,14 +40,6 @@ typedef struct { bool enable; } iotjs_pwm_t; - -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_work_t req; - iotjs_pwm_reqdata_t req_data; - iotjs_pwm_t* pwm_data; -} iotjs_pwm_reqwrap_t; - jerry_value_t iotjs_pwm_set_platform_config(iotjs_pwm_t* pwm, const jerry_value_t jconfig); bool iotjs_pwm_open(iotjs_pwm_t* pwm); diff --git a/src/modules/iotjs_module_spi.c b/src/modules/iotjs_module_spi.c index c9ac77d..4169a6f 100644 --- a/src/modules/iotjs_module_spi.c +++ b/src/modules/iotjs_module_spi.c @@ -16,39 +16,11 @@ #include "iotjs_def.h" #include "iotjs_module_spi.h" #include "iotjs_module_buffer.h" -#include -#define SPI_TX_ARRAY_BIT 1u - IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(spi); -static iotjs_spi_t* spi_create(jerry_value_t jspi) { - iotjs_spi_t* spi = IOTJS_ALLOC(iotjs_spi_t); - iotjs_spi_create_platform_data(spi); - spi->jobject = jspi; - jerry_set_object_native_pointer(jspi, spi, &this_module_native_info); - - return spi; -} - -static iotjs_spi_reqwrap_t* spi_reqwrap_create(jerry_value_t jcallback, - iotjs_spi_t* spi, SpiOp op) { - iotjs_spi_reqwrap_t* spi_reqwrap = IOTJS_ALLOC(iotjs_spi_reqwrap_t); - - iotjs_reqwrap_initialize(&spi_reqwrap->reqwrap, jcallback, - (uv_req_t*)&spi_reqwrap->req); - - spi_reqwrap->req_data.op = op; - spi_reqwrap->spi_data = spi; - - return spi_reqwrap; -} - -static void spi_reqwrap_destroy(iotjs_spi_reqwrap_t* spi_reqwrap) { - iotjs_reqwrap_destroy(&spi_reqwrap->reqwrap); - IOTJS_RELEASE(spi_reqwrap); -} +IOTJS_DEFINE_PERIPH_CREATE_FUNCTION(spi); static void iotjs_spi_destroy(iotjs_spi_t* spi) { iotjs_spi_destroy_platform_data(spi->platform_data); @@ -187,28 +159,27 @@ static jerry_value_t spi_set_configuration(iotjs_spi_t* spi, return jerry_create_undefined(); } - /* * SPI worker function */ static void spi_worker(uv_work_t* work_req) { - iotjs_spi_reqwrap_t* req_wrap = - (iotjs_spi_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)work_req)); - iotjs_spi_reqdata_t* req_data = &req_wrap->req_data; - iotjs_spi_t* spi = req_wrap->spi_data; + iotjs_periph_reqwrap_t* req_wrap = + (iotjs_periph_reqwrap_t*)(iotjs_reqwrap_from_request( + (uv_req_t*)work_req)); + iotjs_spi_t* spi = (iotjs_spi_t*)req_wrap->data; - switch (req_data->op) { + switch (req_wrap->op) { case kSpiOpClose: { - req_data->result = iotjs_spi_close(spi); + req_wrap->result = iotjs_spi_close(spi); break; } case kSpiOpOpen: { - req_data->result = iotjs_spi_open(spi); + req_wrap->result = iotjs_spi_open(spi); break; } case kSpiOpTransferArray: case kSpiOpTransferBuffer: { - req_data->result = iotjs_spi_transfer(spi); + req_wrap->result = iotjs_spi_transfer(spi); break; } default: @@ -216,88 +187,6 @@ static void spi_worker(uv_work_t* work_req) { } } -static const char* spi_error_str(uint8_t op) { - switch (op) { - case kSpiOpClose: - return "Close error, cannot close SPI"; - case kSpiOpOpen: - return "Open error, cannot open SPI"; - case kSpiOpTransferArray: - case kSpiOpTransferBuffer: - return "Transfer error, cannot transfer from SPI device"; - default: - return "Unknown error"; - } -} - -static void spi_after_work(uv_work_t* work_req, int status) { - iotjs_spi_reqwrap_t* req_wrap = - (iotjs_spi_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)work_req)); - iotjs_spi_reqdata_t* req_data = &req_wrap->req_data; - - iotjs_jargs_t jargs = iotjs_jargs_create(2); - - if (status) { - iotjs_jargs_append_error(&jargs, "System error"); - } else { - switch (req_data->op) { - case kSpiOpClose: - case kSpiOpOpen: { - if (!req_data->result) { - iotjs_jargs_append_error(&jargs, spi_error_str(req_data->op)); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - } - case kSpiOpTransferArray: - case kSpiOpTransferBuffer: { - iotjs_spi_t* spi = req_wrap->spi_data; - - if (!req_data->result) { - iotjs_jargs_append_error(&jargs, spi_error_str(req_data->op)); - } else { - iotjs_jargs_append_null(&jargs); - - // Append read data - jerry_value_t result = - iotjs_jval_create_byte_array(spi->buf_len, spi->rx_buf_data); - iotjs_jargs_append_jval(&jargs, result); - jerry_release_value(result); - } - - if (req_data->op == kSpiOpTransferArray) { - iotjs_buffer_release(spi->tx_buf_data); - } - - iotjs_buffer_release(spi->rx_buf_data); - break; - } - default: { - IOTJS_ASSERT(!"Unreachable"); - break; - } - } - } - - jerry_value_t jcallback = iotjs_reqwrap_jcallback(&req_wrap->reqwrap); - if (jerry_value_is_function(jcallback)) { - iotjs_make_callback(jcallback, jerry_create_undefined(), &jargs); - } - - iotjs_jargs_destroy(&jargs); - spi_reqwrap_destroy(req_wrap); -} - -#define SPI_CALL_ASYNC(op, jcallback) \ - do { \ - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); \ - iotjs_spi_reqwrap_t* req_wrap = spi_reqwrap_create(jcallback, spi, op); \ - uv_work_t* req = &req_wrap->req; \ - uv_queue_work(loop, req, spi_worker, spi_after_work); \ - } while (0) - - JS_FUNCTION(SpiCons) { DJS_CHECK_THIS(); DJS_CHECK_ARGS(1, object); @@ -328,9 +217,9 @@ JS_FUNCTION(SpiCons) { // If the callback doesn't exist, it is completed synchronously. // Otherwise, it will be executed asynchronously. if (!jerry_value_is_null(jcallback)) { - SPI_CALL_ASYNC(kSpiOpOpen, jcallback); + iotjs_periph_call_async(spi, jcallback, kSpiOpOpen, spi_worker); } else if (!iotjs_spi_open(spi)) { - return JS_CREATE_ERROR(COMMON, spi_error_str(kSpiOpOpen)); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kSpiOpOpen)); } return jerry_create_undefined(); @@ -361,7 +250,8 @@ JS_FUNCTION(Transfer) { DJS_CHECK_ARG_IF_EXIST(1, function); uint8_t op = spi_transfer_helper(jargv[0], spi); - SPI_CALL_ASYNC((SpiOp)op, JS_GET_ARG_IF_EXIST(1, function)); + iotjs_periph_call_async(spi, JS_GET_ARG_IF_EXIST(1, function), op, + spi_worker); return jerry_create_undefined(); } @@ -373,16 +263,16 @@ JS_FUNCTION(TransferSync) { jerry_value_t result = jerry_create_undefined(); if (!iotjs_spi_transfer(spi)) { - result = JS_CREATE_ERROR(COMMON, spi_error_str(op)); + result = JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(op)); } else { result = iotjs_jval_create_byte_array(spi->buf_len, spi->rx_buf_data); } if (op == kSpiOpTransferArray) { - iotjs_buffer_release(spi->tx_buf_data); + IOTJS_RELEASE(spi->tx_buf_data); } - iotjs_buffer_release(spi->rx_buf_data); + IOTJS_RELEASE(spi->rx_buf_data); return result; } @@ -391,7 +281,8 @@ JS_FUNCTION(Close) { JS_DECLARE_THIS_PTR(spi, spi); DJS_CHECK_ARG_IF_EXIST(1, function); - SPI_CALL_ASYNC(kSpiOpClose, JS_GET_ARG_IF_EXIST(0, function)); + iotjs_periph_call_async(spi, JS_GET_ARG_IF_EXIST(0, function), kSpiOpClose, + spi_worker); return jerry_create_undefined(); } @@ -400,7 +291,7 @@ JS_FUNCTION(CloseSync) { JS_DECLARE_THIS_PTR(spi, spi); if (!iotjs_spi_close(spi)) { - return JS_CREATE_ERROR(COMMON, spi_error_str(kSpiOpClose)); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kSpiOpClose)); } return jerry_create_undefined(); diff --git a/src/modules/iotjs_module_spi.h b/src/modules/iotjs_module_spi.h index cb459dc..fb7e90a 100644 --- a/src/modules/iotjs_module_spi.h +++ b/src/modules/iotjs_module_spi.h @@ -19,24 +19,9 @@ #include "iotjs_def.h" #include "iotjs_module_buffer.h" +#include "iotjs_module_periph_common.h" #include "iotjs_reqwrap.h" -#if defined(__TIZENRT__) -#include -#include -#endif - - -#if defined(__NUTTX__) -#include -#endif - -typedef enum { - kSpiOpClose, - kSpiOpOpen, - kSpiOpTransferArray, - kSpiOpTransferBuffer -} SpiOp; typedef enum { kSpiMode_0, @@ -72,19 +57,6 @@ typedef struct { uint8_t buf_len; } iotjs_spi_t; -typedef struct { - bool result; - SpiOp op; -} iotjs_spi_reqdata_t; - -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_work_t req; - iotjs_spi_reqdata_t req_data; - iotjs_spi_t* spi_data; -} iotjs_spi_reqwrap_t; - - jerry_value_t iotjs_spi_set_platform_config(iotjs_spi_t* spi, const jerry_value_t jconfig); bool iotjs_spi_open(iotjs_spi_t* spi); diff --git a/src/modules/iotjs_module_tcp.c b/src/modules/iotjs_module_tcp.c index 41c5a31..3b37b3a 100644 --- a/src/modules/iotjs_module_tcp.c +++ b/src/modules/iotjs_module_tcp.c @@ -132,11 +132,6 @@ JS_FUNCTION(TCP) { } -JS_FUNCTION(Open) { - return jerry_create_undefined(); -} - - // Socket close result handler. void AfterClose(uv_handle_t* handle) { iotjs_handlewrap_t* wrap = iotjs_handlewrap_from_handle(handle); @@ -280,8 +275,9 @@ static void OnConnection(uv_stream_t* handle, int status) { IOTJS_ASSERT(jerry_value_is_function(jcreate_tcp)); jerry_value_t jclient_tcp = - iotjs_jhelper_call_ok(jcreate_tcp, jerry_create_undefined(), - iotjs_jargs_get_empty()); + iotjs_jhelper_call(jcreate_tcp, jerry_create_undefined(), + iotjs_jargs_get_empty()); + IOTJS_ASSERT(!jerry_value_has_error_flag(jclient_tcp)); IOTJS_ASSERT(jerry_value_is_object(jclient_tcp)); iotjs_tcpwrap_t* tcp_wrap_client = @@ -404,9 +400,8 @@ void OnRead(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { iotjs_jargs_append_bool(&jargs, false); if (nread <= 0) { - if (buf->base != NULL) { - iotjs_buffer_release(buf->base); - } + iotjs_buffer_release(buf->base); + if (nread < 0) { if (nread == UV__EOF) { iotjs_jargs_replace(&jargs, 2, jerry_create_boolean(true)); @@ -570,7 +565,6 @@ jerry_value_t InitTcp() { iotjs_jval_set_property_jval(tcp, IOTJS_MAGIC_STRING_PROTOTYPE, prototype); iotjs_jval_set_method(tcp, IOTJS_MAGIC_STRING_ERRNAME, ErrName); - iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_OPEN, Open); iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_CLOSE, Close); iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_CONNECT, Connect); iotjs_jval_set_method(prototype, IOTJS_MAGIC_STRING_BIND, Bind); diff --git a/src/modules/iotjs_module_testdriver.c b/src/modules/iotjs_module_testdriver.c deleted file mode 100644 index ec922f4..0000000 --- a/src/modules/iotjs_module_testdriver.c +++ /dev/null @@ -1,69 +0,0 @@ -/* Copyright 2016-present Samsung Electronics Co., Ltd. and other contributors - * - * 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 "iotjs_def.h" -#include "iotjs_module_timer.h" - - -// Only for test driver -JS_FUNCTION(IsAliveExceptFor) { - JS_CHECK(jargc == 1); - const iotjs_environment_t* env = iotjs_environment_get(); - uv_loop_t* loop = iotjs_environment_loop(env); - - if (jerry_value_is_null(jargv[0])) { - int alive = uv_loop_alive(loop); - - return jerry_create_boolean(alive); - } else { - JS_CHECK(jerry_value_is_object(jargv[0])); - - jerry_value_t jtimer = - iotjs_jval_get_property(jargv[0], IOTJS_MAGIC_STRING_HANDLER); - - iotjs_timerwrap_t* timer_wrap = iotjs_timerwrap_from_jobject(jtimer); - jerry_release_value(jtimer); - - bool has_active_reqs = uv_loop_has_active_reqs(loop); - bool has_closing_handler = loop->closing_handles != NULL; - - bool ret = true; - bool alive = !has_active_reqs && !has_closing_handler; - if (alive) { - unsigned int active_handlers = loop->active_handles; - if (active_handlers == 1u) { - const uv_timer_t* timer_handle = iotjs_timerwrap_handle(timer_wrap); - int timer_alive = uv_is_active((uv_handle_t*)timer_handle); - - if (timer_alive) { - // If the timer handler we set for test driver is alive, - // then it can be safely terminated. - ret = false; - } - } - } - - return jerry_create_boolean(ret); - } -} - - -jerry_value_t InitTestdriver() { - jerry_value_t testdriver = jerry_create_object(); - iotjs_jval_set_method(testdriver, IOTJS_MAGIC_STRING_ISALIVEEXCEPTFOR, - IsAliveExceptFor); - - return testdriver; -} diff --git a/src/modules/iotjs_module_tizen.c b/src/modules/iotjs_module_tizen.c new file mode 100644 index 0000000..f0bc6e6 --- /dev/null +++ b/src/modules/iotjs_module_tizen.c @@ -0,0 +1,33 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 "iotjs_def.h" +#include "iotjs_module_bridge.h" + +extern void iotjs_tizen_func(const char* command, const char* message, + void* handle); + +/** + * Init method called by IoT.js + */ +jerry_value_t InitTizen() { + char* module_name = IOTJS_MAGIC_STRING_TIZEN; + jerry_value_t mymodule = jerry_create_object(); + iotjs_jval_set_property_string_raw(mymodule, IOTJS_MAGIC_STRING_MODULE_NAME, + module_name); + + iotjs_bridge_register(module_name, iotjs_tizen_func); + return mymodule; +} diff --git a/src/modules/iotjs_module_tls.c b/src/modules/iotjs_module_tls.c new file mode 100644 index 0000000..19825bc --- /dev/null +++ b/src/modules/iotjs_module_tls.c @@ -0,0 +1,634 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 "iotjs_module_tls.h" +#include "iotjs_module_buffer.h" + +#include "stdarg.h" + +static void iotjs_tls_context_destroy(iotjs_tls_context_t *tls_context); + +static const jerry_object_native_info_t tls_context_native_info = { + .free_cb = (jerry_object_native_free_callback_t)iotjs_tls_context_destroy +}; + + +static void iotjs_tls_context_destroy(iotjs_tls_context_t *tls_context) { + if (tls_context->ref_count > 1) { + tls_context->ref_count--; + return; + } + + mbedtls_x509_crt_free(&tls_context->cert_auth); + mbedtls_x509_crt_free(&tls_context->own_cert); + mbedtls_pk_free(&tls_context->pkey); + mbedtls_ctr_drbg_free(&tls_context->ctr_drbg); + mbedtls_entropy_free(&tls_context->entropy); + + IOTJS_RELEASE(tls_context); +} + + +static iotjs_tls_context_t *iotjs_tls_context_create( + const jerry_value_t jobject) { + iotjs_tls_context_t *tls_context = IOTJS_ALLOC(iotjs_tls_context_t); + + tls_context->ref_count = 1; + tls_context->context_flags = 0; + mbedtls_entropy_init(&tls_context->entropy); + mbedtls_ctr_drbg_init(&tls_context->ctr_drbg); + mbedtls_pk_init(&tls_context->pkey); + mbedtls_x509_crt_init(&tls_context->own_cert); + mbedtls_x509_crt_init(&tls_context->cert_auth); + + jerry_set_object_native_pointer(jobject, tls_context, + &tls_context_native_info); + + return tls_context; +} + + +IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(tls); + + +static void iotjs_tls_destroy(iotjs_tls_t *tls_data) { + mbedtls_ssl_free(&tls_data->ssl); + mbedtls_ssl_config_free(&tls_data->conf); + iotjs_tls_context_destroy(tls_data->tls_context); + + IOTJS_RELEASE(tls_data->bio.receive_bio.mem); + IOTJS_RELEASE(tls_data->bio.send_bio.mem); + + IOTJS_RELEASE(tls_data); +} + + +static iotjs_tls_t *iotjs_tls_create(const jerry_value_t jobject, + iotjs_tls_context_t *tls_context) { + iotjs_tls_t *tls_data = IOTJS_ALLOC(iotjs_tls_t); + + tls_context->ref_count++; + + tls_data->tls_context = tls_context; + mbedtls_ssl_config_init(&tls_data->conf); + mbedtls_ssl_init(&tls_data->ssl); + tls_data->state = TLS_HANDSHAKE_READY; + + tls_data->jobject = jobject; + jerry_set_object_native_pointer(jobject, tls_data, &this_module_native_info); + + return tls_data; +} + + +static void iotjs_bio_init(iotjs_bio_t *bio, size_t size) { + bio->mem = (char *)iotjs_buffer_allocate(size); + bio->size = size; + bio->read_index = 0; + bio->write_index = 0; +} + + +static size_t iotjs_bio_pending(iotjs_bio_t *bio) { + if (bio->read_index <= bio->write_index) { + return bio->write_index - bio->read_index; + } + + return bio->write_index + bio->size - bio->read_index; +} + + +static size_t iotjs_bio_remaining(iotjs_bio_t *bio) { + if (bio->write_index < bio->read_index) { + return bio->read_index - bio->write_index - 1; + } + + return bio->read_index + bio->size - bio->write_index - 1; +} + + +static void iotjs_bio_read(iotjs_bio_t *bio, char *buf, size_t size) { + IOTJS_ASSERT(size <= iotjs_bio_pending(bio)); + + if (bio->read_index + size > bio->size) { + size_t copy_size = bio->size - bio->read_index; + + memcpy(buf, bio->mem + bio->read_index, copy_size); + size -= copy_size; + buf += copy_size; + bio->read_index = 0; + } + + memcpy(buf, bio->mem + bio->read_index, size); + bio->read_index += size; +} + + +static void iotjs_bio_write(iotjs_bio_t *bio, const char *buf, size_t size) { + IOTJS_ASSERT(size <= iotjs_bio_remaining(bio)); + + if (bio->write_index + size > bio->size) { + size_t copy_size = bio->size - bio->write_index; + + memcpy(bio->mem + bio->write_index, buf, copy_size); + size -= copy_size; + buf += copy_size; + bio->write_index = 0; + } + + memcpy(bio->mem + bio->write_index, buf, size); + bio->write_index += size; +} + + +static int iotjs_bio_net_send(void *ctx, const unsigned char *buf, size_t len) { + iotjs_bio_t *send_bio = &(((iotjs_bio_pair_t *)ctx)->send_bio); + + size_t remaining = iotjs_bio_remaining(send_bio); + + if (remaining == 0) { + return MBEDTLS_ERR_SSL_WANT_WRITE; + } + + if (len > remaining) { + len = remaining; + } + + iotjs_bio_write(send_bio, (const char *)buf, len); + return (int)len; +} + +static int iotjs_bio_net_receive(void *ctx, unsigned char *buf, size_t len) { + iotjs_bio_t *receive_bio = &(((iotjs_bio_pair_t *)ctx)->receive_bio); + + size_t pending = iotjs_bio_pending(receive_bio); + + if (pending == 0) { + return MBEDTLS_ERR_SSL_WANT_READ; + } + + if (len > pending) { + len = pending; + } + + iotjs_bio_read(receive_bio, (char *)buf, len); + return (int)len; +} + + +JS_FUNCTION(TlsContext) { + DJS_CHECK_THIS(); + DJS_CHECK_ARGS(1, object); + + jerry_value_t jtls = JS_GET_THIS(); + iotjs_tls_context_t *tls_context = iotjs_tls_context_create(jtls); + + jerry_value_t joptions = JS_GET_ARG(0, object); + + // Set deterministic random bit generator + if (mbedtls_ctr_drbg_seed(&tls_context->ctr_drbg, mbedtls_entropy_func, + &tls_context->entropy, NULL, 0) != 0) { + return JS_CREATE_ERROR(COMMON, "drbg seeding failed"); + } + + // User provided certificate + int ret = 0; + jerry_value_t jcert = + iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_CERT); + jerry_value_t jkey = + iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_KEY); + + if (jerry_value_is_string(jcert) && jerry_value_is_string(jkey)) { + iotjs_string_t cert = iotjs_jval_as_string(jcert); + const char *cert_chars = iotjs_string_data(&cert); + + ret = mbedtls_x509_crt_parse(&tls_context->own_cert, + (const unsigned char *)cert_chars, + (size_t)iotjs_string_size(&cert) + 1); + + iotjs_string_destroy(&cert); + + if (ret == 0) { + iotjs_string_t key = iotjs_jval_as_string(jkey); + const char *key_chars = iotjs_string_data(&key); + + ret = mbedtls_pk_parse_key(&tls_context->pkey, + (const unsigned char *)key_chars, + (size_t)iotjs_string_size(&key) + 1, NULL, 0); + + iotjs_string_destroy(&key); + + if (ret == 0) { + tls_context->context_flags |= SSL_CONTEXT_HAS_KEY; + } + } + } + + jerry_release_value(jcert); + jerry_release_value(jkey); + + if (ret != 0) { + return JS_CREATE_ERROR(COMMON, "key or certificate parsing failed"); + } + + // User provided trusted certificates + jerry_value_t jcert_auth = + iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_CA); + + if (jerry_value_is_string(jcert_auth)) { + iotjs_string_t cert_auth = iotjs_jval_as_string(jcert_auth); + const char *cert_auth_chars = iotjs_string_data(&cert_auth); + + ret = mbedtls_x509_crt_parse(&tls_context->cert_auth, + (const unsigned char *)cert_auth_chars, + (size_t)iotjs_string_size(&cert_auth) + 1); + + iotjs_string_destroy(&cert_auth); + } else { + // Parse the default certificate authority + ret = mbedtls_x509_crt_parse(&tls_context->cert_auth, + (const unsigned char *)SSL_CA_PEM, + sizeof(SSL_CA_PEM)); + } + + jerry_release_value(jcert_auth); + + if (ret) { + return JS_CREATE_ERROR(COMMON, "certificate authority (CA) parsing failed"); + } + + return jerry_create_undefined(); +} + + +JS_FUNCTION(TlsInit) { + DJS_CHECK_ARGS(3, object, object, object); + + jerry_value_t jtls_socket = JS_GET_ARG(0, object); + jerry_value_t joptions = JS_GET_ARG(1, object); + + // Get context + jerry_value_t jtls_context = JS_GET_ARG(2, object); + + void *native_ptr; + const jerry_object_native_info_t *native_info; + bool tls_context_available = + jerry_get_object_native_pointer(jtls_context, &native_ptr, &native_info); + + if (!tls_context_available || native_info != &tls_context_native_info) { + return JS_CREATE_ERROR(COMMON, "secure context not available"); + } + + iotjs_tls_context_t *tls_context = (iotjs_tls_context_t *)native_ptr; + + iotjs_tls_t *tls_data = iotjs_tls_create(jtls_socket, tls_context); + + // Check server + jerry_value_t jis_server = + iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_ISSERVER); + bool is_server = jerry_value_to_boolean(jis_server); + jerry_release_value(jis_server); + + if (tls_context->context_flags & SSL_CONTEXT_HAS_KEY) { + if (mbedtls_ssl_conf_own_cert(&tls_data->conf, &tls_context->own_cert, + &tls_context->pkey) != 0) { + return JS_CREATE_ERROR(COMMON, "certificate/private key cannot be set"); + } + } + + mbedtls_ssl_conf_ca_chain(&tls_data->conf, &tls_context->cert_auth, NULL); + + mbedtls_ssl_conf_rng(&tls_data->conf, mbedtls_ctr_drbg_random, + &tls_context->ctr_drbg); + + int endpoint = is_server ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT; + + if (mbedtls_ssl_config_defaults(&tls_data->conf, endpoint, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) { + return JS_CREATE_ERROR(COMMON, "SSL Configuration failed"); + } + + // if true, verifies CAs, must emit error if fails + int auth_mode = + is_server ? MBEDTLS_SSL_VERIFY_NONE : MBEDTLS_SSL_VERIFY_REQUIRED; + + jerry_value_t jauth_mode = + iotjs_jval_get_property(joptions, IOTJS_MAGIC_STRING_REJECTUNAUTHORIZED); + + if (!jerry_value_is_undefined(jauth_mode)) { + if (jerry_value_to_boolean(jauth_mode)) { + auth_mode = MBEDTLS_SSL_VERIFY_REQUIRED; + } else { + auth_mode = MBEDTLS_SSL_VERIFY_OPTIONAL; + } + } + + jerry_release_value(jauth_mode); + + mbedtls_ssl_conf_authmode(&tls_data->conf, auth_mode); + + if (mbedtls_ssl_setup(&tls_data->ssl, &tls_data->conf)) { + return JS_CREATE_ERROR(COMMON, "SSL setup failed"); + } + + // Connect mbedtls with iotjs_net_send and iotjs_net_recv functions + iotjs_bio_init(&(tls_data->bio.receive_bio), SSL_BIO_SIZE); + iotjs_bio_init(&(tls_data->bio.send_bio), SSL_BIO_SIZE); + mbedtls_ssl_set_bio(&tls_data->ssl, &(tls_data->bio), iotjs_bio_net_send, + iotjs_bio_net_receive, NULL); + + return jerry_create_undefined(); +} + + +JS_FUNCTION(Connect) { + JS_DECLARE_THIS_PTR(tls, tls_data); + DJS_CHECK_ARGS(1, string); + + if (tls_data->state == TLS_HANDSHAKE_READY) { + iotjs_string_t server_name = JS_GET_ARG(0, string); + mbedtls_ssl_set_hostname(&tls_data->ssl, iotjs_string_data(&server_name)); + iotjs_string_destroy(&server_name); + } + + return jerry_create_undefined(); +} + + +static void iotjs_tls_send_pending(iotjs_tls_t *tls_data) { + iotjs_bio_t *send_bio = &(tls_data->bio.send_bio); + size_t pending = iotjs_bio_pending(send_bio); + + if (pending == 0) { + return; + } + + jerry_value_t jbuffer = iotjs_bufferwrap_create_buffer(pending); + iotjs_bufferwrap_t *buffer_wrap = iotjs_bufferwrap_from_jbuffer(jbuffer); + iotjs_bio_read(send_bio, buffer_wrap->buffer, pending); + + jerry_value_t jthis = tls_data->jobject; + jerry_value_t fn = iotjs_jval_get_property(jthis, IOTJS_MAGIC_STRING_ONWRITE); + + iotjs_jargs_t jargv = iotjs_jargs_create(1); + iotjs_jargs_append_jval(&jargv, jbuffer); + iotjs_make_callback(fn, jthis, &jargv); + + jerry_release_value(fn); + jerry_release_value(jbuffer); + iotjs_jargs_destroy(&jargv); +} + + +static void iotjs_tls_notify_error(iotjs_tls_t *tls_data) { + jerry_value_t jerror = jerry_create_string((const jerry_char_t *)"error"); + jerry_value_t jmessage = + jerry_create_string((const jerry_char_t *)"TLS error"); + + jerry_value_t jthis = tls_data->jobject; + jerry_value_t fn = iotjs_jval_get_property(jthis, IOTJS_MAGIC_STRING_EMIT); + + iotjs_jargs_t jargv = iotjs_jargs_create(2); + iotjs_jargs_append_jval(&jargv, jerror); + iotjs_jargs_append_jval(&jargv, jmessage); + iotjs_make_callback(fn, jthis, &jargv); + + jerry_release_value(fn); + iotjs_jargs_destroy(&jargv); +} + + +JS_FUNCTION(Write) { + JS_DECLARE_THIS_PTR(tls, tls_data); + + if (tls_data->state != TLS_CONNECTED) { + return jerry_create_null(); + } + + const unsigned char *data = NULL; + size_t length = 0; + bool is_end = false; + + if (jargc >= 1 && jerry_value_to_boolean(jargv[0])) { + jerry_value_t jbuffer = JS_GET_ARG(0, object); + + iotjs_bufferwrap_t *buf = iotjs_bufferwrap_from_jbuffer(jbuffer); + data = (const unsigned char *)buf->buffer; + length = iotjs_bufferwrap_length(buf); + } + + if (jargc >= 2 && jerry_value_to_boolean(jargv[1])) { + is_end = true; + } + + while (true) { + int ret_val = mbedtls_ssl_write(&tls_data->ssl, data, length); + + if ((int)length == ret_val) { + break; + } + + iotjs_tls_send_pending(tls_data); + + if (ret_val > 0) { + data += ret_val; + length -= ret_val; + } else if (ret_val != MBEDTLS_ERR_SSL_WANT_WRITE) { + tls_data->state = TLS_CLOSED; + return jerry_create_null(); + } + } + + if (is_end) { + while (true) { + int ret_val = mbedtls_ssl_close_notify(&tls_data->ssl); + if (ret_val == 0) { + tls_data->state = TLS_CLOSED; + break; + } + + iotjs_tls_send_pending(tls_data); + + if (ret_val != MBEDTLS_ERR_SSL_WANT_WRITE) { + iotjs_tls_notify_error(tls_data); + tls_data->state = TLS_CLOSED; + return jerry_create_null(); + } + } + } + + /* Last package is returned as a buffer. */ + iotjs_bio_t *send_bio = &(tls_data->bio.send_bio); + size_t pending = iotjs_bio_pending(send_bio); + + jerry_value_t jbuffer = iotjs_bufferwrap_create_buffer(pending); + iotjs_bufferwrap_t *buf = iotjs_bufferwrap_from_jbuffer(jbuffer); + iotjs_bio_read(send_bio, buf->buffer, pending); + + return jbuffer; +} + + +static void tls_handshake(iotjs_tls_t *tls_data, jerry_value_t jthis) { + tls_data->state = TLS_HANDSHAKE_IN_PROGRESS; + // Continue handshaking process + int ret_val = mbedtls_ssl_handshake(&tls_data->ssl); + + iotjs_tls_send_pending(tls_data); + + bool error; + bool authorized; + + // Check whether handshake completed + if (ret_val == 0) { + tls_data->state = TLS_CONNECTED; + error = false; + authorized = mbedtls_ssl_get_verify_result(&tls_data->ssl) == 0; + } else { + if (ret_val == MBEDTLS_ERR_SSL_WANT_READ || + ret_val == MBEDTLS_ERR_SSL_WANT_WRITE) { + return; + } + + tls_data->state = TLS_CLOSED; + error = true; + authorized = false; + } + + // Result of certificate verification + iotjs_jargs_t jargv = iotjs_jargs_create(2); + iotjs_jargs_append_bool(&jargv, error); + iotjs_jargs_append_bool(&jargv, authorized); + + jerry_value_t fn = + iotjs_jval_get_property(jthis, IOTJS_MAGIC_STRING_ONHANDSHAKEDONE); + iotjs_make_callback(fn, jthis, &jargv); + + jerry_release_value(fn); + iotjs_jargs_destroy(&jargv); +} + + +JS_FUNCTION(Read) { + JS_DECLARE_THIS_PTR(tls, tls_data); + + if (tls_data->state == TLS_CLOSED) { + return jerry_create_boolean(false); + } + + iotjs_bio_t *receive_bio = &(tls_data->bio.receive_bio); + const char *data = NULL; + size_t length = 0; + + if (jargc >= 1 && jerry_value_to_boolean(jargv[0])) { + jerry_value_t jbuffer = JS_GET_ARG(0, object); + + iotjs_bufferwrap_t *buf = iotjs_bufferwrap_from_jbuffer(jbuffer); + data = buf->buffer; + length = iotjs_bufferwrap_length(buf); + } + + do { + size_t copy_size = iotjs_bio_remaining(receive_bio); + + if (copy_size > length) { + copy_size = length; + } + + iotjs_bio_write(receive_bio, data, length); + data += copy_size; + length -= copy_size; + + if (tls_data->state != TLS_CONNECTED) { + IOTJS_ASSERT(tls_data->state == TLS_HANDSHAKE_READY || + tls_data->state == TLS_HANDSHAKE_IN_PROGRESS); + tls_handshake(tls_data, jthis); + + if (tls_data->state != TLS_CONNECTED) { + IOTJS_ASSERT(tls_data->state == TLS_HANDSHAKE_IN_PROGRESS || + tls_data->state == TLS_CLOSED); + + bool result = (tls_data->state != TLS_CLOSED); + return jerry_create_boolean(result); + } + } + + while (true) { + int ret_val = mbedtls_ssl_read(&tls_data->ssl, NULL, 0); + iotjs_tls_send_pending(tls_data); + + if (ret_val == 0) { + size_t pending = mbedtls_ssl_get_bytes_avail(&tls_data->ssl); + + if (pending == 0) { + continue; + } + + jerry_value_t jbuffer = iotjs_bufferwrap_create_buffer(pending); + iotjs_bufferwrap_t *buf = iotjs_bufferwrap_from_jbuffer(jbuffer); + ret_val = mbedtls_ssl_read(&tls_data->ssl, (unsigned char *)buf->buffer, + pending); + + IOTJS_ASSERT(ret_val == (int)pending); + IOTJS_UNUSED(ret_val); + + jerry_value_t fn = + iotjs_jval_get_property(jthis, IOTJS_MAGIC_STRING_ONREAD); + iotjs_jargs_t jargv = iotjs_jargs_create(1); + + iotjs_jargs_append_jval(&jargv, jbuffer); + iotjs_make_callback(fn, jthis, &jargv); + + jerry_release_value(jbuffer); + jerry_release_value(fn); + iotjs_jargs_destroy(&jargv); + continue; + } + + if (ret_val == MBEDTLS_ERR_SSL_WANT_READ) { + return jerry_create_boolean(true); + } + + if (ret_val == MBEDTLS_ERR_SSL_WANT_WRITE) { + continue; + } + + tls_data->state = TLS_CLOSED; + + if (ret_val == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { + return jerry_create_boolean(true); + } + + iotjs_tls_notify_error(tls_data); + return jerry_create_boolean(false); + } + } while (length > 0); + + return jerry_create_boolean(true); +} + + +jerry_value_t InitTls() { + jerry_value_t jtls = jerry_create_object(); + + iotjs_jval_set_method(jtls, IOTJS_MAGIC_STRING_CONNECT, Connect); + iotjs_jval_set_method(jtls, IOTJS_MAGIC_STRING_READ, Read); + iotjs_jval_set_method(jtls, IOTJS_MAGIC_STRING_TLSCONTEXT, TlsContext); + iotjs_jval_set_method(jtls, IOTJS_MAGIC_STRING_TLSINIT, TlsInit); + iotjs_jval_set_method(jtls, IOTJS_MAGIC_STRING_WRITE, Write); + + return jtls; +} diff --git a/src/modules/iotjs_module_tls.h b/src/modules/iotjs_module_tls.h new file mode 100644 index 0000000..ba55aaa --- /dev/null +++ b/src/modules/iotjs_module_tls.h @@ -0,0 +1,101 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 IOTJS_MODULE_TLS_H +#define IOTJS_MODULE_TLS_H + +#include "iotjs_def.h" +#include "mbedtls/certs.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/entropy.h" +#include "mbedtls/net.h" +#include "mbedtls/net_sockets.h" +#include "mbedtls/ssl.h" + +// Default certificate +const char SSL_CA_PEM[] = + "-----BEGIN CERTIFICATE-----\n" + "MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMX\n" + "R2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMT\n" + "Ckdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQL\n" + "ExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UE\n" + "AxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8o\n" + "mUVCxKs+IVSbC9N/hHD6ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7\n" + "SqbKSaZeqKeMWhG8eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQ\n" + "BoZfXklqtTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd\n" + "C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feq\n" + "CapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8E\n" + "BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IHV2ccHsBqBt5ZtJot39wZhi4w\n" + "NgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWduLm5ldC9yb290LXIyLmNy\n" + "bDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEA\n" + "mYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkI\n" + "k7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRD\n" + "LenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd\n" + "AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7TBj0/VLZ\n" + "jmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==\n" + "-----END CERTIFICATE-----\n"; + +// Handshake states for tls context +enum { + TLS_HANDSHAKE_READY = 0, + TLS_HANDSHAKE_IN_PROGRESS = 1, + TLS_CONNECTED = 2, + TLS_CLOSED = 3 +}; + +typedef struct { + char *mem; + size_t size; + size_t read_index; + size_t write_index; +} iotjs_bio_t; + +typedef struct { + iotjs_bio_t receive_bio; + iotjs_bio_t send_bio; +} iotjs_bio_pair_t; + +enum { + SSL_BIO_SUCCESS = 0, + SSL_BIO_ERROR = -1, + SSL_BIO_UNSET = -2, + SSL_BIO_SIZE = 4096 +}; + +enum { SSL_CONTEXT_HAS_KEY = (1 << 0) }; + +typedef struct { + int ref_count; + uint32_t context_flags; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_pk_context pkey; + mbedtls_x509_crt own_cert; + mbedtls_x509_crt cert_auth; +} iotjs_tls_context_t; + +typedef struct { + jerry_value_t jobject; + int state; + + iotjs_tls_context_t *tls_context; + mbedtls_ssl_config conf; + mbedtls_ssl_context ssl; + + iotjs_bio_pair_t bio; +} iotjs_tls_t; + +#endif /* IOTJS_MODULE_TLS_H */ diff --git a/src/modules/iotjs_module_uart.c b/src/modules/iotjs_module_uart.c index fb4bf98..aa59d8f 100644 --- a/src/modules/iotjs_module_uart.c +++ b/src/modules/iotjs_module_uart.c @@ -23,6 +23,8 @@ IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(uart); static iotjs_uart_t* uart_create(const jerry_value_t juart) { iotjs_uart_t* uart = IOTJS_ALLOC(iotjs_uart_t); + iotjs_uart_create_platform_data(uart); + iotjs_handlewrap_initialize(&uart->handlewrap, juart, (uv_handle_t*)(&uart->poll_handle), &this_module_native_info); @@ -33,108 +35,26 @@ static iotjs_uart_t* uart_create(const jerry_value_t juart) { static void iotjs_uart_destroy(iotjs_uart_t* uart) { iotjs_handlewrap_destroy(&uart->handlewrap); - iotjs_string_destroy(&uart->device_path); + iotjs_uart_destroy_platform_data(uart->platform_data); IOTJS_RELEASE(uart); } -static iotjs_uart_reqwrap_t* uart_reqwrap_create(jerry_value_t jcallback, - iotjs_uart_t* uart, - UartOp op) { - iotjs_uart_reqwrap_t* uart_reqwrap = IOTJS_ALLOC(iotjs_uart_reqwrap_t); - - iotjs_reqwrap_initialize(&uart_reqwrap->reqwrap, jcallback, - (uv_req_t*)&uart_reqwrap->req); - - uart_reqwrap->req_data.op = op; - uart_reqwrap->uart_data = uart; - - return uart_reqwrap; -} - -static void uart_reqwrap_destroy(iotjs_uart_reqwrap_t* uart_reqwrap) { - iotjs_reqwrap_destroy(&uart_reqwrap->reqwrap); - IOTJS_RELEASE(uart_reqwrap); -} - -static const char* uart_error_str(uint8_t op) { - switch (op) { - case kUartOpClose: - return "Close error, failed to close UART device"; - case kUartOpOpen: - return "Open error, failed to open UART device"; - case kUartOpWrite: - return "Write error, cannot write to UART device"; - default: - return "Unknown error"; - } -} - -static void handlewrap_close_callback(uv_handle_t* handle) { - iotjs_uart_t* uart = (iotjs_uart_t*)handle->data; - - if (close(uart->device_fd) < 0) { - DLOG(uart_error_str(kUartOpClose)); - IOTJS_ASSERT(0); - } -} - -static void uart_after_worker(uv_work_t* work_req, int status) { - iotjs_uart_reqwrap_t* req_wrap = - (iotjs_uart_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)work_req)); - iotjs_uart_reqdata_t* req_data = &req_wrap->req_data; - - iotjs_jargs_t jargs = iotjs_jargs_create(1); - - if (status) { - iotjs_jargs_append_error(&jargs, "System error"); - } else { - switch (req_data->op) { - case kUartOpWrite: { - iotjs_uart_t* uart = req_wrap->uart_data; - iotjs_string_destroy(&uart->buf_data); - /* FALLTHRU */ - } - case kUartOpClose: - case kUartOpOpen: { - if (!req_data->result) { - iotjs_jargs_append_error(&jargs, uart_error_str(req_data->op)); - } else { - iotjs_jargs_append_null(&jargs); - } - break; - } - default: { - IOTJS_ASSERT(!"Unreachable"); - break; - } - } - } - - jerry_value_t jcallback = iotjs_reqwrap_jcallback(&req_wrap->reqwrap); - if (jerry_value_is_function(jcallback)) { - iotjs_make_callback(jcallback, jerry_create_undefined(), &jargs); - } - - iotjs_jargs_destroy(&jargs); - uart_reqwrap_destroy(req_wrap); -} - static void uart_worker(uv_work_t* work_req) { - iotjs_uart_reqwrap_t* req_wrap = - (iotjs_uart_reqwrap_t*)(iotjs_reqwrap_from_request((uv_req_t*)work_req)); - iotjs_uart_reqdata_t* req_data = &req_wrap->req_data; - iotjs_uart_t* uart = req_wrap->uart_data; + iotjs_periph_reqwrap_t* req_wrap = + (iotjs_periph_reqwrap_t*)(iotjs_reqwrap_from_request( + (uv_req_t*)work_req)); + iotjs_uart_t* uart = (iotjs_uart_t*)req_wrap->data; - switch (req_data->op) { + switch (req_wrap->op) { case kUartOpOpen: - req_data->result = iotjs_uart_open(uart); + req_wrap->result = iotjs_uart_open(uart); break; case kUartOpWrite: - req_data->result = iotjs_uart_write(uart); + req_wrap->result = iotjs_uart_write(uart); break; case kUartOpClose: - iotjs_handlewrap_close(&uart->handlewrap, handlewrap_close_callback); - req_data->result = true; + iotjs_handlewrap_close(&uart->handlewrap, iotjs_uart_handlewrap_close_cb); + req_wrap->result = true; break; default: IOTJS_ASSERT(!"Invalid Operation"); @@ -159,9 +79,12 @@ static void iotjs_uart_read_cb(uv_poll_t* req, int status, int events) { jerry_value_t data = jerry_create_string((const jerry_char_t*)buf); iotjs_jargs_append_jval(&jargs, str); iotjs_jargs_append_jval(&jargs, data); - iotjs_jhelper_call_ok(jemit, iotjs_handlewrap_jobject(&uart->handlewrap), - &jargs); + jerry_value_t jres = + iotjs_jhelper_call(jemit, iotjs_handlewrap_jobject(&uart->handlewrap), + &jargs); + IOTJS_ASSERT(!jerry_value_has_error_flag(jres)); + jerry_release_value(jres); jerry_release_value(str); jerry_release_value(data); iotjs_jargs_destroy(&jargs); @@ -179,16 +102,6 @@ void iotjs_uart_register_read_cb(iotjs_uart_t* uart) { static jerry_value_t uart_set_configuration(iotjs_uart_t* uart, jerry_value_t jconfig) { - jerry_value_t jdevice = - iotjs_jval_get_property(jconfig, IOTJS_MAGIC_STRING_DEVICE); - if (!jerry_value_is_string(jdevice)) { - jerry_release_value(jdevice); - return JS_CREATE_ERROR( - TYPE, "Bad configuration - device is mandatory and must be a String"); - } - uart->device_path = iotjs_jval_as_string(jdevice); - jerry_release_value(jdevice); - jerry_value_t jbaud_rate = iotjs_jval_get_property(jconfig, IOTJS_MAGIC_STRING_BAUDRATE); if (jerry_value_is_undefined(jbaud_rate)) { @@ -205,7 +118,7 @@ static jerry_value_t uart_set_configuration(iotjs_uart_t* uart, if (br != 230400 && br != 115200 && br != 57600 && br != 38400 && br != 19200 && br != 9600 && br != 4800 && br != 2400 && br != 1800 && br != 1200 && br != 600 && br != 300 && br != 200 && br != 150 && - br != 134 && br != 110 && br != 75 && br != 50) { + br != 134 && br != 110 && br != 75 && br != 50 && br != 0) { return JS_CREATE_ERROR(TYPE, "Invalid baud rate"); } @@ -235,15 +148,6 @@ static jerry_value_t uart_set_configuration(iotjs_uart_t* uart, return jerry_create_undefined(); } -#define UART_CALL_ASYNC(op, jcallback) \ - do { \ - uv_loop_t* loop = iotjs_environment_loop(iotjs_environment_get()); \ - iotjs_uart_reqwrap_t* req_wrap = uart_reqwrap_create(jcallback, uart, op); \ - uv_work_t* req = &req_wrap->req; \ - uv_queue_work(loop, req, uart_worker, uart_after_worker); \ - } while (0) - - JS_FUNCTION(UartCons) { DJS_CHECK_THIS(); DJS_CHECK_ARGS(1, object); @@ -256,13 +160,17 @@ JS_FUNCTION(UartCons) { jerry_value_t jconfig = JS_GET_ARG(0, object); // set configuration - jerry_value_t res = uart_set_configuration(uart, jconfig); + jerry_value_t res = iotjs_uart_set_platform_config(uart, jconfig); + if (jerry_value_has_error_flag(res)) { + return res; + } + + res = uart_set_configuration(uart, jconfig); if (jerry_value_has_error_flag(res)) { return res; } - DDDLOG("%s - path: %s, baudRate: %d, dataBits: %d", __func__, - iotjs_string_data(&uart->device_path), uart->baud_rate, + DDDLOG("%s - baudRate: %d, dataBits: %d", __func__, uart->baud_rate, uart->data_bits); jerry_value_t jcallback = JS_GET_ARG_IF_EXIST(1, function); @@ -270,9 +178,9 @@ JS_FUNCTION(UartCons) { // If the callback doesn't exist, it is completed synchronously. // Otherwise, it will be executed asynchronously. if (!jerry_value_is_null(jcallback)) { - UART_CALL_ASYNC(kUartOpOpen, jcallback); + iotjs_periph_call_async(uart, jcallback, kUartOpOpen, uart_worker); } else if (!iotjs_uart_open(uart)) { - return JS_CREATE_ERROR(COMMON, uart_error_str(kUartOpOpen)); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kUartOpOpen)); } return jerry_create_undefined(); @@ -286,7 +194,8 @@ JS_FUNCTION(Write) { uart->buf_data = JS_GET_ARG(0, string); uart->buf_len = iotjs_string_size(&uart->buf_data); - UART_CALL_ASYNC(kUartOpWrite, JS_GET_ARG_IF_EXIST(1, function)); + iotjs_periph_call_async(uart, JS_GET_ARG_IF_EXIST(1, function), kUartOpWrite, + uart_worker); return jerry_create_undefined(); } @@ -302,7 +211,7 @@ JS_FUNCTION(WriteSync) { iotjs_string_destroy(&uart->buf_data); if (!result) { - return JS_CREATE_ERROR(COMMON, uart_error_str(kUartOpWrite)); + return JS_CREATE_ERROR(COMMON, iotjs_periph_error_str(kUartOpWrite)); } return jerry_create_undefined(); @@ -312,7 +221,8 @@ JS_FUNCTION(Close) { JS_DECLARE_THIS_PTR(uart, uart); DJS_CHECK_ARG_IF_EXIST(0, function); - UART_CALL_ASYNC(kUartOpClose, JS_GET_ARG_IF_EXIST(0, function)); + iotjs_periph_call_async(uart, JS_GET_ARG_IF_EXIST(0, function), kUartOpClose, + uart_worker); return jerry_create_undefined(); } @@ -320,7 +230,7 @@ JS_FUNCTION(Close) { JS_FUNCTION(CloseSync) { JS_DECLARE_THIS_PTR(uart, uart); - iotjs_handlewrap_close(&uart->handlewrap, handlewrap_close_callback); + iotjs_handlewrap_close(&uart->handlewrap, iotjs_uart_handlewrap_close_cb); return jerry_create_undefined(); } diff --git a/src/modules/iotjs_module_uart.h b/src/modules/iotjs_module_uart.h index a08fa51..650fc58 100644 --- a/src/modules/iotjs_module_uart.h +++ b/src/modules/iotjs_module_uart.h @@ -19,43 +19,34 @@ #include "iotjs_def.h" #include "iotjs_handlewrap.h" +#include "iotjs_module_periph_common.h" #include "iotjs_reqwrap.h" #define UART_WRITE_BUFFER_SIZE 512 - -typedef enum { - kUartOpOpen, - kUartOpClose, - kUartOpWrite, -} UartOp; - -typedef struct { - UartOp op; - bool result; -} iotjs_uart_reqdata_t; +typedef struct iotjs_uart_platform_data_s iotjs_uart_platform_data_t; typedef struct { iotjs_handlewrap_t handlewrap; + iotjs_uart_platform_data_t* platform_data; int device_fd; unsigned baud_rate; uint8_t data_bits; - iotjs_string_t device_path; iotjs_string_t buf_data; unsigned buf_len; uv_poll_t poll_handle; } iotjs_uart_t; -typedef struct { - iotjs_reqwrap_t reqwrap; - uv_work_t req; - iotjs_uart_reqdata_t req_data; - iotjs_uart_t* uart_data; -} iotjs_uart_reqwrap_t; +jerry_value_t iotjs_uart_set_platform_config(iotjs_uart_t* uart, + const jerry_value_t jconfig); void iotjs_uart_register_read_cb(iotjs_uart_t* uart); bool iotjs_uart_open(iotjs_uart_t* uart); bool iotjs_uart_write(iotjs_uart_t* uart); +void iotjs_uart_handlewrap_close_cb(uv_handle_t* handle); + +void iotjs_uart_create_platform_data(iotjs_uart_t* uart); +void iotjs_uart_destroy_platform_data(iotjs_uart_platform_data_t* pdata); #endif /* IOTJS_MODULE_UART_H */ diff --git a/src/modules/iotjs_module_udp.c b/src/modules/iotjs_module_udp.c index d18c0d2..36b8ce6 100644 --- a/src/modules/iotjs_module_udp.c +++ b/src/modules/iotjs_module_udp.c @@ -141,8 +141,7 @@ static void OnAlloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { static void OnRecv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned int flags) { if (nread == 0 && addr == NULL) { - if (buf->base != NULL) - iotjs_buffer_release(buf->base); + iotjs_buffer_release(buf->base); return; } @@ -162,8 +161,7 @@ static void OnRecv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, iotjs_jargs_append_jval(&jargs, judp); if (nread < 0) { - if (buf->base != NULL) - iotjs_buffer_release(buf->base); + iotjs_buffer_release(buf->base); iotjs_make_callback(jonmessage, jerry_create_undefined(), &jargs); jerry_release_value(jonmessage); iotjs_jargs_destroy(&jargs); diff --git a/src/modules/linux/iotjs_module_adc-linux.c b/src/modules/linux/iotjs_module_adc-linux.c index f8669a0..50309fb 100644 --- a/src/modules/linux/iotjs_module_adc-linux.c +++ b/src/modules/linux/iotjs_module_adc-linux.c @@ -50,8 +50,8 @@ jerry_value_t iotjs_adc_set_platform_config(iotjs_adc_t* adc, const jerry_value_t jconfig) { iotjs_adc_platform_data_t* platform_data = adc->platform_data; - DJS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->device, - IOTJS_MAGIC_STRING_DEVICE, string); + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->device, + IOTJS_MAGIC_STRING_DEVICE, string); return jerry_create_undefined(); } diff --git a/src/modules/linux/iotjs_module_blehcisocket-linux.c b/src/modules/linux/iotjs_module_blehcisocket-linux.c index 37a366c..b71ade0 100644 --- a/src/modules/linux/iotjs_module_blehcisocket-linux.c +++ b/src/modules/linux/iotjs_module_blehcisocket-linux.c @@ -289,8 +289,10 @@ void iotjs_blehcisocket_poll(iotjs_blehcisocket_t* blehcisocket) { iotjs_bufferwrap_copy(buf_wrap, data, (size_t)length); iotjs_jargs_append_jval(&jargs, str); iotjs_jargs_append_jval(&jargs, jbuf); - iotjs_jhelper_call_ok(jemit, jhcisocket, &jargs); + jerry_value_t jres = iotjs_jhelper_call(jemit, jhcisocket, &jargs); + IOTJS_ASSERT(!jerry_value_has_error_flag(jres)); + jerry_release_value(jres); jerry_release_value(str); jerry_release_value(jbuf); iotjs_jargs_destroy(&jargs); @@ -321,8 +323,10 @@ void iotjs_blehcisocket_emitErrnoError(iotjs_blehcisocket_t* blehcisocket) { jerry_value_t str = jerry_create_string((const jerry_char_t*)"error"); iotjs_jargs_append_jval(&jargs, str); iotjs_jargs_append_error(&jargs, strerror(errno)); - iotjs_jhelper_call_ok(jemit, jhcisocket, &jargs); + jerry_value_t jres = iotjs_jhelper_call(jemit, jhcisocket, &jargs); + IOTJS_ASSERT(!jerry_value_has_error_flag(jres)); + jerry_release_value(jres); jerry_release_value(str); iotjs_jargs_destroy(&jargs); jerry_release_value(jemit); diff --git a/src/modules/linux/iotjs_module_gpio-linux.c b/src/modules/linux/iotjs_module_gpio-linux.c index a3e8796..263d2db 100644 --- a/src/modules/linux/iotjs_module_gpio-linux.c +++ b/src/modules/linux/iotjs_module_gpio-linux.c @@ -78,8 +78,11 @@ static void gpio_emit_change_event(iotjs_gpio_t* gpio) { jerry_value_t jonChange = iotjs_jval_get_property(jgpio, "onChange"); IOTJS_ASSERT(jerry_value_is_function(jonChange)); - iotjs_jhelper_call_ok(jonChange, jgpio, iotjs_jargs_get_empty()); + jerry_value_t jres = + iotjs_jhelper_call(jonChange, jgpio, iotjs_jargs_get_empty()); + IOTJS_ASSERT(!jerry_value_has_error_flag(jres)); + jerry_release_value(jres); jerry_release_value(jonChange); } diff --git a/src/modules/linux/iotjs_module_i2c-linux.c b/src/modules/linux/iotjs_module_i2c-linux.c index 1024775..987d318 100644 --- a/src/modules/linux/iotjs_module_i2c-linux.c +++ b/src/modules/linux/iotjs_module_i2c-linux.c @@ -80,8 +80,8 @@ jerry_value_t iotjs_i2c_set_platform_config(iotjs_i2c_t* i2c, const jerry_value_t jconfig) { iotjs_i2c_platform_data_t* platform_data = i2c->platform_data; - DJS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->device, - IOTJS_MAGIC_STRING_DEVICE, string); + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->device, + IOTJS_MAGIC_STRING_DEVICE, string); return jerry_create_undefined(); } @@ -134,9 +134,8 @@ bool iotjs_i2c_write(iotjs_i2c_t* i2c) { char* data = i2c->buf_data; int ret = write(platform_data->device_fd, data, len); - if (i2c->buf_data != NULL) { - iotjs_buffer_release(i2c->buf_data); - } + + IOTJS_RELEASE(i2c->buf_data); return ret == len; } diff --git a/src/modules/linux/iotjs_module_pwm-linux.c b/src/modules/linux/iotjs_module_pwm-linux.c index 14df5fa..c2d3f45 100644 --- a/src/modules/linux/iotjs_module_pwm-linux.c +++ b/src/modules/linux/iotjs_module_pwm-linux.c @@ -168,7 +168,7 @@ bool iotjs_pwm_set_period(iotjs_pwm_t* pwm) { if (snprintf(buf, sizeof(buf), "%d", value) > 0) { result = iotjs_systemio_open_write_close(devicePath, buf); } - iotjs_buffer_release(devicePath); + IOTJS_RELEASE(devicePath); } } return result; @@ -197,7 +197,7 @@ bool iotjs_pwm_set_dutycycle(iotjs_pwm_t* pwm) { } result = iotjs_systemio_open_write_close(devicePath, buf); - iotjs_buffer_release(devicePath); + IOTJS_RELEASE(devicePath); } } return result; @@ -223,7 +223,7 @@ bool iotjs_pwm_set_enable(iotjs_pwm_t* pwm) { } result = iotjs_systemio_open_write_close(devicePath, buf); - iotjs_buffer_release(devicePath); + IOTJS_RELEASE(devicePath); } return result; } diff --git a/src/modules/linux/iotjs_module_spi-linux.c b/src/modules/linux/iotjs_module_spi-linux.c index d10af9d..9cede21 100644 --- a/src/modules/linux/iotjs_module_spi-linux.c +++ b/src/modules/linux/iotjs_module_spi-linux.c @@ -44,8 +44,8 @@ jerry_value_t iotjs_spi_set_platform_config(iotjs_spi_t* spi, const jerry_value_t jconfig) { iotjs_spi_platform_data_t* platform_data = spi->platform_data; - DJS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->device, - IOTJS_MAGIC_STRING_DEVICE, string); + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->device, + IOTJS_MAGIC_STRING_DEVICE, string); return jerry_create_undefined(); } diff --git a/src/modules/linux/iotjs_module_uart-linux.c b/src/modules/linux/iotjs_module_uart-linux.c index 628f6f4..7a33f1f 100644 --- a/src/modules/linux/iotjs_module_uart-linux.c +++ b/src/modules/linux/iotjs_module_uart-linux.c @@ -20,6 +20,10 @@ #include "modules/iotjs_module_uart.h" +struct iotjs_uart_platform_data_s { + iotjs_string_t device_path; +}; + static unsigned baud_to_constant(unsigned baudRate) { switch (baudRate) { case 50: @@ -76,9 +80,29 @@ static int databits_to_constant(int dataBits) { return -1; } +void iotjs_uart_create_platform_data(iotjs_uart_t* uart) { + uart->platform_data = IOTJS_ALLOC(iotjs_uart_platform_data_t); +} + +void iotjs_uart_destroy_platform_data( + iotjs_uart_platform_data_t* platform_data) { + IOTJS_ASSERT(platform_data); + + iotjs_string_destroy(&platform_data->device_path); + IOTJS_RELEASE(platform_data); +} + +jerry_value_t iotjs_uart_set_platform_config(iotjs_uart_t* uart, + const jerry_value_t jconfig) { + JS_GET_REQUIRED_CONF_VALUE(jconfig, uart->platform_data->device_path, + IOTJS_MAGIC_STRING_DEVICE, string); + + return jerry_create_undefined(); +} + bool iotjs_uart_open(iotjs_uart_t* uart) { - int fd = - open(iotjs_string_data(&uart->device_path), O_RDWR | O_NOCTTY | O_NDELAY); + int fd = open(iotjs_string_data(&uart->platform_data->device_path), + O_RDWR | O_NOCTTY | O_NDELAY); if (fd < 0) { return false; } @@ -130,3 +154,12 @@ bool iotjs_uart_write(iotjs_uart_t* uart) { return true; } + +void iotjs_uart_handlewrap_close_cb(uv_handle_t* handle) { + iotjs_uart_t* uart = (iotjs_uart_t*)handle->data; + + if (close(uart->device_fd) < 0) { + DLOG(iotjs_periph_error_str(kUartOpClose)); + IOTJS_ASSERT(0); + } +} diff --git a/src/modules/nuttx/iotjs_module_adc-nuttx.c b/src/modules/nuttx/iotjs_module_adc-nuttx.c index d9353a2..b64256e 100644 --- a/src/modules/nuttx/iotjs_module_adc-nuttx.c +++ b/src/modules/nuttx/iotjs_module_adc-nuttx.c @@ -48,8 +48,8 @@ jerry_value_t iotjs_adc_set_platform_config(iotjs_adc_t* adc, const jerry_value_t jconfig) { iotjs_adc_platform_data_t* platform_data = adc->platform_data; - DJS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->pin, - IOTJS_MAGIC_STRING_PIN, number); + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->pin, + IOTJS_MAGIC_STRING_PIN, number); return jerry_create_undefined(); } diff --git a/src/modules/nuttx/iotjs_module_i2c-nuttx.c b/src/modules/nuttx/iotjs_module_i2c-nuttx.c index 508c304..6ce25f8 100644 --- a/src/modules/nuttx/iotjs_module_i2c-nuttx.c +++ b/src/modules/nuttx/iotjs_module_i2c-nuttx.c @@ -47,8 +47,8 @@ jerry_value_t iotjs_i2c_set_platform_config(iotjs_i2c_t* i2c, const jerry_value_t jconfig) { iotjs_i2c_platform_data_t* platform_data = i2c->platform_data; - DJS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->bus, - IOTJS_MAGIC_STRING_BUS, number); + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->bus, + IOTJS_MAGIC_STRING_BUS, number); return jerry_create_undefined(); } @@ -100,9 +100,7 @@ bool iotjs_i2c_write(iotjs_i2c_t* i2c) { int ret = i2c_write(platform_data->i2c_master, &platform_data->config, data, len); - if (i2c->buf_data != NULL) { - iotjs_buffer_release(i2c->buf_data); - } + IOTJS_RELEASE(i2c->buf_data); if (ret < 0) { DLOG("%s : cannot write - %d", __func__, ret); diff --git a/src/modules/nuttx/iotjs_module_spi-nuttx.c b/src/modules/nuttx/iotjs_module_spi-nuttx.c index 4b96e5a..72cfa0b 100644 --- a/src/modules/nuttx/iotjs_module_spi-nuttx.c +++ b/src/modules/nuttx/iotjs_module_spi-nuttx.c @@ -45,8 +45,8 @@ jerry_value_t iotjs_spi_set_platform_config(iotjs_spi_t* spi, const jerry_value_t jconfig) { iotjs_spi_platform_data_t* platform_data = spi->platform_data; - DJS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->bus, - IOTJS_MAGIC_STRING_BUS, number); + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->bus, + IOTJS_MAGIC_STRING_BUS, number); return jerry_create_undefined(); } diff --git a/src/modules/nuttx/iotjs_module_uart-nuttx.c b/src/modules/nuttx/iotjs_module_uart-nuttx.c index c46e219..5a3bf2f 100644 --- a/src/modules/nuttx/iotjs_module_uart-nuttx.c +++ b/src/modules/nuttx/iotjs_module_uart-nuttx.c @@ -13,16 +13,35 @@ * limitations under the License. */ -#if !defined(__NUTTX__) -#error "Module __FILE__ is for nuttx only" -#endif - #include "modules/iotjs_module_uart.h" +struct iotjs_uart_platform_data_s { + iotjs_string_t device_path; +}; + +void iotjs_uart_create_platform_data(iotjs_uart_t* uart) { + uart->platform_data = IOTJS_ALLOC(iotjs_uart_platform_data_t); +} + +void iotjs_uart_destroy_platform_data( + iotjs_uart_platform_data_t* platform_data) { + IOTJS_ASSERT(platform_data); + + iotjs_string_destroy(&platform_data->device_path); + IOTJS_RELEASE(platform_data); +} + +jerry_value_t iotjs_uart_set_platform_config(iotjs_uart_t* uart, + const jerry_value_t jconfig) { + JS_GET_REQUIRED_CONF_VALUE(jconfig, uart->platform_data->device_path, + IOTJS_MAGIC_STRING_DEVICE, string); + + return jerry_create_undefined(); +} bool iotjs_uart_open(iotjs_uart_t* uart) { - int fd = - open(iotjs_string_data(&uart->device_path), O_RDWR | O_NOCTTY | O_NDELAY); + int fd = open(iotjs_string_data(&uart->platform_data->device_path), + O_RDWR | O_NOCTTY | O_NDELAY); if (fd < 0) { return false; @@ -63,3 +82,12 @@ bool iotjs_uart_write(iotjs_uart_t* uart) { return true; } + +void iotjs_uart_handlewrap_close_cb(uv_handle_t* handle) { + iotjs_uart_t* uart = (iotjs_uart_t*)handle->data; + + if (close(uart->device_fd) < 0) { + DLOG(iotjs_periph_error_str(kUartOpClose)); + IOTJS_ASSERT(0); + } +} diff --git a/src/modules/tizen/iotjs_module_i2c-tizen.c b/src/modules/tizen/iotjs_module_i2c-tizen.c new file mode 100644 index 0000000..434c69a --- /dev/null +++ b/src/modules/tizen/iotjs_module_i2c-tizen.c @@ -0,0 +1,116 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +#if !defined(__TIZEN__) +#error "Module __FILE__ is for Tizen only" +#endif + +#include + +#include "modules/iotjs_module_i2c.h" + + +struct iotjs_i2c_platform_data_s { + int bus; + peripheral_i2c_h i2c_h; +}; + +void iotjs_i2c_create_platform_data(iotjs_i2c_t* i2c) { + i2c->platform_data = IOTJS_ALLOC(iotjs_i2c_platform_data_t); + + i2c->platform_data->i2c_h = NULL; +} + +void iotjs_i2c_destroy_platform_data(iotjs_i2c_platform_data_t* pdata) { + IOTJS_RELEASE(pdata); +} + +jerry_value_t iotjs_i2c_set_platform_config(iotjs_i2c_t* i2c, + const jerry_value_t jconfig) { + iotjs_i2c_platform_data_t* platform_data = i2c->platform_data; + + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->bus, + IOTJS_MAGIC_STRING_BUS, number); + + return jerry_create_undefined(); +} + +#define I2C_METHOD_HEADER(arg) \ + iotjs_i2c_platform_data_t* platform_data = arg->platform_data; \ + IOTJS_ASSERT(platform_data); \ + if (!platform_data->i2c_h) { \ + DLOG("%s: I2C is not opened", __func__); \ + return false; \ + } + +bool iotjs_i2c_open(iotjs_i2c_t* i2c) { + iotjs_i2c_platform_data_t* platform_data = i2c->platform_data; + IOTJS_ASSERT(platform_data); + + int ret = peripheral_i2c_open(platform_data->bus, i2c->address, + &platform_data->i2c_h); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot open(%d)", __func__, ret); + return false; + } + + return true; +} + +bool iotjs_i2c_close(iotjs_i2c_t* i2c) { + I2C_METHOD_HEADER(i2c); + + int ret = peripheral_i2c_close(platform_data->i2c_h); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot close(%d)", __func__, ret); + return false; + } + + return true; +} + +bool iotjs_i2c_write(iotjs_i2c_t* i2c) { + I2C_METHOD_HEADER(i2c); + + IOTJS_ASSERT(i2c->buf_len > 0); + + int ret = peripheral_i2c_write(platform_data->i2c_h, (uint8_t*)i2c->buf_data, + i2c->buf_len); + + IOTJS_RELEASE(i2c->buf_data); + + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot write(%d)", __func__, ret); + return false; + } + return true; +} + +bool iotjs_i2c_read(iotjs_i2c_t* i2c) { + I2C_METHOD_HEADER(i2c); + + uint8_t len = i2c->buf_len; + i2c->buf_data = iotjs_buffer_allocate(len); + IOTJS_ASSERT(len > 0); + + int ret = + peripheral_i2c_read(platform_data->i2c_h, (uint8_t*)i2c->buf_data, len); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot read(%d)", __func__, ret); + return false; + } + + return true; +} diff --git a/src/modules/tizen/iotjs_module_pwm-tizen.c b/src/modules/tizen/iotjs_module_pwm-tizen.c new file mode 100644 index 0000000..19f2ba3 --- /dev/null +++ b/src/modules/tizen/iotjs_module_pwm-tizen.c @@ -0,0 +1,119 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 + +#include "modules/iotjs_module_pwm.h" + +struct iotjs_pwm_platform_data_s { + peripheral_pwm_h pwm_h; +}; + +void iotjs_pwm_create_platform_data(iotjs_pwm_t* pwm) { + pwm->platform_data = IOTJS_ALLOC(iotjs_pwm_platform_data_t); + pwm->platform_data->pwm_h = NULL; +} + +void iotjs_pwm_destroy_platform_data(iotjs_pwm_platform_data_t* pdata) { + IOTJS_RELEASE(pdata); +} + +jerry_value_t iotjs_pwm_set_platform_config(iotjs_pwm_t* pwm, + const jerry_value_t jconfig) { + return jerry_create_undefined(); +} + +static bool pwm_set_options(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + + if (platform_data->pwm_h == NULL) { + DLOG("%s - cannot set options", __func__); + return false; + } + + return iotjs_pwm_set_period(pwm) && iotjs_pwm_set_dutycycle(pwm); +} + +bool iotjs_pwm_open(iotjs_pwm_t* pwm) { + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; + + int ret = peripheral_pwm_open(0, (int)pwm->pin, &platform_data->pwm_h); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot open(%d)", __func__, ret); + return false; + } + + return pwm_set_options(pwm); +} + +#define PWM_METHOD_HEADER \ + IOTJS_ASSERT(pwm && pwm->platform_data); \ + iotjs_pwm_platform_data_t* platform_data = pwm->platform_data; \ + if (platform_data->pwm_h == NULL) { \ + DLOG("%s: PWM is not opened", __func__); \ + return false; \ + } + +bool iotjs_pwm_set_period(iotjs_pwm_t* pwm) { + PWM_METHOD_HEADER + + uint32_t period_ns = pwm->period * 1E9; + int ret = peripheral_pwm_set_period(platform_data->pwm_h, period_ns); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot set period(%d)", __func__, ret); + return false; + } + + return true; +} + +bool iotjs_pwm_set_dutycycle(iotjs_pwm_t* pwm) { + PWM_METHOD_HEADER + + uint32_t duty_cycle_ns = pwm->period * pwm->duty_cycle * 1E9; + int ret = peripheral_pwm_set_duty_cycle(platform_data->pwm_h, duty_cycle_ns); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot set duty-cycle(%d)", __func__, ret); + return false; + } + + return true; +} + +bool iotjs_pwm_set_enable(iotjs_pwm_t* pwm) { + PWM_METHOD_HEADER + + int ret = peripheral_pwm_set_enabled(platform_data->pwm_h, pwm->enable); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot set enable(%d)", __func__, ret); + return false; + } + + return true; +} + +bool iotjs_pwm_close(iotjs_pwm_t* pwm) { + PWM_METHOD_HEADER + + int ret = peripheral_pwm_close(platform_data->pwm_h); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s : cannot close(%d)", __func__, ret); + return false; + } + platform_data->pwm_h = NULL; + + return true; +} diff --git a/src/modules/tizen/iotjs_module_spi-tizen.c b/src/modules/tizen/iotjs_module_spi-tizen.c new file mode 100644 index 0000000..e6147a8 --- /dev/null +++ b/src/modules/tizen/iotjs_module_spi-tizen.c @@ -0,0 +1,153 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 + +#include "modules/iotjs_module_spi.h" + + +struct iotjs_spi_platform_data_s { + int bus; + peripheral_spi_h spi_h; +}; + +static peripheral_spi_mode_e mode_to_constant(SpiMode mode) { + switch (mode) { + case kSpiMode_0: + return PERIPHERAL_SPI_MODE_0; + case kSpiMode_1: + return PERIPHERAL_SPI_MODE_1; + case kSpiMode_2: + return PERIPHERAL_SPI_MODE_2; + case kSpiMode_3: + return PERIPHERAL_SPI_MODE_3; + default: + IOTJS_ASSERT(!"Invalid SPI mode"); + return PERIPHERAL_SPI_MODE_0; + } +} + +static peripheral_spi_bit_order_e bit_order_to_constant(SpiOrder order) { + switch (order) { + case kSpiOrderLsb: + return PERIPHERAL_SPI_BIT_ORDER_LSB; + case kSpiOrderMsb: + return PERIPHERAL_SPI_BIT_ORDER_MSB; + default: + IOTJS_ASSERT(!"Invalid SPI bitOrder"); + return PERIPHERAL_SPI_BIT_ORDER_MSB; + } +} + +void iotjs_spi_create_platform_data(iotjs_spi_t* spi) { + spi->platform_data = IOTJS_ALLOC(iotjs_spi_platform_data_t); + + spi->platform_data->spi_h = NULL; +} + +void iotjs_spi_destroy_platform_data(iotjs_spi_platform_data_t* platform_data) { + IOTJS_ASSERT(platform_data); + IOTJS_RELEASE(platform_data); +} + +jerry_value_t iotjs_spi_set_platform_config(iotjs_spi_t* spi, + const jerry_value_t jconfig) { + JS_GET_REQUIRED_CONF_VALUE(jconfig, spi->platform_data->bus, + IOTJS_MAGIC_STRING_BUS, number); + + return jerry_create_undefined(); +} + +#define SPI_METHOD_HEADER(arg) \ + iotjs_spi_platform_data_t* platform_data = arg->platform_data; \ + IOTJS_ASSERT(platform_data); \ + if (!platform_data->spi_h) { \ + DLOG("%s: SPI is not opened", __func__); \ + return false; \ + } + +bool iotjs_spi_open(iotjs_spi_t* spi) { + iotjs_spi_platform_data_t* platform_data = spi->platform_data; + + int ret = peripheral_spi_open(platform_data->bus, spi->chip_select, + &platform_data->spi_h); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot open(%d)", __func__, ret); + return false; + } + + // Set mode + ret = peripheral_spi_set_mode(platform_data->spi_h, + mode_to_constant(spi->mode)); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot set mode(%d)", __func__, ret); + peripheral_spi_close(platform_data->spi_h); + return false; + } + + // Set bit order + ret = peripheral_spi_set_bit_order(platform_data->spi_h, + bit_order_to_constant(spi->bit_order)); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot set bit order(%d)", __func__, ret); + peripheral_spi_close(platform_data->spi_h); + return false; + } + + // Set bits per word + ret = peripheral_spi_set_bits_per_word(platform_data->spi_h, + spi->bits_per_word); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot set bit per word(%d)", __func__, ret); + peripheral_spi_close(platform_data->spi_h); + return false; + } + + // Set maxSpeed + ret = peripheral_spi_set_frequency(platform_data->spi_h, spi->max_speed); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot set maxSpeed(%d)", __func__, ret); + peripheral_spi_close(platform_data->spi_h); + return false; + } + return true; +} + +bool iotjs_spi_transfer(iotjs_spi_t* spi) { + SPI_METHOD_HEADER(spi) + + int ret = + peripheral_spi_transfer(platform_data->spi_h, (uint8_t*)spi->tx_buf_data, + (uint8_t*)spi->rx_buf_data, spi->buf_len); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot transfer(%d)", __func__, ret); + return false; + } + + return true; +} + +bool iotjs_spi_close(iotjs_spi_t* spi) { + SPI_METHOD_HEADER(spi) + + int ret = peripheral_spi_close(platform_data->spi_h); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot close(%d)", __func__, ret); + return false; + } + + platform_data->spi_h = NULL; + return true; +} diff --git a/src/modules/tizen/iotjs_module_tizen-tizen.c b/src/modules/tizen/iotjs_module_tizen-tizen.c new file mode 100644 index 0000000..d58b871 --- /dev/null +++ b/src/modules/tizen/iotjs_module_tizen-tizen.c @@ -0,0 +1,151 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 "iotjs_def.h" +#include "modules/iotjs_module_bridge.h" + +#include +#include +#include + +typedef enum { + IOTJS_ERROR_NONE = 0, + IOTJS_ERROR_RESULT_FAILED, + IOTJS_ERROR_INVALID_PARAMETER, +} iotjs_error_t; + +// application control +#include +#include + +iotjs_error_t send_launch_request(const char* json, void* hbridge) { + DDDLOG("%s", __func__); + + bundle* b; + int ret; + + ret = bundle_from_json(json, &b); + if (ret != BUNDLE_ERROR_NONE) { + DDLOG("bundle_from_json failed"); + return IOTJS_ERROR_INVALID_PARAMETER; + } + + app_control_h app_control = NULL; + + app_control_create(&app_control); + app_control_import_from_bundle(app_control, b); + + ret = app_control_send_launch_request(app_control, NULL, NULL); + + if (ret != APP_CONTROL_ERROR_NONE) { + DDDLOG("app_control_send_launch_request failed"); + switch (ret) { + case APP_CONTROL_ERROR_INVALID_PARAMETER: + iotjs_bridge_set_err(hbridge, "APP_CONTROL_ERROR_INVALID_PARAMETER"); + break; + case APP_CONTROL_ERROR_OUT_OF_MEMORY: + iotjs_bridge_set_err(hbridge, "APP_CONTROL_ERROR_OUT_OF_MEMORY"); + break; + case APP_CONTROL_ERROR_APP_NOT_FOUND: + iotjs_bridge_set_err(hbridge, "APP_CONTROL_ERROR_APP_NOT_FOUND"); + break; + case APP_CONTROL_ERROR_LAUNCH_REJECTED: + iotjs_bridge_set_err(hbridge, "APP_CONTROL_ERROR_LAUNCH_REJECTED"); + break; + case APP_CONTROL_ERROR_LAUNCH_FAILED: + iotjs_bridge_set_err(hbridge, "APP_CONTROL_ERROR_LAUNCH_FAILED"); + break; + case APP_CONTROL_ERROR_TIMED_OUT: + iotjs_bridge_set_err(hbridge, "APP_CONTROL_ERROR_TIMED_OUT"); + break; + case APP_CONTROL_ERROR_PERMISSION_DENIED: + iotjs_bridge_set_err(hbridge, "APP_CONTROL_ERROR_PERMISSION_DENIED"); + break; + default: + iotjs_bridge_set_err(hbridge, "APP_CONTROL_ERROR_UNKNOWN"); + break; + } + return IOTJS_ERROR_RESULT_FAILED; + } + + bundle_free(b); + app_control_destroy(app_control); + + return IOTJS_ERROR_NONE; +} + + +void iotjs_service_app_control_cb(app_control_h app_control, void* user_data) { + DDDLOG("%s", __func__); + + iotjs_environment_t* env = iotjs_environment_get(); + + if (env->state != kRunningMain && env->state != kRunningLoop) { + return; + } + + // parse app control + char* json = NULL; + bundle* b = NULL; + + app_control_export_as_bundle(app_control, &b); + + if (BUNDLE_ERROR_NONE != bundle_to_json(b, &json)) { + DDLOG("bundle_to_json failed"); + bundle_free(b); + return; + } + DDDLOG("JSON: %s", json); + + // prepare emit + const char* event_emitter_name = IOTJS_MAGIC_STRING_TIZEN; + const char* event_name = IOTJS_MAGIC_STRING_APP_CONTROL; + + jerry_value_t tizen = iotjs_module_get(event_emitter_name); + jerry_value_t fn = iotjs_jval_get_property(tizen, IOTJS_MAGIC_STRING_EMIT); + + // call emit + iotjs_jargs_t jargv = iotjs_jargs_create(2); + iotjs_jargs_append_string_raw(&jargv, event_name); + iotjs_jargs_append_string_raw(&jargv, json); + + iotjs_make_callback(fn, tizen, &jargv); + + IOTJS_RELEASE(json); + bundle_free(b); + + jerry_release_value(fn); + iotjs_jargs_destroy(&jargv); +} + + +void iotjs_tizen_func(const char* command, const char* message, void* handle) { + DDDLOG("%s, cmd: %s, msg: %s", __func__, command, message); + + if (strncmp(command, "getResPath", strlen("getResPath")) == 0) { + char* app_res_path = app_get_resource_path(); + iotjs_bridge_set_msg(handle, app_res_path); + + } else if (strncmp(command, "launchAppControl", strlen("launchAppControl")) == + 0) { + iotjs_error_t err = send_launch_request(message, handle); + if (err == IOTJS_ERROR_NONE) { + iotjs_bridge_set_msg(handle, "OK"); + } + + } else { + iotjs_bridge_set_err(handle, "Can't find command"); + } +} diff --git a/src/modules/tizen/iotjs_module_uart-tizen.c b/src/modules/tizen/iotjs_module_uart-tizen.c new file mode 100644 index 0000000..d7325eb --- /dev/null +++ b/src/modules/tizen/iotjs_module_uart-tizen.c @@ -0,0 +1,176 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 + +#include "modules/iotjs_module_uart.h" + +struct _peripheral_uart_s { + unsigned handle; + int fd; +}; + +struct iotjs_uart_platform_data_s { + peripheral_uart_h uart_h; + uint8_t port; +}; + +static peripheral_uart_baud_rate_e baud_to_constant(unsigned baudRate) { + switch (baudRate) { + case 0: + return PERIPHERAL_UART_BAUD_RATE_0; + case 50: + return PERIPHERAL_UART_BAUD_RATE_50; + case 75: + return PERIPHERAL_UART_BAUD_RATE_75; + case 110: + return PERIPHERAL_UART_BAUD_RATE_110; + case 134: + return PERIPHERAL_UART_BAUD_RATE_134; + case 150: + return PERIPHERAL_UART_BAUD_RATE_150; + case 200: + return PERIPHERAL_UART_BAUD_RATE_200; + case 300: + return PERIPHERAL_UART_BAUD_RATE_300; + case 600: + return PERIPHERAL_UART_BAUD_RATE_600; + case 1200: + return PERIPHERAL_UART_BAUD_RATE_1200; + case 1800: + return PERIPHERAL_UART_BAUD_RATE_1800; + case 2400: + return PERIPHERAL_UART_BAUD_RATE_2400; + case 4800: + return PERIPHERAL_UART_BAUD_RATE_4800; + case 9600: + return PERIPHERAL_UART_BAUD_RATE_9600; + case 19200: + return PERIPHERAL_UART_BAUD_RATE_19200; + case 38400: + return PERIPHERAL_UART_BAUD_RATE_38400; + case 57600: + return PERIPHERAL_UART_BAUD_RATE_57600; + case 115200: + return PERIPHERAL_UART_BAUD_RATE_115200; + case 230400: + return PERIPHERAL_UART_BAUD_RATE_230400; + } + + IOTJS_ASSERT(!"Invalid baud rate"); + return -1; +} + +static peripheral_uart_byte_size_e databits_to_constant(uint8_t dataBits) { + switch (dataBits) { + case 8: + return PERIPHERAL_UART_BYTE_SIZE_8BIT; + case 7: + return PERIPHERAL_UART_BYTE_SIZE_7BIT; + case 6: + return PERIPHERAL_UART_BYTE_SIZE_6BIT; + case 5: + return PERIPHERAL_UART_BYTE_SIZE_5BIT; + } + + IOTJS_ASSERT(!"Invalid data bits"); + return -1; +} + +void iotjs_uart_create_platform_data(iotjs_uart_t* uart) { + uart->platform_data = IOTJS_ALLOC(iotjs_uart_platform_data_t); + uart->platform_data->uart_h = NULL; +} + +void iotjs_uart_destroy_platform_data( + iotjs_uart_platform_data_t* platform_data) { + IOTJS_ASSERT(platform_data); + IOTJS_RELEASE(platform_data); +} + +jerry_value_t iotjs_uart_set_platform_config(iotjs_uart_t* uart, + const jerry_value_t jconfig) { + JS_GET_REQUIRED_CONF_VALUE(jconfig, uart->platform_data->port, + IOTJS_MAGIC_STRING_PORT, number); + + return jerry_create_undefined(); +} + +bool iotjs_uart_open(iotjs_uart_t* uart) { + iotjs_uart_platform_data_t* platform_data = uart->platform_data; + IOTJS_ASSERT(platform_data); + + int ret = peripheral_uart_open(platform_data->port, &platform_data->uart_h); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot open(%d)", __func__, ret); + return false; + } + + // Set baud rate + ret = peripheral_uart_set_baud_rate(platform_data->uart_h, + baud_to_constant(uart->baud_rate)); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot set baud rate(%d)", __func__, ret); + peripheral_uart_close(platform_data->uart_h); + return false; + } + + // Set data bits + ret = peripheral_uart_set_byte_size(platform_data->uart_h, + databits_to_constant(uart->data_bits)); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot set data bits(%d)", __func__, ret); + peripheral_uart_close(platform_data->uart_h); + return false; + } + + uart->device_fd = platform_data->uart_h->fd; + iotjs_uart_register_read_cb(uart); + + return true; +} + +bool iotjs_uart_write(iotjs_uart_t* uart) { + iotjs_uart_platform_data_t* platform_data = uart->platform_data; + IOTJS_ASSERT(platform_data); + if (!platform_data->uart_h) { + DLOG("%s: UART is not opened", __func__); + return false; + } + + const char* buf_data = iotjs_string_data(&uart->buf_data); + DDDLOG("%s: data: %s", __func__, buf_data); + + int ret = peripheral_uart_write(platform_data->uart_h, (uint8_t*)buf_data, + uart->buf_len); + if (ret != PERIPHERAL_ERROR_NONE) { + DLOG("%s: cannot write(%d)", __func__, ret); + return false; + } + + return true; +} + +void iotjs_uart_handlewrap_close_cb(uv_handle_t* handle) { + iotjs_uart_t* uart = (iotjs_uart_t*)handle->data; + + if (peripheral_uart_close(uart->platform_data->uart_h) != + PERIPHERAL_ERROR_NONE) { + DLOG(iotjs_periph_error_str(kUartOpClose)); + IOTJS_ASSERT(0); + } + + uart->platform_data->uart_h = NULL; +} diff --git a/src/modules/tizenrt/iotjs_module_adc-tizenrt.c b/src/modules/tizenrt/iotjs_module_adc-tizenrt.c index 6d62283..2b72c4e 100644 --- a/src/modules/tizenrt/iotjs_module_adc-tizenrt.c +++ b/src/modules/tizenrt/iotjs_module_adc-tizenrt.c @@ -57,8 +57,8 @@ jerry_value_t iotjs_adc_set_platform_config(iotjs_adc_t* adc, const jerry_value_t jconfig) { iotjs_adc_platform_data_t* platform_data = adc->platform_data; - DJS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->pin, - IOTJS_MAGIC_STRING_PIN, number); + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->pin, + IOTJS_MAGIC_STRING_PIN, number); return jerry_create_undefined(); } diff --git a/src/modules/tizenrt/iotjs_module_i2c-tizenrt.c b/src/modules/tizenrt/iotjs_module_i2c-tizenrt.c index bf3906e..d899af1 100644 --- a/src/modules/tizenrt/iotjs_module_i2c-tizenrt.c +++ b/src/modules/tizenrt/iotjs_module_i2c-tizenrt.c @@ -51,8 +51,8 @@ jerry_value_t iotjs_i2c_set_platform_config(iotjs_i2c_t* i2c, const jerry_value_t jconfig) { iotjs_i2c_platform_data_t* platform_data = i2c->platform_data; - DJS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->bus, - IOTJS_MAGIC_STRING_BUS, number); + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->bus, + IOTJS_MAGIC_STRING_BUS, number); return jerry_create_undefined(); } @@ -116,9 +116,7 @@ bool iotjs_i2c_write(iotjs_i2c_t* i2c) { int ret = iotbus_i2c_write(platform_data->i2c_context, data, len); - if (i2c->buf_data != NULL) { - iotjs_buffer_release(i2c->buf_data); - } + IOTJS_RELEASE(i2c->buf_data); if (ret < 0) { DLOG("%s: cannot write data", __func__); diff --git a/src/modules/tizenrt/iotjs_module_spi-tizenrt.c b/src/modules/tizenrt/iotjs_module_spi-tizenrt.c index 5cc33a6..11f91d8 100644 --- a/src/modules/tizenrt/iotjs_module_spi-tizenrt.c +++ b/src/modules/tizenrt/iotjs_module_spi-tizenrt.c @@ -53,8 +53,8 @@ jerry_value_t iotjs_spi_set_platform_config(iotjs_spi_t* spi, const jerry_value_t jconfig) { iotjs_spi_platform_data_t* platform_data = spi->platform_data; - DJS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->bus, - IOTJS_MAGIC_STRING_BUS, number); + JS_GET_REQUIRED_CONF_VALUE(jconfig, platform_data->bus, + IOTJS_MAGIC_STRING_BUS, number); return jerry_create_undefined(); } diff --git a/src/modules/tizenrt/iotjs_module_uart-tizenrt.c b/src/modules/tizenrt/iotjs_module_uart-tizenrt.c index 03dbd94..c14f524 100644 --- a/src/modules/tizenrt/iotjs_module_uart-tizenrt.c +++ b/src/modules/tizenrt/iotjs_module_uart-tizenrt.c @@ -19,9 +19,33 @@ #include "modules/iotjs_module_uart.h" +struct iotjs_uart_platform_data_s { + iotjs_string_t device_path; +}; + +void iotjs_uart_create_platform_data(iotjs_uart_t* uart) { + uart->platform_data = IOTJS_ALLOC(iotjs_uart_platform_data_t); +} + +void iotjs_uart_destroy_platform_data( + iotjs_uart_platform_data_t* platform_data) { + IOTJS_ASSERT(platform_data); + + iotjs_string_destroy(&platform_data->device_path); + IOTJS_RELEASE(platform_data); +} + +jerry_value_t iotjs_uart_set_platform_config(iotjs_uart_t* uart, + const jerry_value_t jconfig) { + JS_GET_REQUIRED_CONF_VALUE(jconfig, uart->platform_data->device_path, + IOTJS_MAGIC_STRING_DEVICE, string); + + return jerry_create_undefined(); +} + bool iotjs_uart_open(iotjs_uart_t* uart) { - int fd = - open(iotjs_string_data(&uart->device_path), O_RDWR | O_NOCTTY | O_NDELAY); + int fd = open(iotjs_string_data(&uart->platform_data->device_path), + O_RDWR | O_NOCTTY | O_NDELAY); if (fd < 0) { return false; @@ -62,3 +86,12 @@ bool iotjs_uart_write(iotjs_uart_t* uart) { return true; } + +void iotjs_uart_handlewrap_close_cb(uv_handle_t* handle) { + iotjs_uart_t* uart = (iotjs_uart_t*)handle->data; + + if (close(uart->device_fd) < 0) { + DLOG(iotjs_periph_error_str(kUartOpClose)); + IOTJS_ASSERT(0); + } +} diff --git a/src/platform/tizen/iotjs_tizen_service_app.c b/src/platform/tizen/iotjs_tizen_service_app.c new file mode 100644 index 0000000..56d5847 --- /dev/null +++ b/src/platform/tizen/iotjs_tizen_service_app.c @@ -0,0 +1,195 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 +#include +#include +#include +#include + +#include "iotjs_def.h" +#include "iotjs.h" + +extern bool iotjs_initialize(iotjs_environment_t* env); +extern void iotjs_run(iotjs_environment_t* env); +extern void iotjs_end(iotjs_environment_t* env); +extern void iotjs_terminate(iotjs_environment_t* env); + +static char js_absolute_path[128]; +static GMainLoop* gmain_loop; +static bool is_env_initialized = false; + +typedef struct { + GSource source; + iotjs_environment_t* env; +} iotjs_gmain_source_t; + +static int console_log(int level, const char* format, ...) { + va_list args; + va_start(args, format); + dlog_vprint(DLOG_INFO, "IOTJS", format, args); + va_end(args); + return 0; +} + +static gboolean gmain_loop_check(GSource* source) { + return TRUE; +} + +static gboolean gmain_loop_dispatch(GSource* source, GSourceFunc callback, + gpointer user_data) { + iotjs_environment_t* env = ((iotjs_gmain_source_t*)source)->env; + + bool more = uv_run(iotjs_environment_loop(env), UV_RUN_NOWAIT); + more |= iotjs_process_next_tick(); + + jerry_value_t ret_val = jerry_run_all_enqueued_jobs(); + if (jerry_value_has_error_flag(ret_val)) { + DLOG("jerry_run_all_enqueued_jobs() failed"); + } + + if (more == false) { + more = uv_loop_alive(iotjs_environment_loop(env)); + } + + if (!more || iotjs_environment_is_exiting(env)) { + service_app_exit(); + return false; + } + return true; +} + +static void loop_method_init_cb(int argc, char** argv, void* data) { + int iotjs_argc = 2; + char* iotjs_argv[2] = { "iotjs", js_absolute_path }; + +#ifdef ENABLE_DEBUG_LOG + setenv("IOTJS_DEBUG_LEVEL", "3", 0); // Enable all log. +#endif + + // Initialize debug log and environments + iotjs_debuglog_init(); + + iotjs_environment_t* env = iotjs_environment_get(); + + if (!iotjs_environment_parse_command_line_arguments(env, (uint32_t)iotjs_argc, + iotjs_argv)) { + DLOG("iotjs_environment_parse_command_line_arguments failed"); + service_app_exit(); + return; + } + is_env_initialized = true; + + if (!iotjs_initialize(env)) { + DLOG("iotjs_initialize failed"); + service_app_exit(); + return; + } + + DDDLOG("%s", __func__); + + iotjs_conf_console_out(console_log); +} + +static void loop_method_run_cb(void* data) { + DDDLOG("%s", __func__); + iotjs_environment_t* env = iotjs_environment_get(); + iotjs_environment_set_state(env, kRunningMain); + + // Load and call iotjs.js. + iotjs_run(env); + + if (iotjs_environment_is_exiting(env)) { + service_app_exit(); + return; + } + + // Create GMain loop. + gmain_loop = g_main_loop_new(g_main_context_default(), FALSE); + + // Add GSource in GMain context. + GSourceFuncs source_funcs = { + .check = gmain_loop_check, .dispatch = gmain_loop_dispatch, + }; + + iotjs_gmain_source_t* source = + (iotjs_gmain_source_t*)g_source_new(&source_funcs, + sizeof(iotjs_gmain_source_t)); + source->env = env; + uv_loop_t* uv_loop = iotjs_environment_loop(env); + g_source_add_unix_fd(&source->source, uv_loop->backend_fd, + (GIOCondition)(G_IO_IN | G_IO_OUT | G_IO_ERR)); + g_source_attach(&source->source, g_main_context_default()); + + iotjs_environment_set_state(env, kRunningLoop); + + g_main_loop_run(gmain_loop); // Blocks until loop is quit. + + + if (!iotjs_environment_is_exiting(env)) { + // Emit 'exit' event. + iotjs_process_emit_exit(iotjs_process_exitcode()); + + iotjs_environment_set_state(env, kExiting); + } + + DDDLOG("%s: Exit IoT.js(%d).", __func__, iotjs_process_exitcode()); + + iotjs_end(env); +} + +static void loop_method_exit_cb(void* data) { + DDDLOG("%s", __func__); + + if (g_main_loop_is_running(gmain_loop)) { + g_main_loop_quit(gmain_loop); + g_main_loop_unref(gmain_loop); + } +} + +static void loop_method_fini_cb(void) { + DDDLOG("%s", __func__); + iotjs_environment_t* env = iotjs_environment_get(); + + if (is_env_initialized) { + iotjs_terminate(env); + } + + iotjs_environment_release(); + iotjs_debuglog_release(); +} + +int iotjs_service_app_start(int argc, char** argv, char* js_path, + void* event_callbacks, void* user_data) { + DDDLOG("%s", __func__); + char* app_res_path = app_get_resource_path(); + if (!app_res_path) { + DLOG("app_res_path is NULL!"); + return 1; + } + + snprintf(js_absolute_path, sizeof(js_absolute_path), "%s%s", app_res_path, + js_path); + IOTJS_RELEASE(app_res_path); + + service_app_loop_method_s loop_method = {.init = loop_method_init_cb, + .run = loop_method_run_cb, + .exit = loop_method_exit_cb, + .fini = loop_method_fini_cb }; + + return service_app_main_ext(argc, argv, (service_app_lifecycle_callback_s*) + event_callbacks, + &loop_method, user_data); +} diff --git a/src/platform/tizen/iotjs_tizen_service_app.h b/src/platform/tizen/iotjs_tizen_service_app.h new file mode 100644 index 0000000..eb56a88 --- /dev/null +++ b/src/platform/tizen/iotjs_tizen_service_app.h @@ -0,0 +1,32 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 IOTJS_TIZEN_SERVICE_APP_H +#define IOTJS_TIZEN_SERVICE_APP_H + + +#ifdef __cplusplus +#define IOTJS_EXTERN_C extern "C" +#else /* !__cplusplus */ +#define IOTJS_EXTERN_C extern +#endif /* !__cplusplus */ + + +IOTJS_EXTERN_C int iotjs_service_app_start(int argc, char** argv, char* js_path, + void* event_callbacks, + void* user_data); + + +#endif /* IOTJS_TIZEN_SERVICE_APP_H */ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..e3a13f8 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors +# +# 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. + +cmake_minimum_required(VERSION 2.8) + +set(IOTJS_INCLUDE_DIR ${IOTJS_SOURCE_DIR}) +#set(JERRY_INCLUDE_DIR +add_subdirectory(dynamicmodule) diff --git a/test/dynamicmodule/CMakeLists.txt b/test/dynamicmodule/CMakeLists.txt new file mode 100644 index 0000000..7821553 --- /dev/null +++ b/test/dynamicmodule/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors +# +# 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. + +# +# This is a standalone shared libray which +# only requires the iotjs and jerry header file(s). +# +cmake_minimum_required(VERSION 2.8) +set(NAME test-dynamicmodule) + +# Currently only Linux and Tizen targets are supported +if(("${TARGET_OS}" STREQUAL "LINUX") OR ("${TARGET_OS}" STREQUAL "TIZEN")) + + if((NOT IOTJS_INCLUDE_DIR) OR (NOT JERRY_INCLUDE_DIR)) + message(FATAL_ERROR "No 'IOTJS_INCLUDE_DIR' or 'JERRY_INCLUDE_DIR'") + endif() + + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") + + add_library(${NAME} SHARED + src/module_entry.c) + target_include_directories(${NAME} + PRIVATE ${IOTJS_INCLUDE_DIR} ${JERRY_INCLUDE_DIR}) + set_target_properties(${NAME} PROPERTIES + PREFIX "" + SUFFIX ".iotjs") +endif() diff --git a/test/dynamicmodule/README.md b/test/dynamicmodule/README.md new file mode 100644 index 0000000..915c21a --- /dev/null +++ b/test/dynamicmodule/README.md @@ -0,0 +1 @@ +Minimalistic dynamically loadable IoT.js module diff --git a/test/dynamicmodule/src/module_entry.c b/test/dynamicmodule/src/module_entry.c new file mode 100644 index 0000000..f0bd97f --- /dev/null +++ b/test/dynamicmodule/src/module_entry.c @@ -0,0 +1,36 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 + +static uint32_t counter = 0; + +jerry_value_t init_dynamicmodule(void) { + jerry_value_t object = jerry_create_object(); + + jerry_value_t prop_name = jerry_create_string((const jerry_char_t*)"demokey"); + jerry_value_t prop_value = jerry_create_number(3.4); + + jerry_set_property(object, prop_name, prop_value); + + jerry_release_value(prop_name); + jerry_release_value(prop_value); + + iotjs_jval_set_property_number(object, "counter", ++counter); + + return object; +} + +IOTJS_MODULE(IOTJS_CURRENT_MODULE_VERSION, 1, dynamicmodule) diff --git a/test/external_modules/test-external-module1.js b/test/external_modules/test-external-module1.js new file mode 100644 index 0000000..3564974 --- /dev/null +++ b/test/external_modules/test-external-module1.js @@ -0,0 +1,19 @@ +/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +var assert = require('assert'); +var mymodule = require('mymodule1'); + +assert.equal(mymodule.foo() + mymodule.message, "Hello world!"); diff --git a/test/external_modules/test-external-module2.js b/test/external_modules/test-external-module2.js new file mode 100644 index 0000000..0911d7d --- /dev/null +++ b/test/external_modules/test-external-module2.js @@ -0,0 +1,19 @@ +/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +var assert = require('assert'); +var mymodule = require('mymodule2'); + +assert.equal(mymodule.message, "Hello world!"); diff --git a/test/external_modules/test_external_module1.js b/test/external_modules/test_external_module1.js deleted file mode 100644 index 3564974..0000000 --- a/test/external_modules/test_external_module1.js +++ /dev/null @@ -1,19 +0,0 @@ -/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors - * - * 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. - */ - -var assert = require('assert'); -var mymodule = require('mymodule1'); - -assert.equal(mymodule.foo() + mymodule.message, "Hello world!"); diff --git a/test/external_modules/test_external_module2.js b/test/external_modules/test_external_module2.js deleted file mode 100644 index 0911d7d..0000000 --- a/test/external_modules/test_external_module2.js +++ /dev/null @@ -1,19 +0,0 @@ -/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors - * - * 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. - */ - -var assert = require('assert'); -var mymodule = require('mymodule2'); - -assert.equal(mymodule.message, "Hello world!"); diff --git a/test/node/common.js b/test/node/common.js index f00d34f..e3aa286 100644 --- a/test/node/common.js +++ b/test/node/common.js @@ -57,6 +57,7 @@ exports.isLinuxPPCBE = (process.platform === 'linux') && exports.isSunOS = process.platform === 'sunos'; exports.isFreeBSD = process.platform === 'freebsd'; exports.isLinux = process.platform === 'linux'; +exports.isTizen = process.platform === 'tizen'; exports.isOSX = process.platform === 'darwin'; exports.enoughTestMem = false; @@ -101,7 +102,7 @@ function rmdirSync(p, originalEr) { if (e.code === 'ENOTDIR') throw originalEr; if (e.code === 'ENOTEMPTY' || e.code === 'EEXIST' || e.code === 'EPERM') { - var enc = exports.isLinux ? 'buffer' : 'utf8'; + var enc = (exports.isLinux || exports.isTizen) ? 'buffer' : 'utf8'; fs.readdirSync(p, enc).forEach(function(f) { if (f instanceof Buffer) { var buf = Buffer.concat([Buffer.from(p), Buffer.from(path.sep), f]); @@ -131,7 +132,7 @@ var inFreeBSDJail = null; var localhostIPv4 = null; exports.localIPv6Hosts = ['localhost']; -if (exports.isLinux) { +if (exports.isLinux || exports.isTizen) { exports.localIPv6Hosts = [ // Debian/Ubuntu 'ip6-localhost', @@ -359,7 +360,7 @@ if (global.ArrayBuffer) { knownGlobals.push(Uint32Array); knownGlobals.push(Float32Array); knownGlobals.push(Float64Array); - knownGlobals.push(DataView); + // knownGlobals.push(DataView); } // Harmony features. diff --git a/test/node/parallel/test-module-circular-b.js b/test/node/parallel/test-module-circular-b.js new file mode 100644 index 0000000..68937d0 --- /dev/null +++ b/test/node/parallel/test-module-circular-b.js @@ -0,0 +1,40 @@ +/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +require('./test-module-circular'); + diff --git a/test/node/parallel/test-module-circular.js b/test/node/parallel/test-module-circular.js new file mode 100644 index 0000000..daf40c2 --- /dev/null +++ b/test/node/parallel/test-module-circular.js @@ -0,0 +1,43 @@ +/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; +require('node/common'); + +var assert = require('assert'); +require('./test-module-circular-b'); + +assert.ok(true); diff --git a/test/profiles/host-darwin.profile b/test/profiles/host-darwin.profile index d496e8f..397f0d4 100644 --- a/test/profiles/host-darwin.profile +++ b/test/profiles/host-darwin.profile @@ -1,2 +1,3 @@ ENABLE_MODULE_IOTJS_BASIC_MODULES ENABLE_MODULE_IOTJS_CORE_MODULES +ENABLE_MODULE_HTTPS diff --git a/test/profiles/host-linux.profile b/test/profiles/host-linux.profile index 7126bdb..68135c5 100644 --- a/test/profiles/host-linux.profile +++ b/test/profiles/host-linux.profile @@ -4,6 +4,7 @@ ENABLE_MODULE_ADC ENABLE_MODULE_BLE ENABLE_MODULE_DGRAM ENABLE_MODULE_GPIO +ENABLE_MODULE_HTTPS ENABLE_MODULE_I2C ENABLE_MODULE_PWM ENABLE_MODULE_SPI diff --git a/test/profiles/rpi2-linux.profile b/test/profiles/rpi2-linux.profile index fd32710..8ed4b59 100644 --- a/test/profiles/rpi2-linux.profile +++ b/test/profiles/rpi2-linux.profile @@ -3,6 +3,7 @@ ENABLE_MODULE_IOTJS_CORE_MODULES ENABLE_MODULE_BLE ENABLE_MODULE_DGRAM ENABLE_MODULE_GPIO +ENABLE_MODULE_HTTPS ENABLE_MODULE_I2C ENABLE_MODULE_PWM ENABLE_MODULE_SPI diff --git a/test/profiles/tizen.profile b/test/profiles/tizen.profile index 68135c5..bf9c925 100644 --- a/test/profiles/tizen.profile +++ b/test/profiles/tizen.profile @@ -1,11 +1,11 @@ ENABLE_MODULE_IOTJS_BASIC_MODULES ENABLE_MODULE_IOTJS_CORE_MODULES -ENABLE_MODULE_ADC -ENABLE_MODULE_BLE +ENABLE_MODULE_BRIDGE ENABLE_MODULE_DGRAM ENABLE_MODULE_GPIO ENABLE_MODULE_HTTPS ENABLE_MODULE_I2C ENABLE_MODULE_PWM ENABLE_MODULE_SPI +ENABLE_MODULE_TIZEN ENABLE_MODULE_UART diff --git a/test/resources/my_crt.pem b/test/resources/my_crt.pem new file mode 100644 index 0000000..798292d --- /dev/null +++ b/test/resources/my_crt.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFQDCCAyigAwIBAgIBATANBgkqhkiG9w0BAQsFADA5MREwDwYDVQQDEwhteXNl +cnZlcjEXMBUGA1UEChMObXlvcmdhbmlzYXRpb24xCzAJBgNVBAYTAk5MMB4XDTEz +MDEwMTAwMDAwMFoXDTE5MTIzMTIzNTk1OVowOTERMA8GA1UEAxMIbXlzZXJ2ZXIx +FzAVBgNVBAoTDm15b3JnYW5pc2F0aW9uMQswCQYDVQQGEwJOTDCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAKXf+Q90/RFky3CS05PGso3PhnUmQYkTWKOC +UgAn+C0q0wTon+FDf9z2YtNsJj3rDxcj2POnKiRov+yFcWl19rLSiwUWvmROz6e0 +/bSI5Mcf0cNRjBBy0oyTOCTAVCdlW+mtIyzwLzajvY4l3msOlyVbb1yaxO9c1To9 +EdU7atG91UNdKEIGVX2kcsYzBQ9rEzBaOwA5BsPl1Kr6dGTJXnjpNsirn5b0JK/w +VB853HqQbbDHcRm/F5ufGUG1aHS5Wwg/jQKEaU51aYVcUqRrGEXyzXxB1mAPAg/t +Sd5z0wGFPbewMWWD7KnB1hh3NgOm2nZ8C7IOIzW1BseGzkticLX+blUMTyx6GyOJ +TBQGVwQRx7skj9zvVkzwfJv0h0RT9kwSwESV+AwqYrGnmdn9JLIXVAmWsSgiqIok +NBKPNuokSSLYgDsflKNxOFT/fqpKYToz1ttxEcPBA2OQpv//z6eKv75RiAk596Xq +MQ52HMvhQz728PnWpED7SiMbq0AvNEald3/lui4Vcd7mUGDdhZHzoUGjG33avowe +nXK124dRVD8GtNHmj3X18xatcVqX8xOhq404YowtB5Bq1E+k4UFRtJ6xw4c2ysPt +uxVA5IcJzqzbQictRoEvZk1A9Qr6A33UUr6j+Ddc68TSuDzZ2LjfJv8XMnJ/Iu2j +K6EBRBkhAgMBAAGjUzBRMA8GA1UdEwQIMAYBAf8CAQAwHQYDVR0OBBYEFDq9Z6I3 +rL5uuud2JuA1G9V4QP2sMB8GA1UdIwQYMBaAFDq9Z6I3rL5uuud2JuA1G9V4QP2s +MA0GCSqGSIb3DQEBCwUAA4ICAQBVibU3yI7w3181J/QWp5QXO7Z8Ew1xdhp5thX4 +HWD/cW7Q7SR5hFkRViMvcFsF3K6bYZa8MJHdhURPKZe+jWYwDlPQ47Bk0eoPn28V +edhwMEqTeIaAvZFIAP9fx0388p0+1ZPsH+B6jcbO89ViLbTrEXOmv+LppqYHpyq1 +NSlLong+S8qX9ILdLfeINP8a3OklEPkoqIoOt5SU3t1q6op+5fY+7KELVxGFa5c/ +rUrxjSGc1IrboMO8pMtUytbytWakZ2YdSfg7Nk8k/vsgymKD+7oN6IapA52MPTjZ +G2lw8U98GCCsToaF95ctfCVjz6AcFhGLxtDgi1dlw6jChBOR8HhjBFptwloCucq5 +2TTvIO/UAkMp+CHLpz3lM8aK818SCiHqoyS7IS4mh5b6Vchb+qjiM68Jva9KZn8O +5WjWj87VMGQ9k7t08zvHt9UmCteSnAJB81HxMIg8z3718tPqY/Ila5y0fgU18+9M +uc1nCI4hAHorlkZh8jeVQRWQ6X1MF4IJOpVMjADeWjPOBOboRgpEB5EEKE0LrajW +8UZZmuLOIXhrM+H4HYqVSiExqVyfqwHhGunPc2UKCo+Z5LWDHUfqNFhswjpa3o2J +yc/Gu+aoHsXJ0fjtfEjA1b8ZxWOjLmALAX7Bl4fCl7IS87GytE9MwRlBfa0Jg1E8 +RB15XA== +-----END CERTIFICATE----- diff --git a/test/resources/my_key.pem b/test/resources/my_key.pem new file mode 100644 index 0000000..c7e28e6 --- /dev/null +++ b/test/resources/my_key.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJJwIBAAKCAgEApd/5D3T9EWTLcJLTk8ayjc+GdSZBiRNYo4JSACf4LSrTBOif +4UN/3PZi02wmPesPFyPY86cqJGi/7IVxaXX2stKLBRa+ZE7Pp7T9tIjkxx/Rw1GM +EHLSjJM4JMBUJ2Vb6a0jLPAvNqO9jiXeaw6XJVtvXJrE71zVOj0R1Ttq0b3VQ10o +QgZVfaRyxjMFD2sTMFo7ADkGw+XUqvp0ZMleeOk2yKuflvQkr/BUHzncepBtsMdx +Gb8Xm58ZQbVodLlbCD+NAoRpTnVphVxSpGsYRfLNfEHWYA8CD+1J3nPTAYU9t7Ax +ZYPsqcHWGHc2A6badnwLsg4jNbUGx4bOS2Jwtf5uVQxPLHobI4lMFAZXBBHHuySP +3O9WTPB8m/SHRFP2TBLARJX4DCpisaeZ2f0kshdUCZaxKCKoiiQ0Eo826iRJItiA +Ox+Uo3E4VP9+qkphOjPW23ERw8EDY5Cm///Pp4q/vlGICTn3peoxDnYcy+FDPvbw ++dakQPtKIxurQC80RqV3f+W6LhVx3uZQYN2FkfOhQaMbfdq+jB6dcrXbh1FUPwa0 +0eaPdfXzFq1xWpfzE6GrjThijC0HkGrUT6ThQVG0nrHDhzbKw+27FUDkhwnOrNtC +Jy1GgS9mTUD1CvoDfdRSvqP4N1zrxNK4PNnYuN8m/xcycn8i7aMroQFEGSECAwEA +AQKCAgBU1Z3dx+l+MdzScGWBWMgNOyv7UluGLbzRs18Y8Vg+UX6nLgpG/Wyxp9mX +Y+KTHFsVbKISy1YEVQaDgyQj2c8YWhH7wkwRpTUTAsAWy0SmiqGPkW9fIjqI5up5 +8VuY4oAFnSU2YIjlGw1hXADLJCUtV/w2knlSKlprdLxgIAlbyAkAcO6cBf1HSwng +UEuwPQUNX7h5PrE1E6CW6Y0J1utYT35TV2NBow/4Y6PCbKdUj/VpyjcQAemjD9Wt +A4iu2fWy3D3UIcBx/h6/tB4YNSWu8KUjfdCURFi7qJJ1ESvDxU9xWM2Kq9QoZhiH +XsDjUTy+CGc643wihbk35rwvVeNqfN2GfkrrdyTzqIszJAqKtImoXv8BuEf+kgeX +0s9Wtl8BF4Hv6jAZ28NI1DwXXjEFkuqG6Z1yn5UTAxcmKqAudZFVoI5dgeGu8c6x +LVkudR7QOkeSuHTrn4ILYiWMsuP8No/qmnQBCHbfJT4xp2dBHdZ0vDml7LFZjzg1 +If1ZGStOBB7uZqDXyx4wdYdMdV05dvUelWwJqI0KLWF8doX6fr+Huh1Q3owYoOQ5 +MZOoXbHMegu5fOrkDFfaYeATTnCeE1RjoYjT9zf4rYjX3IOryj66b0DadXpYdNhk +5vSAA+NRj3fLGFScdCFxwJjwPbw1Xsn0uSwRHHEQnF9H5hmsoQKCAQEA5poLkJ1s +1ZeEWVr5CDU0js8QsEbeRGpXsm+Aj9X9gf4+D3HQ573lnXO8wiB+PoikETWp45Jf +yq1XK2dcbygcxrSo6Zr+GtzE6grCztn8jE4omkqduJhViAr4hdg59R4UdNG1Qpgg +Z9cFBYwnI/IWMJJBTiqKIVwD3RKQM75WKDT/ccDtUp2MxxNjUKAsVHpmOHW2ZC4T +A2vwbqp+egQ5SfSUBcGkD034PjG2uOJGmHXcKnnG4Dm+9SeutvTF9JZwMJmg3WlG +5AdVUnl4qN2g4t3TYasV4Y8i00EJPcQW5v4UV9sq4dAQ0GXfu/r/TXwMKkQp/cN1 +95I+xXsBjKQDdQKCAQEAuCTqVZJMZ5uovPzyPmnMOBqdtac5Hd7/eglN945sAK7n +ssg3X1hRsHCf8Dx1X95lxCDVn97ac9C2uIEeiLy/+JDFQcOxcgj1vDeF6IaGzaFh +Dc9qIDo4b0bhhD1kMxtowOAkI4YR/+iSIuGOJXq7wu71a6+dIm4meb+4d3L+O5Jq +sOsOBLClL7Ymv1iZ3fol0XPQsuSv1eGoDqDdiNNXOBJHgKy0zMEXs4hpjL2vCGDN +m8MbtqpMg4jCuesy/zh/b+CCkrX0AdW/fkw/euZ/ZTMEageqH5RfitX9CGOw2CuS ++78XmWeFqbr2YVbAZFo09I8Ytv40yO1ZyVQkyKSlfQKCAQA1ooCsGyF0MHCVA+bG +NPHLgXfFOEZ8LSvGkc6aJdB3yrWOjA9lxzI/w+qUUFBspQVcB1pDVwk2r8iFjN3f +8Ll4sg5Tfzw47T5TnTsgN21ZCNjCwjYa+Dt0j/Cr2NXqIBvr69a37YAkBsvhNW7p +GmZ015+e2aAVEDzJz4aAsnWBlooPYCsSuxhCOU0xNH/7Chj6as6IUHsVoaZjZv5R +zOeyPtOq3xYUhTMG7DMun1qCHW+e5YIPJv82MAuf/CCKue7QLvtOZC0b3mTG8P/S +bvH7slJ29f753nvgHNFUb2ZQRapfoNdBfE5c2kUGiOOWlxKRRhdqMWsfsQEul2SN +3Jv9AoIBAASuW46lU2/m0xlKzNWtVtWuR4gQojESNChkCClc43349EblNBMmaZ00 +n7w5rTosqyWbOBMCVUdQbPSvw5jyQ2cMNxd+5AnkFGsedjb9BHxBt/fj5+y9ziV2 +BdGYxe1OqxEMIZ8Nj3OT8/MTDMwDHLbN4EtGgZYYer3pk8TllXTqOfAZaZfQ7cIS +vVVr6S1taHy0lv+VNKsZO25zxG3wAW2ZeVvaCBaUagfUVeqP/90UqOVmxlOUbLGD +Tn/vbLJ0Ozka2fbkzTkmt+F8CrkTFvX5oAkZ/MckvHEJE4+dCSfVo7zmlLD/orQ3 +3n+G9wkWCfaVlKlCORFKh1fI3c6D8PkCggEAI/zEfC6+CndqrmehoCGgHZMP7B+a +rytCeG3Qyoqjta0sKGC8/LUe85PSWDR9xHrrWgEriRF9gHvYxF8YCBXhfInIHDd+ +pdcsWEaoUWlvBqhbKaPhVF/0difpjogWH388sdVXT6PefHEO5maYii9EaPjWckKf +314Eh0KW/oUiSo5rwAgdnu1J84qBOxXqMI2eDZaKLphueytHjt7QRnZW91zeYwrP +3E7MbkKVJPaViIm3MvXUUsL8Gpqji9MY0wHjZAq1PXtZ5WP+K3wHUOte6OGkBcSQ +7oUxhOoMlN0VC4FGtSHu1LLTvmWeYrHk9J6mpfNAj1/TfA/VvVKpNQVlaw== +-----END RSA PRIVATE KEY----- diff --git a/test/run_fail/test-issue-1349.js b/test/run_fail/test-issue-1349.js new file mode 100644 index 0000000..790b1a7 --- /dev/null +++ b/test/run_fail/test-issue-1349.js @@ -0,0 +1,18 @@ +/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +var dns = require( 'dns' ); +var assert = require( 'assert' ); +assert.throws(function ( ) { dns.lookup ('localhost', require) } ); diff --git a/test/run_fail/test-issue-1360.js b/test/run_fail/test-issue-1360.js new file mode 100644 index 0000000..0eea6c1 --- /dev/null +++ b/test/run_fail/test-issue-1360.js @@ -0,0 +1,17 @@ +/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +process.on('exit', function() {}); +setTimeout(function() { Array.prototype.slice += 'B' }, 500); diff --git a/test/run_pass/issue/issue-1101.js b/test/run_pass/issue/issue-1101.js index 3b43a28..5f88577 100644 --- a/test/run_pass/issue/issue-1101.js +++ b/test/run_pass/issue/issue-1101.js @@ -13,8 +13,7 @@ * limitations under the License. */ -var UART = require('uart'); -var uart = new UART(); +var uart = require('uart'); var res = uart.open({ device: '/dev/ttyS1', baudRate: 115200, diff --git a/test/run_pass/issue/issue-1348.js b/test/run_pass/issue/issue-1348.js new file mode 100644 index 0000000..e490963 --- /dev/null +++ b/test/run_pass/issue/issue-1348.js @@ -0,0 +1,17 @@ +/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + + process.on('uncaughtException', function(err) { } ); + process.exit('callback'); diff --git a/test/run_pass/issue/issue-1350.js b/test/run_pass/issue/issue-1350.js new file mode 100644 index 0000000..0c3645d --- /dev/null +++ b/test/run_pass/issue/issue-1350.js @@ -0,0 +1,16 @@ +/* Copyright 2015-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +process.on('exit', function() { process.exit("callback"); } ); diff --git a/test/run_pass/issue/issue-1485.js b/test/run_pass/issue/issue-1485.js new file mode 100644 index 0000000..83ebbb8 --- /dev/null +++ b/test/run_pass/issue/issue-1485.js @@ -0,0 +1,16 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +process.emitExit = 1; diff --git a/test/run_pass/issue/issue-1507.js b/test/run_pass/issue/issue-1507.js new file mode 100644 index 0000000..2130924 --- /dev/null +++ b/test/run_pass/issue/issue-1507.js @@ -0,0 +1,17 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +var x = require("console"); +process.exitCode = x.id_0; diff --git a/test/run_pass/issue/issue-1557.js b/test/run_pass/issue/issue-1557.js new file mode 100644 index 0000000..3c51283 --- /dev/null +++ b/test/run_pass/issue/issue-1557.js @@ -0,0 +1,22 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +var fz_globalObject = Function("return this")( ) +var prop_names = Object.getOwnPropertyNames(fz_globalObject) +console.log(prop_names) +for (var i = 0; i < 10; i++) { + var prop_name = prop_names[i] + console.log(prop_name) +} diff --git a/test/run_pass/test_buffer.js b/test/run_pass/test_buffer.js index 3d0664d..5f1d251 100644 --- a/test/run_pass/test_buffer.js +++ b/test/run_pass/test_buffer.js @@ -19,15 +19,15 @@ var assert = require('assert'); var buff1 = new Buffer("test"); assert.equal(buff1.toString(), "test"); -assert.equal(buff1.toString(0, 0), ""); -assert.equal(buff1.toString(0, 1), "t"); -assert.equal(buff1.toString(0, 2), "te"); -assert.equal(buff1.toString(0, 3), "tes"); -assert.equal(buff1.toString(0, 4), "test"); -assert.equal(buff1.toString(1, 4), "est"); -assert.equal(buff1.toString(2, 4), "st"); -assert.equal(buff1.toString(3, 4), "t"); -assert.equal(buff1.toString(4, 4), ""); +assert.equal(buff1.toString(undefined, 0, 0), ""); +assert.equal(buff1.toString(undefined, 0, 1), "t"); +assert.equal(buff1.toString(undefined, 0, 2), "te"); +assert.equal(buff1.toString(undefined, 0, 3), "tes"); +assert.equal(buff1.toString(undefined, 0, 4), "test"); +assert.equal(buff1.toString(undefined, 1, 4), "est"); +assert.equal(buff1.toString(undefined, 2, 4), "st"); +assert.equal(buff1.toString(undefined, 3, 4), "t"); +assert.equal(buff1.toString(undefined, 4, 4), ""); assert.equal(buff1.length, 4); var buff2 = new Buffer(10); diff --git a/test/run_pass/test_buffer_builtin.js b/test/run_pass/test_buffer_builtin.js deleted file mode 100644 index 66d3d57..0000000 --- a/test/run_pass/test_buffer_builtin.js +++ /dev/null @@ -1,111 +0,0 @@ -/* Copyright 2016-present Samsung Electronics Co., Ltd. and other contributors - * - * 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. - */ - - - -var assert = require('assert'); - - -var buff1 = new Buffer("test"); -assert.equal(buff1._builtin.toString(0, 0), ""); -assert.equal(buff1._builtin.toString(0, 1), "t"); -assert.equal(buff1._builtin.toString(0, 2), "te"); -assert.equal(buff1._builtin.toString(0, 3), "tes"); -assert.equal(buff1._builtin.toString(0, 4), "test"); -assert.equal(buff1._builtin.toString(1, 4), "est"); -assert.equal(buff1._builtin.toString(2, 4), "st"); -assert.equal(buff1._builtin.toString(3, 4), "t"); -assert.equal(buff1._builtin.toString(4, 4), ""); - -assert.equal(buff1._builtin.toString(-1, 5), "test"); -assert.equal(buff1._builtin.toString(-1, 2), "te"); -assert.equal(buff1._builtin.toString(2, 5), "st"); - - -var buff2 = new Buffer(10); -buff2._builtin.write("abcde", 0, 5); -assert.equal(buff2.toString(), "abcde"); -assert.equal(buff2.length, 10); - -buff2._builtin.write("fgh", 5, 3); -assert.equal(buff2.toString(), "abcdefgh"); -assert.equal(buff2.length, 10); - -buff2._builtin.write("AB", 0, 10); -assert.equal(buff2.toString(), "ABcdefgh"); -assert.equal(buff2.length, 10); - -buff2._builtin.write("ab", -1, 11); -assert.equal(buff2.toString(), "abcdefgh"); -assert.equal(buff2.length, 10); - -buff2._builtin.write("ijklmnopqrstu", 8, 5); -assert.equal(buff2.toString(), "abcdefghij"); -assert.equal(buff2.length, 10); - -buff2._builtin.write("\0\0", 8, 2); -assert.equal(buff2.toString(), "abcdefgh"); -assert.equal(buff2.length, 10); - - -var buff3 = Buffer.concat([buff1, buff2]); - - -var buff4 = new Buffer(10); -var buff5 = new Buffer('a1b2c3'); -buff5._builtin.copy(buff4, 0, 0, 6); -assert.equal(buff4.toString(), 'a1b2c3'); -buff5._builtin.copy(buff4, 4, 2, 6); -assert.equal(buff4.toString(), 'a1b2b2c3'); - - -var buff6 = buff3._builtin.slice(1, buff3.length); -assert.equal(buff6.toString(), 'estabcdefgh'); -assert.equal(buff6.length, 13); - -var buff7 = buff6._builtin.slice(3, 5); -assert.equal(buff7.toString(), 'ab'); -assert.equal(buff7.length, 2); - -var buff8 = new Buffer(buff5); -assert.equal(buff8.toString(), 'a1b2c3'); -assert.equal(buff8.equals(buff5), true); -assert.equal(buff8.equals(buff6), false); - -var buff9 = new Buffer('abcabcabcd'); -var buff10 = buff9._builtin.slice(0, 3); -var buff11 = buff9._builtin.slice(3, 6); -var buff12 = buff9._builtin.slice(6, buff9.length); -assert.equal(buff10.equals(buff11), true); -assert.equal(buff11.equals(buff10), true); -assert.equal(buff11.equals(buff12), false); -assert.equal(buff10.compare(buff11), 0); -assert.equal(buff11.compare(buff10), 0); -assert.equal(buff11.compare(buff12), -1); -assert.equal(buff12.compare(buff11), 1); - -assert.equal(buff9._builtin.slice(-2, buff9.length).toString(), 'cd'); -assert.equal(buff9._builtin.slice(-3, -2).toString(), 'b'); -assert.equal(buff9._builtin.slice(0, -2).toString(), 'abcabcab'); - - -assert.equal(buff3.toString(), 'testabcdefgh'); - - -assert.equal(Buffer.byteLength('\u007F'), 1); -assert.equal(Buffer.byteLength('\u008F'), 2); -assert.equal(Buffer.byteLength('\u08FF'), 3); -assert.equal(Buffer.byteLength('abc'), 'abc'.length); -assert.notEqual(Buffer.byteLength('\u2040'), '\u2040'.length); diff --git a/test/run_pass/test_buffer_str_conv.js b/test/run_pass/test_buffer_str_conv.js new file mode 100644 index 0000000..7aeae86 --- /dev/null +++ b/test/run_pass/test_buffer_str_conv.js @@ -0,0 +1,100 @@ +/* Copyright 2015-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +var assert = require('assert'); + +function decodeError(string, encode) +{ + try { + new Buffer(string, encode); + } catch (e) { + assert.assert(e instanceof TypeError); + } +} + +function testWrite(input, string, offset, length, + encoding, expected, expectedLength) +{ + var buf = new Buffer(input); + + assert.equal(buf.write(string, offset, length, encoding), expectedLength); + assert.equal(buf.toString(), expected); +} + +/* Base64 tests. */ + +assert.equal((new Buffer('YnVmZg==', 'base64')).toString(), 'buff'); +assert.equal((new Buffer('YnVmZmU=', 'base64')).toString(), 'buffe'); +assert.equal((new Buffer('YnVmZmVy', 'base64')).toString(), 'buffer'); +assert.equal((new Buffer('KiAxMjM0ICo=', 'base64')).toString(), '* 1234 *'); +assert.equal((new Buffer('f39/fw==', 'base64')).toString(), + '\u007f\u007f\u007f\u007f'); +assert.equal((new Buffer('fn5+fg==', 'base64')).toString(), + '\u007e\u007e\u007e\u007e'); + +decodeError('Yn=mZg==', 'base64'); +decodeError('YnVmZ===', 'base64'); +decodeError('YnVmZm', 'base64'); +decodeError('KiAx*jM0ICo=', 'base64'); + +testWrite('xxxxxxxx', 'MTIzNA==', 2, 16, 'base64', 'xx1234xx', 4); +testWrite('xxxxxxxx', 'MTIzNA==', 2, 0, 'base64', 'xxxxxxxx', 0); +testWrite('xxxxxxxx', 'MTIzNA==', 3, 2, 'base64', 'xxx12xxx', 2); +testWrite('xxxx', 'MTIzNA==', 2, 16, 'base64', 'xx12', 2); + +assert.throws(function () { + /* Malformed string must throw error regardless of the buffer length. */ + testWrite('xxxxxxxx', 'MTIzNA=!', 2, 2, 'base64', 'xx12xxxx'); +}); + + +assert.equal((new Buffer('buff')).toString('base64'), 'YnVmZg=='); +assert.equal((new Buffer('buffe')).toString('base64'), 'YnVmZmU='); +assert.equal((new Buffer('buffer')).toString('base64'), 'YnVmZmVy'); +assert.equal((new Buffer('\u007f\u007f\u007f\u007f')).toString('base64'), + 'f39/fw=='); +assert.equal((new Buffer('\u007e\u007e\u007e\u007e')).toString('base64'), + 'fn5+fg=='); + +assert.equal((new Buffer('**buffer**')).toString('base64', 2, 7), 'YnVmZmU='); + + +/* Hex tests. */ + +assert.equal((new Buffer('6768696A6b6c6D6e6f70', 'hex')).toString(), + 'ghijklmnop'); +assert.equal((new Buffer('2a20427546663352202a', 'hex')).toString(), + '* BuFf3R *'); +assert.equal((new Buffer('eFbfBf', 'hex')).toString(), '\uffff'); + +decodeError('0*12', 'hex'); +decodeError('0fe', 'hex'); +decodeError('0g', 'hex'); + +testWrite('xxxxxxxx', '31323334', 2, 16, 'hex', 'xx1234xx', 4); +testWrite('xxxxxxxx', '31323334', 2, 0, 'hex', 'xxxxxxxx', 0); +testWrite('xxxxxxxx', '31323334', 3, 2, 'hex', 'xxx12xxx', 2); +testWrite('xxxx', '31323334', 2, 16, 'hex', 'xx12', 2); + +assert.throws(function () { + /* Malformed string must throw error regardless of the buffer length. */ + testWrite('xxxxxxxx', '3132333g', 2, 2, 'base64', 'xx12xxxx'); +}); + +assert.equal((new Buffer('ghijklmnop')).toString('hex'), + '6768696a6b6c6d6e6f70'); + +assert.equal((new Buffer('ghijklmnop')).toString('hex', 2, 8), + '696a6b6c6d6e'); diff --git a/test/run_pass/test_fs_mkdir_rmdir.js b/test/run_pass/test_fs_mkdir_rmdir.js index e948c22..ee167b7 100644 --- a/test/run_pass/test_fs_mkdir_rmdir.js +++ b/test/run_pass/test_fs_mkdir_rmdir.js @@ -54,40 +54,33 @@ function unlink(path) { fs.rmdir(root, function() { assert.equal(fs.existsSync(root), false); - }); - - var root2 = testRoot + "/test_dir2"; + var root2 = testRoot + "/test_dir2"; - fs.mkdir(root2, 777, function(err) { - assert.equal(err, null); - assert.equal(fs.existsSync(root2), true); + fs.mkdir(root2, 777, function(err) { + assert.equal(err, null); + assert.equal(fs.existsSync(root2), true); - fs.rmdir(root2, function(){ - assert.equal(fs.existsSync(root2), false); - }); + fs.rmdir(root2, function() { + assert.equal(fs.existsSync(root2), false); + }); - // Run read-only directory test only on linux - // NuttX does not support read-only attribute. - if (process.platform === 'linux') { - // Try to create a folder in a read-only directory. - fs.mkdir(root, '0444', function(err) { - assert.equal(fs.existsSync(root), true); + // Run read-only directory test only on linux and Tizen + // NuttX does not support read-only attribute. + if (process.platform === 'linux' || process.platform === 'tizen') { + var testMode = '0444'; + fs.mkdir(root, testMode, function(err) { + assert.equal(err, null); + assert.equal(fs.existsSync(root), true); - var dirname = root + "/permission_test"; - try { - fs.mkdirSync(dirname); - assert.assert(false); - } catch (e) { - assert.equal(e instanceof Error, true); - assert.equal(e instanceof assert.AssertionError, false); - } + var mode = fs.statSync(root).mode; + assert.strictEqual(mode.toString(8).slice(-4), testMode); - assert.equal(fs.existsSync(dirname), false); - fs.rmdir(root, function() { - assert.equal(fs.existsSync(root), false); + fs.rmdir(root, function() { + assert.equal(fs.existsSync(root), false); + }); }); - }); - } + } + }); }); }); } diff --git a/test/run_pass/test_gpio_input.js b/test/run_pass/test_gpio_input.js index 84bf4db..c586fc6 100644 --- a/test/run_pass/test_gpio_input.js +++ b/test/run_pass/test_gpio_input.js @@ -16,9 +16,10 @@ var assert = require('assert'); var gpio = require('gpio'); +var pin = require('tools/systemio_common').pin; +var checkError = require('tools/systemio_common').checkError; var ledGpio = null, switchGpio = null; -var ledPin, switchPin, ledMode; var SWITCH_ON = false, LED_ON = true, @@ -26,34 +27,16 @@ var SWITCH_ON = false, var loopCnt = 0; -if (process.platform === 'linux') { - ledPin = 20; - switchPin = 13; - ledMode = gpio.MODE.NONE; -} else if (process.platform === 'nuttx') { - var pin = require('stm32f4dis').pin; - ledPin = pin.PA10; - switchPin = pin.PA15; - ledMode = gpio.MODE.PUSHPULL; -} else if(process.platform === 'tizenrt') { - ledPin = 41; - switchPin = 39; - ledMode = gpio.MODE.NONE; -} else { - assert.fail(); -} - ledGpio = gpio.open({ - pin: ledPin, + pin: pin.led, direction: gpio.DIRECTION.OUT, - mode: ledMode }, function(err) { - assert.equal(err, null); + checkError(err); ledGpio.writeSync(LED_OFF); }); switchGpio = gpio.openSync({ - pin: switchPin, + pin: pin.switch, direction: gpio.DIRECTION.IN }); diff --git a/test/run_pass/test_gpio_output.js b/test/run_pass/test_gpio_output.js index c269a92..d9a7300 100644 --- a/test/run_pass/test_gpio_output.js +++ b/test/run_pass/test_gpio_output.js @@ -16,31 +16,18 @@ var assert = require('assert'); var gpio = require('gpio'); +var pin = require('tools/systemio_common').pin; +var checkError = require('tools/systemio_common').checkError; var LED_ON = true, LED_OFF = false; -var pin, mode; var gpio20; -if (process.platform === 'linux') { - pin = 20; - mode = gpio.MODE.NONE; -} else if (process.platform === 'nuttx') { - pin = require('stm32f4dis').pin.PA10; - mode = gpio.MODE.PUSHPULL; -} else if(process.platform === 'tizenrt') { - pin = 41; - mode = gpio.MODE.NONE; -} else { - assert.fail(); -} - test1(); gpio20 = gpio.open({ - pin: pin, + pin: pin.led, direction: gpio.DIRECTION.OUT, - mode: mode }, test2); function test1() { @@ -70,11 +57,11 @@ function test2(err) { assert.equal(err, null); gpio20.write(LED_ON, function(writeErr) { - assert.equal(writeErr, null); + checkError(writeErr); console.log('gpio write'); gpio20.read(function(readErr, value) { - assert.equal(readErr, null); + checkError(readErr); console.log('gpio read:', value); assert.equal(LED_ON, value); @@ -84,7 +71,7 @@ function test2(err) { console.log('gpio read:', value); assert.equal(LED_OFF, value); gpio20.close(function(closeErr) { - assert.equal(closeErr, null); + checkError(closeErr); console.log('finish test'); }); }, 3000); diff --git a/test/run_pass/test_iotjs_promise.js b/test/run_pass/test_iotjs_promise.js index f2725cd..9024d5d 100644 --- a/test/run_pass/test_iotjs_promise.js +++ b/test/run_pass/test_iotjs_promise.js @@ -16,7 +16,7 @@ var assert = require('assert'); var fulfill_ret; var p = new Promise(function(resolve, reject) { // mimic asynchronous operation via setTimeout - setTimeout(function() { resolve("Resolved") }, 100);; + setTimeout(function() { resolve("Resolved") }, 100); }); p.then(function (msg) { @@ -26,4 +26,4 @@ p.then(function (msg) { }); // If Promise's fulfill worked well, assertion must be valid. -setTimeout(function() { assert.equal(fulfill_ret, "Resolved"); }, 200); +setTimeout(function() { assert.equal(fulfill_ret, "Resolved"); }, 1000); diff --git a/test/run_pass/test_module_dynamicload.js b/test/run_pass/test_module_dynamicload.js new file mode 100644 index 0000000..1aa072f --- /dev/null +++ b/test/run_pass/test_module_dynamicload.js @@ -0,0 +1,40 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +var assert = require('assert'); +var fs = require('fs'); + +var iotjs_path = process.env["IOTJS_PATH"] +/* Currenlty it is expected tha the loadable test module is at a given path. */ +var dynamicmodule_dir = iotjs_path + "/../test/dynamicmodule/" +var dynamicmodule_name = "test-dynamicmodule" +var dynamicmodule_path = dynamicmodule_dir + dynamicmodule_name + ".iotjs"; + +assert.assert(fs.existsSync(dynamicmodule_path), + "Dynamic module does not exists: " + dynamicmodule_path); + +var testmodule = require(dynamicmodule_path); +assert.equal(testmodule.demokey, 3.4); +assert.equal(testmodule.counter, 1); +testmodule.new_value = "hello"; + +/* Loading the module via a differnt key. + * This should not initialize the module again. + */ +var load_2 = require(dynamicmodule_dir + dynamicmodule_name) +assert.equal(load_2.demokey, 3.4); +/* if the counter is not one then the module initializer was invoked again. */ +assert.equal(load_2.counter, 1); +assert.equal(load_2.new_value, "hello"); diff --git a/test/run_pass/test_net_7.js b/test/run_pass/test_net_7.js index 70a7075..027d69d 100644 --- a/test/run_pass/test_net_7.js +++ b/test/run_pass/test_net_7.js @@ -23,7 +23,8 @@ var port = 22707; var count = 40; var connectionCount = 0; -if (process.platform === 'linux' || process.platform === 'darwin') { +if (process.platform === 'linux' || process.platform === 'darwin' || + process.platform === 'tizen') { var maxConnection = 40; } else if (process.platform === 'nuttx' || process.platform === 'tizenrt') { var maxConnection = 5; diff --git a/test/run_pass/test_net_headers.js b/test/run_pass/test_net_headers.js index 7a559e6..6653822 100644 --- a/test/run_pass/test_net_headers.js +++ b/test/run_pass/test_net_headers.js @@ -42,7 +42,7 @@ var server = http.createServer(function (req, res) { // final res.headers = { 'h1' : 'h1', 'h3': 'h3prime' } var responseSize; - if (process.platform === 'linux') { + if (process.platform === 'linux' || process.platform === 'tizen') { // For Desktop and RPI, test with large header. responseSize = 500; } else { diff --git a/test/run_pass/test_net_http_request_response.js b/test/run_pass/test_net_http_request_response.js index 7c976d3..e7615b7 100644 --- a/test/run_pass/test_net_http_request_response.js +++ b/test/run_pass/test_net_http_request_response.js @@ -73,12 +73,6 @@ request2.end(message, function() { isRequest2Finished = true; }); -// Call the request2 end again to test the finish state. -request2.end(message, function() { - // This clabback should never be called. - assert.equal(isRequest2Finished, false); -}); - var server3 = http.createServer(function(request, response) { var str = ''; diff --git a/test/run_pass/test_net_http_server.js b/test/run_pass/test_net_http_server.js new file mode 100644 index 0000000..2033f11 --- /dev/null +++ b/test/run_pass/test_net_http_server.js @@ -0,0 +1,196 @@ +/* Copyright 2015-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +var assert = require('assert'); +var http = require('http'); +var Server = http.Server; + +var responseCheck = ''; +var connectionEvent = 0; +var serverCloseEvent = 0; +var requestEvent = 0; +var responseEvent = 0; +var socketEvent = 0; +// server side code +// server will return the received msg from client +// and shutdown +var server = http.createServer(function (req, res) { + + var body = ''; + var url = req.url; + + req.on('data', function (chunk) { + body += chunk; + }); + + var endHandler = function () { + + res.writeHead(200, { 'Connection' : 'close', + 'Content-Length' : body.length + }); + res.write(body); + res.end(function(){ + if(body == 'close server') { + server.close(); + } + }); + }; + + req.on('end', endHandler); + +}); + +server.on('request', function() { + requestEvent++; +}); + +server.on('connection', function() { + connectionEvent++; +}); + +server.on('close', function() { + serverCloseEvent++; +}); + +server.listen(3001, 3); + + +// client side code +// 1. send POST req to server and check response msg +// 2. send GET req to server and check response msg +// 3. send 'close server' msg + +// 1. POST req +var msg = 'http request test msg'; +var options = { + method : 'POST', + port : 3001, + rejectUnauthorized: false, + headers : {'Content-Length': msg.length} +}; + + +var postResponseHandler = function (res) { + var res_body = ''; + + assert.equal(200, res.statusCode); + var endHandler = function(){ + assert.equal(msg, res_body); + responseCheck += '1'; + }; + res.on('end', endHandler); + + res.on('data', function(chunk){ + res_body += chunk.toString(); + }); +}; + +var req = http.request(options, postResponseHandler); +req.on('response', function() { + responseEvent++; +}); +req.on('socket', function() { + socketEvent++; +}); +req.write(msg); +req.end(); + + +// 2. GET req +options = { + method : 'GET', + port : 3001 +}; + +var getResponseHandler = function (res) { + var res_body = ''; + + assert.equal(200, res.statusCode); + + var endHandler = function(){ + // GET msg, no received body + assert.equal('', res_body); + responseCheck += '2'; + }; + res.on('end', endHandler); + + res.on('data', function(chunk){ + res_body += chunk.toString(); + }); +}; + + +var getReq = http.request(options, getResponseHandler); +getReq.on('response', function() { + responseEvent++; +}); +getReq.on('socket', function() { + socketEvent++; +}); +getReq.end(); + + + +// 3. close server req +var finalMsg = 'close server'; +var finalOptions = { + method : 'POST', + port : 3001, + rejectUnauthorized: false, + headers : {'Content-Length': finalMsg.length} +}; + +var finalResponseHandler = function (res) { + var res_body = ''; + + assert.equal(200, res.statusCode); + + var endHandler = function(){ + assert.equal(finalMsg, res_body); + responseCheck += '3'; + }; + res.on('end', endHandler); + + res.on('data', function(chunk){ + res_body += chunk.toString(); + }); +}; + +var finalReq = http.request(finalOptions, finalResponseHandler); +finalReq.on('response', function() { + responseEvent++; +}); +finalReq.on('socket', function() { + socketEvent++; +}); +finalReq.write(finalMsg); +finalReq.end(); + +// Create server without requestListener. +var server2 = http.createServer(); + +// Create server instance without new keyword. +var server3 = Server(function(request, response) {}); + +process.on('exit', function() { + assert.equal(responseCheck.length, 3); + assert.equal(connectionEvent, 3); + assert.equal(serverCloseEvent, 1); + assert.equal(requestEvent, 3); + assert.equal(responseEvent, 3); + assert.equal(socketEvent, 3); + assert.equal(server2 instanceof Server, true); + assert.equal(server3 instanceof Server, true); +}); diff --git a/test/run_pass/test_net_http_server_timeout.js b/test/run_pass/test_net_http_server_timeout.js new file mode 100644 index 0000000..bb44cc4 --- /dev/null +++ b/test/run_pass/test_net_http_server_timeout.js @@ -0,0 +1,51 @@ +/* Copyright 2015-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + + + +var assert = require('assert'); +var http = require('http'); + +var timeouted = false; + +var server = http.createServer(function(req, res) { + // do nothing +}); + +server.listen(3003); + +server.setTimeout(100, function(socket) { + timeouted = true; + socket.destroy(); + server.close(); +}); + + +// client will connect to server, and do nothing. +var options = { + method : 'GET', + port : 3003 +}; + + +var getReq = http.request(options); +getReq.on('error', function() {}); + +process.on('exit', function(code) { + assert.equal(timeouted, true); + assert.equal(code, 0); +}); + +getReq.end(); diff --git a/test/run_pass/test_net_https_get.js b/test/run_pass/test_net_https_get.js index 3ef93e2..83c09db 100644 --- a/test/run_pass/test_net_https_get.js +++ b/test/run_pass/test_net_https_get.js @@ -22,8 +22,9 @@ var isRequest1Finished = false; // 1. GET req options = { method: 'GET', - host: "httpbin.org", + host: 'httpbin.org', path: '/user-agent', + rejectUnauthorized: false, headers: {'user-agent': 'iotjs'} }; @@ -50,8 +51,9 @@ https.get(options, getResponseHandler); var testMsg = 'Hello IoT.js'; var finalOptions = { method: 'POST', - host: "httpbin.org", + host: 'httpbin.org', path: '/post', + rejectUnauthorized: false, headers: {'Content-Length': testMsg.length, 'Content-Type': 'application/json'} }; diff --git a/test/run_pass/test_net_https_post_status_codes.js b/test/run_pass/test_net_https_post_status_codes.js index 49853b8..09c7d91 100644 --- a/test/run_pass/test_net_https_post_status_codes.js +++ b/test/run_pass/test_net_https_post_status_codes.js @@ -24,13 +24,14 @@ var data = JSON.stringify({ data: { temp: 50, onFire: false }, type: 'message' }); var options = { - "method": "POST", - "hostname": "api.artik.cloud", - "path": "/v1.1/messages", - "headers": { - "content-type": "application/json", - "content-length": data.length, - "authorization": "Bearer 1718113118564ad495ad03f04116f379" + method: 'POST', + hostname: 'api.artik.cloud', + path: '/v1.1/messages', + rejectUnauthorized: false, + headers: { + 'content-type': 'application/json', + 'content-length': data.length, + 'authorization': 'Bearer 1718113118564ad495ad03f04116f379' } }; diff --git a/test/run_pass/test_net_https_request_response.js b/test/run_pass/test_net_https_request_response.js index 5054afd..e9bdd4d 100644 --- a/test/run_pass/test_net_https_request_response.js +++ b/test/run_pass/test_net_https_request_response.js @@ -24,8 +24,9 @@ var message = 'Hello IoT.js'; // Options for further requests. var options = { method: 'POST', - host: "httpbin.org", + host: 'httpbin.org', path: '/post', + rejectUnauthorized: false, headers: {'Content-Length': message.length, 'Content-Type': 'application/json'} }; @@ -67,12 +68,6 @@ request2.end(message, function() { isRequest2Finished = true; }); -// Call the request2 end again to test the finish state. -request2.end(message, function() { - // This clabback should never be called. - assert.equal(isRequest2Finished, false); -}); - // Simple request with buffer chunk as message parameter. var isRequest3Finished = false; @@ -96,7 +91,8 @@ request3.end(new Buffer(message)); var isRequest4Finished = false; var readRequest = https.request({ method: 'GET', - host: "httpbin.org", + host: 'httpbin.org', + rejectUnauthorized: false, path: '/get' }); diff --git a/test/run_pass/test_net_https_server.js b/test/run_pass/test_net_https_server.js new file mode 100644 index 0000000..aaad8dc --- /dev/null +++ b/test/run_pass/test_net_https_server.js @@ -0,0 +1,54 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +var assert = require('assert'); +var https = require('https'); +var fs = require('fs'); + +var server_options = { + key: fs.readFileSync('resources/my_key.pem').toString(), + cert: fs.readFileSync('resources/my_crt.pem').toString() +}; + +var server = https.createServer(server_options, function(req, res) { + res.writeHead(200); + res.end('hello world\n'); +}).listen(8000); + + +var client_options = { + host: 'localhost', + port: 8000, + rejectUnauthorized: false +} + +var responseHandler = function (res) { + var res_body = ''; + + assert.equal(200, res.statusCode); + + var endHandler = function(){ + assert.equal(res_body, 'hello world\n'); + }; + res.on('end', endHandler); + + res.on('data', function(chunk){ + res_body += chunk.toString(); + }); + + server.close(); +} + +https.get(client_options, responseHandler); diff --git a/test/run_pass/test_net_https_timeout.js b/test/run_pass/test_net_https_timeout.js index 95531b6..a722040 100644 --- a/test/run_pass/test_net_https_timeout.js +++ b/test/run_pass/test_net_https_timeout.js @@ -21,6 +21,7 @@ var https = require('https'); options = { method: 'GET', host: 'httpbin.org', + rejectUnauthorized: false, path: '/delay/10' }; diff --git a/test/run_pass/test_net_httpserver.js b/test/run_pass/test_net_httpserver.js deleted file mode 100644 index 912c9ec..0000000 --- a/test/run_pass/test_net_httpserver.js +++ /dev/null @@ -1,195 +0,0 @@ -/* Copyright 2015-present Samsung Electronics Co., Ltd. and other contributors - * - * 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. - */ - -var assert = require('assert'); -var Server = require('http_server').Server; -var http = require('http'); - - -var responseCheck = ''; -var connectionEvent = 0; -var serverCloseEvent = 0; -var requestEvent = 0; -var responseEvent = 0; -var socketEvent = 0; -// server side code -// server will return the received msg from client -// and shutdown -var server = http.createServer(function (req, res) { - - var body = ''; - var url = req.url; - - req.on('data', function (chunk) { - body += chunk; - }); - - var endHandler = function () { - - res.writeHead(200, { 'Connection' : 'close', - 'Content-Length' : body.length - }); - res.write(body); - res.end(function(){ - if(body == 'close server') { - server.close(); - } - }); - }; - - req.on('end', endHandler); - -}); - -server.on('request', function() { - requestEvent++; -}); - -server.on('connection', function() { - connectionEvent++; -}); - -server.on('close', function() { - serverCloseEvent++; -}); - -server.listen(3001, 3); - - -// client side code -// 1. send POST req to server and check response msg -// 2. send GET req to server and check response msg -// 3. send 'close server' msg - -// 1. POST req -var msg = 'http request test msg'; -var options = { - method : 'POST', - port : 3001, - headers : {'Content-Length': msg.length} -}; - - -var postResponseHandler = function (res) { - var res_body = ''; - - assert.equal(200, res.statusCode); - var endHandler = function(){ - assert.equal(msg, res_body); - responseCheck += '1'; - }; - res.on('end', endHandler); - - res.on('data', function(chunk){ - res_body += chunk.toString(); - }); -}; - -var req = http.request(options, postResponseHandler); -req.on('response', function() { - responseEvent++; -}); -req.on('socket', function() { - socketEvent++; -}); -req.write(msg); -req.end(); - - -// 2. GET req -options = { - method : 'GET', - port : 3001 -}; - -var getResponseHandler = function (res) { - var res_body = ''; - - assert.equal(200, res.statusCode); - - var endHandler = function(){ - // GET msg, no received body - assert.equal('', res_body); - responseCheck += '2'; - }; - res.on('end', endHandler); - - res.on('data', function(chunk){ - res_body += chunk.toString(); - }); -}; - - -var getReq = http.request(options, getResponseHandler); -getReq.on('response', function() { - responseEvent++; -}); -getReq.on('socket', function() { - socketEvent++; -}); -getReq.end(); - - - -// 3. close server req -var finalMsg = 'close server'; -var finalOptions = { - method : 'POST', - port : 3001, - headers : {'Content-Length': finalMsg.length} -}; - -var finalResponseHandler = function (res) { - var res_body = ''; - - assert.equal(200, res.statusCode); - - var endHandler = function(){ - assert.equal(finalMsg, res_body); - responseCheck += '3'; - }; - res.on('end', endHandler); - - res.on('data', function(chunk){ - res_body += chunk.toString(); - }); -}; - -var finalReq = http.request(finalOptions, finalResponseHandler); -finalReq.on('response', function() { - responseEvent++; -}); -finalReq.on('socket', function() { - socketEvent++; -}); -finalReq.write(finalMsg); -finalReq.end(); - -// Create server without requestListener. -var server2 = http.createServer(); - -// Create server instance without new keyword. -var server3 = Server(function(request, response) {}); - -process.on('exit', function() { - assert.equal(responseCheck.length, 3); - assert.equal(connectionEvent, 3); - assert.equal(serverCloseEvent, 1); - assert.equal(requestEvent, 3); - assert.equal(responseEvent, 3); - assert.equal(socketEvent, 3); - assert.equal(server2 instanceof Server, true); - assert.equal(server3 instanceof Server, true); -}); diff --git a/test/run_pass/test_net_httpserver_timeout.js b/test/run_pass/test_net_httpserver_timeout.js deleted file mode 100644 index 5139066..0000000 --- a/test/run_pass/test_net_httpserver_timeout.js +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright 2015-present Samsung Electronics Co., Ltd. and other contributors - * - * 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. - */ - - - -var assert = require('assert'); -var http = require('http'); - -var timeouted = false; - -var server = http.createServer(function(req, res) { - // do nothing -}); - -server.listen(3003); - -server.setTimeout(100, function(socket) { - timeouted = true; - socket.destroy(); - server.close(); -}); - - -// client will connect to server, and do nothing. -var options = { - method : 'GET', - port : 3003 -}; - - -var getReq = http.request(options); -getReq.on('error', function() {}); - -process.on('exit', function(code) { - assert.equal(timeouted, true); - assert.equal(code, 0); -}); diff --git a/test/run_pass/test_spi.js b/test/run_pass/test_spi.js index 5a65884..4fd01d0 100644 --- a/test/run_pass/test_spi.js +++ b/test/run_pass/test_spi.js @@ -15,18 +15,12 @@ var assert = require('assert'); var spi = require('spi'); +var pin = require('tools/systemio_common').pin; -var configuration = {}; - -if (process.platform === 'linux') { - configuration.device = '/dev/spidev0.0'; -} else if (process.platform === 'nuttx') { - configuration.bus = 1; -} else if (process.platform === 'tizenrt') { - configuration.bus = 0; -} else { - assert.fail('OS not supported:' + process.platform); -} +var configuration = { + device: pin.spi1, // for Linux + bus: pin.spi1, // for Tizen, TizenRT and Nuttx +}; // ------ Test API existance diff --git a/test/run_pass/test_spi_buffer_async.js b/test/run_pass/test_spi_buffer_async.js index 0b11de3..04ad0a9 100644 --- a/test/run_pass/test_spi_buffer_async.js +++ b/test/run_pass/test_spi_buffer_async.js @@ -15,36 +15,34 @@ var assert = require('assert'); var spi = require('spi'); +var pin = require('tools/systemio_common').pin; +var checkError = require('tools/systemio_common').checkError; -var configuration = {}; - -if (process.platform === 'linux') { - configuration.device = '/dev/spidev0.0'; -} else if (process.platform === 'nuttx' || process.platform === 'tizenrt') { - configuration.bus = 1; -} else { - assert.fail(); -} +var configuration = { + device: pin.spi1, // for Linux + bus: pin.spi1, // for Tizen, TizenRT and Nuttx +}; // Buffer test var spi1 = spi.open(configuration, function(err) { - assert.equal(err, null); + checkError(err); var data = 'Hello IoTjs'; var tx = new Buffer(data); spi1.transfer(tx, function(err, rx) { - assert.equal(err, null); - assert.equal(rx.length, 11); + checkError(err); + var len = data.length; + assert.equal(rx.length, len); var value = ''; - for (var i = 0; i < 11; i++) { + for (var i = 0; i < len; i++) { value += String.fromCharCode(rx[i]); } console.log(value); assert.equal(value, data); - spi1.close(function (err) { - assert.equal(err, null); + spi1.close(function(err) { + checkError(err); }); }); }); diff --git a/test/run_pass/test_spi_buffer_sync.js b/test/run_pass/test_spi_buffer_sync.js index ef049ea..2539e4b 100644 --- a/test/run_pass/test_spi_buffer_sync.js +++ b/test/run_pass/test_spi_buffer_sync.js @@ -15,16 +15,12 @@ var assert = require('assert'); var spi = require('spi'); +var pin = require('tools/systemio_common').pin; -var configuration = {}; - -if (process.platform === 'linux') { - configuration.device = '/dev/spidev0.0'; -} else if (process.platform === 'nuttx' || process.platform === 'tizenrt') { - configuration.bus = 1; -} else { - assert.fail(); -} +var configuration = { + device: pin.spi1, // for Linux + bus: pin.spi1, // for Tizen, TizenRT and Nuttx +}; // Buffer test var spi1 = spi.openSync(configuration); @@ -32,9 +28,10 @@ var data = 'Hello IoTjs'; var tx = new Buffer(data); var rx = spi1.transferSync(tx); -assert.equal(rx.length, 11); +var len = data.length; +assert.equal(rx.length, len); var value = ''; -for (var i = 0; i < 11; i++) { +for (var i = 0; i < len; i++) { value += String.fromCharCode(rx[i]); } console.log(value); diff --git a/test/run_pass/test_spi_mcp3008.js b/test/run_pass/test_spi_mcp3008.js index b120f33..c1b88c3 100644 --- a/test/run_pass/test_spi_mcp3008.js +++ b/test/run_pass/test_spi_mcp3008.js @@ -15,20 +15,19 @@ var assert = require('assert'); var spi = require('spi'); +var pin = require('tools/systemio_common').pin; +var checkError = require('tools/systemio_common').checkError; -var configuration = {}; - -if (process.platform === 'linux') { - configuration.device = '/dev/spidev0.0'; -} else if (process.platform === 'nuttx' || process.platform === 'tizenrt') { - configuration.bus = 1; -} else { - assert.fail(); -} +var configuration = { + device: pin.spi1, // for Linux + bus: pin.spi1, // for Tizen, TizenRT and Nuttx +}; // mcp3008 test var channel = 0; -var spi0 = spi.open(configuration, function() { +var spi0 = spi.open(configuration, function(err) { + checkError(err); + var mode = (8 + channel) << 4; var tx = [1, mode, 0]; @@ -38,7 +37,7 @@ var spi0 = spi.open(configuration, function() { var loopCnt = 10; var loop = setInterval(function() { spi0.transfer(tx, function(err, rx) { - assert.equal(err, null); + checkError(err); assert.equal(rx.length, 3); var value = ((rx[1] & 0x03) << 8) + rx[2]; diff --git a/test/run_pass/test_tizen_app_control.js b/test/run_pass/test_tizen_app_control.js new file mode 100644 index 0000000..c72c0c6 --- /dev/null +++ b/test/run_pass/test_tizen_app_control.js @@ -0,0 +1,42 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +var tizen = require('tizen'); + +// Need to set target APP_ID e.g) app.control.receiver +var app_id = ''; +var data = { + str: 'iotjs' +}; + +// test: tizen.on +tizen.on('appControl', function(msg) { + console.log('appControl', msg); + + var extra_data = msg.extra_data; + if(extra_data && extra_data.key === 'iotjs' ) { + + //test: tizen.launchAppControl + try { + var res = tizen.launchAppControl({ + app_id: app_id, + extra_data: data, + }); + console.log('Result', res); + } catch(e) { + console.log(e); + } + } +}); diff --git a/test/run_pass/test_tls.js b/test/run_pass/test_tls.js new file mode 100644 index 0000000..70193bb --- /dev/null +++ b/test/run_pass/test_tls.js @@ -0,0 +1,226 @@ +/* Copyright 2017-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + + var tls = require('tls'); + var assert = require('assert'); + var fs = require('fs'); + + var port = 8080; + + var server_closed = false; + var expected_client_msg = 'Client hello'; + var expected_server_msg = 'Server hello'; + var client_message = ''; + var server_message = ''; + var server_handshake_done = false; + var tlsClientError_caught = false; + var socket_handshake_error_caught = false; + + var options = { + key: fs.readFileSync('resources/my_key.pem').toString(), + cert: fs.readFileSync('resources/my_crt.pem').toString(), + rejectUnauthorized: false, + isServer: true, + }; + + var server = tls.createServer(options, function(socket) { + socket.write('Server hello'); + + socket.on('data', function(data) { + client_message += data.toString(); + }); + + }).listen(port, function() { }); + + server.on('secureConnection', function() { + server_handshake_done = true; + }); + + server.on('close', function() { + server_closed = true; + }); + + var error_caught = false; + var handshake_done = false; + + var sockOpts = { + host: '127.0.0.1', + port: 8080, + rejectUnauthorized: false, + } + + var socket = tls.connect(sockOpts, function() { + }); + + socket.on('secureConnect', function(){ + handshake_done = true; + }); + + socket.on('end', function() { + server.close(); + }); + + socket.on('data', function(data) { + server_message += data.toString(); + socket.write('Client hello'); + socket.end(); + }); + + var socket2 = tls.connect({host: '127.123.123.123', port: 444}, function() { + socket2.end(); + }); + + socket2.on('error', function(err) { + error_caught = true; + }); + + +var nocert_options = { + rejectUnauthorized: false, + isServer: true, +} + +var server2_port = 8081; + +sockOpts = { + host: '127.0.0.1', + port: server2_port, + rejectUnauthorized: false, +} + +var server2 = tls.createServer(nocert_options, function(socket) { +}).listen(server2_port, function() { }); + +server2.on('tlsClientError', function(error) { + tlsClientError_caught = error instanceof Error; + server2.close(); +}); + +var socket3 = tls.connect(sockOpts, function() { }); + +socket3.on('error', function(error) { + socket_handshake_error_caught = error instanceof Error; +}); + +var server3 = tls.createServer(options, function(socket) { + socket.write('Server hello'); + + socket.on('data', function(data) { + client_message = data.toString(); + }); + +}).listen(9090, function() { }); + +server3.on('secureConnection', function() { + server_handshake_done = true; +}); + +server3.on('close', function() { + server_closed = true; +}); + +var opt = { + rejectUnauthorized: false, +} + +var socket4 = tls.connect(9090); + +socket4.on('secureConnect', function(){ + handshake_done = true; +}); + +socket4.on('data', function(data) { + server_message = data.toString(); + socket4.write('Client hello'); + socket4.end(); +}); + +var socket5 = tls.connect(9090, 'localhost'); + +socket5.on('secureConnect', function(){ + handshake_done = true; +}); + +socket5.on('data', function(data) { + server_message = data.toString(); + socket5.write('Client hello'); + socket5.end(); +}); + +var socket6 = tls.connect(9090, 'localhost', opt); + +socket6.on('secureConnect', function(){ + handshake_done = true; +}); + +socket6.on('data', function(data) { + server_message = data.toString(); + socket6.write('Client hello'); + socket6.end(); +}); + +var socket7 = tls.connect(9090, 'localhost', opt, function() { +}); + +socket7.on('secureConnect', function(){ + handshake_done = true; +}); + +socket7.on('data', function(data) { + server_message = data.toString(); + socket7.write('Client hello'); + socket7.end(); +}); + +var socket8 = tls.connect(9090, 'localhost', function() { +}); + +socket8.on('secureConnect', function(){ + handshake_done = true; +}); + +socket8.on('data', function(data) { + server_message = data.toString(); + socket8.write('Client hello'); + socket8.end(); +}); + +var socket9 = tls.connect(9090, function() { +}); + +socket9.on('secureConnect', function(){ + handshake_done = true; +}); + +socket9.on('end', function() { + server3.close(); +}); + +socket9.on('data', function(data) { + server_message = data.toString(); + socket9.write('Client hello'); + socket9.end(); +}); + +process.on('exit', function() { + assert.equal(error_caught, true); + assert.equal(handshake_done, true); + assert.equal(server_handshake_done, true); + assert.equal(client_message === expected_client_msg, true); + assert.equal(server_message === expected_server_msg, true); + assert.equal(server_closed, true); + assert.equal(tlsClientError_caught, true); + assert.equal(socket_handshake_error_caught, true); +}); diff --git a/test/run_pass/test_uart.js b/test/run_pass/test_uart.js index eeecbd6..3b2ef0e 100644 --- a/test/run_pass/test_uart.js +++ b/test/run_pass/test_uart.js @@ -13,29 +13,24 @@ * limitations under the License. */ -var assert = require('assert'); var uart = require('uart'); +var pin = require('tools/systemio_common').pin; +var checkError = require('tools/systemio_common').checkError; var configuration = { + device: pin.uart1, // for Linux, TizenRT and Nuttx + port: pin.uart1, // for Tizen baudRate: 115200, - dataBits: 8 + dataBits: 8, }; -if (process.platform === 'linux') { - configuration.device = '/dev/ttyS0'; -} else if (process.platform === 'nuttx' || process.platform === 'tizenrt') { - configuration.device = '/dev/ttyS1'; -} else { - assert.fail(); -} - writeTest(); function writeTest() { var serial = uart.openSync(configuration); console.log('open done'); - serial.writeSync("Hello IoT.js.\n\r"); + serial.writeSync('Hello IoT.js.\n\r'); serial.closeSync(); console.log('close done'); writeReadTest(); @@ -46,7 +41,7 @@ function writeReadTest() { var write = 0; var serial = uart.open(configuration, function(err) { - assert.equal(err, null); + checkError(err); console.log('open done'); serial.on('data', function(data) { @@ -59,14 +54,14 @@ function writeReadTest() { } }); - serial.write("Hello there?\n\r", function(err) { - assert.equal(err, null); + serial.write('Hello there?\n\r', function(err) { + checkError(err); console.log('write done'); write = 1; if (read && write) { serial.close(function(err) { - assert.equal(err, null); + checkError(err); }); console.log('close done'); } diff --git a/test/testsets-es2015.json b/test/testsets-es2015.json new file mode 100644 index 0000000..b3449fd --- /dev/null +++ b/test/testsets-es2015.json @@ -0,0 +1,6 @@ +{ + "run_pass": [ + { "name": "test_iotjs_promise.js" }, + { "name": "test_iotjs_promise_chain_calls.js" } + ] +} diff --git a/test/testsets-external-modules.json b/test/testsets-external-modules.json new file mode 100644 index 0000000..d5e3d8a --- /dev/null +++ b/test/testsets-external-modules.json @@ -0,0 +1,6 @@ +{ + "external_modules": [ + { "name": "test-external-module1.js" }, + { "name": "test-external-module2.js" } + ] +} diff --git a/test/testsets-host-darwin.json b/test/testsets-host-darwin.json new file mode 100644 index 0000000..da9f345 --- /dev/null +++ b/test/testsets-host-darwin.json @@ -0,0 +1,10 @@ +{ + "run_pass": [ + { "name": "test_net_https_get.js", "timeout": 10 }, + { "name": "test_net_https_post_status_codes.js", "timeout": 10 }, + { "name": "test_net_https_request_response.js", "timeout": 10 }, + { "name": "test_net_https_timeout.js", "timeout": 10 }, + { "name": "test_net_https_server.js", "timeout": 10 }, + { "name": "test_tls.js" } + ] +} diff --git a/test/testsets-host-linux.json b/test/testsets-host-linux.json new file mode 100644 index 0000000..da9f345 --- /dev/null +++ b/test/testsets-host-linux.json @@ -0,0 +1,10 @@ +{ + "run_pass": [ + { "name": "test_net_https_get.js", "timeout": 10 }, + { "name": "test_net_https_post_status_codes.js", "timeout": 10 }, + { "name": "test_net_https_request_response.js", "timeout": 10 }, + { "name": "test_net_https_timeout.js", "timeout": 10 }, + { "name": "test_net_https_server.js", "timeout": 10 }, + { "name": "test_tls.js" } + ] +} diff --git a/test/testsets-minimal.json b/test/testsets-minimal.json new file mode 100644 index 0000000..1cee36c --- /dev/null +++ b/test/testsets-minimal.json @@ -0,0 +1,16 @@ +{ + "run_pass/issue": [ + { "name": "issue-223.js", "skip": ["all"], "reason": "unsupported module by iotjs build" }, + { "name": "issue-266.js", "skip": ["all"], "reason": "unsupported module by iotjs build" } + ], + "node/parallel": [ + { "name": "test-assert.js", "skip": ["all"], "reason": "unsupported module by iotjs build" }, + { "name": "test-http-catch-uncaughtexception.js", "skip": ["all"], "reason": "unsupported module by iotjs build" }, + { "name": "test-http-status-message.js", "skip": ["all"], "reason": "unsupported module by iotjs build" }, + { "name": "test-http-write-head.js", "skip": ["all"], "reason": "unsupported module by iotjs build" }, + { "name": "test-net-bind-twice.js", "skip": ["all"], "reason": "unsupported module by iotjs build" }, + { "name": "test-net-end-without-connect.js", "skip": ["all"], "reason": "unsupported module by iotjs build" }, + { "name": "test-net-keepalive.js", "skip": ["all"], "reason": "unsupported module by iotjs build" }, + { "name": "test-timers-clear-null-does-not-throw-error.js", "skip": ["all"], "reason": "unsupported module by iotjs build" } + ] +} diff --git a/test/testsets.json b/test/testsets.json index f87287a..23e8f49 100644 --- a/test/testsets.json +++ b/test/testsets.json @@ -5,27 +5,27 @@ { "name": "test_ble_advertisement.js", "skip": ["all"], "reason": "need to setup test environment" }, { "name": "test_ble_setservices.js", "skip": ["all"], "reason": "need to setup test environment" }, { "name": "test_ble_setservices_central.js", "skip": ["all"], "reason": "run it with nodejs after running test_ble_setservices.js" }, - { "name": "test_buffer_builtin.js" }, { "name": "test_buffer.js" }, + { "name": "test_buffer_str_conv.js" }, { "name": "test_console.js" }, { "name": "test_dgram_1_server_1_client.js" }, { "name": "test_dgram_1_server_n_clients.js", "skip": ["linux"], "reason": "[linux]: flaky on Travis" }, - { "name": "test_dgram_address.js", "skip": ["linux", "nuttx"], "reason": "[linux]: flaky on Travis, [nuttx]: not implemented for nuttx" }, + { "name": "test_dgram_address.js", "skip": ["nuttx"], "reason": "[nuttx]: not implemented for nuttx" }, { "name": "test_dgram_broadcast.js", "skip": ["all"], "reason": "need to setup test environment" }, { "name": "test_dgram_multicast_membership.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_dgram_multicast_set_multicast_loop.js", "skip": ["linux", "nuttx"], "reason": "[linux]: flaky on Travis, [nuttx]: not implemented for nuttx" }, + { "name": "test_dgram_multicast_set_multicast_loop.js", "skip": ["nuttx"], "reason": "[nuttx]: not implemented for nuttx" }, { "name": "test_dgram_setttl_client.js", "skip": ["all"], "reason": "need to setup test environment" }, { "name": "test_dgram_setttl_server.js", "skip": ["all"], "reason": "need to setup test environment" }, { "name": "test_dns.js" }, { "name": "test_dns_lookup.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, { "name": "test_events.js" }, - { "name": "test_events_assert_emit_error.js", "uncaught": true }, - { "name": "test_events_uncaught_error.js", "uncaught": true }, + { "name": "test_events_assert_emit_error.js" }, + { "name": "test_events_uncaught_error.js" }, { "name": "test_fs_exists.js" }, { "name": "test_fs_exists_sync.js" }, { "name": "test_fs_fstat.js", "skip": ["nuttx", "tizenrt"], "reason": "not implemented for nuttx/TizenRT" }, { "name": "test_fs_fstat_sync.js", "skip": ["nuttx", "tizenrt"], "reason": "not implemented for nuttx/TizenRT" }, - { "name": "test_fs_mkdir_rmdir.js", "skip": ["linux", "nuttx"], "reason": "[linux]: flaky on Travis, [nuttx]: implemented, run manually in default configuration" }, + { "name": "test_fs_mkdir_rmdir.js", "skip": ["nuttx"], "reason": "[nuttx]: implemented, run manually in default configuration" }, { "name": "test_fs_open_close.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, { "name": "test_fs_readdir.js" }, { "name": "test_fs_readfile.js" }, @@ -43,22 +43,23 @@ { "name": "test_fs_open_read_sync_1.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, { "name": "test_fs_open_read_sync_2.js" }, { "name": "test_fs_open_read_sync_3.js" }, - { "name": "test_gpio_input.js", "skip": ["all"], "reason": "needs hardware" }, - { "name": "test_gpio_output.js", "skip": ["all"], "reason": "need user input"}, + { "name": "test_gpio_input.js", "skip": ["all"], "reason": "need to setup test environment" }, + { "name": "test_gpio_output.js", "skip": ["all"], "reason": "need to setup test environment"}, { "name": "test_i2c_gy30.js", "skip": ["all"], "reason": "need to setup test environment" }, { "name": "test_iotjs_promise.js", "skip": ["all"], "reason": "es2015 is off by default" }, { "name": "test_iotjs_promise_chain_calls.js", "skip": ["all"], "reason": "es2015 is off by default" }, { "name": "test_module_cache.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, { "name": "test_module_json.js" }, { "name": "test_module_require.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, + { "name": "test_module_dynamicload.js", "skip": ["darwin", "nuttx", "tizenrt"], "reason": "embedded and macos does not support dynamic loading" }, { "name": "test_net_1.js" }, { "name": "test_net_2.js" }, - { "name": "test_net_3.js", "skip": ["linux", "nuttx"], "reason": "[linux]: flaky on Travis, [nuttx]: requires too many socket descriptors and too large buffers" }, + { "name": "test_net_3.js", "skip": ["nuttx"], "reason": "[nuttx]: requires too many socket descriptors and too large buffers" }, { "name": "test_net_4.js" }, { "name": "test_net_5.js" }, { "name": "test_net_6.js" }, { "name": "test_net_7.js", "skip": ["nuttx"], "reason": "requires too many socket descriptors" }, - { "name": "test_net_8.js", "skip": ["linux"], "reason": "[linux]: flaky on Travis" }, + { "name": "test_net_8.js" }, { "name": "test_net_9.js" }, { "name": "test_net_10.js" }, { "name": "test_net_connect.js" }, @@ -66,17 +67,18 @@ { "name": "test_net_http_get.js" }, { "name": "test_net_http_response_twice.js" }, { "name": "test_net_http_request_response.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_net_http_status_codes.js", "skip": ["linux", "nuttx"], "reason": "[linux]: flaky on Travis, [nuttx]: not implemented" }, + { "name": "test_net_http_status_codes.js", "skip": ["nuttx"], "reason": "[nuttx]: not implemented" }, { "name": "test_net_httpclient_error.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, { "name": "test_net_httpclient_parse_error.js" }, { "name": "test_net_httpclient_timeout_1.js" }, { "name": "test_net_httpclient_timeout_2.js" }, - { "name": "test_net_httpserver_timeout.js" }, - { "name": "test_net_httpserver.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, - { "name": "test_net_https_get.js", "timeout": 40, "skip": ["all"], "reason": "Implemented only for Tizen" }, - { "name": "test_net_https_post_status_codes.js", "timeout": 40, "skip": ["all"], "reason": "Implemented only for Tizen" }, - { "name": "test_net_https_request_response.js", "timeout": 40, "skip": ["all"], "reason": "Implemented only for Tizen" }, - { "name": "test_net_https_timeout.js", "timeout": 40, "skip": ["all"], "reason": "Implemented only for Tizen" }, + { "name": "test_net_http_server_timeout.js" }, + { "name": "test_net_http_server.js", "skip": ["nuttx"], "reason": "not implemented for nuttx" }, + { "name": "test_net_https_get.js", "timeout": 10, "skip": ["all"], "reason": "HTTPS module is not enabled by default" }, + { "name": "test_net_https_post_status_codes.js", "timeout": 10, "skip": ["all"], "reason": "HTTPS module is not enabled by default" }, + { "name": "test_net_https_request_response.js", "timeout": 10, "skip": ["all"], "reason": "HTTPS module is not enabled by default" }, + { "name": "test_net_https_timeout.js", "timeout": 10, "skip": ["all"], "reason": "HTTPS module is not enabled by default" }, + { "name": "test_net_https_server.js", "timeout": 10, "skip": ["all"], "reason": "HTTPS module is not enabled by default" }, { "name": "test_process.js" }, { "name": "test_process_chdir.js" }, { "name": "test_process_cwd.js" }, @@ -85,20 +87,22 @@ { "name": "test_process_experimental_on.js", "skip": ["stable"], "reason": "needed if testing stablity is set with experimental" }, { "name": "test_process_next_tick.js" }, { "name": "test_process_readsource.js" }, - { "name": "test_process_uncaught_order.js", "uncaught": true }, - { "name": "test_process_uncaught_simple.js", "uncaught": true }, + { "name": "test_process_uncaught_order.js" }, + { "name": "test_process_uncaught_simple.js" }, { "name": "test_pwm_async.js", "skip": ["all"], "reason": "need to setup test environment" }, { "name": "test_pwm_sync.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "test_spi.js", "skip": ["linux"], "reason": "Differend env on Linux desktop/travis/rpi" }, + { "name": "test_spi.js", "skip": ["linux"], "reason": "Different env on Linux desktop/travis/rpi" }, { "name": "test_spi_buffer_async.js", "skip": ["all"], "reason": "need to setup test environment" }, { "name": "test_spi_buffer_sync.js", "skip": ["all"], "reason": "need to setup test environment" }, { "name": "test_spi_mcp3008.js", "skip": ["all"], "reason": "need to setup test environment" }, { "name": "test_stream.js" }, - { "name": "test_stream_duplex.js"}, + { "name": "test_stream_duplex.js" }, { "name": "test_timers_arguments.js" }, { "name": "test_timers_error.js" }, { "name": "test_timers_simple.js", "timeout": 10 }, - { "name": "test_uart.js", "timeout": 10, "skip": ["all"], "reason": "need to setup test environment" }, + { "name": "test_tizen_app_control.js", "skip": ["all"], "reason": "need to setup test environment" }, + { "name": "test_tls.js", "skip": ["all"], "reason": "TLS module is not enabled by default" }, + { "name": "test_uart.js", "skip": ["all"], "reason": "need to setup test environment" }, { "name": "test_uart_api.js" }, { "name": "test_util.js" } ], @@ -113,7 +117,11 @@ { "name": "issue-1046.js" }, { "name": "issue-1077.js" }, { "name": "issue-1101.js", "skip": ["all"], "reason": "need to setup test environment" }, - { "name": "issue-1351.js" } + { "name": "issue-1348.js" }, + { "name": "issue-1351.js" }, + { "name": "issue-1485.js" }, + { "name": "issue-1507.js" }, + { "name": "issue-1557.js" } ], "run_fail": [ { "name": "test_assert_equal.js", "expected-failure": true }, @@ -123,6 +131,8 @@ { "name": "test_fs_callbacks_called.js", "expected-failure": true }, { "name": "test_iotjs_runtime_error.js", "expected-failure": true }, { "name": "test_iotjs_syntax_error.js", "expected-failure": true }, + { "name": "test-issue-1349.js", "expected-failure": true}, + { "name": "test-issue-1360.js", "expected-failure": true}, { "name": "test_module_require_invalid_file.js", "expected-failure": true }, { "name": "test_module_require_path_below_root.js", "expected-failure": true }, { "name": "test_process_exitcode_arg.js", "expected-failure": true }, @@ -133,6 +143,7 @@ ], "node/parallel": [ { "name": "test-assert.js" }, + { "name": "test-module-circular.js" }, { "name": "test-http-catch-uncaughtexception.js" }, { "name": "test-http-status-message.js" }, { "name": "test-http-write-head.js" }, diff --git a/test/tools/systemio_common.js b/test/tools/systemio_common.js index 74ad617..d5568bc 100644 --- a/test/tools/systemio_common.js +++ b/test/tools/systemio_common.js @@ -18,15 +18,34 @@ var assert = require('assert'); var pin = {}; if (process.platform === 'linux') { + pin.led = 20; + pin.switch = 13; pin.pwm1 = 0; pin.i2c1 = '/dev/i2c-1'; + pin.spi1 = '/dev/spidev0.0'; + pin.uart1 = '/dev/ttyS0'; +} else if (process.platform === 'tizen') { + pin.led = 20; + pin.switch = 13; + pin.pwm1 = 2; + pin.i2c1 = 1; + pin.spi1 = 0; + pin.uart1 = 0; } else if (process.platform === 'nuttx') { var stm32_pin = require('stm32f4dis').pin; + pin.led = stm32_pin.PA10; + pin.switch = stm32_pin.PA15; pin.pwm1 = stm32_pin.PWM1.CH1_1; pin.i2c1 = 1; + pin.spi1 = 1; + pin.uart1 = '/dev/ttyS1'; } else if (process.platform === 'tizenrt') { + pin.led = 41; + pin.switch = 39; pin.pwm1 = 0; pin.i2c1 = 1; + pin.spi1 = 1; + pin.uart1 = '/dev/ttyS1'; } else { throw new Error('Unsupported platform'); } diff --git a/tools/build.py b/tools/build.py index b03370b..91250e3 100755 --- a/tools/build.py +++ b/tools/build.py @@ -93,12 +93,13 @@ def init_options(): help='Specify the module profile file for IoT.js') parser.add_argument('--target-arch', - choices=['arm', 'x86', 'i686', 'x86_64', 'x64', 'noarch'], + choices=['arm', 'x86', 'i686', 'x86_64', 'x64', 'mips', 'noarch'], default=platform.arch(), help='Specify the target architecture: ' '%(choices)s (default: %(default)s)') parser.add_argument('--target-os', - choices=['linux', 'darwin', 'osx', 'nuttx', 'tizen', 'tizenrt'], + choices=['linux', 'darwin', 'osx', 'nuttx', 'tizen', 'tizenrt', + 'openwrt'], default=platform.os(), help='Specify the target os: %(choices)s (default: %(default)s)') @@ -176,21 +177,24 @@ def init_options(): action='store_true', default=False, help='Disable test execution with valgrind after build') parser.add_argument('--run-test', - action='store_true', default=False, - help='Execute tests after build') - parser.add_argument('--test-driver', - choices=['js', 'py'], default='py', - help='Specify the test driver for IoT.js: %(choices)s' - ' (default: %(default)s)') + nargs='?', default=False, const="quiet", choices=["full", "quiet"], + help='Execute tests after build, optional argument specifies ' + 'the level of output for the testrunner') parser.add_argument('--no-parallel-build', action='store_true', default=False, help='Disable parallel build') parser.add_argument('--no-snapshot', action='store_true', default=False, help='Disable snapshot generation for IoT.js') + parser.add_argument('--js-backtrace', + choices=['ON', 'OFF'], type=str.upper, + help='Enable/disable backtrace information of JavaScript code ' + '(%(choices)s; default: ON in debug and OFF in release build)') parser.add_argument('-e', '--experimental', action='store_true', default=False, help='Enable to build experimental features') + parser.add_argument('--testsets', + help='Specify the additional testsets file for IoT.js') options = parser.parse_args(argv) options.config = build_config @@ -339,7 +343,16 @@ def build_iotjs(options): # --jerry-debugger if options.jerry_debugger: - cmake_opt.append('-DFEATURE_DEBUGGER=ON') + cmake_opt.append("-DFEATURE_DEBUGGER=ON") + + # --js-backtrace + if not options.js_backtrace: + if options.buildtype == 'debug': + options.js_backtrace = "ON" + else: + options.js_backtrace = "OFF" + cmake_opt.append("-DFEATURE_JS_BACKTRACE=%s" % + options.js_backtrace) # --cmake-param cmake_opt.extend(options.cmake_param) @@ -355,7 +368,7 @@ def build_iotjs(options): # --experimental if options.experimental: - options.compile_flag.append('-DEXPERIMENTAL') + cmake_opt.append('-DEXPERIMENTAL=ON') # --profile if options.profile: @@ -371,27 +384,18 @@ def build_iotjs(options): def run_checktest(options): - checktest_quiet = 'yes' - if os.getenv('TRAVIS') == "true": - checktest_quiet = 'no' - # IoT.js executable iotjs = fs.join(options.build_root, 'bin', 'iotjs') - cmd = [] - args = [] - if options.test_driver == "js": - cmd = iotjs - args = [path.CHECKTEST_PATH, 'quiet=' + checktest_quiet] - # experimental - if options.experimental: - cmd.append('experimental=' + 'yes'); - else: - cmd = fs.join(path.TOOLS_ROOT, 'testrunner.py') - args = [iotjs] - if checktest_quiet: - args.append('--quiet') + cmd = fs.join(path.TOOLS_ROOT, 'testrunner.py') + args = [iotjs] + # testsets + if options.testsets: + args.append('--testsets=' + options.testsets); + + if options.run_test == "quiet": + args.append('--quiet') fs.chdir(path.PROJECT_ROOT) code = ex.run_cmd(cmd, args) @@ -399,19 +403,9 @@ def run_checktest(options): ex.fail('Failed to pass unit tests') if not options.no_check_valgrind: - if options.test_driver == "js": - code = ex.run_cmd('valgrind', ['--leak-check=full', - '--error-exitcode=5', - '--undef-value-errors=no', - cmd] + args) - if code == 5: - ex.fail('Failed to pass valgrind test') - if code != 0: - ex.fail('Failed to pass unit tests in valgrind environment') - else: - code = ex.run_cmd(cmd, ['--valgrind'] + args) - if code != 0: - ex.fail('Failed to pass unit tests in valgrind environment') + code = ex.run_cmd(cmd, ['--valgrind'] + args) + if code != 0: + ex.fail('Failed to pass unit tests in valgrind environment') if __name__ == '__main__': @@ -447,9 +441,5 @@ if __name__ == '__main__': print("\n%sTo run tests use '--run-test' " "or one of the folowing commands:%s" % (ex._TERM_BLUE, ex._TERM_EMPTY)) - print("\n tools/testrunner.py %s/%s/%s/bin/iotjs" + print("\n tools/testrunner.py %s/%s/%s/bin/iotjs\n" % (options.builddir, options.target_tuple, options.buildtype)) - print("OR\n %s(deprecated)%s %s/%s/%s/bin/iotjs " - "tools/check_test.js\n" - % (ex._TERM_RED, ex._TERM_EMPTY, options.builddir, - options.target_tuple, options.buildtype)) diff --git a/tools/check_test.js b/tools/check_test.js deleted file mode 100644 index 8cb015f..0000000 --- a/tools/check_test.js +++ /dev/null @@ -1,268 +0,0 @@ -/* Copyright 2016-present Samsung Electronics Co., Ltd. and other contributors - * - * 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. - */ - -var fs = require('fs'); -var Runner = require('test_runner').Runner; -var Logger = require('common_js/logger').Logger; -var OptionParser = require('common_js/option_parser').OptionParser; -var util = require('common_js/util'); -var EventEmitter = require('events').EventEmitter; - -var root = 'test'; -var parent = '..'; -var watch = new util.Watch(); - -function Driver() { - this.results = { - pass: 0, - fail: 0, - skip: 0, - timeout: 0, - }; - - this.emitter = new EventEmitter(); - this.emitter.addListener('nextTest', function(driver, status, test) { - var elapsedTime = ' (' + watch.delta().toFixed(2) + 's) '; - - if (driver.runner) { - driver.runner.cleanup(); - } - var filename = test['name']; - - if (status == 'pass') { - driver.results.pass++; - driver.logger.message('PASS : ' + filename + elapsedTime, status); - } else if (status == 'fail') { - driver.results.fail++; - driver.logger.message('FAIL : ' + filename + elapsedTime, status); - } else if (status == 'skip') { - driver.results.skip++; - driver.logger.message('SKIP : ' + filename + - ' (reason : ' + test.reason + ")", status); - } else if (status == 'timeout') { - driver.results.timeout++; - driver.logger.message('TIMEOUT : ' + filename + elapsedTime, status); - } - driver.fIdx++; - driver.runNextTest(); - }); - - this.os = process.platform; - this.board = process.iotjs.board; - - this.root = util.absolutePath(root); - process.chdir(this.root); - - return this; -} - -Driver.prototype.config = function() { - var parser = new OptionParser(); - - parser.addOption('start-from', "", "", - "a test case file name where the driver starts."); - parser.addOption('quiet', "yes|no", "yes", - "a flag that indicates if the driver suppresses " + - "console outputs of test case"); - parser.addOption('output-file', "", "", - "a file name where the driver leaves output"); - parser.addOption('skip-module', "", "", - "a module list to skip test of specific modules"); - parser.addOption('output-coverage', "yes|no", "no", - "output coverage information"); - parser.addOption('experimental', "yes|no", "no", - "a flag that indicates if tests for experimental are needed"); - parser.addOption('default-timeout', "", 240, - "the default timeout in seconds"); - - var options = parser.parse(); - - if (options == null) { - parser.printHelp(); - return false; - } - - var output = options['output-file']; - if (output) { - if (this.os == 'nuttx') { - var path = util.join('/mnt/sdcard', output); - } else { - var path = util.join(this.root, '..', output); - } - fs.writeFileSync(path, new Buffer('')); - } - var skipModule = options['skip-module']; - if (skipModule) { - this.skipModule = skipModule.split(','); - } - - var experimental = options['experimental']; - if (experimental == 'no') { - this.stability = 'stable'; - } else { - this.stability = 'experimental'; - } - - this.logger = new Logger(path); - - this.options = options; - - var testfile = util.join(this.root, 'testsets.json'); - var testsets = fs.readFileSync(testfile).toString(); - - this.tests = JSON.parse(testsets); - - this.dIdx = 0; - this.dLength = Object.keys(this.tests).length; - - var skipped = this.skipTestSet(options['start-from']); - - this.nextTestSet(skipped); - return true; -}; - -Driver.prototype.runNextTest = function() { - if (this.dIdx == this.dLength) { - this.finish(); - } else { - if (this.fIdx == this.fLength) { - this.dIdx++; - if (this.dIdx == this.dLength) { - this.finish(); - } else { - this.nextTestSet(); - this.runNextTest(); - } - } else { - this.runner = new Runner(this); - this.runner.run(); - } - } -}; - -Driver.prototype.skipTestSet = function(filename) { - if (!filename) - return false; - - var dLength = this.dLength; - for (var dIdx = 0; dIdx < dLength; dIdx++) { - var dirname = Object.keys(this.tests)[dIdx]; - var dir = this.tests[dirname]; - var fLength = dir.length; - for (var fIdx = 0; fIdx < fLength; fIdx++) { - if (dir[fIdx]['name'] == filename) { - this.fIdx = fIdx; - this.dIdx = dIdx; - return true; - } - } - } - - return false; -}; - -Driver.prototype.nextTestSet = function(skipped) { - if (!skipped) { - this.fIdx = 0; - } - - var dirname = this.dirname(); - this.fLength = this.tests[dirname].length; - this.logger.message("\n"); - this.logger.message(">>>> " + dirname, "summary"); -}; - -Driver.prototype.dirname = function() { - return Object.keys(this.tests)[this.dIdx] -}; - -Driver.prototype.currentTest = function() { - var dirname = this.dirname(); - return this.tests[dirname][this.fIdx]; -}; - -Driver.prototype.test = function() { - var test = this.currentTest(); - var dirname = this.dirname(); - var testfile = util.absolutePath(util.join(dirname, test['name'])); - - return fs.readFileSync(testfile).toString(); -}; - -Driver.prototype.finish = function() { - this.logger.message('\n\nfinish all tests', this.logger.status.summary); - - this.logger.message('PASS : ' + this.results.pass, this.logger.status.pass); - this.logger.message('FAIL : ' + this.results.fail, this.logger.status.fail); - this.logger.message('TIMEOUT : ' + - this.results.timeout, this.logger.status.timeout); - this.logger.message('SKIP : ' + this.results.skip, this.logger.status.skip); - - if (this.options["output-coverage"] == "yes" - && typeof __coverage__ !== "undefined") { - data = JSON.stringify(__coverage__); - - if (!fs.existsSync("../.coverage_output/")) { - fs.mkdirSync("../.coverage_output/"); - } - - fs.writeFileSync("../.coverage_output/js_coverage.data", Buffer(data)); - } - else if (this.results.fail > 0 || this.results.timeout > 0) { - originalExit(1); - } - - originalExit(0); -}; - -var driver = new Driver(); - -var originalExit = process.exit; -process.exit = function(code) { - // this function is called when the following happens. - // 1. the test case is finished normally. - // 2. assertion inside the callback function is failed. - var should_fail = driver.runner.test['expected-failure']; - try { - process.emitExit(code); - } catch(e) { - // when assertion inside the process.on('exit', function { ... }) is failed, - // this procedure is executed. - process.removeAllListeners('exit'); - - if (should_fail) { - driver.runner.finish('pass'); - } else { - console.error(e); - driver.runner.finish('fail'); - } - } finally { - process.removeAllListeners('exit'); - - if (code != 0 && !should_fail) { - driver.runner.finish('fail'); - } else if (code == 0 && should_fail) { - driver.runner.finish('fail'); - } else { - driver.runner.finish('pass'); - } - } -}; - -var conf = driver.config(); -if (conf) { - watch.delta(); - driver.runNextTest(); -} diff --git a/tools/check_tidy.py b/tools/check_tidy.py index b6f1357..9852488 100755 --- a/tools/check_tidy.py +++ b/tools/check_tidy.py @@ -22,6 +22,7 @@ import functools import os import subprocess import tempfile +import re from distutils import spawn @@ -33,7 +34,7 @@ from common_py.system.executor import Executor as ex def parse_option(): parser = argparse.ArgumentParser() parser.add_argument('--autoedit', action='store_true', default=False, - help='Automatically edit the detected clang format errors.' + help='Automatically edit the detected clang format and eslint errors.' 'No diffs will be displayed') option = parser.parse_args() @@ -48,6 +49,8 @@ class StyleChecker(object): self.count_lines = 0 self.count_empty_lines = 0 self.errors = [] + self.rules = [] + self.err_msgs = [] @property def error_count(self): @@ -62,26 +65,31 @@ class StyleChecker(object): line = fileinput.filelineno() self.errors.append("%s:%d: %s" % (name, line, msg)) + def set_rules(self): + limit = StyleChecker.column_limit + self.rules.append(re.compile(r"[\t]")) + self.err_msgs.append("TAB character") + self.rules.append(re.compile(r"[\r]")) + self.err_msgs.append("CR character") + self.rules.append(re.compile(r"[ \t]+[\n]$")) + self.err_msgs.append("Trailing Whitespace") + self.rules.append(re.compile(r"[^\n]\Z")) + self.err_msgs.append("Line ends without NEW LINE character") + self.rules.append(re.compile("^.{" + str(limit+1) + ",}")) + self.err_msgs.append("Line exceeds %d characters" % limit) + # append additional rules + def check(self, files): for line in fileinput.input(files): - if '\t' in line: - self.report_error('TAB character') - if '\r' in line: - self.report_error('CR character') - if line.endswith(' \n') or line.endswith('\t\n'): - self.report_error('trailing whitespace') - if not line.endswith('\n'): - self.report_error('line ends without NEW LINE character') - - if len(line) - 1 > StyleChecker.column_limit: - self.report_error('line exceeds %d characters' - % StyleChecker.column_limit) + for i, rule in enumerate(self.rules): + mc = rule.search(line) + if mc: + self.report_error(self.err_msgs[i]) if fileinput.isfirstline(): if not CheckLicenser.check(fileinput.filename()): self.report_error('incorrect license') - self.count_lines += 1 if not line.strip(): self.count_empty_lines += 1 @@ -126,9 +134,8 @@ class ClangFormat(object): args = ['-style=file', file] if self._options and self._options.autoedit: args.append('-i') - output = ex.run_cmd_output(self._clang_format, - args, - quiet=True) + output = ex.check_run_cmd_output(self._clang_format, + args, quiet=True) if output: with tempfile.NamedTemporaryFile() as temp: @@ -145,6 +152,43 @@ class ClangFormat(object): # the diff from that it. Otherwise nothing to do. self.diffs.append(error.output.decode()) +class EslintChecker(object): + + def __init__(self, options=None): + self._check_eslint() + self._options = options + + def _check_eslint(self): + self._node = spawn.find_executable('node') + if not self._node: + print('%sNo node found.%s' + % (ex._TERM_RED, ex._TERM_EMPTY)) + return + + self._eslint = spawn.find_executable('node_modules/.bin/eslint') + if not self._eslint: + self._eslint = spawn.find_executable('eslint') + if not self._eslint: + print('%sNo eslint found.%s' + % (ex._TERM_RED, ex._TERM_EMPTY)) + + def check(self): + self.error_count = 0 + + if not self._node or not self._eslint: + return + args = ['src', '-f', 'codeframe'] + if self._options and self._options.autoedit: + args.append('--fix') + + output = ex.run_cmd_output(self._eslint, args, quiet=True) + match = re.search('(\d+) error', output) + if match: + self.error_count = int(match.group(1)) + + # Delete unnecessary error messages. + self.errors = output.split('\n')[:-4] + class FileFilter(object): @@ -168,7 +212,8 @@ def check_tidy(src_dir, options=None): allowed_exts = ['.c', '.h', '.js', '.py', '.sh', '.cmake'] allowed_files = ['CMakeLists.txt'] clang_format_exts = ['.c', '.h'] - skip_dirs = ['deps', 'build', '.git', 'node_modules', 'coverage'] + skip_dirs = ['deps', 'build', '.git', 'node_modules', 'coverage', + 'iotjs_modules', 'IoTjsApp'] skip_files = ['check_signed_off.sh', '__init__.py', 'iotjs_js.c', 'iotjs_js.h', 'iotjs_string_ext.inl.h', "iotjs_module_inl.h", @@ -186,13 +231,16 @@ def check_tidy(src_dir, options=None): ] style = StyleChecker() + style.set_rules() clang = ClangFormat(clang_format_exts, skip_files, options) + eslint = EslintChecker(options) file_filter = FileFilter(allowed_exts, allowed_files, skip_files) files = fs.files_under(src_dir, skip_dirs, file_filter) clang.check(files) style.check(files) + eslint.check() if clang.error_count: print("Detected clang-format problems:") @@ -204,17 +252,24 @@ def check_tidy(src_dir, options=None): print("\n".join(style.errors)) print() - total_errors = style.error_count + clang.error_count + if eslint.error_count: + print("Detected eslint problems:") + print("\n".join(eslint.errors)) + print() + + total_errors = style.error_count + clang.error_count + eslint.error_count print("* total lines of code: %d" % style.count_lines) print("* total non-blank lines of code: %d" % style.count_valid_lines) print("* style errors: %d" % style.error_count) print("* clang-format errors: %d" % clang.error_count) + print("* eslint errors: %d" % eslint.error_count) msg_color = ex._TERM_RED if total_errors > 0 else ex._TERM_GREEN print("%s* total errors: %d%s" % (msg_color, total_errors, ex._TERM_EMPTY)) print() - return total_errors == 0 + if total_errors: + ex.fail("Failed tidy check") diff --git a/tools/common_py/path.py b/tools/common_py/path.py index c7c0141..ed7d145 100644 --- a/tools/common_py/path.py +++ b/tools/common_py/path.py @@ -52,9 +52,6 @@ TUV_ROOT = fs.join(DEPS_ROOT, 'libtuv') # Root directory for http-parser submodule. HTTPPARSER_ROOT = fs.join(DEPS_ROOT, 'http-parser') -# checktest -CHECKTEST_PATH = fs.join(TOOLS_ROOT, 'check_test.js') - # Build configuration file path. BUILD_CONFIG_PATH = fs.join(PROJECT_ROOT, 'build.config') diff --git a/tools/common_py/system/executor.py b/tools/common_py/system/executor.py index a8d721e..f372d54 100644 --- a/tools/common_py/system/executor.py +++ b/tools/common_py/system/executor.py @@ -52,6 +52,18 @@ class Executor(object): @staticmethod def run_cmd_output(cmd, args=[], quiet=False): + if not quiet: + Executor.print_cmd_line(cmd, args) + try: + process = subprocess.Popen([cmd] + args, stdout=subprocess.PIPE) + output = process.communicate()[0] + + return output + except OSError as e: + Executor.fail("[Failed - %s] %s" % (cmd, e.strerror)) + + @staticmethod + def check_run_cmd_output(cmd, args=[], quiet=False): if not quiet: Executor.print_cmd_line(cmd, args) try: diff --git a/tools/iotjs-create-module.py b/tools/iotjs-create-module.py new file mode 100755 index 0000000..020023d --- /dev/null +++ b/tools/iotjs-create-module.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python + +# Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors +# +# 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. + +from __future__ import print_function + +import os +import re + +IOTJS_BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) +TEMPLATE_BASE_DIR = os.path.join(os.path.dirname(__file__), 'module_templates') +MODULE_NAME_RE = "^[a-z0-9][a-z0-9\._]*$" + +def load_templates(template_dir): + for root, dirs, files in os.walk(template_dir): + for fp in files: + yield os.path.relpath(os.path.join(root, fp), template_dir) + + +def replace_contents(input_file, module_name): + with open(input_file) as fp: + data = fp.read() + data = data.replace("$MODULE_NAME$", module_name) + data = data.replace("$IOTJS_PATH$", IOTJS_BASE_DIR) + + return data + +def create_module(output_dir, module_name, template_dir, template_files): + module_path = os.path.join(output_dir, module_name) + print("Creating module in {}".format(module_path)) + + if os.path.exists(module_path): + print("Module path ({}) already exists! Exiting".format(module_path)) + return False + + for file_name in template_files: + file_path = os.path.join(template_dir, file_name) + print("loading template file: {}".format(file_path)) + contents = replace_contents(file_path, module_name) + output_path = os.path.join(module_path, file_name) + + # create sub-dir if required + base_dir = os.path.dirname(output_path) + if not os.path.exists(base_dir): + os.mkdir(base_dir) + + with open(output_path, "w") as fp: + fp.write(contents) + + return True + +def valid_module_name(value): + if not re.match(MODULE_NAME_RE, value): + msg = "Invalid module name, should match regexp: %s" % MODULE_NAME_RE + raise argparse.ArgumentTypeError(msg) + return value + +if __name__ == "__main__": + import argparse + import sys + + desc = "Create an IoT.js external module using a template" + parser = argparse.ArgumentParser(description=desc) + parser.add_argument("module_name", metavar="", nargs=1, + type=valid_module_name, + help="name of the new module ((must be in lowercase " + + "and should match regexp: %s)" % MODULE_NAME_RE) + parser.add_argument("--path", default=".", + help="directory where the module will be created " + + "(default: %(default)s)") + parser.add_argument("--template", default="basic", + choices=["basic", "shared"], + help="type of the template which should be used " + "(default: %(default)s)") + args = parser.parse_args() + + + template_dir = os.path.join(TEMPLATE_BASE_DIR, + "%s_module_template" % args.template) + template_files = load_templates(template_dir) + created = create_module(args.path, + args.module_name[0], + template_dir, + template_files) + if created: + module_path = os.path.join(args.path, args.module_name[0]) + print("Module created in: {}".format(os.path.abspath(module_path))) diff --git a/tools/js2c.py b/tools/js2c.py index da9bac6..3a8c488 100755 --- a/tools/js2c.py +++ b/tools/js2c.py @@ -55,7 +55,7 @@ def force_str(string): def parse_literals(code): - JERRY_SNAPSHOT_VERSION = 8 + JERRY_SNAPSHOT_VERSION = 12 JERRY_SNAPSHOT_MAGIC = 0x5952524A literals = set() @@ -237,7 +237,6 @@ def get_snapshot_contents(js_path, snapshot_tool): ret = subprocess.call([snapshot_tool, "generate", - "--context", "eval", "-o", snapshot_path, wrapped_path]) diff --git a/tools/measure_coverage.sh b/tools/measure_coverage.sh index fd00c2a..1f42862 100755 --- a/tools/measure_coverage.sh +++ b/tools/measure_coverage.sh @@ -48,10 +48,6 @@ print_usage() echo " --node-modules-dir Specifies the node_module directory, where" echo " the nodejs dependencies are installed." echo "" - echo " --testdriver Specifies the testrunner that should be used" - echo " for measuring JavaScript coverage." - echo " Possible values: jsdriver, pydriver" - echo "" echo " --target-board Specifies the target board, where the" echo " coverage measurement will happen." echo " Possible values: rpi2" @@ -76,9 +72,6 @@ fail_with_msg() exit 1 } -# Use Python based testrunner by default. -test_driver="pydriver" - # Parse the given arguments. while [[ $# -gt 0 ]] do @@ -89,10 +82,6 @@ do node_modules_dir="$2" shift ;; - --testdriver) - test_driver="$2" - shift - ;; --target-board) target_board="$2" shift @@ -204,15 +193,7 @@ else fi # Run the appropriate testrunner. -if [ $test_driver = "jsdriver" ]; -then - ${build_path}/bin/iotjs tools/check_test.js output-coverage=yes -elif [ $test_driver = "pydriver" ]; -then - python tools/testrunner.py ${build_path}/bin/iotjs --quiet --coverage -else - fail_with_msg "Not supported testdriver: $test_driver" -fi +python tools/testrunner.py ${build_path}/bin/iotjs --quiet --coverage # Revert to original module files rm -rf src/js diff --git a/tools/module_templates/basic_module_template/js/module.js b/tools/module_templates/basic_module_template/js/module.js new file mode 100644 index 0000000..33d708a --- /dev/null +++ b/tools/module_templates/basic_module_template/js/module.js @@ -0,0 +1,29 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +/** + * To export an object/value use the 'module.exports' object. + */ +var demo_value = "Hello"; + +/* Export an object with two properties. */ +module.exports = { + /* the 'native' means the object returned by the C init method. */ + demo2: function() { return native.message; }, + add: native.add +} + +/* Export a local variable. */ +module.exports.demo_value = demo_value; diff --git a/tools/module_templates/basic_module_template/module.cmake b/tools/module_templates/basic_module_template/module.cmake new file mode 100644 index 0000000..9a6e3b3 --- /dev/null +++ b/tools/module_templates/basic_module_template/module.cmake @@ -0,0 +1,41 @@ +# Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors +# +# 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. + +# General variables usable from IoT.js cmake: +# - TARGET_ARCH - the target architecture (as specified during cmake step) +# - TARGET_BOARD - the target board(/device) +# - TARGET_OS - the target operating system +# +# Module related variables usable from IoT.js cmake: +# - MODULE_DIR - the modules root directory +# - MODULE_BINARY_DIR - the build directory for the current module +# - MODULE_LIBS - list of libraries to use during linking (set this) +set(MODULE_NAME "$MODULE_NAME$") + +# DO NOT include the source files which are already in the modules.json file. + +# If the module builds its own files into a lib please use the line below. +# Note: the subdir 'lib' should contain the CMakeLists.txt describing how the +# module should be built. +#add_subdirectory(${MODULE_DIR}/lib/ ${MODULE_BINARY_DIR}/${MODULE_NAME}) + +# If you wish to link external libraries please add it to +# the MODULE_LIBS list. +# +# IMPORTANT! +# if the module builds its own library that should also be specified! +# +# Example (to add the 'demo' library for linking): +# +# list(APPEND MODULE_LIBS demo) diff --git a/tools/module_templates/basic_module_template/modules.json b/tools/module_templates/basic_module_template/modules.json new file mode 100644 index 0000000..a9acb4b --- /dev/null +++ b/tools/module_templates/basic_module_template/modules.json @@ -0,0 +1,10 @@ +{ + "modules": { + "$MODULE_NAME$": { + "js_file": "js/module.js", + "native_files": ["src/module.c"], + "init": "Init$MODULE_NAME$", + "cmakefile": "module.cmake" + } + } +} diff --git a/tools/module_templates/basic_module_template/src/module.c b/tools/module_templates/basic_module_template/src/module.c new file mode 100644 index 0000000..608764d --- /dev/null +++ b/tools/module_templates/basic_module_template/src/module.c @@ -0,0 +1,53 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 "iotjs_def.h" + +/** + * Demo method + */ +static jerry_value_t demo_method( + const jerry_value_t func_value, /**< function object */ + const jerry_value_t this_value, /**< this arg */ + const jerry_value_t *args_p, /**< function arguments */ + const jerry_length_t args_cnt) /**< number of function arguments */ +{ + if (args_cnt < 2) { + static char *error_msg = "Incorrect parameter count"; + return jerry_create_error(JERRY_ERROR_TYPE, + (const jerry_char_t *)error_msg); + } + + if (!jerry_value_is_number(args_p[0]) || !jerry_value_is_number(args_p[1])) { + static char *error_msg = "Incorrect parameter type(s)"; + return jerry_create_error(JERRY_ERROR_TYPE, + (const jerry_char_t *)error_msg); + } + + int arg_a = jerry_get_number_value(args_p[0]); + int arg_b = jerry_get_number_value(args_p[1]); + + return jerry_create_number(arg_a + arg_b); +} + +/** + * Init method called by IoT.js + */ +jerry_value_t Init$MODULE_NAME$() { + jerry_value_t mymodule = jerry_create_object(); + iotjs_jval_set_property_string_raw(mymodule, "message", "Hello world!"); + iotjs_jval_set_method(mymodule, "add", demo_method); + return mymodule; +} diff --git a/tools/module_templates/shared_module_template/CMakeLists.txt b/tools/module_templates/shared_module_template/CMakeLists.txt new file mode 100644 index 0000000..0f74117 --- /dev/null +++ b/tools/module_templates/shared_module_template/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors +# +# 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. + +# +# This is a standalone shared libray which +# only requires the iotjs and jerry header file(s). +# +cmake_minimum_required(VERSION 2.8) +set(NAME $MODULE_NAME$) + +set(IOTJS_INCLUDE_DIR "$IOTJS_PATH$/src") +set(JERRY_INCLUDE_DIR "$IOTJS_PATH$/deps/jerry/jerry-core/include") + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") + +add_library(${NAME} SHARED + src/module_entry.c) +target_include_directories(${NAME} + PRIVATE ${IOTJS_INCLUDE_DIR} ${JERRY_INCLUDE_DIR}) +set_target_properties(${NAME} PROPERTIES + PREFIX "" + SUFFIX ".iotjs") diff --git a/tools/module_templates/shared_module_template/README.md b/tools/module_templates/shared_module_template/README.md new file mode 100644 index 0000000..1452602 --- /dev/null +++ b/tools/module_templates/shared_module_template/README.md @@ -0,0 +1,18 @@ +# IoT.js module: $MODULE_NAME$ + +## How to build? + +In the source directory of the module: + +```sh +$ cmake -Bbuild -H. +$ make -C build +``` + +## How to test? + +In the source directory of the module: + +```sh +$ iotjs js/test.js +``` diff --git a/tools/module_templates/shared_module_template/js/test.js b/tools/module_templates/shared_module_template/js/test.js new file mode 100644 index 0000000..58c5585 --- /dev/null +++ b/tools/module_templates/shared_module_template/js/test.js @@ -0,0 +1,20 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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. + */ + +var console = require("console"); +var demomod = require("build/lib/$MODULE_NAME$"); + +console.log(demomod); + diff --git a/tools/module_templates/shared_module_template/src/module_entry.c b/tools/module_templates/shared_module_template/src/module_entry.c new file mode 100644 index 0000000..686077c --- /dev/null +++ b/tools/module_templates/shared_module_template/src/module_entry.c @@ -0,0 +1,32 @@ +/* Copyright 2018-present Samsung Electronics Co., Ltd. and other contributors + * + * 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 + +jerry_value_t init_$MODULE_NAME$(void) { + jerry_value_t object = jerry_create_object(); + + jerry_value_t prop_name = jerry_create_string((const jerry_char_t*)"demokey"); + jerry_value_t prop_value = jerry_create_number(3.4); + + jerry_set_property(object, prop_name, prop_value); + + jerry_release_value(prop_name); + jerry_release_value(prop_value); + + return object; +} + +IOTJS_MODULE(IOTJS_CURRENT_MODULE_VERSION, 1, $MODULE_NAME$) diff --git a/tools/test_runner.js b/tools/test_runner.js deleted file mode 100644 index 0b52f8a..0000000 --- a/tools/test_runner.js +++ /dev/null @@ -1,175 +0,0 @@ -/* Copyright 2016-present Samsung Electronics Co., Ltd. and other contributors - * - * 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. - */ - -var assert = require('assert'); -var util = require('util'); -var testdriver = require('testdriver'); -var console_wrapper = require('common_js/module/console'); -var builtin_modules = Object.keys(process.builtin_modules); - -function Runner(driver) { - this.driver = driver; - this.test = driver.currentTest(); - this.finished = false; - if (driver.skipModule) { - this.skipModule = driver.skipModule; - this.skipModuleLength = this.skipModule.length; - } else { - this.skipModuleLength = 0; - } - if (driver.options.quiet == 'yes') { - this.console = console; - console = console_wrapper; - } - - this.timeout = this.test['timeout']; - if (!this.timeout) { - this.timeout = driver.options['default-timeout']; - } - assert.assert(util.isNumber(this.timeout), "Timeout is not a number."); - - return this; -} - -Runner.prototype.cleanup = function() { - if (this.driver.options.quiet == 'yes') { - console = this.console; - } - - this.driver = null; - this.test = null; - if (this.timer != null) { - clearTimeout(this.timer); - this.timer = null; - } - if (this.timer_spin != null) { - clearTimeout(this.timer_spin); - this.timer_spin = null; - } -}; - -Runner.prototype.spin = function() { - var that = this; - this.timer_spin = setTimeout(function() { - var timerOnlyAlive = !testdriver.isAliveExceptFor(that.timer); - if (timerOnlyAlive) { - timerOnlyAlive = !process._onNextTick(); - } - - if (timerOnlyAlive) { - process.exit(0); - } else { - if (!that.finished) { - that.spin(); - } - } - }, 0); -}; - -Runner.prototype.checkSkipModule = function() { - for (var i = 0; i < this.skipModuleLength; i++) { - if (this.test['name'].indexOf(this.skipModule[i]) >= 0) { - return true; - } - } - - return false; -}; - -Runner.prototype.checkSupportedModule = function() { - // Cut off the '.js' ending - var name = this.test['name'].slice(0, -3); - - // test_mod_smt -> [test, mod, smt] - // test_modsmt -> [test, modsmt] - var parts = name.split('_'); - if (parts[0] != 'test') { - // test filename does not start with 'test_' so we'll just - // assume we support it. - return true; - } - - // The second part of the array contains the module - // which is under test - var tested_module = parts[1]; - for (var i = 0; i < builtin_modules.length; i++) { - if (tested_module == builtin_modules[i]) { - return true; - } - } - - // In any other case we do not support this js file. - return false; -} - -Runner.prototype.run = function() { - if (!this.checkSupportedModule()) { - this.test.reason = 'unsupported module by iotjs build'; - this.finish('skip'); - return; - } - - var skip = this.test['skip']; - if (skip) { - if ((skip.indexOf('all') >= 0) || (skip.indexOf(this.driver.os) >= 0) - || (skip.indexOf(this.driver.stability) >= 0)) { - this.finish('skip'); - return; - } - } - - if (this.skipModuleLength && this.checkSkipModule()) { - this.test.reason = 'exclude module'; - this.finish('skip'); - return; - } - - this.timer = null; - - var that = this; - this.timer = setTimeout(function () { - that.finish('timeout'); - }, this.timeout * 1000); - - try { - var source = this.driver.test(); - eval(source); - } catch(e) { - if (this.test['expected-failure']) { - this.finish('pass'); - } else if (this.test['uncaught']) { - throw e; - } else { - console.error(e); - this.finish('fail'); - } - } finally { - if (!this.finished) { - this.spin(); - } - } -}; - -Runner.prototype.finish = function(status) { - if (this.finished) - return; - - this.finished = true; - process._exiting = false; - - this.driver.emitter.emit('nextTest', this.driver, status, this.test); -}; - -module.exports.Runner = Runner; diff --git a/tools/testrunner.py b/tools/testrunner.py index 2a77cae..02957a8 100755 --- a/tools/testrunner.py +++ b/tools/testrunner.py @@ -18,6 +18,7 @@ from __future__ import print_function import argparse import json +import os import signal import subprocess import sys @@ -28,6 +29,7 @@ from common_py import path from common_py.system.filesystem import FileSystem as fs from common_py.system.executor import Executor as ex from common_py.system.platform import Platform +from jsonmerge import Merger # Defines the folder that will contain the coverage info. @@ -53,6 +55,14 @@ process.on('exit', function() {{ """ ) +JSON_SCHEMA = { + "properties": { + "run_pass": { + "mergeStrategy": "arrayMergeById", + "mergeOptions": { "idRef": "name"} + } + } +} # Append coverage source to the appropriate test. def append_coverage_code(testfile, coverage): @@ -144,17 +154,21 @@ class TestRunner(object): def __init__(self, options): self.iotjs = fs.abspath(options.iotjs) self.quiet = options.quiet + self.testsets = options.testsets self.timeout = options.timeout self.valgrind = options.valgrind self.coverage = options.coverage self.skip_modules = [] self.results = {} + self._environment = os.environ.copy() + self._environment["IOTJS_PATH"] = fs.dirname(self.iotjs) if options.skip_modules: self.skip_modules = options.skip_modules.split(",") # Process the iotjs build information. - iotjs_output = ex.run_cmd_output(self.iotjs, [path.BUILD_INFO_PATH]) + iotjs_output = ex.check_run_cmd_output(self.iotjs, + [path.BUILD_INFO_PATH]) build_info = json.loads(iotjs_output) self.builtins = build_info["builtins"] @@ -176,6 +190,13 @@ class TestRunner(object): with open(fs.join(path.TEST_ROOT, "testsets.json")) as testsets_file: testsets = json.load(testsets_file, object_pairs_hook=OrderedDict) + if self.testsets: + with open(fs.join(path.TEST_ROOT, self.testsets)) as testsets_file: + ext_testsets = json.load(testsets_file, + object_pairs_hook=OrderedDict) + merger = Merger(JSON_SCHEMA) + testsets = merger.merge(testsets, ext_testsets) + for testset, tests in testsets.items(): self.run_testset(testset, tests) @@ -210,7 +231,9 @@ class TestRunner(object): if not self.quiet: print(output, end="") - if not expected_failure or (expected_failure and exitcode <= 2): + is_normal_run = (not expected_failure and exitcode == 0) + is_expected_fail = (expected_failure and exitcode <= 2) + if is_normal_run or is_expected_fail: Reporter.report_pass(test["name"], runtime) self.results["pass"] += 1 else: @@ -237,7 +260,8 @@ class TestRunner(object): process = subprocess.Popen(args=command, cwd=path.TEST_ROOT, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) + stderr=subprocess.STDOUT, + env=self._environment) stdout = process.communicate()[0] exitcode = process.returncode @@ -292,6 +316,9 @@ def get_args(): help="show or hide the output of the tests") parser.add_argument("--skip-modules", action="store", metavar='list', help="module list to skip test of specific modules") + parser.add_argument("--testsets", action="store", + help="JSON file to extend or override the default " + "testsets") parser.add_argument("--timeout", action="store", default=300, type=int, help="default timeout for the tests in seconds") parser.add_argument("--valgrind", action="store_true", default=False, diff --git a/tools/travis_script.py b/tools/travis_script.py index 2429b75..c85fb70 100755 --- a/tools/travis_script.py +++ b/tools/travis_script.py @@ -29,7 +29,7 @@ DOCKER_ROOT_PATH = fs.join('/root') TRAVIS_BUILD_PATH = fs.join(os.environ['TRAVIS_BUILD_DIR']) # IoT.js path in docker -DOCKER_IOTJS_PATH = fs.join(DOCKER_ROOT_PATH, 'iotjs') +DOCKER_IOTJS_PATH = fs.join(DOCKER_ROOT_PATH, 'work_space/iotjs') DOCKER_TIZENRT_PATH = fs.join(DOCKER_ROOT_PATH, 'TizenRT') DOCKER_TIZENRT_OS_PATH = fs.join(DOCKER_TIZENRT_PATH, 'os') @@ -52,13 +52,16 @@ BUILDOPTIONS_SANITIZER = [ '--no-check-valgrind', '--no-snapshot', '--profile=test/profiles/host-linux.profile', + '--testsets=testsets-host-linux.json', + '--run-test=full', '--target-arch=i686' ] def run_docker(): - ex.check_run_cmd('docker', ['run', '-dit', '--name', DOCKER_NAME, '-v', + ex.check_run_cmd('docker', ['run', '-dit', '--privileged', + '--name', DOCKER_NAME, '-v', '%s:%s' % (TRAVIS_BUILD_PATH, DOCKER_IOTJS_PATH), - 'iotjs/ubuntu:0.3']) + 'iotjs/ubuntu:0.6']) def exec_docker(cwd, cmd): exec_cmd = 'cd %s && ' % cwd + ' '.join(cmd) @@ -82,13 +85,18 @@ if __name__ == '__main__': test = os.getenv('OPTS') if test == 'host-linux': - build_iotjs('debug', [ - '--profile=profiles/minimal.profile']) + for buildtype in BUILDTYPES: + build_iotjs(buildtype, [ + '--cmake-param=-DENABLE_MODULE_ASSERT=ON', + '--run-test=full', + '--profile=profiles/minimal.profile', + '--testsets=testsets-minimal.json']) for buildtype in BUILDTYPES: build_iotjs(buildtype, [ - '--run-test', - '--profile=test/profiles/host-linux.profile']) + '--run-test=full', + '--profile=test/profiles/host-linux.profile', + '--testsets=testsets-host-linux.json']) elif test == 'rpi2': for buildtype in BUILDTYPES: @@ -108,7 +116,7 @@ if __name__ == '__main__': if buildtype == 'release': set_release_config_tizenrt() exec_docker(DOCKER_TIZENRT_OS_PATH, [ - 'make', 'IOTJS_ROOT_DIR=../../iotjs', + 'make', 'IOTJS_ROOT_DIR=' + DOCKER_IOTJS_PATH, 'IOTJS_BUILD_OPTION=' '--profile=test/profiles/tizenrt.profile']) @@ -133,43 +141,52 @@ if __name__ == '__main__': 'make', 'all', 'IOTJS_ROOT_DIR=' + DOCKER_IOTJS_PATH, rflag]) + elif test == 'tizen': + for buildtype in BUILDTYPES: + if buildtype == "debug": + exec_docker(DOCKER_IOTJS_PATH, [ + 'config/tizen/gbsbuild.sh', + '--debug', '--clean']) + else: + exec_docker(DOCKER_IOTJS_PATH, ['config/tizen/gbsbuild.sh', + '--clean']) + elif test == "misc": ex.check_run_cmd('tools/check_signed_off.sh', ['--travis']) - if not check_tidy(TRAVIS_BUILD_PATH): - ex.fail("Failed tidy check") + exec_docker(DOCKER_IOTJS_PATH, ['tools/check_tidy.py']) elif test == "external-modules": for buildtype in BUILDTYPES: build_iotjs(buildtype, [ - '--run-test', + '--run-test=full', + '--testsets=testsets-external-modules.json', '--profile=test/profiles/host-linux.profile', '--external-modules=test/external_modules/' 'mymodule1,test/external_modules/mymodule2', '--cmake-param=-DENABLE_MODULE_MYMODULE1=ON', '--cmake-param=-DENABLE_MODULE_MYMODULE2=ON']) - binary = fs.join('build', - platform.arch() + '-' + platform.os(), - buildtype, 'bin', 'iotjs') - ext_mod_tests = [ - 'test/external_modules/test_external_module1.js', - 'test/external_modules/test_external_module2.js'] - # TODO: Use testrunner to run an extended test set - for test in ext_mod_tests: - exec_docker(DOCKER_IOTJS_PATH, [binary, test]) + + elif test == 'es2015': + for buildtype in BUILDTYPES: + build_iotjs(buildtype, [ + '--run-test=full', + '--jerry-profile=es2015-subset', + '--testsets=testsets-es2015.json']) elif test == "no-snapshot": for buildtype in BUILDTYPES: - build_iotjs(buildtype, ['--run-test', '--no-snapshot', + build_iotjs(buildtype, ['--run-test=full', '--no-snapshot', '--jerry-lto']) elif test == "host-darwin": for buildtype in BUILDTYPES: ex.check_run_cmd('./tools/build.py', [ - '--run-test', + '--run-test=full', '--buildtype=' + buildtype, '--clean', - '--profile=test/profiles/host-darwin.profile']) + '--profile=test/profiles/host-darwin.profile', + '--testsets=testsets-host-linux.json']) elif test == "asan": ex.check_run_cmd('./tools/build.py', [